perf(harness): add 2D-highway frame-time measurement + capture the R3c gate (H0) (#848)

* perf(harness): add 2D-highway frame-time measurement + capture the R3c gate (H0)

scripts/perf-baseline.mjs gains a `--song` mode: it wraps requestAnimationFrame
before any page script, TAGS the frames the highway actually painted (via
highway.addDrawHook), starts playback, and reports draw-frame p50/p95/p99 over
`--frames` seconds across `--runs` runs. Tagging is the point — ~half the rAF
callbacks are other cheap loops (~0.1 ms); averaging them in would hide a
renderer regression, so only draw frames are counted.

This is the metric the plan says gates the highway.js split (R3c) but the harness
never measured (it did server latency + boot + heap only, and the R0 numbers were
against an empty library). docs/perf-baseline.md now records the pre-lift baseline
on the Arcturus feedpak: p50 ~2.2 ms, p95 spread 2.7-3.2 ms across 3 runs. The
H-container lift (next) re-runs this on the same box and must stay within noise.

Maintainer/CI-only tooling; the existing no-`--song` run is unchanged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* perf(harness): close page on error + MD040 fence + CHANGELOG (CodeRabbit)

- frameTimeOnce now closes its page in a finally, so a failing run doesn't leak
  the page until the final browser.close() (CodeRabbit).
- fenced code block gets a bash language hint (MD040).
- CHANGELOG mentions the new --song frame-time mode.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Byron Gamatos
2026-07-10 23:15:07 +02:00
committed by GitHub
co-authored by Claude Opus 4.8
parent cbc65458e3
commit b6098e3695
3 changed files with 113 additions and 4 deletions
+25
View File
@@ -37,6 +37,31 @@ the hooks, they just need real songs in `DLC_DIR`.
## Results
### R3c pre-lift baseline — 2026-07-10 (2D highway draw cost)
The gate for the `highway.js` split. Captured on a seeded library (the 33 MB
Arcturus feedpak) with the new `--song` mode, which measures **per-frame draw
cost** — rAF callbacks are tagged via `highway.addDrawHook`, so only frames the
highway actually painted count (the other ~half are cheap no-op loops that would
otherwise mask a regression). Any `highway.js` change must re-run this on the
same machine and stay within noise of these numbers.
```bash
node scripts/perf-baseline.mjs --base http://127.0.0.1:8300 \
--song "Arcturus - The Sham Mirrors - Kinetic.feedpak"
```
| run | draw frames | p50 | p95 | p99 | max |
|---|---|---|---|---|---|
| 1 | 53/106 | 2.2 | 3.2 | 3.6 | 3.6 |
| 2 | 50/100 | 2.2 | 2.9 | 3.2 | 3.2 |
| 3 | 53/106 | 2.1 | 2.7 | 3.5 | 3.5 |
**p50 ≈ 2.2 ms · p95 spread 2.73.2 ms** (3 runs × 10 s playback, headless
chromium on the dev box). The `H`-container lift changes each closure-slot read
to a `H.<slot>` property load; this is the number that proves it doesn't cost the
hot loop.
### R0 baseline — 2026-07-08 (branch `feat/r0-plugin-module-rails`)
> ⚠️ A quick capture (`--n 50 --soak 8`) against an **empty** library (no charts