From a2276bd7414ded75a23999c8a9226c2265750c54 Mon Sep 17 00:00:00 2001 From: Swapnil <78632212+swapnilpaliwal-sd@users.noreply.github.com> Date: Mon, 28 Sep 2026 08:59:02 -0700 Subject: [PATCH] ci: key the compiled engine cache on the CPU's feature flags, and drop a cached engine that dies with SIGILL The engine is compiled with -march=native, and the CI cache key named the CPU by its model name only. Hosted runners that report the same model name do not all expose the same instruction set, so a binary compiled on one was restored onto another and died with an illegal instruction on every TypeScript case. The key now hashes the model name and the flags line of /proc/cpuinfo. The driver also removes a locally cached binary that exits with SIGILL, so a bad entry in a shared cache kills one run, not every run after it. --- .github/workflows/ci.yml | 7 +++++-- graph/pipeline/run-souffle.sh | 13 ++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e09200258..a59ce1fd6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -397,12 +397,15 @@ jobs: # Two things decide the binary that ENGINE_ID does not cover, so they are in the # key too: the driver that compiles it (run-souffle.sh holds the compiler flags), # and the runner's CPU, because the driver compiles with -march=native and a - # binary built on one CPU model can die with an illegal instruction on another. + # binary built on one CPU can die with an illegal instruction on another. + # The CPU part hashes the FEATURE FLAGS, not only the model name: hosted runners + # that report the same model name do not all expose the same instruction set, so + # a model-name key restored a binary that died with SIGILL on every case. - name: this language's engine id id: eid run: | echo "id=$(bash graph/pipeline/run-souffle.sh --language ${{ matrix.lang }} --print-engine-id)" >> "$GITHUB_OUTPUT" - echo "cpu=$(grep -m1 'model name' /proc/cpuinfo | sha256sum | cut -c1-12)" >> "$GITHUB_OUTPUT" + echo "cpu=$(grep -E '^(model name|flags)[[:space:]]*:' /proc/cpuinfo | sort -u | sha256sum | cut -c1-12)" >> "$GITHUB_OUTPUT" - name: cache the compiled Soufflé engine if: ${{ !inputs.fresh }} diff --git a/graph/pipeline/run-souffle.sh b/graph/pipeline/run-souffle.sh index 5cf84aacf..2b0cb5424 100755 --- a/graph/pipeline/run-souffle.sh +++ b/graph/pipeline/run-souffle.sh @@ -699,7 +699,18 @@ while [ "$iter" -lt 50 ]; do echo "▶ solving with profiling -> $AXIOM_SOUFFLE_PROFILE" "$PBIN" -F "$FACTS" -D "$RAW" -p "$AXIOM_SOUFFLE_PROFILE" else - "$BIN" -F "$FACTS" -D "$RAW" + # A cached binary is compiled with -march=native. Restored onto a CPU without one of + # the instructions it uses (a shared cache, a CI cache keyed too coarsely), it dies + # with SIGILL (exit 132) before solving anything. Never leave it there to kill every + # later run the same way: drop the cache entry, so the next run recompiles, and say so. + rc=0; "$BIN" -F "$FACTS" -D "$RAW" || rc=$? + if [ "$rc" -ne 0 ]; then + if [ "$rc" -eq 132 ] && [ -z "$PACKAGED" ]; then + rm -f "$BIN" + echo "❌ the cached engine $BIN died with an illegal instruction: it was compiled for a different CPU. Removed it; the next run recompiles." >&2 + fi + exit "$rc" + fi fi # No frontier declared for this language: the solve above is the whole answer. Break # BEFORE the count, because the count is what misreported it. See issue #475.