bench: keep the warm startup daemon alive and refuse legs the display cannot present #427

Merged
natsukium merged 3 commits from bench/warm-daemon-and-display-state into main 2026-09-25 10:38:59 +09:00
Owner

Closes #408.

Warm startup daemon

On macOS the autospawned daemon is a forked child of the client, so stop_launch killed it with each launch's process tree. As a result, every "felis (warm)" launch spawned a fresh daemon. The warm row now primes its daemon with one untimed launch, on a socket first verified to be free, and stop_launch(proc, spare=[daemon]) skips that daemon when it stops later launches. Before every launch, each row checks the daemon: the cold row checks that none is bound, and the warm row checks that the primed pid still is. A failed check ends the row as a recorded failure. Each row records daemon_checked. Both rows are always recorded, because the warm row no longer depends on the cold one.

Display state

envinfo.leg_env() now carries display: {locked, asleep}:

  • macOS reads IOConsoleLocked via ioreg and CGDisplayIsAsleep for the main display via osascript.
  • Linux reads logind's LockedHint. Sleep is null because there is no reading to take.

A leg whose display cannot present at its start is not launched. A leg whose display cannot present at its end is marked refused. In both cases <name>.env.json records the reason and the console prints it. field.sweep_refused moves a refused leg's artifacts, its .done included, to refused/. It runs before a suite starts and before the report loads a directory, so a late write can neither be charted nor skip the retake. The report note names each refused leg.

Other failure-path hardening that review raised (stale rows after an interrupted retry, process reaping, pid-reuse-safe SIGKILL) is out of scope here and tracked in #426.

Verification

  • python3 tools/bench/crossterm_test.py: 261 tests pass on Linux and on the M4 Max.
  • Linux: crossterm.py run startup --terminals kitty produced both felis rows with daemon_checked 6/6 and no failure. display was {"locked": false, "asleep": null}.
  • macOS (currently locked with the display asleep): envinfo.display_state() returns {'locked': True, 'asleep': True}.
Closes #408. ## Warm startup daemon On macOS the autospawned daemon is a forked child of the client, so `stop_launch` killed it with each launch's process tree. As a result, every "felis (warm)" launch spawned a fresh daemon. The warm row now primes its daemon with one untimed launch, on a socket first verified to be free, and `stop_launch(proc, spare=[daemon])` skips that daemon when it stops later launches. Before every launch, each row checks the daemon: the cold row checks that none is bound, and the warm row checks that the primed pid still is. A failed check ends the row as a recorded failure. Each row records `daemon_checked`. Both rows are always recorded, because the warm row no longer depends on the cold one. ## Display state `envinfo.leg_env()` now carries `display: {locked, asleep}`: - macOS reads `IOConsoleLocked` via `ioreg` and `CGDisplayIsAsleep` for the main display via `osascript`. - Linux reads logind's `LockedHint`. Sleep is `null` because there is no reading to take. A leg whose display cannot present at its start is not launched. A leg whose display cannot present at its end is marked refused. In both cases `<name>.env.json` records the reason and the console prints it. `field.sweep_refused` moves a refused leg's artifacts, its `.done` included, to `refused/`. It runs before a suite starts and before the report loads a directory, so a late write can neither be charted nor skip the retake. The report note names each refused leg. Other failure-path hardening that review raised (stale rows after an interrupted retry, process reaping, pid-reuse-safe SIGKILL) is out of scope here and tracked in #426. ## Verification - `python3 tools/bench/crossterm_test.py`: 261 tests pass on Linux and on the M4 Max. - Linux: `crossterm.py run startup --terminals kitty` produced both felis rows with `daemon_checked` 6/6 and no failure. `display` was `{"locked": false, "asleep": null}`. - macOS (currently locked with the display asleep): `envinfo.display_state()` returns `{'locked': True, 'asleep': True}`.
On macOS the felis (warm) startup row never had a warm daemon. The
autospawned daemon is a forked child of the client there, so stopping
each launch's process tree killed it, and the session cleanup between
launches does not autospawn; every "warm" launch spawned a fresh
daemon. The warm row now primes its daemon with one untimed launch on a
socket verified free, and spares that daemon when stopping later
launches, which keeps the autospawn path a user takes (the systemd
hand-off on Linux, the fork on macOS) rather than a harness-started
daemon. Both rows check their daemon before every launch (none for
cold, the primed pid for warm) and fail rather than publish a number
that belongs to the other row. With that check a failed cold row is an
ordinary outcome, and the warm row no longer depends on it, so both
rows are always recorded.

Legs also did not record whether the display could present. Behind the
lock screen or with the display asleep, macOS presents nothing, and
felis's client then spins on failed surface acquires, so the leg's
throughput, CPU and memory describe that loop rather than a terminal
drawing. Every leg sample now carries the lock and sleep state; a leg
that starts dark is not launched, and one that ends dark is marked
refused in its env record. The refusal is enforced from that record
when a suite starts and when the report reads a directory, by moving
the leg's artifacts aside: moving them at the moment of refusal was
rejected because a stopped launch's children (felis's wrapper runs
under the daemon) can still write a result or resume marker afterwards,
and no process cleanup can rule that out. The report names every
refused leg with its reason.

Assisted-by: Claude Code
The harness spec is what a reader checks a published bar against, so it
has to say how the two felis startup rows get their daemon and which
display states void a leg. The refusal also earns a design record: a
flag beside the bar is the obvious alternative, and it fails because the
bar would still sit on the same axis as the presenting ones.

Assisted-by: Claude Code
bench: retake a refused leg when a suite is resumed on its own
All checks were successful
bench / Criterion full-suite snapshot (pull_request) Has been skipped
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
darwin / build felis (aarch64-darwin) (pull_request) Successful in 54s
darwin / publish felis (aarch64-darwin) (pull_request) Has been skipped
bench / Criterion regression gate (pull_request) Successful in 2m16s
darwin / detect relevant changes (pull_request) Successful in 4s
darwin / darwin docs-only no-op (pull_request) Has been skipped
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 1m8s
pr / nix flake check (pull_request) Successful in 27s
pr / cargo build / clippy / test / deny (pull_request) Successful in 1m43s
pr / wire schema is compatible with the base (pull_request) Successful in 12s
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 1m42s
pr / publish felis (x86_64-linux) (pull_request) Has been skipped
windows / detect relevant changes (pull_request) Successful in 4s
windows / windows docs-only no-op (pull_request) Has been skipped
windows / cargo clippy (Windows cross) (pull_request) Successful in 14s
windows / cargo nextest (Windows) (pull_request) Successful in 4m45s
windows / frontend smoke (Windows) (pull_request) Successful in 2m3s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
f3acc428bf
A refused leg's late resume marker is only set aside when a suite
starts through crossterm.py; the standalone entry point in suites.py
called the suite directly, so rerunning one suite there skipped the
refused leg instead of retaking it.

Assisted-by: Claude Code
natsukium deleted branch bench/warm-daemon-and-display-state 2026-09-25 10:39:00 +09:00
Commenting is not possible because the repository is archived.
No description provided.