feat: comprehensive multi-suite benchmark system (AWFY + CLBG + Wren) - #86
feat: comprehensive multi-suite benchmark system (AWFY + CLBG + Wren)#86txloc1909 wants to merge 11 commits into
Conversation
82ec489 to
250a3fd
Compare
c41e218 to
9be7476
Compare
…ren) Implements all 16 AWFY benchmarks, 6 CLBG benchmarks, and 4 Wren suite benchmarks in Lox++, plus 4 clox-compatible variants. Includes Dockerfiles for Python/Lua/JS/Wren/clox (each bundling third-party sources at pinned commits), manifest.toml, langs.toml, and runner.py with 4 output adapters (awfy/wren/clbg/raw) and podman execution support. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ad011b7 to
7fc9a7d
Compare
Benchmark report — lox++ vs candidate languagesRan the suite on this branch (rebased onto current Environment
lox++ vs clox (the 4 book-Lox benchmarks clox can run)clox is strict book Lox (no lists/maps), so only these four overlap:
lox++ is ~1.05–1.53× slower than clox (geomean ≈ 1.3×). lox++ full-suite coverage (all 26 programs, wall-clock, 60s cap)22/26 run clean. 4 need attention on current
Why the other languages didn't run (multi-language infra is currently broken)The PR description lists 9 infra fixes, but they don't appear to be in the branch — every non-lox path fails:
Happy to do the infra repair (manifest + runner + 5 Dockerfiles + harness wrappers) as a follow-up so a true all-languages matrix can run — it's a meaningful chunk of work on its own. 🤖 Generated with Claude Code |
Each entry put a table header and a key on the same line
("[fib.lox] file = ..."), which tomllib rejects at parse time, so
runner.py could not even load the manifest. Rewrite the per-language
entries as inline tables (lox = { file = "fib.lox" }).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- lox++ runs from the build tree, not a container image, so it must use host paths whether or not --no-container is given (was gated on the flag). - The AWFY adapter regex now accepts scientific notation: lox++ str() prints large averages as "1.07e+06 us", which [\d.]+ silently dropped. - The raw (clox) adapter reads the program's own clock()-reported elapsed instead of container wall time, which is dominated by podman startup for short benchmarks. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dockerfile.clox installed gcc/make but not libc6-dev, so the build failed with "stdlib.h: No such file". Add libc6-dev. Repurpose Dockerfile.lua as a minimal lua5.4 interpreter image for the cross-language microbenchmarks (the previous AWFY-fetch variant pinned a 404 commit). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add crosslang.py: every language runs the identical algorithm at the identical size and self-times the compute region (startup excluded), reported as min-of-N. lox++ and clox share benchmarks/clox/*.lox; add matching python/lua/js ports for fib, towers, queens, mandelbrot. This is the only cross-comparable harness — runner.py's per-language suites each run a different port at a different size. Documented in SOURCES.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Apples-to-apples cross-language resultsReworked the cross-language comparison to be truly apples-to-apples (per review): every language runs the identical algorithm at the identical problem size and self-times only the compute region (interpreter/container startup excluded), reported as min of 5 runs. All languages produce identical results (fib→9227465, towers→1048575, queens→92, mandelbrot→3959). New harness:
Normalized (× the fastest, node):
Reading it
Infra fixed in this PR (4 commits)The original multi-language plumbing didn't run at all; the runnable parts are now fixed:
Still WIP (documented in SOURCES.md)
🤖 Generated with Claude Code |
Build the wren CLI from wren-lang/wren-cli (the wren-lang/wren repo builds only a test runner, not a CLI); it bundles the wren VM + libuv as submodules. Add wren ports of fib/towers/queens/mandelbrot and wire wren into crosslang.py, completing the 6-language matrix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Full 6-language apples-to-apples matrix (wren added)Added wren to the cross-language harness — all 6 candidate languages now run the identical program at the identical size, self-timed (startup excluded), min of 5. All produce identical results (fib→9227465, towers→1048575, queens→92, mandelbrot→3959). The wren CLI is built from
Normalized (× fastest = node):
Reading it
Infra delivered in this PR
🤖 Generated with Claude Code |
The python/lua/js images pinned AWFY commit 5e9fa8e (GitHub 404) and used busybox-incompatible `tar --wildcards`. Repoint to 74306fec and extract the benchmarks/<Lang> tree (harness + som/ + modules) with GNU tar. Dockerfile.lua also keeps lua5.4 for crosslang.py; WORKDIR is the AWFY dir so harness.lua's relative require() resolves. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Run python/lua/js AWFY benchmarks through harness.<ext> <Name> <iters>
<inner>. manifest.toml carries a per-benchmark `inner` matching the lox++
port's workload (and the class Name per language); runner.py substitutes
{inner}. fib/earley (no AWFY port) and havlak (non-AWFY lox signature) stay
lox++-only. Cross-lox apples-to-apple holds for bounce/cd/mandelbrot/nbody/
richards; the other lox++ ports use ad-hoc sizes (reference-only) — see
SOURCES.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AWFY suite wired across python/lua/js
python3 benchmarks/runner.py --suite awfy --lang lox python lua js --format markdownApples-to-apple AWFY rows (lox++ port runs AWFY's exact algorithm at a reproducible size), min-of-5 averages:
¹ clox can't run the AWFY ports (lists/maps); it's in the lox++ tracks CPython closely here (faster on mandelbrot/nbody/richards, slower on cd), with lua ahead and node/V8 well ahead — consistent with the Honest caveatThe remaining lox++ AWFY ports use reduced/ad-hoc sizes that don't map onto AWFY's harness, so those rows are not apples-to-apple and are excluded above: 🤖 Generated with Claude Code |
lox++'s lexer has no /* */ block comments, so `inputsDo(fn) { /* no inputs */ }`
and `execute() { /* no-op */ }` failed to compile (Error at '*'). Replace with
empty bodies + // comments. deltablue now runs and is apples-to-apple with the
AWFY python/lua/js ports.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The lox++ queens/sieve ports are faithful: their benchmark() already does the full AWFY unit (queens loops 10 solves internally; sieve runs sieve(5000) internally), exactly like AWFY's benchmark(). inner is the *repeat* count, so it must be 1 — 10/5000 made the harness do 10x/5000x more than lox++ (sieve was off by ~1800x). With this, all 12 AWFY benchmarks are apples-to-apple across lox++/python/lua/js. See SOURCES.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AWFY lox++ ports aligned — full suite now apples-to-appleRoot cause of the earlier divergences: the lox++ AWFY ports are actually faithful translations of AWFY's All 12 AWFY benchmarks are now apples-to-apple across lox++/python/lua/js (min-of-5 avg):
lox++ vs CPython: roughly even on compute-heavy benchmarks (mandelbrot, nbody, richards, deltablue, cd) and ~2–4× behind on the allocation/list-heavy ones (storage, towers, list, sieve) — pointing at list/object allocation as the next optimization target. lua leads the non-JIT pack; node/V8 JITs to native. Run it: python3 benchmarks/runner.py --suite awfy --lang lox python lua js --format markdownStill lox++-only: 🤖 Generated with Claude Code |
Summary
A benchmark system for Lox++ with two complementary harnesses:
benchmarks/crosslang.py— apples-to-apples cross-language comparison. Every language runs the identical algorithm at the identical problem size and self-times only the compute region (interpreter/container startup excluded), reported as min-of-N. This is the only cross-comparable harness. Covers 6 languages (lox++, clox, wren, python, lua, node) on 4 book-Lox micro-benchmarks (fib, towers, queens, mandelbrot). lox++ and clox sharebenchmarks/clox/*.lox;benchmarks/{python,lua,js,wren}/hold matching ports.benchmarks/runner.py— lox++ suite + AWFY across python/lua/js. Runs lox++ across its own 26-program suite (AWFY / CLBG / Wren ports underbenchmarks/lox/), and the AWFY suite for python/lua/js via the SOM harness. The lox++ ports are faithful AWFY translations andmanifest.tomlsets each benchmark'sinnerto do the identical work, so all 12 AWFY benchmarks are apples-to-apple across lox++/python/lua/js (bounce, cd, deltablue, list, mandelbrot, nbody, permute, queens, richards, sieve, storage, towers).crosslang.pyadds clox + wren on 4 book-Lox micros.Cross-language results (apples-to-apples, min of 5, compute-only)
All languages produce identical results (fib→9227465, towers→1048575, queens→92, mandelbrot→3959).
What's in the suite
benchmarks/lox/— AWFY (16), CLBG (6), Wren (4). 22 run clean today;binary_trees/fannkuchare allocation-heavy (long), anddeltablue(compile error) /havlak(runtime error) need follow-up.benchmarks/clox/(no lists/maps) shared by lox++ and clox.benchmarks/{python,lua,js,wren}/for the 4 micro-benchmarks.Dockerfile.clox(builds clox at a pinned commit),Dockerfile.lua(lua5.4),Dockerfile.wren(builds the wren CLI fromwren-lang/wren-cli); python/node use officialpython:3.12-slim/node:22-alpine. Seebenchmarks/SOURCES.md.manifest.toml(benchmark × language → file) andlangs.toml(interpreter configs) forrunner.py.Infrastructure fixes
The third-party plumbing did not run as originally written; the runnable paths are now fixed:
manifest.tomlwas invalid TOML (table header + key on one line) — rewritten as inline tables sorunner.pycan load it.runner.py: lox++ uses build-tree paths unconditionally; the AWFY adapter accepts scientific notation (str()prints1.07e+06 us); the clox/raw adapter reads the program's self-timed elapsed instead of podman wall time.Dockerfile.clox: addlibc6-dev(was failing onstdlib.h).Dockerfile.wren: build the wren CLI fromwren-lang/wren-cli(thewren-lang/wrenrepo builds only a test runner).Dockerfile.lua: minimal lua5.4 interpreter image.Quick start
Known limitations / follow-ups
havlaklox++ port overflows the 256-frame call stack (recursivedoDFS) and uses a non-AWFY signature, so it's lox++-only and currently errors — needs an iterative rewrite to run/compare.fib/earleyhave no AWFY python/lua/js port.binary_trees/fannkuch(CLBG, lox++-only) are slow (allocation-heavy).🤖 Generated with Claude Code