Make the benchmark harness build optimized binaries on Chez

bench/run.sh was Janet-era: it invoked a 'jolt' binary and set
JOLT_DIRECT_LINK/JOLT_WHOLE_PROGRAM, none of which exist on Chez, where
'joltc run -m' runs fully unoptimized (direct-link and inline default off). So
the suite was measuring jolt's unoptimized path.

run.sh now compiles each benchmark to an optimized AOT binary (joltc build
--direct-link --opt) and times it against JVM Clojure on the same portable
source, auto-detecting the Chez kernel dev files like build-smoke.sh. Adds
bench/deps.edn so joltc resolves the namespaces, NO_JVM to skip the reference.

mandelbrot.clj dropped its jolt.png require so the JVM reference can run it; the
picture demo moved to mandelbrot_png.clj (jolt-only). README scorecard refreshed
with current Chez numbers and the two-regime read (compute ~8-10x substrate floor;
dispatch/alloc ~120-330x architectural gaps the passes don't touch). Stale
'jolt -m' header lines point at bench/run.sh.
This commit is contained in:
Yogthos 2026-06-25 23:47:39 -04:00
parent f3084f8043
commit 5a5ea8058a
11 changed files with 136 additions and 92 deletions

View file

@ -5,10 +5,10 @@
;; on (where devirt/alloc passes measured flat), so it tracks native-arith codegen
;; and loop quality directly.
;;
;; Portable Clojure (jolt + JVM Clojure).
;; jolt -m mandelbrot 1000 (JOLT_DIRECT_LINK=1 JOLT_WHOLE_PROGRAM=1)
(ns mandelbrot
(:require [jolt.png :as png]))
;; Portable Clojure (jolt + JVM Clojure). The jolt.png picture demo lives in
;; mandelbrot_png.clj so this file stays portable for the JVM reference run.
;; bench/run.sh mandelbrot 1000
(ns mandelbrot)
(defn count-point [cr ci cap]
(loop [i 0 zr 0.0 zi 0.0]
@ -32,35 +32,6 @@
(recur (inc y) (+ acc row)))
acc))))
;; --- PNG demo (jolt.png) --------------------------------------------------
;; Render a real picture of the set, reusing count-point as the kernel. `render`
;; is a separate -main subcommand so the numeric-arg bench path is untouched.
(defn- color
"Escape-iteration count -> RGB. In-set points (n>=cap) are black; faster
escapes run through a warm gradient."
[n cap]
(if (>= n cap)
[0 0 0]
(let [t (/ (double n) cap)]
[(int (* 255 (min 1.0 (* 3.0 t))))
(int (* 255 (min 1.0 (max 0.0 (* 3.0 (- t 0.33))))))
(int (* 255 (min 1.0 (max 0.0 (* 3.0 (- t 0.66))))))])))
(defn render!
"Render a size×size view of the Mandelbrot set to a PNG at path."
[path size]
(let [w size h size cap 1000
img (png/image w h)]
(doseq [py (range h)]
(doseq [px (range w)]
(let [cr (- (* 3.5 (/ (double px) w)) 2.5) ; real ∈ [-2.5, 1.0]
ci (- (* 2.8 (/ (double py) h)) 1.4) ; imag ∈ [-1.4, 1.4]
[r g b] (color (count-point cr ci cap) cap)]
(png/put! img r g b))))
(png/write img w h path)
(println "wrote" path (str w "×" h ", cap " cap))))
(defn- run-bench [args]
(let [n (if (seq args) (Integer/parseInt (first args)) 1000)]
(dotimes [_ 2] (run (quot n 2))) ; warmup
@ -78,7 +49,4 @@
(println "mean:" (/ (Math/round (* mean 10.0)) 10.0) "ms"))))
(defn -main [& args]
(if (= (first args) "render")
(render! (or (second args) "mandelbrot.png")
(if (nth args 2 nil) (Integer/parseInt (nth args 2)) 600))
(run-bench args)))
(run-bench args))