jolt/bench/binary_trees.clj
Yogthos 33eff7c7d8 Clean up codebase: rename stdlib layer, strip porting residue, fix tooling
Rename src/jolt -> stdlib (the runtime-loaded layer; jolt-core stays the
seed-baked layer) and update the loader / emit-image / doc paths. Drop dead
code: the spike/ experiments, the duplicate clojuredocs-export.edn (json moves
to tools/), the Janet-era jolt.http binding, and the orphaned
persistent_vector.clj whose ns/path didn't even match.

Strip porting residue from comments and docstrings across host/chez, jolt-core,
stdlib, tests, and docs: internal issue ids, "Phase N" markers, and the "vs
Janet" historical exposition, leaving present-tense descriptions and the real
JVM-Clojure semantic contrasts. Same pass over the corpus suite labels. The seed
is unchanged (docstrings/comments aren't emitted), so the self-host fixpoint and
corpus are untouched.

Port tools/spec_coverage.py off the dead janet probe to bin/joltc and regenerate
coverage.md; drop the dead :host/janet rule from certify.clj and regenerate the
conformance profile. Add docs/host-interop.md (the JVM shims and how to register
your own host class from a library) and a writing-style note in CLAUDE.md.

Stabilize the four racy concurrency corpus cases (future-cancel and agent
send/send-off): give the future a sleeping body and the agent a slow action, so
cancel reliably catches an in-flight future and deref reliably reads the
pre-update snapshot. They certify deterministically now, so drop their :flaky
allowlist entries and the orphaned legend.
2026-06-22 22:18:00 -04:00

54 lines
2.1 KiB
Clojure

;; binary-trees (Computer Language Benchmarks Game) — an ALLOCATION/GC stress
;; test. Builds and discards millions of short-lived `Node` records; the nodes
;; ESCAPE (stored in the tree, walked later), so this is the regime escape analysis
;; targets and the ray tracer never exercises (~7% alloc).
;;
;; Portable Clojure: runs on jolt and JVM Clojure for cross-impl comparison.
;; jolt -m binary-trees 14 (JOLT_DIRECT_LINK=1 JOLT_WHOLE_PROGRAM=1)
;; clojure -M -m binary-trees 14
(ns binary-trees)
(defrecord Node [left right])
(defn make-tree [depth]
(if (zero? depth)
(->Node nil nil)
(->Node (make-tree (dec depth)) (make-tree (dec depth)))))
(defn check-tree [node]
(let [l (:left node)]
(if (nil? l)
1
(+ (+ 1 (check-tree l)) (check-tree (:right node))))))
(defn run [max-depth]
(let [min-depth 4
stretch-depth (inc max-depth)
_ (check-tree (make-tree stretch-depth))
long-lived (make-tree max-depth)]
(loop [d min-depth acc 0]
(if (<= d max-depth)
(let [iterations (bit-shift-left 1 (+ (- max-depth d) min-depth))
sum (loop [i 0 s 0]
(if (< i iterations)
(recur (inc i) (+ s (check-tree (make-tree d))))
s))]
(recur (+ d 2) (+ acc sum)))
;; touch the long-lived tree so it isn't dead-code-eliminated
(+ acc (check-tree long-lived))))))
(defn -main [& args]
(let [max-depth (if (seq args) (Integer/parseInt (first args)) 14)]
(dotimes [_ 2] (run (min max-depth 10))) ; warmup
(let [runs 3
times (mapv (fn [_]
(let [t0 (System/nanoTime)
r (run max-depth)
ms (/ (- (System/nanoTime) t0) 1000000.0)]
[ms r]))
(range runs))
mss (mapv first times)
mean (/ (reduce + mss) runs)]
(println "binary-trees depth" max-depth "checksum" (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"))))