jouleclaw: the NVML sampling floor is ~100 ms, measured, not ~50 ms #316
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/jouleclaw-nvml-sampling-floor"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found by a claim-falsification sweep of the AI/energy literature, then re-read against the primary source before changing anything.
The falsified claim
jouleclaw/SPEC.md§1.3 published a normative floor:feeding the MUST three lines above it — "Implementations MUST surface
resolution_uj()andmin_window_ns()so callers can refuse to claim microjoule accuracy on platforms that cannot deliver it."min_window_ns()returned50_000_000, and the figure was restated atnvml.rs:32,:46,:279andlib.rs:417.Dauner et al., Evaluating the Influence of Measurement Frequency on Energy Readings Using Intel RAPL and NVIDIA NVML, ACM SIGENERGY Energy Informatics Review 6(2), July 2026 (HotCarbon), measured it across 588 controlled runs:
Stale-read fraction: 93.4 % at 0.5 ms, 86.3 % at 10 ms, 79.9 % at 20 ms, falling to 1.0 % at 100 ms and zero from 500 ms.
So 50 ms does not merely understate the floor — it sits inside the stale-read region, where a read mostly returns the preceding value. We graded that
HwShunt, our strongest provenance. "A counter read below its own update rate is not a reading of the span" is the rule this family exists to enforce, and our own SPEC broke it.Two numbers, kept apart on purpose
The paper reports a second, different quantity: accuracy against integrated power. That is device-class dependent — an A100 agreed to ±0.2 % at every interval, while an unvalidated RTX 4090 was still 13.3 % low at 100 ms and came within 1.6 % only at 1 s.
It would have been easy to fold that into
min_window_ns()and return 1 s. I didn't, because:min_window_nsis documented (lib.rs:416) as "the smallest sampling window below which readings are noise-dominated" — the counter's update period. That is exactly what the paper measures at ~100 ms.jouledesk-github'swindow_energyrefuses a figure when the work is shorter than it.So the scalar moves to the measured update period, and the accuracy caveat goes into SPEC §1.3 prose together with the paper's own recommendation — on an unvalidated counter, prefer the power integral, which
Mode::PowerIntegralalready is, gradedModelBased.Open question, flagged not decided: the honest NVML answer is arguably two numbers (validated data-center class vs unvalidated consumer class) and
min_window_nsis one scalar. Either the backend reports a conservative 1 s until a device is validated against integrated power, or the trait grows a validation state. I've taken neither step here.The sharper bug: the liveness probe could fail a healthy counter
PROBE_TICKwas 100 ms, justified as "two of its ~50 ms sample periods". Against the real ~100 ms period the tick equalled the update period, so roughly half the intervals catch no update, the probe missesLIVE_SHARE(four in five) and grades a perfectly healthy counter not-live — silently demoting a genuineHwShuntreading to the power integral.Now 150 ms, which matches
sandbox-meter'sNVML_PROBE_TICK(whose comment already carried the right derivation), andMIN_LIVE_ADVANCES(5) intervals then take 750 ms, inside the 1000 msLIVENESS_BUDGET.Nothing pinned either constant before.
the_probe_tick_clears_the_update_period_and_fits_the_budgetnow pins both halves.Falsification
min_window_nsback to50_000_000nvml_resolution_is_millijoule_floorFAILEDPROBE_TICKback to 100 ms (equal to the period)PROBE_TICKto 250 msF2 and F3 hit opposite halves of the same test, so neither half is decoration.
Not changed
The RAPL floor. The same paper finds RAPL stable at 10 ms or coarser — which is what §1.3 already says. One caveat worth recording: that is validated stability, not validated accuracy against an external meter.
Verification
The
nvmlmodule is not in a default build, so a plaincargo testproves nothing here:cargo test -p jouleclaw-energy --features rapl,nvml— 84 passed (CI'sfeature_testsfor this row)cargo check --workspace --all-targets+cargo test --workspace(jouleclaw-rs) — exit 0, 0 failed, 484 ok suitescargo test -p mesh-meter --features hw-meter-nvml— 14 passedThat last one matters:
jouleclaw-energyhas five consumers outsidejouleclaw/, and three (jouledesk-github,l3-jouleclaw,quantum-meter) pindefault-features = false, features = ["ioreport"], so they never compile this module. Onlymesh-meter'shw-meter-nvmlreaches it — and CI's mesh row does not build that feature, so it would not have been caught. No test or doc anywhere pins the old 50 ms figure.tests/nvml_hardware.rsran 0 tests on the build host: it needs a real GPU and only exercises on thelinux-hwrunner.🤖 Generated with Claude Code