;; lib/perf-smoke.sx — substrate perf smoke test ;; ;; Four micro-benchmarks exercising different substrate hot paths. Each ;; emits its own elapsed-ms via clock-milliseconds. A wrapper script ;; (scripts/perf-smoke.sh) parses the output and compares to reference ;; numbers, exiting non-zero on any 5× or worse regression. ;; ;; Workloads are chosen for distinct failure modes: ;; bench-fib — function-call dispatch (recursive arithmetic) ;; bench-let-chain — env construction (deep let bindings × N) ;; bench-map-sq — HO-form dispatch + lambda creation ;; bench-tail-loop — TCO + primitive dispatch in tight loop (define (bench-fib n) (let ((fib (fn (n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2))))))) (let ((s (clock-milliseconds))) (fib n) (- (clock-milliseconds) s)))) (define (bench-let-chain iters) (let ((s (clock-milliseconds))) (let loop ((i 0) (acc 0)) (if (= i iters) (- (clock-milliseconds) s) (loop (+ i 1) (let ((a 1) (b 2) (c 3) (d 4) (e 5) (f 6) (g 7) (h 8)) (+ a b c d e f g h acc))))))) (define (bench-map-sq n) (let ((s (clock-milliseconds))) (map (fn (x) (* x x)) (range 1 (+ n 1))) (- (clock-milliseconds) s))) (define (bench-tail-loop iters) (let ((s (clock-milliseconds))) (let loop ((i 0)) (if (= i iters) (- (clock-milliseconds) s) (loop (+ i 1)))))) (define (perf-smoke) ;; Warm-up: populate JIT cache so the timed pass sees the steady state. (bench-fib 12) (bench-let-chain 200) (bench-map-sq 100) (bench-tail-loop 500) ;; Timed pass. Sizes tuned for ~50-200 ms each on a quiet machine. (let ((r-fib (bench-fib 18)) (r-let (bench-let-chain 1000)) (r-map (bench-map-sq 500)) (r-tail (bench-tail-loop 5000))) (str "perf-smoke fib18=" r-fib " let1000=" r-let " map500=" r-map " tail5000=" r-tail)))