Repository navigation
Conversation
scripts/perf-gate.sh, bench-sessions.sh and bench-views.sh extracted each baseline with `git archive` and built all of them in one shared target/perf-gate/build. Cargo names a workspace crate's artifacts by its path inside the workspace, not by where the workspace is, and rebuilds one only when a source file is newer than the last build. `git archive` dates every file at its commit, which is older than any build already in the directory, so a later baseline reused an earlier one's workspace crates: the build failed where the APIs had diverged (`missing field code in ServerFrame` after #387), linked another commit's `ws-protocol` or `ontology-client` where they had not, and returned the earlier baseline's whole server where no file had been added or removed between the two commits. The three scripts now build baselines through scripts/perf-gate-baseline.sh: each baseline gets a source and target directory of its own under target/perf-gate/baseline-build/, removed once the binary is cached. The cache moves to target/perf-gate/baseline-servers/, so a binary cached by the shared build is never read again, and the three scripts now share one toolchain key (the gate hashed `rustc -V` without its newline, the benchmarks with it). scripts/perf-gate-baseline-selftest.sh builds two baselines that differ in the root crate and in a path dependency, in both orders, and checks each binary reports its own commit. It runs in `make pre-pr-selftest` and in the full suite's perf-gate tool job.
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Performance regressions and the perf gate in inputlayer/inputlayer are part of getting the engine production ready, and benchmarks run only on the benchmark host. The perf gate there currently produces wrong or failed baseline builds, found while bisecting #374:
scripts/perf-gate.shextracts each baseline withgit archive | tar -x(file mtimes = the commit's time) and builds every baseline in one sharedtarget/perf-gate/build. Cargo's metadata hash does not include the path of a path dependency, so every baseline'sinputlayer-ws-protocolmaps to the same artifact, and an older baseline extracted after a newer one was built sees files older than the fingerprint and reuses the newer crate. The build fails when the APIs diverged (missing field code in ServerFrame, from #387 built by another lane's run on the shared host clone), and silently links the wrong crate when they did not. Five bisect steps failed this way. Fix:touchthe extracted tree, or a per-baselineCARGO_TARGET_DIR. Until then only baselines at or after the newest-builtws-protocolbuild.Fix it so every baseline is built from exactly its own sources. Deliver it as a small PR; done means merged with CI green.
What Changed
scripts/perf-gate-baseline.shbuilds one baseline commit fromgit archivewith its ownCARGO_TARGET_DIR(target/perf-gate/baseline-build/<commit>-<toolchain>/) and prints the path of the cached binary. The build directory is removed when the build ends, including on failure and on SIGTERM/SIGHUP.scripts/perf-gate.sh,scripts/bench-views.shandscripts/bench-sessions.shnow call it instead of each carrying a copy of the build that sharedtarget/perf-gate/build.target/perf-gate/servers/totarget/perf-gate/baseline-servers/, so binaries built in the shared directory are not reused. The CI cache path and key infull-suite.ymlchange to match.scripts/perf-gate-baseline-selftest.shbuilds two commits of a throwaway workspace with a path dependency, in both orders, and checks that each binary comes from its own commit, that a cached baseline is not rebuilt, and that a failed or killed build leaves no build directory. It runs inmake pre-pr-selftestand in theperf-gate-toolCI job;test_pre_pr.py,perf-gate/README.md,CONTRIBUTINGandTESTING.mdare updated to match.🤖 Generated with Claude Code
Risk Assessment
✅ Low: The change replaces three identical inline baseline builds with one small helper that gives each baseline its own source and target directory and a fresh cache location, so no stale or cross-commit artifact is reachable, and the earlier fix round's EXIT trap and plain cp read correctly; nothing was executed in this review.
Testing
No baseline commands had run before this step. I ran the baseline selftest on the target, then against the base commit's shared-directory logic and against the helper without this round's signal trap; both of those fail on exactly the checks they should. On the real repository I built #387 (efa32ce) and then its parent (527bacc) with the new helper and with the base logic: the new helper gives two different servers, the base logic gives the parent #387's binary. I interrupted the helper mid-build with SIGINT, SIGTERM and SIGHUP, to the process group and to the helper alone, on a loaded host; no build directory was left in any try. The perf gate (quick profile, which reports INVALID and exits 3 by design), the session benchmark and the views benchmark each ran a baseline through the helper from the cache without rebuilding it. The pre-pr routing tests pass. Build outputs are removed and the worktree is clean. Nothing here is UI-facing, so the evidence is CLI transcripts.
access_deniedstrings, 527bacc sha256 4382b65d with 0; baseline-build empty aft…access_deniedstrings)Evidence: Real repository, new helper: #387 then its parent
$ new efa32cec -> exit=0 seconds=185; cargo: Finishedreleaseprofile [optimized] target(s) in 3m 04s ws-protocol compiled in this build: 1 baseline-servers/efa32cec62979f089624c76f6846c9b9e27b4381-8dc912acd5bf/inputlayer-server sha256=cc89631edeaa6a8b access_denied strings=10 $ new 527bacc3 -> exit=0 seconds=175; cargo: Finishedreleaseprofile [optimized] target(s) in 2m 53s ws-protocol compiled in this build: 1 baseline-servers/527bacc306ae480504adbdec56c6823672629793-8dc912acd5bf/inputlayer-server sha256=4382b65d6c577d86 access_denied strings=0 baseline-build afterwards: []Evidence: Real repository, base-commit logic: the parent gets #387's server
$ old efa32cec -> exit=0 seconds=186; cargo: Finishedreleaseprofile [optimized] target(s) in 3m 06s ws-protocol compiled in this build: 1 servers/efa32cec62979f089624c76f6846c9b9e27b4381-415a6fa19307/inputlayer-server sha256=cc89631edeaa6a8b access_denied strings=10 $ old 527bacc3 -> exit=0 seconds=1; cargo: Finishedreleaseprofile [optimized] target(s) in 0.25s ws-protocol compiled in this build: 0 servers/527bacc306ae480504adbdec56c6823672629793-415a6fa19307/inputlayer-server sha256=cc89631edeaa6a8b access_denied strings=10Evidence: Baseline selftest at 1de89a4
PASS: the newer baseline is built from its own sources PASS: the older baseline is built from its own sources PASS: the older baseline is built from its own sources PASS: the newer baseline is built from its own sources PASS: a cached baseline is not built again PASS: the older baseline is built from its own sources PASS: a baseline that does not compile fails PASS: no build directory is left behind, built or not PASS: a build killed with SIGTERM leaves no build directory behind PASS: a build killed with SIGHUP leaves no build directory behind perf-gate-baseline-selftest: all checks passed exit=0Evidence: Same selftest against the base commit's shared build directory
PASS: the newer baseline is built from its own sources FAIL: the older baseline was built from other sources: it says 'engine-newer protocol-newer' PASS: the older baseline is built from its own sources FAIL: the newer baseline was built from other sources: it says 'engine-older protocol-older' ... perf-gate-baseline-selftest: 2 failure(s) exit=1Evidence: Selftest kill checks against the helper without the TERM/HUP trap
FAIL: a build killed with SIGTERM left its build directory behind FAIL: a build killed with SIGHUP left its build directory behind perf-gate-baseline-selftest: 2 failure(s) exit=1Evidence: Process-group interrupts mid-build, helper at 1de89a4
SIGINT #1..#3: helper exit 124; baseline-build holds [] right after; [] 2s later SIGTERM #1..#3: helper exit 124; baseline-build holds [] right after; [] 2s later SIGHUP #1..#3: helper exit 124; baseline-build holds [] right after; [] 2s laterEvidence: Process-group interrupts, helper without the TERM/HUP trap (4 of 6 SIGTERM/SIGHUP tries leave the directory)
Evidence: Signals to the helper process alone
SIGTERM to the helper alone at 5s: helper exit 143 after 22s; baseline-build []; baseline-servers []; cargo still running: 0 SIGHUP to the helper alone at 5s: helper exit 143 after 20s; baseline-build []; baseline-servers []; cargo still running: 0 SIGINT to the helper alone at 5s: helper exit 0 after 20s; baseline-build []; baseline-servers [0a561187...-8dc912acd5bf]; cargo still running: 0Evidence: Perf gate, quick profile, baseline 527bacc from the helper
Evidence: Session benchmark with --baseline-rev 527bacc
~/.no-mistakes/evidence/01M47TEA9EZ3HX2FPK9AJ26GTJ/round3/bench-views.log)Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
scripts/perf-gate-baseline.sh:36- The per-baseline work directory (target/perf-gate/baseline-build/<sha>-<toolchain>, an extracted tree plus a full release target dir) is removed only on the success path at line 47. Underset -e, a baseline that fails to compile, or a run that is killed mid-build, leaves it behind; it is reclaimed only if the same commit and toolchain is requested again (line 37). The old sharedtarget/perf-gate/buildwas bounded at one directory; now a bisect over N commits that do not build leaves N full target directories on the benchmark host. Remedy: settrap 'rm -rf "$WORK"' EXITonce WORK is created, and drop the explicitrm -rfat line 47. The selftest's "no build directory is left behind" check (scripts/perf-gate-baseline-selftest.sh:103) covers only the success path.scripts/perf-gate-baseline.sh:44- Simplification: the copy-to-$BIN.tmp-then-mvat lines 44-46 is a new component that guards against an interrupted copy being taken for a cached binary. No intent requirement needs it: the intent is that each baseline is built from its own sources, which the per-baseline source and target directory already delivers, and the previous code used a plaincp. Recommend reverting to a singlecpinto$BIN, unless the author wants to keep this extra hardening.scripts/perf-gate-baseline.sh:32- Moving the cache tobaseline-servers/correctly stops any binary built in the shared directory from being read again, but nothing removes the existingtarget/perf-gate/build,target/perf-gate/srcandtarget/perf-gate/servers/<sha>-*on the benchmark host's clone. They are now dead disk (servers/candidateis still used by scripts/perf-gate.sh:74) and need a one-off manual cleanup. Commits that predate this change still run their own old script when checked out on the host, so they keep using the shared directory; they cannot poison the new cache.🔧 Fix applied.
1 info still open:
ℹ️
scripts/perf-gate-baseline.sh:32- Moving the cache tobaseline-servers/correctly stops any binary built in the shared directory from being read again, but nothing removes the existingtarget/perf-gate/build,target/perf-gate/srcandtarget/perf-gate/servers/<sha>-*on the benchmark host's clone. They are now dead disk (servers/candidateis still used by scripts/perf-gate.sh:74) and need a one-off manual cleanup. Commits that predate this change still run their own old script when checked out on the host, so they keep using the shared directory; they cannot poison the new cache.ℹ️
scripts/perf-gate-baseline.sh:43- Tradeoff, no action needed: because each baseline gets its own target directory, removed by the EXIT trap, every uncached baseline is now a cold release build with all features, third-party dependencies included. The old sharedtarget/perf-gate/buildkept those compiled between baselines, so a bisect over N uncached commits now pays N full builds on the benchmark host. The intent names a per-baselineCARGO_TARGET_DIRas an accepted fix, and finished binaries are still cached per commit and toolchain inbaseline-servers/, so only the first build of each commit pays.✅ No issues found.
access_deniedstrings, efa32ce binary cc89631e… with 10access_deniedstrings)baseline-buildholds the commit's directory during the build and is empty after each signal;baseline-serversis emptytarget/perf-gate/baseline-servers/, both arms measuredscripts/perf-gate-baseline-selftest.sh(fixed helper: all 8 checks pass)scripts/perf-gate-baseline-selftest.shin a scratch repo whosescripts/perf-gate-baseline.shis the base commit's shared-target/perf-gate/buildblock (3 checks fail: reproduces the bug)scripts/perf-gate-baseline.sh efa32cecthenscripts/perf-gate-baseline.sh 527bacc3on the real repo (170 s and 189 s full release builds, both exit 0,baseline-build/empty after each)old-shared-dir-baseline-shim.sh efa32cecthen527bacc3on the real repo (second 'build' finishes in 3 s and returns the #387 binary)sha256sumandgrep -c -a access_deniedover the four resultinginputlayer-serverbinariesinterrupt-check.sh scripts/perf-gate-baseline.sh:timeout -s INT 8andtimeout -s TERM 8on a baseline build held open by a sleeping build scriptscripts/perf-gate.sh --aa --baseline-rev 527bacc3 --profile quick --rounds 1 --fixtures cheap_query --no-verdict(exit 0)scripts/bench-views.sh --baseline-rev 527bacc3 --edges 1000 --writes 3 --large-writes 2 --reads 2 --keyed 1 --recursive-keyed 1 --large-recursive-keyed 1 --filler-rules 5(exit 0)scripts/perf-gate-baseline.sh:38- A baseline build killed with SIGTERM or SIGHUP often leavestarget/perf-gate/baseline-build/<sha>-<toolchain>behind (5 of 8 tries on a loaded host; SIGINT was clean 4 of 4), against the recorded decision to remove it on interruption too. Bash runs the EXIT trap as soon as the signal arrives, sorm -rfraces cargo and rustc, which are still writing. Impact is disk only: no wrong binary is cached, and the directory is wiped if the same commit is requested again. Addingtrap 'exit 143' TERM HUPafter the EXIT trap makes bash wait for cargo to exit first; a copy of the helper with that one line was clean in 9 of 9 tries (3 per signal) under the same load (interrupt-repeat-with-signal-trap.log). The selftest covers only the compile-failure path, not interruption.🚨 live validation verdict: no-go (7 of 7 scenarios were driven live against the product); failed: Kill a baseline build with SIGTERM or SIGHUP (to the process group): no build directory is left behind
Live validation: ❌ no-go - 7 of 7 scenarios driven live against the product
access_deniedc…access_deniedpresent)scripts/perf-gate-baseline-selftest.sh, all 8 checks pass); selftest-base-logic.log (same checks against the base commit's build block: 3 fail, e.g. the older baseline says 'eng…target/releasetree remains,srcis gone); interrupt.log shows one more SIGTERM leftoverscripts/perf-gate.sh --baseline-rev efa32cec~1, quick profile): it measures both arms using the helper's cached baseline and writes a report--baseline-rev efa32cec~1: both compare the working tree against the helper's baseline binaryscripts/perf-gate-baseline-selftest.shat the target commit (all checks pass)The same selftest with the helper swapped for the base commit's build block fromscripts/perf-gate.shat d5df1ba3 (3 checks fail, reproducing the bug)scripts/perf-gate-baseline.sh efa32cecthenscripts/perf-gate-baseline.sh efa32cec~1on the real repository, comparing the two binaries by hash and by presence of theaccess_deniedcodeThe base commit's build block on the same two commits in the same order (older baseline comes back byte-identical to the newer one)timeout -s INT|TERM|HUP 8 scripts/perf-gate-baseline.sh HEADon a slow-building fixture repository, 4 times per signal, listingtarget/perf-gate/baseline-buildafterwardsThe same interruption loop against a copy of the helper withtrap 'exit 143' TERM HUPadded (3 per signal, all clean)scripts/perf-gate.sh --baseline-rev efa32cec~1 --candidate-bin <efa32cec baseline> --profile quick --rounds 2scripts/bench-views.sh --baseline-rev efa32cec~1 --edges 1000 --writes 3 --reads 2 --keyed 1 --recursive-keyed 1 --filler-rules 5scripts/bench-sessions.sh --baseline-rev efa32cec~1 --sessions 1,5 --load-secs 2🔧 Fix applied.
✅ Re-checked - no issues remain.
access_deniedstrings, 527bacc sha256 4382b65d with 0; baseline-build empty aft…access_deniedstrings)scripts/perf-gate-baseline-selftest.shat 1de89a44: all 10 checks passtools/selftest-against-old.sh(same selftest against the base commit's sharedtarget/perf-gate/buildlogic): fails the two second-built baselinesround3/selftest-without-signal-trap.sh(the selftest against the helper minus thetrap 'exit 143' TERM HUPline): fails the SIGTERM and SIGHUP checksscripts/perf-gate-baseline.sh efa32cecthenscripts/perf-gate-baseline.sh 527bacc3on the real repository, comparing sha256 andaccess_deniedstring counts of the two serverstools/old-baseline.sh efa32cecthentools/old-baseline.sh 527bacc3(base-commit logic) on the real repositorytools/interrupt-repeat.sh scripts/perf-gate-baseline.sh 3: SIGINT, SIGTERM and SIGHUP to the helper's process group 8s into a build, 3 tries each; the same against the helper without the signal trapround3/interrupt-helper-only.sh scripts/perf-gate-baseline.sh: SIGTERM, SIGHUP and SIGINT to the helper process alone mid-buildscripts/perf-gate.sh --baseline-rev 527bacc3 --candidate-bin <efa32cec baseline> --profile quick --rounds 2 --fixtures cheap_query,insert_singlescripts/bench-sessions.sh --baseline-rev 527bacc3 --sessions 1,5 --load-secs 2scripts/bench-views.sh --baseline-rev 527bacc3 --edges 1000 --writes 3 --large-writes 3 --reads 2 --keyed 1 --recursive-keyed 1 --large-recursive-keyed 1 --filler-rules 5python3 -m unittest scripts/test_pre_pr.py✅ **Document** - passed
✅ No issues found.
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ No issues found.
✅ **Push** - passed
✅ No issues found.
✅ No issues found.