renderer, termio: count each surface's thread wakes by source
Summary
ghostty_surface_render_counters gains seven fields at the end of the struct. They count each surface's thread wakes by source:
- renderer thread: the wakeup async, the draw-now async, and the cursor blink, animation and scrollback-compression timer fires
- termio thread: the wakeup async, and its timer fires (resize coalesce, synchronized-output reset, selection scroll)
Each count is one relaxed atomic add in a callback that already runs. No behavior changes.
Why
cmux keeps hidden terminals live (its warm set). On cmux24, 24 busy hidden terminals at a warm cap of 25 woke the app 181.8 times a second, against 76.9 at a cap of 8. None of those wakeups were on the main thread.
cmux's own counters show that its output path already runs once per hidden output batch. So the remaining cost, about 2.4-3.4 wakeups a second while idle plus 3-4 per batch for each live hidden terminal, is on the surface's own threads. These counts name the source, per surface, so a cmux test can bound it exactly (cmux SWITCH FRAMES, "hidden output" row).
Base
This is based on release/cmux-9ce9b7d0-e2 (34e73ba8b), the cmux pin, so that one GhosttyNextKit pin bump takes only this change. The struct grows at its end; the existing fields keep their offsets.
Test plan
- Fork CI builds the xcframework for this PR.
- The cmux red test (branch
fix/hidden-terminal-wakeups) reads these counts for live hidden surfaces.
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Adds per-surface thread wake counters to ghostty_surface_render_counters so a cmux test can bound the cost of keeping hidden terminals alive. Each counter is a relaxed atomic add in an existing callback; no behavior changes.
- Renderer thread counters: wakeup async, draw-now async, and cursor blink, animation, and scrollback-compression timer fires.
- Termio thread counters: wakeup async and timer fires (resize coalesce, synchronized-output reset, selection scroll).