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:
parent
3e9fe8d0fb
commit
920fafe032
4 changed files with 76 additions and 11 deletions
|
|
@ -108,14 +108,33 @@
|
|||
(var timeouts 0)
|
||||
(def worst @[])
|
||||
|
||||
# Worker pool: each file is already its own subprocess (isolation + hang
|
||||
# containment), so concurrency only changes wall-clock. A token-channel
|
||||
# semaphore caps the live workers; os/spawn / ev/read / os/proc-wait are
|
||||
# event-loop aware so the fibers genuinely interleave. Totals are
|
||||
# order-independent. Default 4 keeps per-file wall-clock deadlines honest
|
||||
# on small CI runners; override with JOLT_SUITE_WORKERS.
|
||||
(def nworkers
|
||||
(min 8 (max 1 (or (scan-number (or (os/getenv "JOLT_SUITE_WORKERS") ""))
|
||||
(os/cpu-count) 4))))
|
||||
(def sem (ev/chan nworkers))
|
||||
(def done (ev/chan (length files)))
|
||||
(each path files
|
||||
(ev/spawn
|
||||
(ev/give sem :tok) # acquire (blocks when pool is full)
|
||||
(def out (run-file path))
|
||||
(ev/take sem) # release
|
||||
(ev/give done [path out])))
|
||||
(for _ 0 (length files)
|
||||
(def [path out] (ev/take done))
|
||||
(def rel (string/slice path (+ 1 (length suite-dir))))
|
||||
(when progress? (eprintf " %s" rel) (eflush))
|
||||
(def out (run-file path))
|
||||
(def counts (and out (parse-counts out)))
|
||||
(when progress?
|
||||
(eprintf " %s%s" rel (cond (nil? out) " TIMEOUT" (nil? counts) " (no counts)" ""))
|
||||
(eflush))
|
||||
(cond
|
||||
(nil? out) (do (++ timeouts) (when progress? (eprint " TIMEOUT")))
|
||||
(nil? counts) (when progress? (eprint " (no counts)"))
|
||||
(nil? out) (++ timeouts)
|
||||
(nil? counts) nil
|
||||
(let [[pn fn* en] counts]
|
||||
(++ ran-files)
|
||||
(+= total-pass pn)
|
||||
|
|
|
|||
|
|
@ -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))))]))))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue