Skip to content

Tick libghostty on wakeup instead of a 120Hz timer#125

Merged
thdxg merged 2 commits into
mainfrom
wakeup-driven-tick
Jul 4, 2026
Merged

Tick libghostty on wakeup instead of a 120Hz timer#125
thdxg merged 2 commits into
mainfrom
wakeup-driven-tick

Conversation

@thdxg

@thdxg thdxg commented Jul 4, 2026

Copy link
Copy Markdown
Owner

What

Replaces the unconditional 120Hz ghostty_app_tick timer with event-driven ticking via libghostty's wakeup_cb (already wired — GhosttyCallbacks.wakeup schedules tick() on the main queue), keeping a 1s safety-net timer so a missed wakeup degrades to a late tick rather than a wedged UI.

Why

Profiling the post-#115/#123 idle residue showed the 120Hz timer is the largest remaining constant wakeup source — 120/sec even while hidden. Upstream libghostty's own contract is demand-driven: "Tick the event loop. This should be called whenever the 'wakeup' callback is invoked for the runtime" (src/apprt/embedded.zig). The fixed timer was never the intended mechanism; this makes Macterm follow the documented contract, the same way Ghostty.app does.

Verified

Measured head-to-head, debug builds, idle:

main (120Hz timer) this PR
idle CPU ~1.1% ~0.2%
120Hz timer in sample present (GhosttyApp.swift:66, ghostty_app_tick firing) gone — zero tick frames
  • mise run format, mise run lint, mise run test all pass
  • Measured: the 120Hz wakeups are eliminated and idle CPU drops ~5×
  • Verified against upstream libghostty docs that wakeup_cb is the intended on-demand tick driver, and confirmed the wakeup_cb → wakeup() → tick() path is intact and unconditional

Not yet observed live: a keypress→echo confirmation in the running app (my verification build launched with no project selected, so there was no surface to type into). The CPU win is measured and the wakeup contract is upstream-documented, but the empirical input loop is best confirmed by running this branch alongside #126 as a daily driver — a wedged terminal would be immediately obvious. Recommend merging together after that pass.

🤖 Generated with Claude Code

GhosttyApp ran a 120Hz repeating timer calling ghostty_app_tick forever
— 120 wakeups/sec even with the app hidden, the largest remaining idle
cost after #115. The timer was redundant: libghostty's wakeup_cb already
requests a tick whenever the core needs one (GhosttyCallbacks.wakeup
schedules it on the main queue), which is how upstream Ghostty.app
drives ticking.

A 1s safety-net timer (0.5s tolerance) remains so a hypothetically
missed wakeup degrades to a one-second-late tick instead of a wedged
UI.
@github-actions github-actions Bot added the area:terminal Terminal surface, ghostty integration label Jul 4, 2026
@thdxg thdxg marked this pull request as ready for review July 4, 2026 08:05
@thdxg thdxg enabled auto-merge (squash) July 4, 2026 08:05
@thdxg thdxg merged commit 5f5b4df into main Jul 4, 2026
5 checks passed
@thdxg thdxg deleted the wakeup-driven-tick branch July 4, 2026 08:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:terminal Terminal surface, ghostty integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant