Add benchmark suite for alloc/dispatch/collection workloads (jolt-1r86) (#135)
The ray tracer is float-compute-bound (devirt, alloc removal, type-proving all measured flat on it), so it can't validate the optimization passes. Add a small cross-language suite (AWFY + CLBG style, portable Clojure) isolating the axes it misses: binary-trees allocation / GC pressure (escaping short-lived records) dispatch megamorphic protocol dispatch (~1M dispatches/s; WP can't devirt) collections persistent map/vector churn bench/run.sh runs them; bench/README.md maps each to the pass it exercises. collections immediately surfaced jolt-684u: the persistent hash map is O(n) per assoc (flat copy-on-write bucket array, not a HAMT) — n=4000 assocs take 50s. Invisible to the ray tracer (no maps). Co-authored-by: Yogthos <yogthos@gmail.com>
This commit is contained in:
parent
bd9e542c78
commit
c13a8ee402
5 changed files with 243 additions and 0 deletions
46
bench/collections.clj
Normal file
46
bench/collections.clj
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
;; collections — PERSISTENT-COLLECTION churn. Builds and reads persistent maps
|
||||
;; and vectors (32-way hash/array tries) under heavy assoc/update/conj/lookup, a
|
||||
;; word-count-style workload (cf. CLBG k-nucleotide). Exercises jolt's persistent
|
||||
;; data structures and (eventually) transients — an axis the ray tracer (fixed
|
||||
;; records, no collections in the hot loop) doesn't touch.
|
||||
;;
|
||||
;; Portable Clojure (jolt + JVM Clojure).
|
||||
;; jolt -m collections 200000 (JOLT_DIRECT_LINK=1 JOLT_WHOLE_PROGRAM=1)
|
||||
(ns collections)
|
||||
|
||||
;; map churn: accumulate a frequency map over a stream of keys, then sum it back
|
||||
(defn freq-map [n buckets]
|
||||
(loop [i 0 m {}]
|
||||
(if (< i n)
|
||||
(recur (inc i)
|
||||
(let [k (mod (* i 2654435761) buckets)]
|
||||
(assoc m k (+ 1 (get m k 0)))))
|
||||
m)))
|
||||
|
||||
(defn sum-vals [m]
|
||||
(reduce (fn [acc k] (+ acc (get m k))) 0 (keys m)))
|
||||
|
||||
;; vector churn: conj many, then reduce
|
||||
(defn vec-sum [n]
|
||||
(let [v (loop [i 0 v []] (if (< i n) (recur (inc i) (conj v (mod i 1000))) v))]
|
||||
(reduce + 0 v)))
|
||||
|
||||
(defn run [n]
|
||||
(let [m (freq-map n 4096)]
|
||||
(+ (sum-vals m) (vec-sum (quot n 4)))))
|
||||
|
||||
(defn -main [& args]
|
||||
(let [n (if (seq args) (Integer/parseInt (first args)) 200000)]
|
||||
(dotimes [_ 2] (run (quot n 4))) ; warmup
|
||||
(let [runs 3
|
||||
times (mapv (fn [_]
|
||||
(let [t0 (System/nanoTime)
|
||||
r (run n)
|
||||
ms (/ (- (System/nanoTime) t0) 1000000.0)]
|
||||
[ms r]))
|
||||
(range runs))
|
||||
mss (mapv first times)
|
||||
mean (/ (reduce + mss) runs)]
|
||||
(println "collections n" n "result" (second (first times)))
|
||||
(println "runs:" (mapv (fn [t] (/ (Math/round (* t 10.0)) 10.0)) mss))
|
||||
(println "mean:" (/ (Math/round (* mean 10.0)) 10.0) "ms"))))
|
||||
Loading…
Add table
Add a link
Reference in a new issue