bench-terminal-resize: pane check samples each window's frames; unsampled or lagging terminals fail

Closed
LA
10h ago
+202-69

Replaces #36223. Same four commits, cherry-picked onto feat-cmux-next after #36109 merged as one squashed commit (the source, test and bench files are byte-equal to #36223's head ed6ba2075bb). Review of #36109 (comment 6650044486) plus frame-owner-s4's later rules.

Summary

  • Sampler on the window's frames. The pane check sampled on the screen's display link (FrameScheduler.app). Each window that shows a followed terminal now has a FrameClient on FrameScheduler.forWindow(window), the clock its springs and frame presenter tick on. An observer after Core Animation's commit (beforeWaiting, order CFIndex.max) samples only the windows whose frame ticked in that turn. A sample is the geometry that turn's commit carried for that window's frame. The doc comment says exactly this.
  • An unsampled terminal fails. A terminal shown at the round's start with 0 sampled frames fails the round (" was not sampled"). It used to pass on the other terminals' frames.
  • A lagging frame fails. frame-owner-s4 set this rule under the m14 contract: a late frame is a failure. A frame whose layer shows another size than its pane after that frame's commit fails the round. The message names the terminal, its lagging frames and the first sizes. lagging_frames stays in the report.
  • The docstring is fixed. It named DebugTerminalPaneFollow, which does not exist; it now names TerminalPaneFollowProbe.
  • New data to explain lag. Each terminal adds in_flight: frames where a size was asked of Ghostty and was not shown yet. The stop reply adds follow_presenter: the frame presenters' passes, presented, keeps, group waits and fallbacks in the run. The bench carries both into each round, and the arm summaries add in_flight_frames and presenter_keeps.

Bench only. This PR adds no CI job, step, gate or budget. A round does not fail on the presenter's keeps or fallbacks: that gap closes with T-KEYS (branch fix/frame-owner-s4-t-keys), which deletes the keep and fallback and adds a lateLandings stat. The probe stays in CmuxNextTerminal, owned by PL-ghostty (session cmux-b6).

Observed / Not run

  • Red, then green:

    • python3 scripts/cmux-next/tests/test_bench_terminal_resize.py: test_a_terminal_not_sampled_in_the_motion_fails fails at 31c3daf3002 and passes at 6a875677514.
    • test_a_lagging_frame_fails_and_names_the_terminal_its_frames_and_sizes fails at 0c16e59e93c and passes at ed6ba2075bb.
    • All 27 tests pass at the head.
  • Fleet step ad3ccfc1219e74f7aeb7b804 at 6a875677514 compiled CmuxNext, and the 4 TerminalPaneFollowTallyTests passed, including the new in-flight test.

  • Fleet step 85b94233b9a817c1fd731b6a at this head (97c0c1572e9) compiled CmuxNext and its test targets, and the 4 TerminalPaneFollowTallyTests passed.

  • A/B --ab=motion.frameOwner.terminals, keys and keys-stress, 2 rounds per arm, at 6a875677514 (same Swift as the head) on cmux23-perf: step d557f84ae28f821bd9f55bc1. Held and lagging frames are summed over the round's terminals:

    layoutarmround framesheldlaggingin flightpresenter (passes / presented / keeps)Ghostty host presents (fresh / late)
    keysoff176, 183144, 140144, 1400, 00 / 0 / 0-
    keyson182, 1730, 00, 00, 028 / 112 / 0 per round112 / 0 per round
    keys-stressoff147, 156168, 182168, 1820, 00 / 0 / 0-
    keys-stresson150, 1400, 00, 00, 020 / 140 / 0 per round140 / 0 per round

    In this bench build, the ON key rounds still show 0 lagging frames. frame-owner-s4 expected lagging in most spring frames, from pixel-perfect's trace ("presenter request, host frame pending"). I checked whether the 0 comes from sampling at the wrong time. Two counters that do not depend on when the sampler reads say it does not:

    • The window's frame presenter kept no frame: keeps 0, fallbacks 0, and all 112 (keys) or 140 (keys-stress) requests per round were presented in their own pass.
    • Ghostty counted 112 or 140 fresh host presents and 0 late presents per round.

    The sampler also never saw a size in flight after a commit (in_flight 0). So in the optimized bench build (--config=bench) on cmux23, each key-spring frame's new size was drawn and presented in the commit of the same turn. I did not reproduce pixel-perfect's one-tick lag. The likely cause is a different build or display. A known gap: if the host view itself lags its pane, this check cannot see it, because "pane" here means the host's bounds.

  • With this head's rules, the ON key rounds above pass and the OFF rounds fail (held and lagging). A run with lagging > 0 would now fail. That path is covered only by the unit test, not by a bench run.

  • I moved the run off two minis. cmux17-perf showed idle but did not claim step 4fb4e24064b35b4ba1a0e766 for 35 minutes. cmux22-perf was held for a capture pool. I cancelled both steps.

  • Not run: drag layouts on this head, and films.

Changelog

none


Autofix with [code]smith
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

The pane check for bench-terminal-resize now samples each window's own frame clock, so a terminal that is never sampled, or that shows a size other than its pane's, fails the round.

  • Each window that shows a followed terminal gets a frame client on its own clock; sampling reads the geometry that turn's commit carried.
  • A terminal shown at the round's start with 0 sampled frames fails the round; it used to pass on the other terminals' frames.
  • A frame whose layer shows another size than its pane's after that frame's commit fails; the message names the terminal, its lagging frames, and first sizes.
  • The stop reply adds per-terminal in-flight frames and frame-presenter counts; arm summaries add in-flight frames and presenter keeps.
  • A held drag (holds_terminals) is data only and no longer excuses a round.

Bench only: no CI job, step, gate, or budget changes.