open-standards/.github/workflows/energy-hardware.yml
Transaction Science 9318986759
All checks were successful
energy meters on real hardware / RAPL and NVML on jetson-hub (pull_request) Successful in 1m2s
standards workspaces build + test / eoc-rs (pull_request) Successful in 1m53s
standards workspaces build + test / jcp-rs (pull_request) Successful in 1m26s
standards workspaces build + test / proof-rs (pull_request) Successful in 1m12s
standards workspaces build + test / sandbox-rs (pull_request) Successful in 2m13s
standards workspaces build + test / smart-byte-rs (pull_request) Successful in 3m41s
standards workspaces build + test / jouleclaw-rs (pull_request) Successful in 2m32s
standards workspaces build + test / aac-rs (pull_request) Successful in 1m32s
standards workspaces build + test / joule-code-rs (pull_request) Successful in 56s
standards workspaces build + test / joulecontract-rs (pull_request) Successful in 39s
standards workspaces build + test / map-rs (pull_request) Successful in 37s
standards workspaces build + test / mesh-rs (pull_request) Successful in 30s
standards workspaces build + test / openpay (pull_request) Successful in 1m47s
standards workspaces build + test / arl-rs (pull_request) Successful in 3m44s
standards workspaces build + test / joule-ui-rs (pull_request) Successful in 3m49s
standards workspaces build + test / jouledesk-rs (pull_request) Successful in 3m48s
standards workspaces build + test / joulehook-rs (pull_request) Successful in 3m42s
standards workspaces build + test / sense-rs (pull_request) Successful in 3m45s
standards workspaces build + test / macOS energy backends (pull_request) Successful in 5m38s
ci: run the energy meters' RAPL and NVML tests on real hardware
Every existing job runs in a container. Docker masks
/sys/devices/virtual/powercap there and gives no GPU, so the energy
crates' hardware tests only ever took their "unavailable, and the oracle
agrees" branch. This job runs on `linux-hw`, a host executor on
jetson-hub. It runs as an unprivileged user (no sudo, no docker) that
can read powercap and open /dev/nvidia*, on an Intel i9-13900H with
package-0, a core sub-zone, psys and an mmio package, and an RTX 4050
Laptop GPU.

It runs jcp-energy, eoc-meter, sandbox-meter, sandbox-exec-microvm,
proof-cascade and jouleclaw-energy, with their NVML features on. Each
step fails unless the live path ran:
- RAPL: the oracle's package-only bracket was printed;
- NVML: the GPU was seen.

The source is fetched with plain git (the host has no Node), and the
step checks it got the commit the run is for. Target dirs persist in
the runner's home between runs.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-05 12:06:39 -04:00

123 lines
6 KiB
YAML

name: energy meters on real hardware
# The Linux RAPL and NVML meters, run against real counters.
#
# Every other job runs in a container, where Docker masks
# /sys/devices/virtual/powercap and there is no GPU, so the energy crates'
# hardware tests only ever take their "unavailable, and the oracle agrees"
# branch there. This job runs on `linux-hw`: a host executor on jetson-hub
# (Intel i9-13900H: package-0, a core sub-zone, psys, an mmio package; NVIDIA
# RTX 4050 Laptop GPU), as an unprivileged user that can read
# /sys/class/powercap and open /dev/nvidia*. Here the live branch runs, and each
# step fails unless it did:
#
# - RAPL: the test printed the oracle's package-only bracket ("package-only
# inner ... outer ..."), which only the live path prints, after asserting the
# meter read inside it, below package+psys and below package+core.
# - NVML: the test saw the GPU ("nvml hardware: 1 GPU"). On this GPU the
# counter runs past the board while it is polled, so the test asserts the
# meter calls it Implausible and never grades it as hardware.
#
# The host has no Node, so there are no JavaScript actions: the source is
# fetched with plain git, and each workspace keeps its target directory in the
# runner's home between runs.
on:
pull_request:
paths:
- 'jcp/jcp-rs/crates/jcp-energy/**'
- 'eoc/eoc-rs/crates/eoc-meter/**'
- 'sandbox/sandbox-rs/crates/sandbox-meter/**'
- 'sandbox/sandbox-rs/crates/sandbox-exec-microvm/**'
- 'proof/proof-rs/crates/proof-cascade/**'
- 'jouleclaw/jouleclaw-rs/crates/jouleclaw-energy/**'
- '.github/workflows/energy-hardware.yml'
push:
branches:
- main
paths:
- 'jcp/jcp-rs/crates/jcp-energy/**'
- 'eoc/eoc-rs/crates/eoc-meter/**'
- 'sandbox/sandbox-rs/crates/sandbox-meter/**'
- 'sandbox/sandbox-rs/crates/sandbox-exec-microvm/**'
- 'proof/proof-rs/crates/proof-cascade/**'
- 'jouleclaw/jouleclaw-rs/crates/jouleclaw-energy/**'
- '.github/workflows/energy-hardware.yml'
jobs:
hardware:
name: RAPL and NVML on jetson-hub
runs-on: linux-hw
timeout-minutes: 150
env:
CARGO_PROFILE_DEV_DEBUG: '0'
CARGO_BUILD_JOBS: '8'
steps:
- name: Fetch the source
shell: bash
run: |
set -euo pipefail
ref="${{ github.event_name == 'pull_request' && format('refs/pull/{0}/head', github.event.pull_request.number) || github.ref }}"
want="${{ github.event.pull_request.head.sha || github.sha }}"
rm -rf src && mkdir src && cd src
git init -q
git fetch -q --depth 1 http://100.64.224.0:3400/Transaction-Science/open-standards.git "$ref"
git checkout -q FETCH_HEAD
got="$(git rev-parse HEAD)"
echo "fetched $ref at $got"
if [ "$got" != "$want" ]; then
echo "::error::$ref is at $got, not $want: it moved after this run started, and a newer run tests it"
exit 1
fi
- name: jcp-energy (RAPL, NVML)
shell: bash
working-directory: src/jcp/jcp-rs
run: |
set -euo pipefail
log=$(mktemp)
CARGO_TARGET_DIR="$HOME/hw-target/jcp-rs" nice -n 10 cargo test -p jcp-energy --features nvml --test rapl_hardware --test nvml_hardware -- --nocapture --test-threads=1 2>&1 | tee "$log"
grep -q 'package-only inner' "$log" || { echo "::error::the RAPL live path never ran"; exit 1; }
grep -q 'nvml hardware: 1 GPU' "$log" || { echo "::error::NVML saw no GPU"; exit 1; }
- name: eoc-meter (RAPL, NVML)
shell: bash
working-directory: src/eoc/eoc-rs
run: |
set -euo pipefail
log=$(mktemp)
CARGO_TARGET_DIR="$HOME/hw-target/eoc-rs" nice -n 10 cargo test -p eoc-meter --features cuda --test rapl_hardware --test nvml_hardware -- --nocapture --test-threads=1 2>&1 | tee "$log"
grep -q 'package-only inner' "$log" || { echo "::error::the RAPL live path never ran"; exit 1; }
grep -q 'nvml hardware: 1 GPU' "$log" || { echo "::error::NVML saw no GPU"; exit 1; }
- name: sandbox-meter (RAPL, NVML) and sandbox-exec-microvm (RAPL)
shell: bash
working-directory: src/sandbox/sandbox-rs
run: |
set -euo pipefail
log=$(mktemp)
CARGO_TARGET_DIR="$HOME/hw-target/sandbox-rs" nice -n 10 cargo test -p sandbox-meter --test rapl_hardware --test nvml_hardware -- --nocapture --test-threads=1 2>&1 | tee "$log"
grep -q 'package-only inner' "$log" || { echo "::error::sandbox-meter: the RAPL live path never ran"; exit 1; }
grep -q 'nvml hardware: 1 GPU' "$log" || { echo "::error::sandbox-meter: NVML saw no GPU"; exit 1; }
log=$(mktemp)
CARGO_TARGET_DIR="$HOME/hw-target/sandbox-rs" nice -n 10 cargo test -p sandbox-exec-microvm --test rapl_hardware -- --nocapture --test-threads=1 2>&1 | tee "$log"
grep -q 'package-only inner' "$log" || { echo "::error::sandbox-exec-microvm: the RAPL live path never ran"; exit 1; }
- name: proof-cascade (RAPL)
shell: bash
working-directory: src/proof/proof-rs
run: |
set -euo pipefail
log=$(mktemp)
CARGO_TARGET_DIR="$HOME/hw-target/proof-rs" nice -n 10 cargo test -p proof-cascade --test rapl_hardware -- --nocapture --test-threads=1 2>&1 | tee "$log"
grep -q 'rapl hardware:.*oracle Live' "$log" || { echo "::error::the RAPL counter was not live to the oracle"; exit 1; }
- name: jouleclaw-energy (RAPL, NVML)
shell: bash
working-directory: src/jouleclaw/jouleclaw-rs
run: |
set -euo pipefail
log=$(mktemp)
CARGO_TARGET_DIR="$HOME/hw-target/jouleclaw-rs" nice -n 10 cargo test -p jouleclaw-energy --features rapl,nvml --test rapl_hardware --test nvml_hardware -- --nocapture --test-threads=1 2>&1 | tee "$log"
grep -q 'package-only inner' "$log" || { echo "::error::the RAPL live path never ran"; exit 1; }
grep -q 'nvml hardware: 1 GPU' "$log" || { echo "::error::NVML saw no GPU"; exit 1; }