Repository navigation
Description
Host GPU/CPU stays high while an agent spinner dirties a large local surface
Environment
- herdr
0.9.1-preview.2026-09-21-0ff0f27e2226 - macOS 26.6.2 (build 25G83), Apple M1 Max, 10 cores, 32 GB, arm64
- Host terminal: Ghostty 1.3.1 (local client, not SSH)
[experimental] reveal_hidden_cursor_for_cjk_ime = falsealreadyherdr --default-confighas no FPS, idle-throttle, or spinner interval key.[advanced]only documentsscrollback_limit_bytes.- At this revision
MIN_RENDER_INTERVALis hardcoded to 16ms (src/app/mod.rs) and applied bycan_render_now/can_present_now(src/app/runtime.rs). That is a cadence cap when a render is already needed, not proof of a 60fps idle loop.
What happens
With at least one agent pane producing a spinner (no requirement that the agent be "busy" in herdr's status sense — a waiting CLI still writes frames):
- Ghostty sustained about 43–55% of one core across repeated 40s
psTIME deltas on 2026-09-23/24, and 53.6% on one 40.05s delta on 2026-09-24 (231:07.46→231:28.94) while an agent session was active. - Same 2026-09-24 window:
herdr server4.6%,herdrclient 0.5%. - On the earlier passes, WindowServer sat around 35–45%. Stack samples of Ghostty were dominated by glyph work (
addGlyph/rebuildRow/renderGlyph), i.e. the host terminal rasterizing updates, not herdr's own process. - Reported surface at the time of those passes: about 554×109 (client) and 594×109 (surface). Geometry was not re-measured on 2026-09-24.
changed_rows in src/server/headless/retained_surface.rs at this revision already emits a changed cell run (plus one following cell for wide-glyph coverage), not a mandatory full-width row, as long as the dirty snapshot is valid. The expensive part observed here is still on the far side of that update: Ghostty rebuilds glyphs for a very wide row often enough to pin a core, and WindowServer composites it. MIN_RENDER_INTERVAL of 16ms means a spinner that dirties a cell every tick can present up to ~62fps.
This is adjacent to, not the same as:
- Excessive remote bandwidth during CLI animations (~3.6 GB/hour per pane on full surface redraws) #4264 (remote SSH/TCP bandwidth from full surface frames during CLI animation)
- Server burns 10+ CPU cores with many populated agent panes #4506 (herdr server burning many cores)
- Running multiple agents simultaneously causes severe lag, high resource usage, and noisy fans on macOS after upgrading to v0.8.2 #3217 (multi-agent lag / fans on macOS)
Proposal
Add an opt-in coalesce for high-frequency, tiny PTY updates (spinners) before they are presented to the host terminal. Suggested key, default = current behavior:
[advanced]
# Minimum interval between presenting spinner-scale pane updates
# to the host terminal. 0 or unset = today's MIN_RENDER_INTERVAL (16ms).
spinner_render_interval_ms = 100Either a dedicated key or a broader "idle output throttle" is fine. Requirements:
- Default remains 16ms so existing sessions do not change.
- Apply only to small dirty runs (a few cells), not to real streaming transcript output.
- Coalesce in the presenter (drop or merge intermediate spinner frames). Do not busy-wait.
- A 100ms cap would still look animated and would cut host rasterization by roughly 6× versus a 16ms tick, which is the cost center on a ~550-column Ghostty surface.
- Please do not treat herdr status glyphs (
●/◐) as the fix. Those are static. The frames come from the pane's own CLI spinner.
Happy to re-measure with the same 40s ps TIME delta after a build. I have not attached a sample trace here.
Activity
ogulcancelik commentedon Sep 23, 2026
i tested the exact reported herdr preview on macos 26.6.2 with ghostty 1.3.1, using a one-cell spinner over a 568×108 text area on an m2 max.
at 60 hz, 40-second cpu measurements showed ghostty at about 21% directly versus 24% through herdr. windowserver was about 34% directly versus 35–37% through herdr. herdr’s client used about 1.2% and its server about 3.9%. the small-patch path was working.
i didn’t reproduce the full ghostty cpu figure, but most of the animation cost also occurs without herdr. i’m closing this rather than adding a spinner-specific throttle on this evidence.
if you can show a larger herdr-specific difference, please open a new issue using the bug template and link this one. include the agent cli/version, exact reproduction steps, and a direct-versus-herdr comparison. please keep proposed implementations out of the bug report.
perf: avoid redundant client ANSI encoding work (#4552)
kangal-bot commentedon Sep 24, 2026
Implemented on master and queued for the next release. This is not available in a published Herdr release yet.
kangal-bot commentedon Sep 28, 2026
Released on the preview channel in 2026-09-28-80c0c07250d2. This is available to preview users, but is not in a stable Herdr release yet.
sege66 commentedon Sep 28, 2026
The preview feed (
https://herdr.dev/preview.json) still points tobuild_id: 2026-09-21-0ff0f27e2226, and2026-09-28-80c0c07250d2isn't in thebuildsmap either (checked 2026-09-29 with cache-busting). So for a preview install on 09-21,herdr updatereports up to date and the 09-28 build can't be reached from the channel.Manually installing the release binary doesn't stick either: the updater treats the manifest
build_idas the expected preview build, so the next launch detects the mismatch and reinstalls 09-21 over it (observed a fresh binary write plus arelease-notes.jsonrewrite on the next start).Could the preview feed be promoted to 09-28?
kangal-bot commentedon Sep 29, 2026
Released in v0.9.2.
merge: upstream herdrdev/herdr into fork master (round 36)
perf(port): preserve cursor appearance through upstream rendering upd…
kangal-bot commentedon Oct 12, 2026
Released on the preview channel in 2026-10-12-6d697e1e75ff. This is available to preview users, but is not in a stable Herdr release yet.
perf: avoid redundant client ANSI encoding work (herdrdev#4552)