Files
saphid--frame-control/bench/pages/present.html
T
saphidandClaude Opus 5.5 9e4dcdd147 Mac in the headset: measure every frame, adapt to the network, separate windows
- Per-frame timing on the Mac's clock (capture, encode, network, decode,
  draw), viewer clock sync and reports, input echo, /stats and a HUD.
- scripts/macview-bench.py: repeatable runs on the real Frame, a shaping
  relay (no sudo), interleaved A/B between agent settings; results in
  bench/results/.
- Adaptive controller: ack-based send gate with jitter-aware slack, AIMD
  bitrate that knows when a stream is app-limited, fps then size tiers.
  On a 50->3->50 Mbit/s step, scroll p95 went from 4.7 s to 72 ms; no cost
  on a clean link.
- Separate mode: real AppKit event loop (HiDPI and NSScreen now work),
  cropped capture for fixed-size windows, windows kept on their display,
  graceful quit restores windows; stop/start races fixed.
- Encoder timeline clamp (no oversized frame after a pause).
- Frame Control shows each live stream's fps, delay, bitrate and tier.

Reviewed by GPT-6 Astra xhigh (read-only), 7 rounds; findings fixed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 20:56:14 +10:00

25 lines
1.3 KiB
HTML

<!doctype html>
<!-- Control experiment, run on the Frame itself: how often does Chromium on
gamescope put a canvas animation on screen, with no network or decoding
involved? Draws every animation frame for ?s= seconds and writes the
frame-gap histogram per second into the title, where xprop can read it. -->
<html><head><meta charset="utf-8"><title>fmv-present</title></head>
<body style="margin:0;background:#000"><canvas id="c" width="1280" height="720" style="width:100%;height:100%"></canvas>
<script>
const q = new URLSearchParams(location.search), secs = +q.get("s") || 15, tag = q.get("tag") || "";
const ctx = document.getElementById("c").getContext("2d", { alpha: false, desynchronized: true });
const perSec = []; let t0 = 0, last = 0, n = 0, gaps = [];
function frame(t) {
if (!t0) t0 = last = t;
ctx.fillStyle = "#123"; ctx.fillRect(0, 0, 1280, 720);
ctx.fillStyle = "#fff"; ctx.fillRect((n * 21) % 1280, 0, 20, 720); n++;
const s = Math.floor((t - t0) / 1000);
(perSec[s] = perSec[s] || []).push(t - last); last = t;
if (t - t0 < secs * 1000) return requestAnimationFrame(frame);
const out = perSec.map(g => g.length).join(",");
document.title = `[${tag}] done fps/s=${out}`;
}
document.title = `[${tag}] running`;
requestAnimationFrame(frame);
</script></body></html>