mesh-meter: a span shorter than its counter's minimum window is an estimate #630

Merged
dcharlot merged 1 commit from mesh-meter/min-window into main 2026-11-05 04:31:21 -05:00
Owner

Every energy counter declares the smallest window over which its readings aren't noise, its min_window_ns: about 10 ms for RAPL and IOReport, 100 ms for NVML, and 2 s for a Mac's SMC power integral (#622). Over a shorter span, a counter's delta is whatever its updates and rounding happened to give, often zero or a whole update period.

Mesh didn't check this and graded such a span at the counter's grade. So a request lasting a few milliseconds could be sealed HwShunt at 0 µJ, or ModelBased at a power reading stretched over the span.

What changes

  • Spec rule, mesh/SPEC.md §3.3: a span shorter than the minimum window of the counter that would grade it MUST NOT be graded HwShunt or ModelBased from that counter. It counts as an estimate of the request, and SHOULD be billed by an estimator that resolves the span's own length, so a short request is never billed zero.
  • HwMeter:
    • It now opens its own window (Meter::open_span), which Session already prefers, so every span is timed.
    • A span shorter than the backend's minimum window (the new HwMeter::min_window) is billed this crate's EstimatorMeter over the span's own length. It's graded Estimator with no measured_uj, the same way a span across a failed read already is.
    • A span at or past the minimum window keeps the counter's figure and grade, exactly as before.
    • min_window is zero where the bridge already bills by its estimator.
  • ProcessMeter:
    • Where ProcessSpanMeter falls back to the host meter, a span shorter than the host meter's minimum window is billed the same way.
    • Spans that this process's own CPU and GPU counters measured don't go through the host meter, so the rule doesn't apply to them.
  • jouleclaw-energy: adds ProcessSpanMeter::fallback_min_window() (additive), so a caller can apply the rule.

Each span is timed from just after its opening read to just before its closing one. That's slightly shorter than the counter's own window, so a span right at the minimum counts as short rather than long.

A caller that subtracts Meter::snapshots itself gets no such check. Session, which mesh-core serves through, does.

Verified

  • New tests:
    • With a 50 ms minimum window, a 20 ms span is graded Estimator at the estimator's figure for 20 ms. A 60 ms span keeps the counter's figure and grade, for both HwShunt and ModelBased.
    • The bridge reports its counter's minimum window until a read fails, and zero after.
    • A host-meter fallback span under the host's minimum window is an estimate; past it, the host's figure stands. A span this process's own counters measured keeps its grade.
  • Linux x86_64: mesh-meter (default and hw-meter-rapl), mesh-core (hw-meter-rapl) and mesh-conformance pass. Clippy is clean.
  • macOS (M3 Ultra): mesh-meter and mesh-core pass with hw-meter-apple, including a real in-process serve sealed HwShunt. Clippy is clean for mesh-meter and jouleclaw-energy.

Follow-up

Once #622 lands, hw-meter-apple can also enable jouleclaw-energy/smc. The SMC's 2 s floor is now handled, so short serves on a Mac would be estimated rather than sealed ModelBased.

🤖 Generated with Claude Code

Every energy counter declares the smallest window over which its readings aren't noise, its `min_window_ns`: about 10 ms for RAPL and IOReport, 100 ms for NVML, and 2 s for a Mac's SMC power integral (#622). Over a shorter span, a counter's delta is whatever its updates and rounding happened to give, often zero or a whole update period. Mesh didn't check this and graded such a span at the counter's grade. So a request lasting a few milliseconds could be sealed `HwShunt` at 0 µJ, or `ModelBased` at a power reading stretched over the span. ## What changes - **Spec rule, `mesh/SPEC.md` §3.3:** a span shorter than the minimum window of the counter that would grade it MUST NOT be graded `HwShunt` or `ModelBased` from that counter. It counts as an estimate of the request, and SHOULD be billed by an estimator that resolves the span's own length, so a short request is never billed zero. - **`HwMeter`:** - It now opens its own window (`Meter::open_span`), which `Session` already prefers, so every span is timed. - A span shorter than the backend's minimum window (the new `HwMeter::min_window`) is billed this crate's `EstimatorMeter` over the span's own length. It's graded `Estimator` with no `measured_uj`, the same way a span across a failed read already is. - A span at or past the minimum window keeps the counter's figure and grade, exactly as before. - `min_window` is zero where the bridge already bills by its estimator. - **`ProcessMeter`:** - Where `ProcessSpanMeter` falls back to the host meter, a span shorter than the host meter's minimum window is billed the same way. - Spans that this process's own CPU and GPU counters measured don't go through the host meter, so the rule doesn't apply to them. - **`jouleclaw-energy`:** adds `ProcessSpanMeter::fallback_min_window()` (additive), so a caller can apply the rule. Each span is timed from just after its opening read to just before its closing one. That's slightly shorter than the counter's own window, so a span right at the minimum counts as short rather than long. A caller that subtracts `Meter::snapshot`s itself gets no such check. `Session`, which `mesh-core` serves through, does. ## Verified - **New tests:** - With a 50 ms minimum window, a 20 ms span is graded `Estimator` at the estimator's figure for 20 ms. A 60 ms span keeps the counter's figure and grade, for both `HwShunt` and `ModelBased`. - The bridge reports its counter's minimum window until a read fails, and zero after. - A host-meter fallback span under the host's minimum window is an estimate; past it, the host's figure stands. A span this process's own counters measured keeps its grade. - **Linux x86_64:** `mesh-meter` (default and `hw-meter-rapl`), `mesh-core` (`hw-meter-rapl`) and `mesh-conformance` pass. Clippy is clean. - **macOS (M3 Ultra):** `mesh-meter` and `mesh-core` pass with `hw-meter-apple`, including a real in-process serve sealed `HwShunt`. Clippy is clean for `mesh-meter` and `jouleclaw-energy`. ## Follow-up Once #622 lands, `hw-meter-apple` can also enable `jouleclaw-energy/smc`. The SMC's 2 s floor is now handled, so short serves on a Mac would be estimated rather than sealed `ModelBased`. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
mesh-meter: a span shorter than its counter's minimum window is an estimate
All checks were successful
wai-quantum WebGPU member / does this change touch it (pull_request) Successful in 6s
standards workspaces build + test / which workspaces this change touches (pull_request) Successful in 14s
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 49s
standards workspaces build + test / mesh-rs (mesh/mesh-rs, -p mesh-engine-gguf -p mesh-openai --features mesh-engine-gguf/gguf,mesh-openai/server, mesh-rs, linux-arm64) (pull_request) Successful in 54s
standards workspaces build + test / joulehook-rs (joulehook/joulehook-rs, joulehook-rs, linux) (pull_request) Successful in 1m13s
wai-quantum WebGPU member / member · software Vulkan (linux) (pull_request) Successful in 1m49s
standards workspaces build + test / jouleclaw-rs (-nodebug, jouleclaw/jouleclaw-rs, -p jouleclaw-energy --features rapl,nvml, jouleclaw-rs, linux-arm64, -C target-feature=+fp16) (pull_request) Successful in 2m56s
repository checks / lockfiles, advisories, tests in CI, workflow hygiene, spec and section references, public text (pull_request) Successful in 3m30s
wai-quantum WebGPU member / shader checks · browser build · wasip2 inertness (pull_request) Successful in 3m24s
energy meters on real hardware / sink decode table · per-task energy and the GPU rail on macOS (pull_request) Successful in 2m16s
wai-quantum WebGPU member / member · Metal (macos) (pull_request) Successful in 2m46s
standards workspaces build + test / jouledesk-rs (jouledesk/jouledesk-rs, jouledesk-rs, macos) (pull_request) Successful in 1m42s
wai-quantum WebGPU member / member · integrated GPU, Vulkan (framework-128gb) (pull_request) Successful in 7m42s
wai-quantum WebGPU member / member · browser WebGPU (macos) (pull_request) Successful in 3m52s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 6m56s
wai-quantum WebGPU member / member · DX12 and Vulkan (cbio-windows) (pull_request) Successful in 11m48s
energy meters on real hardware / RAPL and NVML on jetson-hub (pull_request) Successful in 35s
energy meters on real hardware / sink decode table · RAPL on jetson-hub (NVML surveyed) (pull_request) Successful in 2m23s
wai-quantum WebGPU member / member · GPU, Vulkan (thor) (pull_request) Successful in 24m54s
wai-quantum WebGPU member / member · GPU, Vulkan (jetson-hub) (pull_request) Successful in 17m32s
4a7ca45718
A counter declares the smallest window over which its readings are not noise
(min_window_ns: about 10 ms for RAPL and IOReport, 100 ms for NVML; 2 s for a
Mac's SMC power integral). Across a shorter span its delta is whatever its
updates and quantization gave, often zero or a whole update period, yet mesh
graded it at the counter's grade: a few-millisecond request could be sealed
HwShunt at 0 µJ, or ModelBased at a power reading's extrapolation.

- SPEC 3.3: a span shorter than the minimum window of the counter that would
  grade it MUST NOT be graded HwShunt or ModelBased from that counter; it is
  an estimate of the request, and SHOULD be billed by an estimator that
  resolves the span's own length, so a short request is never billed zero.
- HwMeter opens its own window (Meter::open_span), which Session uses: it
  times the span, and one shorter than the backend's floor
  (HwMeter::min_window) is billed this crate's EstimatorMeter over the span's
  own length, graded Estimator with no measured_uj, as a span across a failed
  read is. Past the floor the counter's figure stands, graded as before.
  min_window is zero where the bridge already bills by its estimator.
- ProcessMeter: where ProcessSpanMeter falls back to the host meter, a span
  shorter than the host meter's floor is billed the same way. Spans its own
  CPU and GPU counters metered are not the host meter's and are unaffected.
- jouleclaw-energy: ProcessSpanMeter::fallback_min_window, the active fallback
  meter's min_window_ns, so a caller can apply the rule. Additive.

Each span is timed from after its opening read to before its closing one, a
little shorter than the counter's own window, so a span at the floor is judged
short rather than long.

Tests: under a 50 ms floor a 20 ms span is Estimator at the estimator's figure
for 20 ms, and a 60 ms span keeps the counter's figure and grade (HwShunt and
ModelBased); the bridge's minimum window is its counter's until a failed read,
then zero; a host-meter fallback span under the host floor is an estimate,
past it the host figure stands, and a span this process's own counters
metered keeps its grade. Linux x86_64: mesh-meter (default, hw-meter-rapl),
mesh-core (hw-meter-rapl) and mesh-conformance pass; clippy clean. macOS
(M3 Ultra): mesh-meter and mesh-core with hw-meter-apple pass, including a
real in-process serve sealed HwShunt; clippy clean for mesh-meter and
jouleclaw-energy.

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!630
No description provided.