📡 Bench LIVE pane — surface a bench as it runs (P1.3 / C6d)
Design + guide for the LIVE telemetry panel in the
nornir vizBench tab (src/viz/bench_live.rs, rendered first insideTab::Benchbysrc/viz/ops_tabs.rs::BenchState). P1.3 turns the bencher's CPU/mem telemetry (P1.2'sbench_telemetrytable) into a live surface: as a bench runs the pane names the running bench, shows its green/red status, a cores-busy / N indicator, and a small CPU sparkline — updating as rows land in the warehouse. THE_BIG_PLAN LAWs apply: everything rendered is exposed as data (state_json()["bench"]["live"]+$NORNIR_VIZ_TRACEbench.live), the test inject-and-asserts real values, and a wgpu PNG snapshot is the acceptance artifact.
Why
P1.2 built CPU/mem telemetry into the bencher: a 1 Hz /proc/stat sampler folds per-bench min/avg/max cores-busy (of N logical cores) + peak mem and streams them — [cores-busy C/N] on each [BENCH] line, and a dedicated warehouse bench_telemetry table (run_id, repo, bench, n_cores, cpu_pct_*, cores_busy_avg/max, mem_peak_mb, mem_pct_max, elapsed_ms). But the viz Bench tab only charted historical metric series — the live footprint never showed. P1.3 adds the panel that lights up as the bench runs.
What it shows
A list over the warehouse bench_telemetry table (one row per (run_id, repo, bench)), newest run first, each bench unit as one row:
| element | meaning |
| status dot | green ✓ / red ✗ / neutral ·, derived from the run's paired tests outcome (see Status) |
| bench NAME | the bench unit id (znippy.compress, holger.ops, …) |
| cores / N | proc_cores_max / n_cores — this process's peak occupancy (task-clock ÷ wall), colour-ramped (green few → amber mid → red pegged). NOT cores_busy_max: that is /proc/stat, the whole box, and reads N/N for a strictly serial arm on any loaded machine (measured on oden 2026-08-03 — gunnar.walk_1m at 32/32 while holding 0.56 of one core). A row from before 2026-08-03 has no such measurement and must render as ?, not 0. |
| host-busy / N | cores_busy_max / n_cores — ambient context, explicitly labelled as the host so it is never mistaken for the bench's parallelism |
| CPU sparkline | a tiny 3-point trace: [cpu_pct_avg, cpu_pct_max, peak-busy-fraction] (0..100) — HOST-WIDE, so it is the shape of how hard the box was pushed |
| cpu % | cpu_pct_max as a numeral (host-wide) |
| mem badge | mem_peak_mb when > 0 |
| header strip | the live run_id + green/red/neutral tallies + a ↻ re-read button |
Status — green/red per bench
The bench_telemetry row has no pass/fail; the verdict comes from bench_runs. bench_status(repo, bench, runs) pairs a bench with a TestOutcome whose name matches the bench exactly or against the bench's last .-segment (znippy.compress ↔ test compress):
- a matching test that failed → red,
- a matching test that passed → green,
- no paired test → neutral (the bench ran but no test gates it).
Live update — as rows arrive
Source of truth = the warehouse (LAW persist-to-warehouse-stream-not-tmp). Local mode opens the warehouse read-only (lock-tolerant, like the 🧪 Test / 🚀 Release tabs) and reads bench_telemetry + bench_runs. While the tab is open, draw() re-reads every RELOAD_EVERY (~1.5 s) and calls request_repaint_after, so telemetry rows that land mid-run (P1.2 appends per run) appear without user input. A ↻ button forces an immediate re-read; a workspace switch / reload (app.reload() → BenchState::reload()) drops the cache so the next draw re-hydrates.
Remote (thin-client) mode shows a note — there is no Bench.Telemetry RPC yet (same split as Test / Release / Leaderboard). The existing remote Bench history charts are unchanged and render below the live panel.
Architecture — pure fold + thin renderer
bench_telemetry rows ─┐
├─ fold_live() ─► Vec<LiveBench> ─► draw_live_row() (egui)
bench_runs (tests) ───┘ │
└─► state_json()["bench"]["live"]
$NORNIR_VIZ_TRACE bench.live IN/OUT/END
fold_live() is pure (telemetry + runs → Vec<LiveBench>) and unit-tested in isolation. LiveBench::cpu_spark() / cores_label() are the exact values the cell paints, surfaced verbatim in state_json so the headless matrix asserts the rendered content (LAW #6 — "see what the user sees" as data, not pixels).
Ordering: newest run first (run_id descending as a time-prefixed proxy), then by bench name within a run.
state_json shape (LAW #6)
state_json()["bench"]["live"]:
{
"source": "local /…/warehouse",
"error": null,
"live_run_id": "run-2",
"count": 3,
"green": 2, "red": 1, "neutral": 0,
"benches": [
{
"run_id": "run-2", "repo": "znippy", "bench": "znippy.compress",
"status": "green", "ok": true,
"n_cores": 8, "cores_busy_avg": 6.5, "cores_busy_max": 7,
"cores_label": "cores-busy 6.5/8 (peak 7/8)",
"cpu_pct_avg": 55.2, "cpu_pct_max": 92.0,
"mem_peak_mb": 512.0, "elapsed_ms": 2200.0,
"cpu_spark": [55.2, 92.0, 87.5]
}
]
}
bench.live IN/OUT/END trace events carry the same benches payload + the green/red/neutral tally.
Test (inject-and-assert) — tests/viz_bench_pane.rs
bench_pane_exposes_live_telemetry builds the app, injects concrete bench_telemetry rows + paired bench_runs via UrdrThreadsApp::inject_bench_telemetry_for_test, selects the Bench tab, and asserts state_json()["bench"]["live"]:
-
the live run is the newest (
run-2), newest-run-first ordering, -
the green bench (
znippy.compress) reads back name +status="green"+n_cores=8+cores_busy_max=7+cores_label="cores-busy 6.5/8 (peak 7/8)"cpu_pct_max=92+mem_peak_mb=512+ a 3-pointcpu_sparkwhose tail is87.5(= 7/8 cores busy),
-
the red bench (
holger.ops) reads backstatus="red",ok=false,cores_busy_max=4.
viz_snapshot_bench_pane renders the pane via egui_kittest wgpu, asserts the populated state (count=3, red>=1), and writes tests/snapshots/viz_bench_pane.png (LAW #4). Unit tests in bench_live.rs cover fold_live pairing/ordering and the state_json round-trip.
Files
src/viz/bench_live.rs—BenchLivepanel: load/fold/draw/state_json +fold_live.src/viz/ops_tabs.rs—BenchStateembedsBenchLive, draws it first, foldsliveinto itsstate_json, exposeslocal/remote/reload/inject hooks.src/viz/app.rs— constructsBenchState::local|remoteper source, reloads on workspace switch,inject_bench_telemetry_for_test.tests/viz_bench_pane.rs— inject-assert + wgpu snapshot.- Reads:
src/bench/telemetry.rs(P1.2 sampler),src/warehouse/iceberg.rs(bench_telemetrytable +BenchTelemetryRow+query_bench_telemetry).