test: ~11x faster gate — ctx snapshot/fork + parallel suite battery

The gate spent almost all its time rebuilding identical contexts: init is
~50 ms interpreted / ~900 ms compiled (tier loading, analyzer build, macro
recompilation), and both the conformance harness and the spec harness built a
fresh ctx PER CASE — 269 cases x 3 modes for conformance alone (~285 s), and
~1500 spec cases (~90 s). The suite battery additionally ran its 234 worker
subprocesses sequentially (~100 s incl. 5 x 6 s timeout files).

- api: snapshot/fork — marshal a fully-built ctx once (reverse-lookup dicts
  from root-env, built at module load before any ctx exists), unmarshal cheap
  fully-isolated deep copies (~2 ms). A fork shares nothing mutable with its
  siblings, so per-case isolation is preserved exactly.
- conformance: one init per mode + fork per case (self-host pre-builds the
  analyzer before snapshotting). 285 s -> 5 s, same 269x3 results.
- spec harness: jeval/run-spec/expect-throws fork from one lazy module-level
  snapshot. Spec sweep ~90 s -> 9 s, all pass.
- clojure-test-suite: run the per-file worker subprocesses through a
  token-channel worker pool (default 4, JOLT_SUITE_WORKERS to override,
  capped at 8). 17.5 s with counts identical to the sequential run
  (4046/520/116, 5 timeouts).

Full gate wall-clock: ~8 min -> 43 s, everything green (conformance 269x3,
fallback-zero, fixpoint, self-host, sci, staged, suite >= 4034/67, all
specs+unit).
This commit is contained in:
Yogthos 2026-06-10 09:11:58 -04:00
parent 3e9fe8d0fb
commit 920fafe032
4 changed files with 76 additions and 11 deletions

View file

@ -384,9 +384,16 @@
(def init-opts (if selfhost? {} mode))
(defn ev [ctx prog]
(if selfhost? (selfhost/compile-and-eval ctx (parse-string prog)) (eval-string ctx prog)))
# One expensive init per mode; every case runs on a cheap isolated fork (~2 ms)
# instead of its own init (~50 ms interpreted / ~900 ms compiled). Isolation is
# preserved — a fork shares nothing mutable with its siblings. For self-host
# mode, compile one form first so the lazily-built analyzer is in the snapshot.
(def base (init init-opts))
(when selfhost? (selfhost/compile-and-eval base (parse-string "1")))
(def snap (snapshot base))
(def fails @[])
(each [name expected actual] cases
(def ctx (init init-opts))
(def ctx (fork snap))
(def prog (string "(= " expected " " actual ")"))
(def res (protect (ev ctx prog)))
(cond
@ -394,7 +401,7 @@
(array/push fails [name "ERROR" (string (res 1))])
(= (res 1) true)
nil
(let [got (protect (ev (init init-opts) actual))]
(let [got (protect (ev (fork snap) actual))]
(array/push fails [name "MISMATCH"
(string "want=" expected
" got=" (if (= (got 0) true) (string/format "%q" (got 1)) (string "ERR:" (got 1))))]))))