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 sandbox-meter/rapl-msr into main 2026-11-05 04:53:09 -05:00

2026-11-04

Transaction Science
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]>
2026-11-04 21:18:49 -05:00
Transaction Science
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]>
2026-11-04 21:12:32 -05:00