Replaces the watchdog-bump approach with an automated check. The next 5× (or
worse) substrate regression will trip the alarm at build time instead of
hiding behind a deadline bump and only being noticed weeks later.
Components:
* lib/perf-smoke.sx — four micro-benchmarks chosen for distinct substrate
failure modes: function-call dispatch (fib), env construction (let-chain),
HO-form dispatch + lambda creation (map-sq), TCO + primitive dispatch
(tail-loop). Warm-up pass populates JIT cache before the timed pass so we
measure the steady state.
* scripts/perf-smoke.sh — pipes lib/perf-smoke.sx to sx_server.exe, parses
per-bench wall-time, asserts each is within FACTOR× of the recorded
reference (default 5×). `--update` rewrites the reference in-place.
* scripts/sx-build-all.sh — perf-smoke wired in as a post-step after JS
tests. Hard fail if any benchmark regressed beyond budget.
Reference numbers: minimum across 6 back-to-back runs on this dev machine
under typical concurrent-loop contention (load ~9, 2 vCPU, 7.6 GiB RAM,
OCaml 5.2.0, architecture @ 92f6f187). Documented in
plans/jit-perf-regression.md including how to update them.
The 5× factor is chosen so contention noise (~1–2× variance) doesn't trigger
false alarms but a real ≥5× substrate regression — the kind that motivated
this whole investigation — fails the build immediately.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
49 lines
2.3 KiB
Bash
Executable File
49 lines
2.3 KiB
Bash
Executable File
#!/bin/bash
|
||
# Full SX build pipeline — OCaml + JS browser + JS test + JS tests.
|
||
set -euo pipefail
|
||
|
||
cd "$(dirname "$0")/.."
|
||
|
||
echo "=== OCaml build ==="
|
||
(cd hosts/ocaml && eval $(opam env 2>/dev/null) && dune build) || { echo "FAIL: OCaml build"; exit 1; }
|
||
|
||
echo "=== Sync WASM kernel to shared/static/wasm/ ==="
|
||
OCAML_BUILD=hosts/ocaml/_build/default/browser
|
||
cp "$OCAML_BUILD/sx_browser.bc.wasm.js" shared/static/wasm/sx_browser.bc.wasm.js
|
||
cp "$OCAML_BUILD/sx_browser.bc.js" shared/static/wasm/sx_browser.bc.js
|
||
cp -r "$OCAML_BUILD/sx_browser.bc.wasm.assets" shared/static/wasm/
|
||
echo " WASM loader: $(du -sh shared/static/wasm/sx_browser.bc.wasm.js | cut -f1)"
|
||
echo " JS fallback: $(du -sh shared/static/wasm/sx_browser.bc.js | cut -f1)"
|
||
|
||
echo "=== Sync spec .sx to dist (canonical → dist) ==="
|
||
cp spec/signals.sx hosts/ocaml/browser/dist/sx/core-signals.sx
|
||
cp spec/render.sx hosts/ocaml/browser/dist/sx/
|
||
cp spec/harness.sx hosts/ocaml/browser/dist/sx/
|
||
echo " spec → dist: 3 files"
|
||
|
||
echo "=== Sync web .sx to dist (wasm/sx → dist) ==="
|
||
for f in signals.sx deps.sx router.sx page-helpers.sx freeze.sx \
|
||
bytecode.sx compiler.sx vm.sx dom.sx browser.sx \
|
||
adapter-html.sx adapter-sx.sx adapter-dom.sx \
|
||
boot-helpers.sx hypersx.sx harness-reactive.sx harness-web.sx \
|
||
engine.sx orchestration.sx boot.sx \
|
||
tw-layout.sx tw-type.sx tw.sx; do
|
||
if [ -f "shared/static/wasm/sx/$f" ]; then
|
||
cp "shared/static/wasm/sx/$f" "hosts/ocaml/browser/dist/sx/"
|
||
fi
|
||
done
|
||
echo " wasm/sx → dist: web files synced"
|
||
|
||
echo "=== Recompile .sxbc bytecode ==="
|
||
node hosts/ocaml/browser/compile-modules.js || { echo "FAIL: sxbc compile"; exit 1; }
|
||
|
||
echo "=== JS browser build ==="
|
||
python3 hosts/javascript/cli.py --output shared/static/scripts/sx-browser.js || { echo "FAIL: JS build"; exit 1; }
|
||
echo "=== JS test build ==="
|
||
python3 hosts/javascript/cli.py --extensions continuations --spec-modules types --output shared/static/scripts/sx-full-test.js || { echo "FAIL: test build"; exit 1; }
|
||
echo "=== JS tests ==="
|
||
node hosts/javascript/run_tests.js --full 2>&1 | tail -3 || { echo "FAIL: JS tests"; exit 1; }
|
||
echo "=== perf-smoke ==="
|
||
bash scripts/perf-smoke.sh || { echo "FAIL: perf-smoke (substrate regressed ≥5×, see scripts/perf-smoke.sh)"; exit 1; }
|
||
echo "=== All OK ==="
|