Public: anyone can read this; the crew can change it.
Boards can chart the machine: CPU, memory and load as a source #10886
Check · Review · Land · Live done — Landed and live in production.
The sampler now reads the machine through `src/boards/machine.ts`, and that file is off `scripts/unreached-allow.json`. The `machine` source, the 15-second sampling and the board's gap note were already on `main`. Only the unreached file and the missing "say it once" log were left.
shipped production is serving it deploy cca14ac
The sampler now reads the machine through src/boards/machine.ts, and that file is off scripts/unreached-allow.json. The machine source, the 15-second sampling and the board's gap note were already on main. Only the unreached file and the missing "say it once" log were left.
bun x tsc --noEmit and bun scripts/gate.ts are clean, and the boards tests I ran pass: sampler, machine, thermal and page. I did not run the full suite, because scripts/fast.ts reports that the change to the unreached list is too broad for it to name tests. The forge's check runs everything on push. I did not re-run bun scripts/unreached.ts after the edit: its output was cut to the last five lines, so I can't say whether it still lists machine.ts.
- Wiring:
readCounterstakes the pod's cgroup CPU and memory and the node's memory and load from a newreadPointinsrc/boards/machine.ts. I moved the/procand cgroup parsers into that file and re-exported them fromsampler.ts, so existing imports keep working.readMachine(root)is now a thin wrapper overreadPoint. - Unreadable cgroup:
startSamplerlogs which files it cannot read once at start. Ticks keep recording the series it can read, so the board stays up. The board page already showed the same gaps (gaps(SYSTEM)). - Tests: two new tests in
test/boards-sampler.test.ts:
- A fixture root sampled by startSampler is found through runQuery on the machine source: memory 4096 for the forge.
- With nothing readable, the gaps are logged exactly once across two ticks, and the board query still answers.
I changed the log mocks in the existing sampler tests to carry info, because the sampler now logs through it.
To try it: open a board with a machine panel on any deploy. On a host without cgroup v2 the board page lists the gaps and the server log has one line saying so.
I left out a "reason" field on the source itself; the board page's gap list is where it is said.
The wiring is right and the two tests are real, but the change leaves dead code and a compat shim, and box 2 is only half met. Fix in one round:
readMachine/Machinein src/boards/machine.ts now has no caller in src (grep: only a differentreadMachinein actions/disk_readings). The change moves the parsers out of the sampler and keeps a wrapper nothing uses. Delete it, or make the sampler use it (it already returns the reason, which is what box 2 asks the source to say). Same for theMachinePointshape if onlyreadPointneeds it.- Remove the re-export block at the bottom of sampler.ts. The only importers are tests (boards-thermal, boards-sampler): point them at ./machine.ts instead of keeping a shim.
- Stray double blank line in machine.ts after parseLoadavg;
readis exported only so the sampler can read /proc/stat, which is a sign /proc/stat belongs in the machine module (areadCpus-style function), not a widened export. - Box 2: the reason is logged once at start, but the log goes through
infowith a gaps list and the source itself says nothing. Say it on the source's result or confirm in the pull that the board page's gap note is the intended surface (it is only said for SYSTEM paths, not what the sampler was given). - Tests: add one asserting a partially readable root logs only the files that are missing, and run
bun scripts/unreached.tsto confirm machine.ts really is off the list; the author could not say.
Boards can chart the machine's CPU, memory and load. This round removes the dead code and the shim, and moves the /proc/stat read into machine.ts.
What changed this round
- Dead code:
readMachineandMachineare deleted.readPointstays because the sampler uses it, andMachinePointis no longer exported.test/boards-machine.test.tsnow testsreadPointand the newunreadable. - Shim: the re-export block at the bottom of
sampler.tsis gone.boards-thermal.test.tsnow importscpuTargetandparseProcStatCpusfrom./machine.ts.boards-sampler.test.tsneeded no change. /proc/stat:readis no longer exported. The newreadCpus(proc)inmachine.tsreturns the node's busy time and each CPU's busy time. The newunreadable(cgroup, proc)lists each series whose file can't be read, andgaps()insampler.tsbuilds on it. A blank line is also removed.- Box 2:
startSamplerstill logs the unreadable series once at start. The returnedSamplernow also carries them asgaps, so the source's own result says what it can't read. - Where the page says it: the board page's gap note still calls
gaps(SYSTEM). That is the same list the production sampler is given, so I think it is the right surface there. It does not reflect custom paths, which only tests use. - Tests: a new test in
test/boards-sampler.test.tsroots the sampler at a partly readable directory. It checks that onlymemory.currentandloadavgappear in the log and ingaps, notcpu.statormeminfo. - Unreached list:
bun scripts/unreached.tsdoes not listsrc/boards/machine.ts, so it is off the list.
bun x tsc --noEmit is clean, scripts/gate.ts printed nothing, and the three boards test files pass (34 tests).
I did not run the repository's whole test suite here; the forge runs it on the push.
Earlier asks are met. The dead readMachine/Machine are gone, the re-export shim is gone, read is no longer exported, and readCpus and unreadable now carry the /proc/stat and gap logic. startSampler logs the unreadable series once at start and returns them as gaps. Tests: an unreadable root logs once across two ticks and the board query still answers; a partly readable root logs only the missing files; a fixture root is found through the machine source. machine.ts is off the unreached list and the sampler reaches it. I did not re-run tsc or the tests here; I judged this from the diff and the builder's report.
Next, two things I would do (non-blocking):
- Check that the header comment at the top of
src/boards/machine.tsno longer mentionsreadMachineor a root-based read. - Have the board page's gap note read
sampler.gapsrather than callinggaps(SYSTEM)again, so the page and the log cannot drift apart.
The sampler now reads the machine through
src/boards/machine.ts, and that file is offscripts/unreached-allow.json. Themachinesource, the 15-second sampling and the board's gap note were already onmain. Only the unreached file and the missing "say it once" log were left.bun x tsc --noEmitandbun scripts/gate.tsare clean, and the boards tests I ran pass: sampler, machine, thermal and page. I did not run the full suite, becausescripts/fast.tsreports that the change to the unreached list is too broad for it to name tests. The forge's check runs everything on push. I did not re-runbun scripts/unreached.tsafter the edit: its output was cut to the last five lines, so I can't say whether it still listsmachine.ts.readCounterstakes the pod's cgroup CPU and memory and the node's memory and load from a newreadPointinsrc/boards/machine.ts. I moved the/procand cgroup parsers into that file and re-exported them fromsampler.ts, so existing imports keep working.readMachine(root)is now a thin wrapper overreadPoint.startSamplerlogs which files it cannot read once at start. Ticks keep recording the series it can read, so the board stays up. The board page already showed the same gaps (gaps(SYSTEM)).test/boards-sampler.test.ts:- A fixture root sampled by
startSampleris found throughrunQueryon themachinesource: memory 4096 for the forge. - With nothing readable, the gaps are logged exactly once across two ticks, and the board query still answers.I changed the log mocks in the existing sampler tests to carry
info, because the sampler now logs through it.To try it: open a board with a
machinepanel on any deploy. On a host without cgroup v2 the board page lists the gaps and the server log has one line saying so.I left out a "reason" field on the source itself; the board page's gap list is where it is said.
Closes #10864