open-standards/.github/workflows/energy-hardware.yml
Transaction Science 4e8350def7 ci: run the new platform-gated meter tests where their platform is
The resident z3 tree tests (proof-solvers tests/z3_tree.rs) and the local
engine tree tests (sandbox-proof) are gated to Apple Silicon macOS, and the
matrix legs for proof-rs and sandbox-rs run on Linux, so they would run
nowhere. The macOS energy job now runs both and greps the line each metered
run prints ('z3 tree meter:', 'local engine tree:'): a missing z3 or a
per-process counter that is not live prints another line and fails the
step. Likewise the accelerator proof's RAPL path only runs on real
counters: the jetson-hub hardware job now runs sandbox-proof's accelerator
tests and fails unless the RAPL bracket line was printed, and triggers on
sandbox-proof changes.

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

134 lines
6.7 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.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
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/**'
- 'sandbox/sandbox-rs/crates/sandbox-proof/**'
- '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/**'
- 'sandbox/sandbox-rs/crates/sandbox-proof/**'
- '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; }
# sandbox-proof's accelerator proof: the span over a real workload's
# run, its RAPL figure against the package zones read around it.
log=$(mktemp)
CARGO_TARGET_DIR="$HOME/hw-target/sandbox-rs" nice -n 10 cargo test -p sandbox-proof --lib accelerator -- --nocapture --test-threads=1 2>&1 | tee "$log"
grep -q 'RAPL package .* oracle around the call' "$log" || { echo "::error::sandbox-proof: the accelerator span's RAPL 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; }