lang-bench is a reproducible benchmark suite for C, C++, Zig, Odin, and Rust on scientific-style workloads. It keeps algorithms, inputs, data layouts, and correctness checks as consistent as practical, then records the effects of compilers, optimization flags, threading libraries, and accelerator hardware.
The suite does not produce universal language rankings. Results depend on the processor, compiler version, target flags, workload size, and implementation details. The source and runner scripts define the benchmark behavior; docs/language-comparison.md contains measured results and discussion.
| Workload | Implementations | Focus |
|---|---|---|
| Sieve of Eratosthenes | C++, Zig, Odin, Rust | Integer loops, memory traffic, bounds-check elimination |
| Dense matrix multiply | C++, Zig, Odin, Rust | Cache behavior and floating-point loop optimization |
| Tiled matrix multiply | C++, Zig, Odin, Rust | Data layout, loop tiling, fast-math modes, LTO |
| Monte Carlo π | C (GCC and Clang), Zig, Odin, Rust | Multithreading and integer-kernel code generation |
| Trapezoid integration | C (GCC and Clang), Zig, Odin, Rust | Parallel reduction around a sin()-bound workload |
| Ray tracer | C (GCC and Clang), Zig, Odin, Rust, OpenCL | Threaded FP64 ray-sphere intersection and CPU/GPU behavior |
| CNN inference | Python/OpenVINO on CPU, GPU, NPU | Accelerator latency and throughput; separate from the language suite |
C++ implements the single-threaded kernels and C implements the pthread-based workloads. GCC and Clang variants are built for workloads where compiler code generation can materially affect results.
Each compiled benchmark:
- uses the same algorithm, loop order, and data layout across implementations;
- generates deterministic inputs instead of using the operating-system RNG;
- verifies a checksum or numerical result before timings are compared;
- keeps allocation and setup outside the timed section;
- runs a warmup followed by multiple timed iterations;
- emits median, mean, and sample standard deviation as JSON Lines; and
- uses multi-second default workloads where practical to reduce scheduler and timer noise.
The default workloads are intentionally expensive and may take several minutes to complete. Use smaller environment overrides for a smoke test.
The full native suite expects Linux with:
- GCC (
gcc,g++) - Clang
- Zig
- Odin
- Rust and Cargo
- Python 3
- pthreads and libm
- an OpenCL loader and working device for the GPU ray tracer
The optional OpenVINO experiment has separate Python dependencies and is not run by scripts/run_all.sh.
Record compiler versions, CPU model, operating system, available accelerators, and relevant environment variables with every result set. Results from one host should not be treated as portable rankings.
git clone https://github.com/reneotten/lang-bench.git
cd lang-bench
./scripts/build_all.sh
./scripts/run_all.shRun selected workloads by name:
./scripts/run_all.sh sieve matmul
./scripts/run_all.sh monte_carlo integration
./scripts/run_all.sh raytraceFor a shorter validation run, override workload sizes before invoking the runner:
BENCH_ITERS=3 \
BENCH_WARMUP=1 \
BENCH_SIEVE_N=10000000 \
BENCH_MATMUL_N=512 \
BENCH_MATMUL_OPT_N=768 \
BENCH_MC_SAMPLES=100000000 \
BENCH_INT_N=10000000 \
BENCH_RT_W=1280 \
BENCH_RT_H=720 \
./scripts/run_all.shBENCH_THREADS=0 uses all logical CPUs. Set a positive value to compare thread counts. config.env lists the defaults; each benchmark also accepts workload-specific environment variables.
Every implementation emits one JSON object. A complete run is saved to a timestamped file and copied to results/latest.jsonl:
results/run_YYYYMMDDTHHMMSSZ.jsonl
results/latest.jsonl
Summarize a result file with:
python3 scripts/summarize.py results/latest.jsonlGenerated results and binaries are ignored by Git so local measurements stay out of source history. JSON records include the workload name, implementation, input size, thread count, warmup and iteration counts, timings, and a correctness result. For example:
{
"bench": "raytrace_par",
"lang": "c",
"n": 33177600,
"threads": 8,
"iters": 7,
"warmup": 1,
"times_ms": [63.804, 56.529, 57.987],
"median_ms": 57.987,
"mean_ms": 59.44,
"stdev_ms": 3.846,
"result": "sum_par=2931122.255531,sum_seq=2931122.253782,px=33177600"
}The ray tracer uses the same fixed scene and FP64 math in every implementation. Compare its checksum before comparing timings.
./scripts/build_all.sh
./scripts/run_all.sh raytrace
BENCH_RT_W=1920 BENCH_RT_H=1080 ./scripts/run_all.sh raytraceThe OpenCL headers needed for the host program are vendored under third_party/opencl/. Runtime still requires a system OpenCL loader and a compatible device driver.
scripts/npu_bench.py builds two synthetic convolutional networks and measures inference latency on the OpenVINO CPU, GPU, and NPU plugins. It is an accelerator experiment rather than a hand-written language port.
python3 scripts/npu_bench.pyOn Linux, Intel GPU/NPU access commonly requires membership in the render group. You can run the command in that group with:
sg render -c "python3 scripts/npu_bench.py"benches/
common/ shared C and Zig timing helpers
sieve/ C++, Zig, Odin, Rust
matmul/ C++, Zig, Odin, Rust
matmul_opt/ optimized C++, Zig, Odin, Rust
monte_carlo/ C, Zig, Odin, Rust
integration/ C, Zig, Odin, Rust
raytrace/ C, Zig, Odin, Rust, OpenCL
scripts/
build_all.sh compile the native suite
run_all.sh run workloads and collect JSONL
summarize.py print result tables
npu_bench.py optional OpenVINO CPU/GPU/NPU experiment
docs/
language-comparison.md measured results and conclusions
language-implementation-quickstart.md
language pickup guide
config.env default workload sizes and iteration counts
Compare checksums first, then wall time and variance. Speedup can mislead when sequential baselines differ. Workload size, compiler, CPU target, and loop structure can change relative results; document these conditions alongside any published comparison.