#!/bin/sh # Run the jolt benchmark suite against JVM Clojure and print a jolt/JVM scorecard. # # jolt's optimizing passes (direct-linking, inlining, scalar-replace, whole-program # inference) fire only in an AOT BUILD — `joltc run -m` is unoptimized — so each # benchmark is compiled to an optimized standalone binary and timed. JVM Clojure # runs the same portable source for the absolute reference. Each benchmark prints # `runs: [...]` and `mean: N ms`; the table shows the means and the jolt/JVM ratio. # # bench/run.sh # full suite + JVM scorecard # bench/run.sh fib # one benchmark, default size # bench/run.sh fib 32 # one benchmark, custom size # NO_JVM=1 bench/run.sh # jolt only (skip the JVM reference) # # Building needs Chez's kernel dev files (libkernel.a + scheme.h) and a C compiler, # the same as `jolt build`; set JOLT_CHEZ_CSV to override the detected csv dir. set -e cd "$(dirname "$0")" root="$(cd .. && pwd)" joltc="$root/bin/joltc" export JOLT_PWD="$PWD" # Locate Chez's kernel dev files for the optimized build (as build-smoke.sh does). csv="$JOLT_CHEZ_CSV" if [ -z "$csv" ]; then chez_bin="$(command -v chez || command -v scheme || command -v petite || true)" if [ -n "$chez_bin" ]; then base="$(cd "$(dirname "$chez_bin")/.." 2>/dev/null && pwd)" for d in "$base"/lib/csv*/*/; do [ -f "${d}libkernel.a" ] && csv="${d%/}" && break done fi fi if [ -z "$csv" ] || [ ! -f "$csv/libkernel.a" ] || [ ! -f "$csv/scheme.h" ] || ! command -v cc >/dev/null 2>&1; then echo "error: the optimized build needs Chez kernel dev files (libkernel.a + scheme.h) and cc." >&2 echo " set JOLT_CHEZ_CSV to the csv dir, e.g. \$(brew --prefix chezscheme)/lib/csv*/." >&2 exit 1 fi export JOLT_CHEZ_CSV="$csv" bindir="$(mktemp -d)" trap 'rm -rf "$bindir"' EXIT # name:default-arg, each sized to run in a few seconds. Axes: see README.md. BENCHES="fib:30 mandelbrot:200 collections:30000 mono-dispatch:2000 dispatch:2000 binary-trees:14" run_one() { ns="${1%%:*}"; arg="${2:-${1##*:}}" if ! "$joltc" build -m "$ns" -o "$bindir/$ns" --direct-link --opt >/dev/null 2>&1; then printf '%-16s jolt build FAILED\n' "$ns"; return fi jmean=$("$bindir/$ns" "$arg" 2>/dev/null | awk '/^mean:/{print $2}') if [ -z "$NO_JVM" ]; then vmean=$(clojure -Sdeps '{:paths ["."]}' -M -m "$ns" "$arg" 2>/dev/null | awk '/^mean:/{print $2}') ratio=$(awk "BEGIN{ if (\"$vmean\"+0>0 && \"$jmean\"+0>0) printf \"%.1fx\", (\"$jmean\"+0)/(\"$vmean\"+0); else printf \"-\" }") printf '%-16s jolt %9s ms jvm %8s ms %s\n' "$ns" "${jmean:--}" "${vmean:--}" "$ratio" else printf '%-16s jolt %9s ms\n' "$ns" "${jmean:--}" fi } if [ -n "$1" ]; then spec="" for s in $BENCHES; do [ "${s%%:*}" = "$1" ] && spec="$s"; done [ -n "$spec" ] || { echo "unknown benchmark: $1 (have: ${BENCHES})" >&2; exit 1; } run_one "$spec" "$2" else echo "jolt benchmark suite — optimized AOT binaries${NO_JVM:+ }${NO_JVM:-, vs JVM Clojure}" for spec in $BENCHES; do run_one "$spec"; done fi