Files
hyperframes/packages/studio/tests/e2e/studio-runtime-cost.baseline.json
Miguel Angel Simon Sierra b5571f758c test(studio): measure idle CPU, scrub, request volume and switch retention
Open time is one number at one instant. It cannot see the CPU Studio burns
while idle, the full-document media scan every scrub frame, the same media file
fetched eight times on open, or the heap kept after a project switch. This adds
a browser gate for all four and the baseline they read today, before any fix.

The idle window samples consecutive ten-second windows until the style-recalc
count settles rather than sleeping: the first window on a media project drains
the thumbnail-extraction backlog and reads 56% of a core against a flat steady
state, so a fixed sleep would gate on a transient. Animation-frame scheduling is
attributed by call site in every frame, which is what makes a future regression
debuggable rather than merely red.

The scrub window counts full-document video/audio queries during a synthetic
playhead drag, patched in every frame — all of those queries happen inside the
preview iframe, not the Studio document.

The Chrome resolver both e2e gates need moves to a shared puppeteerEnv module.
2026-08-03 21:51:43 -07:00

125 lines
7.0 KiB
JSON

{
"note": "What the build cost on the day the gate was written, before any fix landed. Every number here is a browser measurement from tests/e2e/studio-runtime-cost.mjs; none is a target. Targets live in src/lib/studioRuntimeBudgets.ts, and every window below is red against them today.",
"capturedAt": "2026-08-01",
"commit": "0ac09e1f8",
"branch": "perf/studio-real-projects",
"machine": {
"model": "Apple M4 Pro",
"os": "darwin 26.5.1",
"architecture": "arm64",
"cores": 14,
"totalMemoryBytes": 25769803776,
"browser": "Chrome/150.0.7871.24 (headless)",
"server": "Studio Vite dev server on http://localhost:5190"
},
"caveat": "The dev server is not the build users run. These numbers are a regression signal and the baseline the fixes are measured against, not a product claim.",
"runToRunVariance": "A repeat run of the fixture arm reproduced every window: idle 60.0 recalcs/s and 13.5% of a core, scrub 157 queries, open 8.38x, switch 0.38 MB per cycle. Counting assertions repeat exactly; CPU fraction, byte totals and heap slope move by a few percent.",
"arms": {
"fixture": {
"what": "Generated by tests/e2e/generateStudioLoadFixture.mjs into data/projects/ (gitignored). studio-runtime-cost-a: 133 clips, 12 tracks, 20 media sources, 140 media clips (7 clips per source). studio-runtime-cost-b: 90 clips, 15 sources, 105 media clips.",
"command": "STUDIO_URL=http://localhost:5190 bun tests/e2e/studio-runtime-cost.mjs",
"idle": {
"styleRecalcsPerWindow": [759, 600, 601, 600],
"quiescentWindowIndex": 3,
"cpuFractionOfCore": 0.1358,
"styleRecalcsPerSecond": 60,
"layoutsPerSecond": 0,
"animationFrameCallsPerSecond": 303,
"animationFrameCallsPerWindowBySite": {
"studio-document": {
"update (src/components/editor/SnapGuideOverlay.tsx:52:15)": 600,
"update (src/components/editor/useDomEditOverlayRects.ts:77:15)": 600,
"update (src/components/editor/useDomEditCompositionRect.ts:22:15)": 600,
"update (src/components/editor/offCanvasIndicatorRefresh.ts:40:13)": 600
},
"preview-iframe": {
"ia (api/runtime.js) — transportTick": 600,
"jc (api/runtime.js)": 30
}
}
},
"scrub": {
"fullDocumentMediaQueries": 157,
"perDragStep": 3.93,
"allInPreviewIframe": true
},
"open": {
"requests": 842,
"bytes": 29538065,
"mediaRequests": 65,
"distinctMediaSources": 8,
"mediaRequestsPerDistinctSource": 8.13,
"imageRequests": 15,
"distinctImageSources": 13
},
"switch": {
"cycles": 8,
"jsHeapUsedMbPerCycle": [60.26, 59.91, 60.5, 61.43, 62.53, 62.19, 62.67, 62.39],
"heapBytesPerCycle": 432052,
"nodeDriftSameProject": 35,
"listenerDriftSameProject": 9,
"documentDriftSameProject": 0
}
},
"realProject": {
"what": "eliana-montage (273 clips: 77 video, 23 audio, 263 images) alternating with biweekly-2026-07-31 (35 clips). Not in the repo; symlinked into data/projects/ for this capture. Recorded so the fixture arm can be trusted to stand in for a real project.",
"command": "STUDIO_URL=http://localhost:5190 STUDIO_RUNTIME_PROJECTS=eliana-montage,biweekly-2026-07-31 bun tests/e2e/studio-runtime-cost.mjs",
"idle": {
"styleRecalcsPerWindow": [1085, 1112, 1118],
"firstWindowLayouts": 129,
"quiescentWindowIndex": 2,
"cpuFractionOfCore": 0.2713,
"styleRecalcsPerSecond": 111.8,
"layoutsPerSecond": 0,
"animationFrameCallsPerSecond": 338.2,
"animationFrameCallsPerWindowBySite": {
"studio-document": {
"update (src/components/editor/SnapGuideOverlay.tsx:52:15)": 559,
"update (src/components/editor/useDomEditOverlayRects.ts:77:15)": 559,
"update (src/components/editor/useDomEditCompositionRect.ts:22:15)": 559,
"update (src/components/editor/offCanvasIndicatorRefresh.ts:40:13)": 559
},
"preview-iframe": {
"ia (api/runtime.js) — transportTick": 559,
"Al (gsap.min.js) — GSAP ticker": 559,
"jc (api/runtime.js)": 28
}
}
},
"scrub": {
"fullDocumentMediaQueries": 124,
"perDragStep": 3.1,
"allInPreviewIframe": true
},
"open": {
"requests": 1771,
"bytes": 233769675,
"mediaRequests": 435,
"distinctMediaSources": 79,
"mediaRequestsPerDistinctSource": 5.51,
"imageRequests": 529,
"distinctImageSources": 264
},
"switch": {
"cycles": 8,
"jsHeapUsedMbPerCycle": [73.02, 73.94, 94.14, 74.79, 76.93, 75.38, 74.84, 75.73],
"heapBytesPerCycle": 314008,
"nodeDriftSameProject": 40,
"listenerDriftSameProject": 9,
"documentDriftSameProject": 1
}
}
},
"agreementWithTheProblemFrame": {
"idleBacklogThenSteadyState": "Reproduced. The real project's first window carries 129 layouts and 56% of a core; every window after it has ZERO layouts and a flat recalc count. A fixed sleep would have gated on the first window.",
"idleStyleRecalcRate": "Reproduced: 111.8/s measured against 120/s in the Problem Frame — two per frame at 60fps.",
"idleCpu": "27.1% of a core measured against 16-17% in the Problem Frame. Same order, not the same number: this capture is headless Chrome against a Vite dev server. The deterministic counts agree; the CPU fraction is environment-sensitive, which is why the gate carries a constrained tier.",
"idleCallSites": "Reproduced exactly: SnapGuideOverlay, useDomEditOverlayRects, useDomEditCompositionRect, offCanvasIndicatorRefresh in the Studio document, plus transportTick and the GSAP ticker inside the preview iframe.",
"scrub": "Every full-document media query happens inside the preview iframe; the Studio document issues none. Roughly three to four per drag step.",
"openAmplification": "Reproduced: 79 distinct media sources and 264 distinct images on the real project, matching the Problem Frame's 79 and 263. The request ratio measured 5.5x against 4.3x reported.",
"openBytes": "233.8 MB measured against 534.6 MB reported. This gate sums CDP encodedDataLength — bytes actually moved over the wire — so requests served from the browser cache contribute nothing. The request COUNT (1,771 against 1,737) agrees closely, so the difference is accounting, not behaviour.",
"switchRetention": "Reproduced: monotonic heap growth of 0.31 MB per cycle on the real project and 0.43 MB on the fixture, against ~0.5 MB reported, with nodes, listeners and documents flat."
},
"verdictToday": "All four windows fail. idle CPU 13.6% vs 1% budget; idle recalcs 60/s vs 5/s; idle animation-frame calls 303/s vs 5/s; scrub 157 full-document media queries vs 0; open 8.13x per distinct media source vs 1.2x; switch 0.41 MB per cycle vs 0.10 MB."
}