sandbox-meter: RAPL reads each domain's energy-status MSR where powercap lists none; die zones are packages #629
Merged
dcharlot
merged 2 commits from 2026-11-05 04:53:09 -05:00
sandbox-meter/rapl-msr into main 2026-11-04
sandbox-meter: a powercap zone named package-<p>-die-<d> is a package's domain
All checks were successful
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 8s
standards workspaces build + test / joule-ui-rs (joule-ui/joule-ui-rs, joule-ui-rs, linux) (pull_request) Successful in 1m8s
standards workspaces build + test / jcp-rs (jcp-conformance, jcp/jcp-rs, -p jcp-energy --features nvml, jcp-rs, linux) (pull_request) Successful in 1m21s
standards workspaces build + test / proof-rs (proof/conformance/v1/joulespec.toml, proof-conformance, proof/proof-rs, proof-rs, linux, true) (pull_request) Successful in 1m23s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 1m38s
standards workspaces build + test / sandbox-rs (sandbox-conformance, sandbox/sandbox-rs, -p sandbox-tee --features amd-kds,intel-pcs, sandbox-rs, linux) (pull_request) Successful in 5m1s
energy meters on real hardware / sink decode table · per-task energy and the GPU rail on macOS (pull_request) Successful in 2m56s
standards workspaces build + test / joulecontract-rs (joulecontract/joulecontract-rs, joulecontract-rs, linux-arm64, true) (pull_request) Successful in 5m1s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 4m44s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 6m47s
standards workspaces build + test / joule-code-rs (joule-code/joule-code-rs, joule-code-rs, linux-arm64, true) (pull_request) Successful in 16m21s
energy meters on real hardware / RAPL and NVML on jetson-hub (pull_request) Successful in 36s
energy meters on real hardware / sink decode table · RAPL on jetson-hub (NVML surveyed) (pull_request) Successful in 2m21s
On a multi-die Intel package the kernel scopes RAPL per die and lists one top-level intel-rapl:<n> zone per die, named "package-<p>-die-<d>" (intel_rapl_common's "package-%d-die-%d", used when the MSRs are not package scope and a package has more than one die). The probe accepted only "package-<n>", so such a host listed no package zone: estimated, or, with the MSR fallback, read through the MSRs as root only. A zone's name now names a package's domain when it is "package-<digits>" or "package-<digits>-die-<digits>", and nothing looser (not psys, dram, "package-", "package-0-die-", "package-0-core-0", "package-0-die-1-die-2"), so every die's zone is summed into the CPU figure under the same rules: every domain readable and live, or no figure. The hardware tests' oracles (the powercap one, and the MSR one's check for a powercap package) apply the same name rule. Tests: the name rule over both forms and the near misses; a fake two-die powercap tree (two die zones, psys, each die's core subzone) holding exactly the two die zones, metering a span as their rise alone, and frozen when one die holds. Pass on Linux x86_64 (cargo test -p sandbox-meter; clippy clean apart from the existing type_complexity errors in tests/nvml_hardware.rs) and in the macOS CI step (both greps; clippy on sandbox-meter and sandbox-proof clean). Co-Authored-By: Claude Opus 5.5 <[email protected]>
sandbox-meter: RAPL reads each package's energy-status MSR where powercap lists none
Some kernels ship without the powercap RAPL driver (Ubuntu without linux-modules-extra, as on some rented bare-metal servers), so /sys/class/powercap lists no package while the counters are there, and the meter estimated hosts that can measure. Where powercap lists no package zone, the RAPL probe now reads the same counters directly, as `rapl-msr`: each domain's MSR_PKG_ENERGY_STATUS (0x611, Intel family 6; 0xC001029B, AMD Zen and Hygon) through /dev/cpu/<n>/msr, the 32-bit count converted at the domain's own unit (bits 12:8 of the power-unit MSR, 0x606 or 0xC0010299), so it wraps at 2^32 counts in microjoules. A domain is a package on AMD and Hygon and a die of a package on Intel, as sandbox-exec-microvm's MSR meter has it, read through the first of its CPUs whose MSRs read. Every domain or none: a CPU with no readable topology (offline), a domain whose MSRs read through none of its CPUs, or a zero unit (KVM guests read zeros) opens nothing. Powercap is still preferred, and a tree that lists a package zone, or a zone that may be one, is read through powercap or not at all. The liveness rule is unchanged: every domain readable and live, or no figure. A declined probe now says why its counters did not open: the probe run records the reason, and RaplPackages::host() / RaplProbe::given append it to the gate's text. Without CAP_SYS_RAWIO: "no RAPL package zone in /sys/class/powercap; and the energy-status MSRs: package-0-die-0: the RAPL MSRs read through none of its CPUs (16 tried; first /dev/cpu/0/msr: Permission denied (os error 13)); reading an MSR needs the msr module, CAP_SYS_RAWIO and read access to /dev/cpu/<n>/msr". joule-meter prints the RAPL interface it reads, or that reason. RaplPackages gains live_at (a fake host: powercap tree plus filesystem root) and source(); live_in stays powercap-only. On two bare-metal servers with no powercap zone (msr module loaded), as root: a one-socket Xeon E-2278G live (package-0-die-0, 12 of 12 intervals), a 300 ms one-thread burn 8.85 J inside the oracle's bracket (8.849 to 8.877 J), joule-meter 2.04 W idle and 122.3 W on all cores; two Xeon Silver 4215R sockets live (package-0-die-0 and package-1-die-0), the burn 23.07 J (76.9 W) inside the bracket, joule-meter 26.8 W idle and 207.1 W on all cores. As an unprivileged user the probe declines with the reason above and the meter estimates. Tests: fake roots (a register's bytes at its offset in a fake device file) cover a two-socket Intel host, the 32-bit wrap, AMD's registers and per-package scope, an Intel package of two dies, a domain read through its second CPU, a zero unit, an unknown CPU, a missing device, an offline CPU, a missing die_id, no CPU, powercap preferred (and an unreadable powercap package not falling through), the public counter and the liveness run over MSR domains, and the declined probe's reason. A new hardware test, tests/rapl_msr_hardware.rs, checks the MSR path against an oracle of its own that reads the MSRs; the powercap hardware test hands such a host to it. Unit and hardware tests pass on Linux x86_64 (powercap host) and on both servers above as root and unprivileged; the macOS CI step passes (both greps), and clippy is clean on macOS (sandbox-meter, sandbox-proof) and on Linux apart from three existing type_complexity errors in tests/nvml_hardware.rs. Co-Authored-By: Claude Opus 5.5 <[email protected]>