|
1 | 1 | #!/bin/sh |
2 | | -# SIMD codegen oracle -- proves what actually vectorizes (crates/simd-codegen-oracle), |
3 | | -# in both directions: Group A probes must show packed AVX2 instructions, Group B |
4 | | -# probes must show none, Group C probes are reported without a pass/fail verdict |
5 | | -# (the open question this oracle was extended to answer). Mirrors the build/locate |
6 | | -# shape of scripts/neon-parity.sh / scripts/wasm-parity.sh, but the analysis itself |
7 | | -# (instruction classification, baseline comparison) lives in the Python helper |
8 | | -# scripts/codegen_oracle_analyze.py -- see its module docstring for the exact |
9 | | -# packed-vector / scalar-lane-arith / loop-control / memory / other classification |
10 | | -# rules and the documented honesty rule (a loop-counter decl is not lane |
11 | | -# arithmetic). |
| 2 | +# SIMD codegen oracle -- measures what actually vectorizes, in both directions: |
| 3 | +# Group A probes must show packed SIMD, Group B probes must show none, Group C |
| 4 | +# probes are reported without a pass/fail verdict. |
12 | 5 | # |
13 | | -# Usage: scripts/codegen-oracle.sh [target-triple] [-- --verbose] |
14 | | -# target-triple defaults to the host triple (`rustc -vV | grep ^host`). |
15 | | -# Everything after the target is forwarded to the analyzer (e.g. --verbose |
16 | | -# to print the raw instruction list per bucket). |
| 6 | +# This is an ON-DEMAND instrument, not a CI job. Run it when a codegen question |
| 7 | +# is genuinely open, record the answer in a doc, and stop. See README.md. |
| 8 | +# |
| 9 | +# Self-contained: builds a throwaway crate from probes.rs against the ndarray |
| 10 | +# checkout this file lives in, so nothing needs to exist under crates/. |
| 11 | +# |
| 12 | +# Usage: sh run.sh [target-triple] [--verbose] |
| 13 | +# target-triple defaults to the host triple. |
17 | 14 | set -eu |
18 | 15 |
|
19 | | -ROOT="$(cd "$(dirname "$0")/.." && pwd)" |
20 | | -MANIFEST="$ROOT/crates/simd-codegen-oracle/Cargo.toml" |
| 16 | +HERE="$(cd "$(dirname "$0")" && pwd)" |
| 17 | +# .claude/knowledge/simd-codegen-oracle -> repo root is three levels up. |
| 18 | +REPO="$(cd "$HERE/../../.." && pwd)" |
| 19 | +if [ ! -f "$REPO/Cargo.toml" ]; then |
| 20 | + echo "==> cannot locate the ndarray repo root from $HERE" >&2 |
| 21 | + exit 91 |
| 22 | +fi |
21 | 23 |
|
22 | 24 | TARGET="${1:-}" |
23 | 25 | case "$TARGET" in |
24 | | - "" | -*) |
25 | | - TARGET="$(rustc -vV | sed -n 's/^host: //p')" |
26 | | - ;; |
27 | | - *) |
28 | | - shift |
29 | | - ;; |
| 26 | + "" | -*) TARGET="$(rustc -vV | sed -n 's/^host: //p')" ;; |
| 27 | + *) shift ;; |
30 | 28 | esac |
31 | | -# Remaining args (an optional `--` and/or analyzer flags like --verbose) forward as-is. |
32 | | -if [ "${1:-}" = "--" ]; then |
33 | | - shift |
34 | | -fi |
35 | 29 |
|
36 | | -BASELINE="$ROOT/crates/simd-codegen-oracle/baselines/$TARGET.toml" |
| 30 | +case "$TARGET" in |
| 31 | + x86_64-*) BASELINE="$HERE/baseline-x86_64-v3.toml"; CPU="x86-64-v3" ;; |
| 32 | + *) BASELINE="$HERE/baseline-$TARGET.toml"; CPU="" ;; |
| 33 | +esac |
37 | 34 | if [ ! -f "$BASELINE" ]; then |
38 | | - echo "==> no baseline for target $TARGET at $BASELINE" >&2 |
| 35 | + echo "==> no baseline for $TARGET at $BASELINE" >&2 |
| 36 | + echo " (run with --verbose and record the observed counts to make one)" >&2 |
39 | 37 | exit 90 |
40 | 38 | fi |
41 | 39 |
|
42 | | -# The measured baseline is DECLARED here, never inherited from the ambient |
43 | | -# environment. This is load-bearing: |
| 40 | +SCRATCH="${TMPDIR:-/tmp}/simd-codegen-oracle-$$" |
| 41 | +trap 'rm -rf "$SCRATCH"' EXIT |
| 42 | +mkdir -p "$SCRATCH/src" |
| 43 | +cp "$HERE/probes.rs" "$SCRATCH/src/main.rs" |
| 44 | +cat > "$SCRATCH/Cargo.toml" <<EOF |
| 45 | +[package] |
| 46 | +name = "simd-codegen-oracle" |
| 47 | +version = "0.0.0" |
| 48 | +edition = "2021" |
| 49 | +
|
| 50 | +[dependencies] |
| 51 | +ndarray = { path = "$REPO", default-features = false, features = ["std"] } |
| 52 | +
|
| 53 | +[profile.release] |
| 54 | +debug = false |
| 55 | +EOF |
| 56 | + |
| 57 | +# The measured baseline is DECLARED, never inherited. Two independent reasons, |
| 58 | +# and the first alone is NOT sufficient: |
44 | 59 | # |
45 | | -# `.cargo/config.toml` sets `-Ctarget-cpu=x86-64-v3` via |
46 | | -# `[target.'cfg(target_arch = "x86_64")'].rustflags`, but cargo's RUSTFLAGS |
47 | | -# env var REPLACES that config wholesale — the two do not merge. CI sets |
48 | | -# `RUSTFLAGS: "-D warnings"` at workflow level (.github/workflows/ci.yaml), |
49 | | -# so on CI the target-cpu flag is silently DROPPED and everything compiles |
50 | | -# at baseline x86-64 (SSE2). Verified: |
51 | | -# $ cargo build -v | grep target-cpu -> target-cpu=x86-64-v3 |
52 | | -# $ RUSTFLAGS="-D warnings" cargo build -v | grep target-cpu -> (empty) |
| 60 | +# 1. cargo resolves .cargo/config.toml from the CURRENT WORKING DIRECTORY, |
| 61 | +# not from --manifest-path. Running from elsewhere silently misses the |
| 62 | +# repo's config. Hence the `cd "$REPO"` below. |
| 63 | +# 2. Even from the right directory, cargo's RUSTFLAGS env var REPLACES |
| 64 | +# `[target.'cfg(...)'].rustflags` rather than merging with it. CI sets |
| 65 | +# RUSTFLAGS="-D warnings" at workflow level, which drops the target-cpu |
| 66 | +# pin entirely: |
| 67 | +# $ cargo build -v | grep target-cpu -> x86-64-v3 |
| 68 | +# $ RUSTFLAGS="-D warnings" cargo build -v | grep ... -> (nothing) |
53 | 69 | # |
54 | | -# An oracle that inherits the ambient baseline therefore measures a |
55 | | -# DIFFERENT machine's codegen depending on where it runs, which is exactly |
56 | | -# the class of error it exists to catch. Passing `-C target-cpu` after the |
57 | | -# `--` puts it on the final rustc invocation, where it wins regardless of |
58 | | -# RUSTFLAGS. |
59 | | -case "$TARGET" in |
60 | | - x86_64-*) BASELINE_CPU="x86-64-v3" ;; |
61 | | - *) BASELINE_CPU="" ;; |
62 | | -esac |
63 | | - |
64 | | -if [ -n "$BASELINE_CPU" ]; then |
65 | | - CPU_FLAG="-C target-cpu=$BASELINE_CPU" |
66 | | - echo "==> baseline: $TARGET @ target-cpu=$BASELINE_CPU (declared, not inherited)" |
| 70 | +# Only passing `-C target-cpu` on the final rustc invocation survives both. |
| 71 | +# An oracle that inherits its baseline measures a different machine depending |
| 72 | +# on where it runs -- exactly the class of error it exists to catch. |
| 73 | +if [ -n "$CPU" ]; then |
| 74 | + CPU_FLAG="-C target-cpu=$CPU" |
| 75 | + echo "==> baseline: $TARGET @ target-cpu=$CPU (declared, not inherited)" |
67 | 76 | else |
68 | 77 | CPU_FLAG="" |
69 | 78 | echo "==> baseline: $TARGET @ target default (no target-cpu override)" |
70 | 79 | fi |
71 | 80 |
|
72 | | -echo "==> building simd-codegen-oracle (--emit asm) for $TARGET" |
| 81 | +cd "$REPO" |
| 82 | +echo "==> building probes (--emit asm) for $TARGET" |
73 | 83 | if [ "$TARGET" = "$(rustc -vV | sed -n 's/^host: //p')" ]; then |
74 | 84 | # shellcheck disable=SC2086 |
75 | | - cargo rustc --release --manifest-path "$MANIFEST" -- --emit asm -C debuginfo=0 $CPU_FLAG |
| 85 | + cargo rustc --release --manifest-path "$SCRATCH/Cargo.toml" -- \ |
| 86 | + --emit asm -C debuginfo=0 $CPU_FLAG |
76 | 87 | else |
77 | 88 | # shellcheck disable=SC2086 |
78 | | - cargo rustc --release --manifest-path "$MANIFEST" --target "$TARGET" -- --emit asm -C debuginfo=0 $CPU_FLAG |
| 89 | + cargo rustc --release --manifest-path "$SCRATCH/Cargo.toml" --target "$TARGET" -- \ |
| 90 | + --emit asm -C debuginfo=0 $CPU_FLAG |
79 | 91 | fi |
80 | 92 |
|
81 | | -# Excluded crate -> cargo places `deps/` either under the crate's own target |
82 | | -# dir or falls back to the workspace target dir, exactly like neon/wasm-parity. |
83 | | -ASM="" |
84 | | -for CAND_ROOT in "$ROOT/crates/simd-codegen-oracle/target" "$ROOT/target"; do |
85 | | - if [ "$TARGET" = "$(rustc -vV | sed -n 's/^host: //p')" ]; then |
86 | | - CAND_DIR="$CAND_ROOT/release/deps" |
87 | | - else |
88 | | - CAND_DIR="$CAND_ROOT/$TARGET/release/deps" |
89 | | - fi |
90 | | - if [ -d "$CAND_DIR" ]; then |
91 | | - FOUND="$(ls -t "$CAND_DIR"/simd_codegen_oracle-*.s 2>/dev/null | head -n1 || true)" |
92 | | - if [ -n "$FOUND" ]; then |
93 | | - ASM="$FOUND" |
94 | | - break |
95 | | - fi |
96 | | - fi |
97 | | -done |
98 | | - |
| 93 | +ASM="$(find "$SCRATCH/target" -name 'simd_codegen_oracle-*.s' 2>/dev/null | head -1)" |
99 | 94 | if [ -z "$ASM" ]; then |
100 | | - echo "==> could not locate emitted simd_codegen_oracle-*.s under $ROOT" >&2 |
101 | | - exit 91 |
| 95 | + echo "==> no emitted assembly found under $SCRATCH/target" >&2 |
| 96 | + exit 92 |
102 | 97 | fi |
103 | 98 |
|
104 | | -echo "==> analyzing $ASM against $BASELINE" |
105 | | -python3 "$ROOT/scripts/codegen_oracle_analyze.py" "$ASM" "$BASELINE" "$@" |
| 99 | +echo "==> analyzing $(basename "$ASM") against $(basename "$BASELINE")" |
| 100 | +python3 "$HERE/analyze.py" "$ASM" "$BASELINE" "$@" |
0 commit comments