journeys tui-kit: tk-beacon, the SWITCH FRAMES beacon in compiled Rust (uptime clock, rt pacing)

Merged
LA
5d ago
+553-6

Summary

This is item 4 of the compiled-load plan (STATUS 4801). It answers the SWITCH FRAMES owner's request for a compiled beacon. The spec and decoder are in cp/switch-frames-kit scripts/journeys/ext_switch.py (ansi, rows). This PR is stacked on #31764; its own change is the top commit, 43989b93df90.

  • tk-beacon: it draws the same three rows as ext_switch.py:
    • row 0: Y, ws[6], pane[4], parity, R;
    • row 1: Y, gray(clock) bits 17..9, parity, R;
    • row 2: Y, gray(clock) bits 8..0, parity, R.
    • Magenta is 1 and cyan is 0. Each block is --cell-cols columns wide.
    • The clock is CLOCK_UPTIME_RAW, in 2 ms units, 18 bits. The SWITCH owner asked for this clock because the recorder's frames.json uses it. The Python beacon reads time.time_ns.
    • Each frame is one DEC 2026 update. The label row is WS n PANE m frame k, and --fill adds the moving shade.
    • The end event has achieved_hz, target_hz and verdict (NOT RUN below 95 %).
    • tuikit.py beacon --ws N --pane M execs it. There is no Python engine.
  • New pace mode rt (macOS): the thread becomes a time-constraint thread (thread_policy_set: period 1/hz, computation 0.75 ms, constraint 1.5 ms) and waits with mach_wait_until. This avoids timer coalescing, and it does not spin.
    • The beacon defaults to rt. A SWITCH profile runs 18 beacons at 240 Hz, and 18 spinning cores would become the load under test.
    • The gradient keeps spin, which is proven on a mini.
    • pace_probe adds a rust-rt variant to compare the two.
    • The start event records whether the kernel accepted the real-time policy (realtime).

Testing

Observed / Not run

Observed (cmux-orchestrator-1):

  • test_tuikit.py: 37 tests OK, 3 skipped. The skipped tests are the Rust ones, because no Rust is built on this VM. The new BeaconRust test decodes the rows from a real pty: the ws and pane ids, the parity, and a clock that advances, at no less than 95 % of 240 Hz.
  • test_load_profiles.py: 15 tests OK.
  • rustfmt --check: clean.
  • prepush-gate.py: no new violations.

Not run:

  • Nothing here is compiled yet. The macOS self-test after the merge compiles it and runs the parity, decode and rate tests with CMUX_TUIKIT_REQUIRE_RUST=1.
  • Whether rt holds 240 Hz without spinning on a mini is unknown. The rust-rt pace_probe row and each run's verdict will say.

Changelog

none


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


Summary by cubic

Adds tk-beacon, a compiled Rust binary that draws the SWITCH FRAMES beacon spec (ext_switch.py ansi/rows) on CLOCK_UPTIME_RAW in 2 ms units, so the beacon matches the clock the recorder's frames.json uses. tuikit.py beacon execs it; there is no Python engine.

Adds a new rt pace mode on macOS: a time-constraint thread (thread_policy_set with period 1/hz, computation 0.75 ms, constraint 1.5 ms) that waits via mach_wait_until, avoiding timer coalescing without spinning. The beacon defaults to rt because 18 spinning beacons at 240 Hz would be the load under test; both the beacon and tk-gradient accept it, while the gradient keeps spin as its default. pace_probe adds a rust-rt variant to compare against spin. Runs below 95 % of the asked rate now record verdict NOT RUN across the gradients, storms, and beacons.

Migration

  • Run tuikit.py build-bins once per Mac to compile tk-gradient, tk-storm, and tk-beacon (std only, no dependencies, not built by CI).