open-standards/jouleclaw/jouleclaw-rs/crates/jouleclaw-loader-gguf/tests/process_calibration.rs
Transaction Science 68aa43bafd
All checks were successful
energy meters on real hardware / RAPL and NVML on jetson-hub (pull_request) Successful in 37s
joule-code conformance gate / Build + round-trip C1-C4 vectors (pull_request) Successful in 2m6s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m48s
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
jouleclaw public surface must stay documented / Public-surface audit (jouleclaw-rs) (pull_request) Successful in 1m1s
standards workspaces build + test / arl-rs (pull_request) Successful in 1m9s
standards workspaces build + test / eoc-rs (pull_request) Successful in 2m0s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m35s
standards workspaces build + test / aac-rs (pull_request) Successful in 3m23s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 1m11s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 1m11s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 56s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m22s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 39s
standards workspaces build + test / map-rs (pull_request) Successful in 28s
standards workspaces build + test / mesh-rs (pull_request) Successful in 28s
standards workspaces build + test / sense-rs (pull_request) Successful in 1m9s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m23s
workflow hygiene / every workflow supersedes its own queue (pull_request) Successful in 4s
standards workspaces build + test / openpay (pull_request) Successful in 1m19s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 4m5s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 2m58s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 9m53s
ci: run the L3 and fabric-meter oracle tests on the macOS energy job
No job ran the oracle assertions this branch added. joule-code-rs's matrix
entry runs on linux-arm64, where joule-fix's L3 energy test has no tree
meter and takes its fallback branch; jouleclaw-loader-gguf's calibration
tests need the fabric-meter feature, which no job passed, and their oracle
needs macOS.

The macOS energy job now runs both, each step in the job's style (pipefail,
a tee'd log, a grep gate on a line the test prints only where its gated
assertion ran):
- joule-code-remediate `l3_`: 'l3 model process:' (the model's reading
  checked against the stand-in's own count). The stand-in itself stays
  #[ignore]: it is the subprocess the oracle test runs (filtered to it,
  --ignored), not a test of its own, and the oracle test is not ignored.
- jouleclaw-loader-gguf --features "rayon fabric-meter": the marginal_energy
  tests ('calibration row stamped on macOS:') and tests/process_calibration
  ('process calibration: CPU member'); this also builds the fabric-meter
  examples. joule-code-rs's target dir and Cargo.lock join the job's cache.

The l3-jouleclaw example workspace stays out of this job (a heavy separate
build on the one macOS runner); its README says its oracle tests run locally.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 22:24:17 -04:00

84 lines
4.3 KiB
Rust

//! A fabric member priced on this process's own counters
//! (`marginal_energy::measure_member_process`, what `fabric_calibrate` and
//! `mpp_energy` fall back to where the IOReport CPU rail is frozen), against an
//! oracle sharing no code with the meter: this process's own CPU energy count,
//! read around the same span with a bare `proc_pid_rusage`.
//!
//! One test in its own binary, so no other test's thread runs in this process
//! during the span (the span, and the oracle, read every thread of it).
#![cfg(feature = "fabric-meter")]
use jouleclaw_energy::span::ProcessSpanMeter;
use jouleclaw_loader_gguf::marginal_energy::{measure_member_process, MemberRuns, NotMeasured};
/// This process's own CPU energy count, nJ: `proc_pid_rusage(getpid(),
/// RUSAGE_INFO_V6)`'s `ri_energy_nj`, read with a bare buffer of the struct's 464
/// bytes at its SDK offset, 336. Written out here, sharing no code with the meter
/// it checks.
#[cfg(target_os = "macos")]
fn own_energy_nj() -> u64 {
unsafe extern "C" {
fn proc_pid_rusage(pid: i32, flavor: i32, buffer: *mut std::ffi::c_void) -> i32;
}
let mut buf = [0u64; 58];
// SAFETY: `buf` is 464 writable bytes, the size of `rusage_info_v6`.
let rc = unsafe { proc_pid_rusage(std::process::id() as i32, 6, buf.as_mut_ptr().cast()) };
assert_eq!(rc, 0, "proc_pid_rusage on this process");
buf[336 / 8]
}
#[cfg(not(target_os = "macos"))]
fn own_energy_nj() -> u64 {
0
}
/// A CPU member (the NEON BF16 matmul) priced on this process: where both of this
/// process's counters are live, the figure is given, its GPU part an exact zero, and
/// its CPU part agrees with the oracle, read inside the span at the first operation's
/// start and the last one's end — so the span holds the oracle's window and differs
/// from it only by the meter's last and first reads around it — and the per-GFLOP
/// figure is that energy over the work. Where they are not, the member is refused,
/// never priced on the host meter. Twice, three seconds each, however loaded the host.
#[test]
fn a_cpu_member_is_priced_on_this_process_as_its_own_count_says() {
use std::cell::Cell;
let meter = ProcessSpanMeter::new(jouleclaw_backend_apple::gpu_liveness_load);
let (m, n, k) = (16usize, 512usize, 512usize);
let gflop = 2.0 * (m * n * k) as f64 / 1e9;
let a: Vec<f32> = (0..m * k).map(|i| ((i % 101) as f32 / 50.0) - 1.0).collect();
let w: Vec<u8> = (0..n * k)
.flat_map(|i| jouleclaw_loader_gguf::matmul_bf16::f32_to_bf16_rne(((i % 97) as f32 / 48.0 - 1.0) * 0.1).to_le_bytes())
.collect();
let mut out = vec![0f32; m * n];
for round in 1..=2 {
let (first, last) = (Cell::new(None), Cell::new(0u64));
let figure = measure_member_process(&meter, MemberRuns::Cpu, gflop, 3.0, || {
if first.get().is_none() {
first.set(Some(own_energy_nj()));
}
jouleclaw_loader_gguf::matmul_bf16::matmul_bf16_neon(&a, &w, &[], m, n, k, &mut out);
last.set(own_energy_nj());
});
let oracle_uj = (last.get() - first.get().expect("the work ran")) / 1_000;
eprintln!("CPU member round {round}: oracle {oracle_uj} µJ; metered={} {figure:?}", meter.is_metered());
if meter.is_metered() {
let f = figure.expect("a CPU member on live counters is priced");
assert_eq!(f.gpu_uj, 0, "the NEON matmul spent GPU energy: {f:?}");
assert_eq!(f.provenance, jouleclaw_energy::Provenance::HwShunt);
assert!(oracle_uj > 100_000, "setup: the work read {oracle_uj} µJ");
let ratio = f.cpu_uj as f64 / oracle_uj as f64;
assert!((0.9..=1.1).contains(&ratio), "the span read {} µJ of {oracle_uj} µJ", f.cpu_uj);
let total = f.uj_per_gflop * f.ops as f64 * gflop;
assert!((total - f.cpu_uj as f64).abs() <= 1.0, "{total} µJ priced of {} µJ read", f.cpu_uj);
// CI's macOS energy job greps for this line: the oracle ran on live counters.
eprintln!("process calibration: CPU member round {round} read {} µJ of {oracle_uj} µJ", f.cpu_uj);
} else {
let why = figure.expect_err("no live counters, yet a figure");
assert!(
matches!(why, NotMeasured::NotWhole(_) | NotMeasured::NotOwnCounters(_) | NotMeasured::SpanFailed(_)),
"{why}"
);
}
}
}