Skip to content

perf(studio): an idle editor stops waking the GPU four times a second - #6109

Merged
vanceingalls merged 2 commits into
mainfrom
perf/studio-overlay-idle-backoff
Oct 23, 2026
Merged

vanceingalls merged 2 commits into
mainfrom
perf/studio-overlay-idle-backoff

Conversation

@vanceingalls

@vanceingalls vanceingalls commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

What

The overlay frame loop's safety-net poll (IDLE_POLL_MS, overlayFrameLoop.ts) requested one animation frame every 250 ms for as long as an editor stayed open. Each frame request restarts the display's vsync (a fresh CVDisplayLink on macOS) for a few frames, so a paused, untouched editor kept the GPU process waking ~65 times a second, the main idle battery cost in HyperFrames Desktop with a project open.

Now the poll:

  • doubles its wait after each idle frame, 250 ms → 4 s (MAX_IDLE_POLL_MS), and resets to 250 ms on any wake. A missed wake is likeliest right after activity (a CSS transition no event reports), which is when the poll is still fast.
  • stops while document.hidden; visibilitychange is already a wake source.

No visible change

The overlays track the same geometry on the same wake sources; only how often an idle, untouched editor polls changes. Under 20 source lines, no .tsx/.css/.html.

Measured

HyperFrames Desktop at origin/main (studio 0.8.186), paused project, 20 s of app.getAppMetrics() per run, M4 Pro. Baseline vs this change applied to the same 0.8.186 dist (two runs):

  • GPU process idle wakeups: 167/s → 24 and 31/s
  • Renderer idle wakeups: 40/s → 13 and 18/s
  • App CPU: 0.84% → 0.38 and 0.41%

Home and playback are unchanged (other sources dominate there). Earlier isolation on the same build: removing only this loop's idle rAFs took a paused project's GPU wakeups from 85/s to 20/s. Method and charts: https://www.heygenverse.com/a/efa8d156-d36a-4c3e-80c7-c9b1a4f07dcf

Tests

Two new cases in overlayFrameLoop.test.ts: the poll backs off and comes back fast after a wake, and no poll is armed while hidden. Both fail on main (47 polls in 12 s idle, where ≤4 is expected; 31 polls while hidden, where ≤1 is expected). All 15 pass with the change.

Not exercised

No Studio walk in a browser; the measurement is Desktop's embedded Studio. A missed wake source now costs up to 4 s of overlay staleness after long idle instead of 250 ms; none was seen, but the wake sources were not exhaustively audited.

🤖 Generated with Claude Code

The overlay frame loop's safety-net poll requested one animation frame every
250 ms for as long as the editor stayed open. Each request restarts the
display's vsync for a few frames, so a paused, untouched editor kept the GPU
process waking ~65 times a second. The poll now doubles its wait after each
idle frame up to 4 s, resets to 250 ms on any wake, and stops while the page
is hidden (visibilitychange already wakes it).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 154 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

Unstable (1)

  • seqheldtwice-tlhold-px-r0-root-z100: tracking 120.29, pressJump 312.3, drop 0, reload 0, render 0.02, renderKey -, undo true, teleport false / tracking 0.08, pressJump 0.11, drop 0.35, reload 0.35, render 0.02, renderKey -, undo true, teleport true / tracking 0.08, pressJump 0.11, drop 0.35, reload 0.35, render 0.02, renderKey -, undo true, teleport true

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 0 blocker · 0 important · 1 nit · head 3a61eba5

While the page is hidden, nothing is armed, and it re-arms correctly: visibilitychange fires at document and bubbles to the capture listener on window. A pending rAF simply waits until the page is visible again. Every wake resets the backoff. CI is green on this head (the red PR captures run was superseded by a passing one).

  • nit: the module header (overlayFrameLoop.ts:16-17) still says a missed wake costs "a quarter second of staleness". After long idle it is now up to 4 s (MAX_IDLE_POLL_MS), as the PR body says.

— Genesis (Claude)

@vanceingalls
vanceingalls added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit 6ad7c82 Oct 23, 2026
104 of 105 checks passed
@vanceingalls
vanceingalls deleted the perf/studio-overlay-idle-backoff branch October 23, 2026 21:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant