quantum-meter: wai-quantum's RunMeter over this process's CPU and GPU counters #232

Merged
dcharlot merged 2 commits from wai/quantum-run-meter into main 2026-10-13 06:37:59 -04:00
Owner

What

wai-quantum defines RunMeter and ships no implementation, because a meter belongs with the energy source it reads. This PR adds one: wai/tools/quantum-meter, a crate of its own beside quantum-wgsl-check, so the energy counters never compile in wai-quantum's own builds.

The meter

  • Source. jouleclaw-energy's span meter:
    • this process's CPU energy, from the kernel's per-process count;
    • this process's GPU energy, from the GPU rail over a span this process all but owned, or an exact zero where it spent no GPU time.
  • Label. Both are counters the hardware keeps about itself, so a figure is OnChipCounter, with filtering unknown.
  • Domain. This process's CPU and the GPU. It is the same domain for the CPU reference and for an accelerator member, so their figures can be compared.

A window gets no figure, and never an estimate, when:

  • the counters are not live (always the case off macOS on Apple Silicon);
  • the GPU counter gives none (the GPU was shared, a client went away, or the rail was not current);
  • it is shorter than its counters resolve: 1 s with GPU time, 1 ms without;
  • its label misses the fabric's resolution floor.

The declared uncertainty adds three terms:

  • the operator's own figure for the counters (--counter-ppm). The platform publishes none, so there is no default.
  • the window's ends: one CPU quantum or one rail republish at each end, as a share of the window.
  • with GPU time, the share of the GPU other clients may hold.

Calibration

The fabric's own calibrations open one window per corpus circuit. A corpus circuit runs for microseconds, so this meter refuses every such window. span_of_runs is the calibration it supports: one window around as many runs of a circuit as fill a stated time, giving one reading over all their operations, which EnergyCalibration::add takes as it takes a single run's.

Measured (M4 Max, macOS 27.0.1)

GPU member (Metal) CPU reference
tool, 20 qubits, 3 s windows 4 nJ/op 9 nJ/op
device test, 18 qubits, three repeats 4 nJ/op each time 9 to 10 nJ/op

With both figures in hand, the fabric placed the 20-qubit circuit on the GPU member.

On the Linux host, where no per-process counter exists, every window came out unmetered, as it should.

One limit belongs to the fabric, not this meter: a figure is whole nanojoules per operation, rounded up, so at 4 nJ/op the rounding alone adds up to 25% to the declared uncertainty.

CI

  • Metal job: the device test must print what it read, and the tool must run a window on the CPU reference.
  • Software Vulkan job: the meter must find its counters not live, and a run of the member through it must be unmetered.
  • Path triggers: now include the meter and the jouleclaw-energy crates it reads.

🤖 Generated with Claude Code

## What `wai-quantum` defines `RunMeter` and ships no implementation, because a meter belongs with the energy source it reads. This PR adds one: `wai/tools/quantum-meter`, a crate of its own beside `quantum-wgsl-check`, so the energy counters never compile in `wai-quantum`'s own builds. ## The meter - **Source.** `jouleclaw-energy`'s span meter: - this process's CPU energy, from the kernel's per-process count; - this process's GPU energy, from the GPU rail over a span this process all but owned, or an exact zero where it spent no GPU time. - **Label.** Both are counters the hardware keeps about itself, so a figure is `OnChipCounter`, with filtering unknown. - **Domain.** This process's CPU and the GPU. It is the same domain for the CPU reference and for an accelerator member, so their figures can be compared. A window gets no figure, and never an estimate, when: - the counters are not live (always the case off macOS on Apple Silicon); - the GPU counter gives none (the GPU was shared, a client went away, or the rail was not current); - it is shorter than its counters resolve: 1 s with GPU time, 1 ms without; - its label misses the fabric's resolution floor. The declared uncertainty adds three terms: - the operator's own figure for the counters (`--counter-ppm`). The platform publishes none, so there is no default. - the window's ends: one CPU quantum or one rail republish at each end, as a share of the window. - with GPU time, the share of the GPU other clients may hold. ## Calibration The fabric's own calibrations open one window per corpus circuit. A corpus circuit runs for microseconds, so this meter refuses every such window. `span_of_runs` is the calibration it supports: one window around as many runs of a circuit as fill a stated time, giving one reading over all their operations, which `EnergyCalibration::add` takes as it takes a single run's. ## Measured (M4 Max, macOS 27.0.1) | | GPU member (Metal) | CPU reference | |---|---|---| | tool, 20 qubits, 3 s windows | 4 nJ/op | 9 nJ/op | | device test, 18 qubits, three repeats | 4 nJ/op each time | 9 to 10 nJ/op | With both figures in hand, the fabric placed the 20-qubit circuit on the GPU member. On the Linux host, where no per-process counter exists, every window came out unmetered, as it should. One limit belongs to the fabric, not this meter: a figure is whole nanojoules per operation, rounded up, so at 4 nJ/op the rounding alone adds up to 25% to the declared uncertainty. ## CI - **Metal job:** the device test must print what it read, and the tool must run a window on the CPU reference. - **Software Vulkan job:** the meter must find its counters not live, and a run of the member through it must be unmetered. - **Path triggers:** now include the meter and the `jouleclaw-energy` crates it reads. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
quantum-meter: wai-quantum's RunMeter over this process's CPU and GPU counters
Some checks failed
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 56s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m32s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 1m25s
standards workspaces build + test / aac-rs (pull_request) Successful in 2m36s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 55s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 4m24s
standards workspaces build + test / map-rs (pull_request) Successful in 58s
standards workspaces build + test / mesh-rs (pull_request) Successful in 57s
wai-quantum WebGPU member / member · discrete GPU, Vulkan (jetson-hub) (pull_request) Successful in 11m5s
wai-quantum WebGPU member / member · Metal (macos) (pull_request) Failing after 2m25s
standards workspaces build + test / openpay (pull_request) Successful in 3m23s
wai-quantum WebGPU member / member · browser WebGPU (macos) (pull_request) Successful in 1m41s
lockfiles / every Cargo.lock is current (pull_request) Has been cancelled
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no comparison (pull_request) Has been cancelled
no-vanity-metrics / WAI public text names no company or product (pull_request) Has been cancelled
standards workspaces build + test / arl-rs (pull_request) Has been cancelled
standards workspaces build + test / eoc-rs (pull_request) Has been cancelled
standards workspaces build + test / jcp-rs (pull_request) Has been cancelled
standards workspaces build + test / joule-ui-rs (pull_request) Has been cancelled
standards workspaces build + test / joulehook-rs (pull_request) Has been cancelled
standards workspaces build + test / proof-rs (pull_request) Has been cancelled
standards workspaces build + test / sandbox-rs (pull_request) Has been cancelled
standards workspaces build + test / sense-rs (pull_request) Has been cancelled
standards workspaces build + test / smart-byte-rs (pull_request) Has been cancelled
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness · MSRV (pull_request) Has been cancelled
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Has been cancelled
workflow hygiene / every workflow supersedes its own queue (pull_request) Has been cancelled
644b5edb9f
wai-quantum defines RunMeter and ships no implementation: a meter belongs
with the energy source it reads. This is one, in its own crate beside
quantum-wgsl-check, so the counters never compile in wai-quantum's builds.

The source is jouleclaw-energy's span meter: this process's CPU energy
(the kernel's per-process count) and its GPU energy (the GPU rail over a
span this process all but owned, or an exact zero where it spent no GPU
time). Both are counters the hardware keeps, so a figure is OnChipCounter,
filtering unknown. The domain is this process's CPU and the GPU, the same
for the CPU reference and an accelerator member, so their figures compare.

A window has no figure, never an estimate, when the counters are not live
(off macOS on Apple Silicon, always), when the GPU counter gives none (the
GPU shared, a client gone, the rail not current), when it is shorter than
its counters resolve (1 s with GPU time, 1 ms without), or when the label
misses the fabric's resolution floor. The declared uncertainty is the
operator's own figure for the counters (the platform publishes none, so
there is no default), plus each window's ends (a quantum of a CPU thread,
a republish of the rail, at each end, over the window) and, with GPU time,
the share other clients may hold.

The fabric's own calibrations open one window per corpus circuit, which
runs for microseconds and is always refused here. span_of_runs is the
calibration this meter supports: one window around as many runs of a
circuit as fill a stated time, one reading over all their operations.

The quantum-meter tool calibrates the CPU reference and a WebGPU member
that way and places a circuit by the figures. On an M4 Max, 20 qubits, 3 s
windows: the Metal member 4 nJ per operation, the CPU reference 9, so the
fabric placed the circuit on the GPU. Three repeats of the device test at
18 qubits read 4 and 9 to 10.

CI: the Metal job must print what the device test read and run the tool;
the software Vulkan job, where no such counter exists, must find the
meter not live and its runs unmetered.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
quantum-meter: the GPU probe's load runs for 50 ms each call, not one run
All checks were successful
wai-quantum WebGPU member / member · discrete GPU, Vulkan (jetson-hub) (pull_request) Successful in 10m31s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 50s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m32s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 4m25s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 1m20s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 57s
standards workspaces build + test / aac-rs (pull_request) Successful in 2m29s
wai-quantum WebGPU member / member · Metal (macos) (pull_request) Successful in 2m20s
standards workspaces build + test / map-rs (pull_request) Successful in 56s
standards workspaces build + test / mesh-rs (pull_request) Successful in 53s
wai-quantum WebGPU member / member · browser WebGPU (macos) (pull_request) Successful in 1m36s
standards workspaces build + test / openpay (pull_request) Successful in 2m54s
lockfiles / every Cargo.lock is current (pull_request) Successful in 40s
no-vanity-metrics / Scan committed Markdown for vanity metrics (pull_request) Successful in 3s
no-vanity-metrics / WAI public text names no comparison (pull_request) Successful in 3s
no-vanity-metrics / WAI public text names no company or product (pull_request) Successful in 3s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m9s
standards workspaces build + test / eoc-rs (pull_request) Successful in 2m1s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m30s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m10s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m12s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m16s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m19s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m7s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m49s
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness · MSRV (pull_request) Successful in 3m5s
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Successful in 2m5s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
8606de265c
The first meter in a process probes the GPU counter with a load, and the
probe needs a few tens of milliseconds of this process's GPU work between
its samples. One 18-qubit run of the member, about 2 ms on an M4 Max,
passed there by margin; on the CI Mac (M3 Ultra), whose GPU counter the
energy crate's own test finds live under a real burn, it was judged
Frozen, and every window was rightly unmetered.

probe_load wraps one run of a member so each call repeats it until 50 ms
have passed. The tool and the device test use it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Transaction-Science/open-standards!232
No description provided.