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; }