open-standards/.github/workflows/wai-quantum-vector.yml
Transaction Science e5191a6079 ci: the 0.5.1 member workflows run only when the pull request's own diff touches them
Neural processor, matrix extension, signal processor, vector units and the
dataflow device gain the same gate as the other wai-quantum workflows.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-14 19:56:41 -04:00

198 lines
9.8 KiB
YAML

name: wai-quantum CPU vector units
# The fabric's CPU vector-unit members: the gate's fixed-point arithmetic in
# the processor's own vector extension, certified bit-exact against the CPU
# reference's pinned corpus digests.
#
# - avx2 on silicon: the container runner's x86-64 processor;
# - sve and rvv under the host's user-mode emulator (its binfmt handler), at
# several vector lengths each: the scalable kernels set their length per
# pass, and every leg checks the length the member read from the unit is the
# one the emulator was given, so a leg cannot pass at the wrong length;
# - the macOS runner, whose processor has no vector extension these kernels
# use outside streaming mode, finding no member.
#
# Silicon for sve and rvv: a processor with them runs the same tests with no
# emulator declared.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
on:
push:
branches: [main]
paths:
- 'wai/wai-quantum/**'
- 'rust-toolchain.toml'
- '.github/workflows/wai-quantum-vector.yml'
pull_request:
paths:
- 'wai/wai-quantum/**'
- 'rust-toolchain.toml'
- '.github/workflows/wai-quantum-vector.yml'
jobs:
# Does this pull request's own diff touch the paths below? This forge matches a
# workflow's `paths:` against the push, so a merge of main into a branch fires the
# workflow whatever the pull request changes; every job here waits on this answer.
# A push to main, a schedule, or anything the script cannot determine answers
# `true` (scripts/pr-touches-paths.py).
relevant:
name: does this change touch it
runs-on: linux-arm64
outputs:
run: ${{ steps.gate.outputs.run }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- id: gate
run: |
set -euo pipefail
r=$(python3 scripts/pr-touches-paths.py .github/workflows/wai-quantum-vector.yml \
"${{ github.event.pull_request.base.sha }}" \
"${{ github.event.pull_request.head.sha }}")
echo "this change touches wai-quantum-vector: $r"
echo "run=$r" >> "$GITHUB_OUTPUT"
vector:
name: member · vector unit, ${{ matrix.name }}
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: linux
timeout-minutes: 120
strategy:
fail-fast: false
max-parallel: 1
matrix:
include:
- name: avx2 (x86_64 silicon)
target: x86_64-unknown-linux-gnu
image: ghcr.io/cross-rs/aarch64-unknown-linux-gnu@sha256:7f8308a8734d9fcd2ebbe9a3e4bdea74af293f0799d80c3cc341e340cda49a4c
key: cpu-vector-avx2
bits: 256
emulator: ''
qemu_cpu: ''
- name: sve 128-bit (aarch64, emulated)
target: aarch64-unknown-linux-gnu
image: ghcr.io/cross-rs/aarch64-unknown-linux-gnu@sha256:7f8308a8734d9fcd2ebbe9a3e4bdea74af293f0799d80c3cc341e340cda49a4c
key: cpu-vector-sve
bits: 128
emulator: qemu-user 8.2.2 (the host's binfmt handler)
qemu_cpu: max,sve-default-vector-length=16
- name: sve 512-bit (aarch64, emulated)
target: aarch64-unknown-linux-gnu
image: ghcr.io/cross-rs/aarch64-unknown-linux-gnu@sha256:7f8308a8734d9fcd2ebbe9a3e4bdea74af293f0799d80c3cc341e340cda49a4c
key: cpu-vector-sve
bits: 512
emulator: qemu-user 8.2.2 (the host's binfmt handler)
qemu_cpu: max,sve-default-vector-length=64
- name: sve 2048-bit (aarch64, emulated)
target: aarch64-unknown-linux-gnu
image: ghcr.io/cross-rs/aarch64-unknown-linux-gnu@sha256:7f8308a8734d9fcd2ebbe9a3e4bdea74af293f0799d80c3cc341e340cda49a4c
key: cpu-vector-sve
bits: 2048
emulator: qemu-user 8.2.2 (the host's binfmt handler)
qemu_cpu: max,sve-default-vector-length=256
- name: rvv 128-bit (riscv64, emulated)
target: riscv64gc-unknown-linux-gnu
image: ghcr.io/cross-rs/riscv64gc-unknown-linux-gnu@sha256:67ee97dd4719390d299edfcf39f226360ccfb1539e08b078ec187d4848415794
key: cpu-vector-rvv
bits: 128
emulator: qemu-user 8.2.2 (the host's binfmt handler)
qemu_cpu: rv64,v=true,vlen=128,elen=64
- name: rvv 1024-bit (riscv64, emulated)
target: riscv64gc-unknown-linux-gnu
image: ghcr.io/cross-rs/riscv64gc-unknown-linux-gnu@sha256:67ee97dd4719390d299edfcf39f226360ccfb1539e08b078ec187d4848415794
key: cpu-vector-rvv
bits: 1024
emulator: qemu-user 8.2.2 (the host's binfmt handler)
qemu_cpu: rv64,v=true,vlen=1024,elen=64
container:
image: ${{ matrix.image }}
options: --memory=6g --memory-swap=6g
env:
WAI_QUANTUM_VECTOR_EXPECT: ${{ matrix.key }}
WAI_QUANTUM_VECTOR_EMULATOR: ${{ matrix.emulator }}
# Run test binaries directly, so the host's handler runs them with the
# processor given here, not the image's older emulator.
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER: env
CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER: env
steps:
# The image has no Node for a checkout action: the forge's archive of the
# exact commit, its embedded commit id checked.
- name: Fetch the source
shell: bash
run: |
set -euo pipefail
want="${{ github.event.pull_request.head.sha || github.sha }}"
rm -rf src src.tar.gz src.tar && mkdir src
curl -sSf -o src.tar.gz "http://100.64.224.0:3400/Transaction-Science/open-standards/archive/$want.tar.gz"
gzip -dc src.tar.gz > src.tar
got="$(git get-tar-commit-id < src.tar)"
[ "$got" = "$want" ] || { echo "::error::the archive is of $got, not $want"; exit 1; }
tar -xf src.tar -C src --strip-components=1
rm src.tar.gz src.tar
- name: The member's tests
shell: bash
working-directory: src/wai/wai-quantum
run: |
set -euo pipefail
cache=/ci-cache/wai-quantum-vector
mkdir -p "$cache"
exec 9>"$cache/.lock"
flock 9
export RUSTUP_HOME="$cache/rustup" CARGO_HOME="$cache/cargo" CARGO_TARGET_DIR="$cache/target-${{ matrix.target }}"
export PATH="$CARGO_HOME/bin:$PATH"
if ! command -v rustup >/dev/null; then
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --no-modify-path --profile minimal --default-toolchain none
fi
rustup toolchain install
rustup target add ${{ matrix.target }}
# The emulated processor, for the test binaries only.
if [ -n "${{ matrix.qemu_cpu }}" ]; then export QEMU_CPU="${{ matrix.qemu_cpu }}"; fi
t="--target ${{ matrix.target }} --features quantum_fabric_vector"
cargo test --locked --release -j 6 $t --lib -- quantum_fabric_vector:: 2>&1 | tee "$cache/unit.log"
grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$cache/unit.log" || { echo "::error::no unit test ran"; exit 1; }
report="$(mktemp)"
WAI_QUANTUM_VECTOR_REPORT="$report" cargo test --locked --release -j 6 $t --test vector_member -- --test-threads=1 2>&1 | tee "$cache/device.log"
grep -qE '^test result: ok\. 9 passed; 0 failed' "$cache/device.log" || { echo "::error::not every device test ran and passed"; exit 1; }
cat "$report"
key="$WAI_QUANTUM_VECTOR_EXPECT"
grep -qx "vector devices: as declared ($key)" "$report" || { echo "::error::the unit found is not the declared one"; exit 1; }
grep -q "^vector member: key=$key .* bits=${{ matrix.bits }} " "$report" || { echo "::error::the unit's vector length is not ${{ matrix.bits }} bits"; exit 1; }
if [ -n "$WAI_QUANTUM_VECTOR_EMULATOR" ]; then
grep -q "^vector member: key=$key .*emulator:qemu-user" "$report" || { echo "::error::the member does not say it ran under the emulator"; exit 1; }
else
grep -q "^vector member: key=$key .*; silicon;" "$report" || { echo "::error::the member does not say it ran on silicon"; exit 1; }
fi
n="$(grep -c "^vector certified: key=$key .* parity=bit-exact " "$report")"
[ "$n" = 4 ] || { echo "::error::$n of 4 certificates were earned"; exit 1; }
grep -qx "vector mutants: key=$key killed 3 of 3" "$report" || { echo "::error::a kernel mutant survived"; exit 1; }
vector-absent:
name: member · vector unit absent (macos)
needs: relevant
if: needs.relevant.outputs.run == 'true'
runs-on: macos
timeout-minutes: 60
env:
WAI_QUANTUM_VECTOR_EXPECT: none
steps:
- uses: actions/checkout@v5
# launchd's PATH omits cargo on the macOS host runner.
- name: Put cargo on PATH
shell: bash
run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: No vector unit these kernels use, and the member says so
shell: bash
working-directory: wai/wai-quantum
run: |
set -euo pipefail
report="$RUNNER_TEMP/vector-report.txt"; : > "$report"
nice -n 10 cargo test --locked --features quantum_fabric_vector --lib -- quantum_fabric_vector:: 2>&1 | tee "$RUNNER_TEMP/unit.log"
grep -qE '^test result: ok\. [1-9][0-9]* passed; 0 failed' "$RUNNER_TEMP/unit.log" || { echo "::error::no unit test ran"; exit 1; }
WAI_QUANTUM_VECTOR_REPORT="$report" nice -n 10 cargo test --locked --features quantum_fabric_vector --test vector_member -- --test-threads=1 2>&1 | tee "$RUNNER_TEMP/device.log"
grep -qE '^test result: ok\. 9 passed; 0 failed' "$RUNNER_TEMP/device.log" || { echo "::error::not every device test ran and passed"; exit 1; }
grep -qx 'vector devices: as declared (none)' "$report" || { echo "::error::the absent case was not established"; exit 1; }