Benchmarks

Every number, with its machine and method.

These results come from the benchmark suites in the Alice repository. Every program has a twin in the other language with the same algorithm and the same checksum. Numbers from different machines are never compared directly.

Bend 2 runtime suite

The eight workloads behind the numbers on bend-lang.com, ported 1:1 to Alice: same algorithm, same fork tree, same checksum as Bend's own C twin, at Bend's big sizes.

Machine

x86-64 build box, 32 cores, 61 GB, Arch Linux, .NET 10.0.114, clang 23 with libomp. Shared with other jobs during the run (load average 8-10), so read ratios within 1.2x as equal.

Compiler: Alice development build after 0.14.0

Method

  • Cold-process wall time: startup, JIT and the work together (hyperfine -N, median of 5 after one warm-up).
  • Serial: 1 core, pinned with taskset; Alice also runs with DOTNET_PROCESSOR_COUNT=1.
  • Parallel: all 32 cores. Alice forks the pure recursive pairs itself, with no annotations. C is Bend's main.c with an OpenMP path added (clang -O3 -march=native -fopenmp).
  • Every Alice checksum equals the C checksum.

Source: benchmarks/bend2/README.md

All cores, relative to serial C on the same machineRatio, lower is better
bfs
Alice parallel / C serial: 0.13
Bend parallel / C serial (M4): 0.096
editdist
Alice parallel / C serial: 0.083
Bend parallel / C serial (M4): 0.118
gameoflife
Alice parallel / C serial: 0.071
Bend parallel / C serial (M4): 0.095
hashmap
Alice parallel / C serial: 0.114
Bend parallel / C serial (M4): 0.383
kmeans
Alice parallel / C serial: 0.987
Bend parallel / C serial (M4): 0.13
lexer
Alice parallel / C serial: 0.133
Bend parallel / C serial (M4): 0.191
mandelbrot
Alice parallel / C serial: 0.142
Bend parallel / C serial (M4): 0.105
merkle
Alice parallel / C serial: 0.163
Bend parallel / C serial (M4): 0.123
Serial, 1 core (median ms, lower is better)
WorkloadAliceC (clang -O3)Alice / C (clang -O3)
bfs10,8436,4411.68x
editdist11,3488,7741.29x
gameoflife14,29615,8070.90x
hashmap1,4641,4261.03x
kmeans32,9042,80911.71x
lexer2,0971,5131.39x
mandelbrot3,7122,4621.51x
merkle11,9636,8801.74x
Parallel, 32 cores (median ms, lower is better)
WorkloadAliceC (OpenMP)Alice / C (OpenMP)
bfs8393012.79x
editdist7265071.43x
gameoflife1,1236371.76x
hashmap162871.86x
kmeans2,77426910.31x
lexer2011641.23x
mandelbrot3491831.91x
merkle1,1205102.20x
Parallel speedup (serial median / parallel median) (speedup, higher is better)
WorkloadAlice, 32 coresC (OpenMP), 32 coresBend, 16 cores (Apple M4 Max, other machine)
bfs12.9x21.4x11.4x
editdist15.6x17.3x10.8x
gameoflife12.7x24.8x12.1x
hashmap9.0x16.4x11.5x
kmeans11.9x10.4x7.7x
lexer10.4x9.2x10.8x
mandelbrot10.6x13.5x11.3x
merkle10.7x13.5x10.0x
Alice against Bend, machine-independent: each language divided by the serial C twin on its own machine (ratio, lower is better)
WorkloadAlice / C, serialBend / C, serial (M4)Alice parallel / C serialBend parallel / C serial (M4)
bfs1.681.090.130.096
editdist1.291.280.0830.118
gameoflife0.901.150.0710.095
hashmap1.034.410.1140.383
kmeans11.711.000.9870.13
lexer1.392.070.1330.191
mandelbrot1.511.190.1420.105
merkle1.741.230.1630.123

Notes

  • Bend was not run on this machine. Bend numbers are Bend's own pinned results from an Apple M4 Max (16 cores); compare them only through the ratios to C, never as milliseconds.
  • Alice's startup floor (bfs with the smallest input) is 26 ms serial and 43 ms on 32 cores; it is part of every cold-process time.
  • kmeans is Alice's largest gap to C. The fix (arena-backed sum types) is tracked in the roadmap.

Alice vs C# on the same .NET runtime

Eight kernels, each with an idiomatic C# twin and an expert hand-optimized C# twin: same algorithm, same checksum.

Machine

12th Gen Intel Core i5-1235U laptop (12 threads, turbo and thermal limits), Linux 7.0.9, .NET 10.0.4. Run-to-run spread is 10-20%, so read ratios within 1.2x as equal.

Compiler: Alice 0.12.0 (run 8, 2026-10-22)

Method

  • Each kernel warms up for at least 50 calls and 1 s so tier-1 and PGO code is running, then 15 timed calls; the median is reported.
  • Each timed call checks its checksum, so the JIT cannot drop the work. All checksums match.
  • One process per benchmark variant. Both sides use server GC.

Source: benchmarks/README.md (run 8)

Warm kernels, median of 15 (median ms, lower is better)
WorkloadAliceC# idiomaticC# hand-optimizedAlice / C# idiomatic
nbody47.853.348.90.90x
binarytrees17116891.41.02x
pipeline237.72.10.05x
expr10.31110.50.94x
wordfreq6.980.55.30.09x
mandelbrot9.71058.70.09x
parallel34.840.4340.86x
particles2.41362.40.02x

Notes

  • pipeline: Alice fuses map.select.sum into one vectorized loop split across cores; LINQ pays for delegates and iterators.
  • Hand-optimized C# still leads on binarytrees (1.87x) and wordfreq (1.30x).

Alice vs C

Five of the .NET suite kernels written as idiomatic C, serial and with pthreads.

Machine

12th Gen Intel Core i5-1235U laptop (12 threads), Linux, clang 22 -O3 -march=native.

Compiler: Alice development build (runs 6 and 7, 2026-10-16)

Method

  • Alice: warm kernel, median of 15, as in the .NET suite.
  • C: c/bench.c, serial and pthreads-parallel. Same checksums as Alice and C#.

Source: benchmarks/README.md (runs 6 and 7)

Alice against the faster of C serial and C parallel (median ms, lower is better)
WorkloadAliceC serialC parallel (pthreads)
binarytrees90.1301321
pipeline2.515.34
mandelbrot9.810215.3
particles2.422.42.9
nbody*47.229.9–
  • * nbody: With @[Native] (run 7), Alice measured 31.8-32.9 ms against C's 33.4-34.5 ms in the same session.

Notes

  • nbody without @[Native] is a .NET code-generation limit: expert hand-optimized C# is also about 50 ms.

Fork/join on one machine: Bend, Alice, C, Rust, C#

Six fork/join workloads, same algorithm and the same binary fork shape in every language. All five languages ran on the same laptop.

Machine

12th Gen Intel Core i5-1235U laptop (2 performance + 8 efficiency cores, 12 threads), CachyOS Linux 7.0.9, .NET 10.0.4.

Compiler: Alice 0.13.x development build, Bend 2.0.39

Method

  • Cold-process wall time (hyperfine -N, median of 5 after one warm-up). .NET pays about 22-27 ms of startup and JIT; Bend, C and Rust about 1 ms.
  • Serial is pinned to one core. Parallel uses 12 threads: Bend forks every parallel let, Alice forks pure recursive pairs itself, C uses OpenMP tasks, Rust rayon::join, C# Parallel.Invoke.

Source: benchmarks/bend-vs/README.md

Parallel, 12 threads (median ms, lower is better)
WorkloadBendAliceCRustC#
pow2*21019331158247
fib43140274294
tree906811625651,019
nqueens14428278111187
mandel10015212192218
collatz15935618683326
  • * pow2: clang turns pow2 into a closed form; the C number measures nothing.
Serial, 1 core (median ms, lower is better)
WorkloadBendAliceCRustC#
pow2*1,5411,21811,2061,414
fib280625146245381
tree1231,5424727741,430
nqueens331620240357430
mandel6727496736721,117
collatz1,1592,7876536952,537
  • * pow2: clang turns pow2 into a closed form; the C number measures nothing.

Notes

  • Bend wins allocation-heavy trees by a wide margin: its nodes have no headers and are freed as they are read. Struct- and arena-backed trees are Alice's planned answer.
  • Branchy integer loops (collatz) favour native compilers; Alice and C# land at the same time there, so the gap is in .NET's code generation, not in Alice's compiler.

Run them yourself

Each suite has a run.sh that builds the compiler and every program, then measures. See benchmarks/ in the repository. Please report results from your machine as an issue, with the machine and the command you ran.