vyrn

Benchmarks

The Benchmarks Game programs in Vyrn, C, Rust and JavaScript, run on one machine.

AMD Ryzen 5 9600X 6-Core Processor, Windows 11 10.0.26200, vyrn 0.1.0-indev, wasmtime 49.0.3, 2026-10-17 · p50 and p99 of 100 runs

Results by program

A lane is one engine's build, then its run at p50, with the hatch reaching p99; light grey is startup. A row is a deviation when Vyrn native is more than ten per cent off Rust, the noise of this machine.

nbody

N = 25,000,000882 ms2026-09-012026-09-01-run22026-10-162026-10-16-run22026-10-16-run32026-10-17974 ms1.53x Rust · a deviation
  1. Rustrun 637 ms849 ms4.2 MB
  2. Crun 847 ms989 ms3.8 MB
  3. Vyrn wasm-optrun 933 ms1003 ms13.8 MB
  4. noderun 1030 ms1030 ms40.2 MB
  5. Vyrn wasmrun 1059 ms1091 ms13.8 MB
  6. Vyrn nativerun 974 ms1395 ms4.1 MB
  7. bunrun 1455 ms1455 ms23.9 MB

no vector instructions — Rust's compiler pairs the inner loop's multiplies into vector instructions, and Vyrn's does not: 103 paired multiplies against 5.

spectral-norm

N = 5,5001012 ms2026-09-012026-09-01-run22026-10-162026-10-16-run22026-10-16-run32026-10-17924 ms0.99x Rust · inside the noise band
  1. Vyrn wasm-optrun 949 ms1017 ms14.1 MB
  2. Crun 928 ms1059 ms3.7 MB
  3. Rustrun 932 ms1125 ms4.2 MB
  4. noderun 1263 ms1263 ms40.7 MB
  5. bunrun 1300 ms1300 ms25.0 MB
  6. Vyrn nativerun 924 ms1327 ms4.3 MB
  7. Vyrn wasmrun 2693 ms2726 ms14.1 MB

fannkuch-redux

N = 111958 ms2026-09-012026-09-01-run22026-10-162026-10-16-run22026-10-16-run32026-10-171991 ms1.08x Rust · at the edge of the band
  1. Crun 1842 ms1979 ms3.8 MB
  2. Rustrun 1839 ms2053 ms4.2 MB
  3. Vyrn wasm-optrun 2002 ms2080 ms13.8 MB
  4. Vyrn wasmrun 2139 ms2179 ms13.9 MB
  5. Vyrn nativerun 1991 ms2406 ms4.1 MB
  6. noderun 2569 ms2569 ms43.3 MB
  7. bunrun 2608 ms2608 ms36.7 MB

nothing allocated in the loop — The loop allocates nothing and checks no index. Where the remaining 152 ms against Rust goes is not yet measured.

binary-trees

N = 182004 ms2026-09-012026-09-01-run22026-10-162026-10-16-run22026-10-16-run32026-10-17462 ms0.29x Rust · ahead of the band
  1. bunrun 338 ms338 ms122.1 MB
  2. noderun 386 ms386 ms332.5 MB
  3. Vyrn wasmrun 544 ms576 ms45.9 MB
  4. Vyrn wasm-optrun 555 ms619 ms45.9 MB
  5. Vyrn nativerun 462 ms870 ms36.2 MB
  6. Crun 790 ms910 ms19.6 MB
  7. Rustrun 1597 ms1768 ms36.3 MB

who allocates the memory — Both Vyrn builds reuse freed nodes from a free list of their size; the C and Rust entries call the system allocator for every node.

fasta

N = 5,000,000977 ms2026-09-012026-09-01-run22026-10-162026-10-16-run22026-10-16-run32026-10-17526 ms1.15x Rust · a deviation
  1. Crun 492 ms625 ms3.8 MB
  2. Rustrun 459 ms687 ms4.2 MB
  3. Vyrn wasm-optrun 668 ms728 ms13.9 MB
  4. Vyrn wasmrun 727 ms759 ms13.9 MB
  5. noderun 801 ms801 ms120.7 MB
  6. Vyrn nativerun 526 ms913 ms4.1 MB
  7. bunrun 1062 ms1062 ms435.3 MB

a seed kept in memory — The random seed lives in a module global, so every byte drawn reads and writes memory where Rust keeps the seed in a register.

reverse-complement

N = 4,000,000561 ms2026-09-012026-09-01-run22026-10-162026-10-16-run22026-10-16-run32026-10-17103 ms1.50x Rust · a deviation
  1. Vyrn wasmrun 258 ms289 ms94.8 MB
  2. Rustrun 69.0 ms293 ms43.8 MB
  3. Crun 176 ms304 ms42.5 MB
  4. Vyrn wasm-optrun 273 ms350 ms94.8 MB
  5. noderun 419 ms419 ms242.9 MB
  6. bunrun 494 ms494 ms831.0 MB
  7. Vyrn nativerun 103 ms504 ms84.9 MB

a capacity check per byte — Every byte goes in through an append that checks capacity, where Rust writes it into place. C is 2.6 times Rust here.

k-nucleotide

N = 400,000125 ms2026-09-012026-09-01-run22026-10-162026-10-16-run22026-10-16-run32026-10-17102 ms0.52x Rust · ahead of the band
  1. Vyrn wasmrun 245 ms285 ms31.1 MB
  2. Vyrn wasm-optrun 238 ms346 ms31.1 MB
  3. Crun 302 ms451 ms262.3 MB
  4. Rustrun 195 ms490 ms16.8 MB
  5. bunrun 596 ms596 ms126.5 MB
  6. Vyrn nativerun 102 ms630 ms21.2 MB
  7. noderun 720 ms720 ms117.1 MB

faster than C, and why — Maps carry a hash index, and the key is one number rolled along the sequence, not a fresh piece of text per position.

pidigits

N = 12,0001330 ms2026-09-012026-09-01-run22026-10-162026-10-16-run22026-10-16-run32026-10-171267 ms1.01x Rust · inside the noise band
  1. Crun 1266 ms1394 ms3.8 MB
  2. Rustrun 1258 ms1512 ms4.3 MB
  3. Vyrn nativerun 1267 ms1688 ms5.1 MB
  4. Vyrn wasmrun 1822 ms1858 ms14.8 MB
  5. Vyrn wasm-optrun 1923 ms1998 ms14.8 MB
  6. bunrun 2942 ms2942 ms26.5 MB
  7. noderun 3021 ms3021 ms41.4 MB

mandelbrot

N = 4,000675 ms2026-09-012026-09-01-run22026-10-162026-10-16-run22026-10-16-run32026-10-17652 ms1.03x Rust · inside the noise band
  1. noderun 652 ms652 ms43.5 MB
  2. bunrun 680 ms680 ms29.3 MB
  3. Crun 617 ms740 ms3.8 MB
  4. Vyrn wasmrun 719 ms751 ms13.9 MB
  5. Rustrun 634 ms801 ms4.2 MB
  6. Vyrn wasm-optrun 799 ms862 ms13.8 MB
  7. Vyrn nativerun 652 ms1031 ms4.1 MB

the closest six readings here — Plain floating-point arithmetic with no allocation, so six of the seven readings sit within 17% of C.

regex-redux

N = 100,0001177 ms2026-09-012026-09-01-run22026-10-162026-10-16-run22026-10-16-run32026-10-1781.1 ms1.17x Rust · a deviation
  1. bunrun 27.1 ms27.1 ms30.0 MB
  2. noderun 61.5 ms61.5 ms57.6 MB
  3. Crun 73.4 ms209 ms10.2 MB
  4. Vyrn wasmrun 106 ms241 ms29.9 MB
  5. Rustrun 69.5 ms282 ms10.6 MB
  6. Vyrn wasm-optrun 115 ms322 ms29.8 MB
  7. Vyrn nativerun 81.1 ms826 ms19.9 MB

not the same engine on both sides — Vyrn runs a general regular-expression engine written in Vyrn; the C and Rust entries carry a sixty-line matcher fitted to this corpus.

Method

  • Plain C11, safe standard-library Rust, plain JavaScript under node and bun. No hand-written vector code and no threads.
  • Vyrn wasm-opt is the WebAssembly build after wasm-opt -O3; plain Vyrn wasm is the module as the compiler writes it.
  • All seven print the same bytes. 100 runs per engine at its own defaults; p50 and p99 by nearest rank.
  • Build time and build peak memory are medians of three builds. Output is the shipped file: the executable, the .wasm module, or the source for node and bun.
  • The harness runs by hand, not in CI. The record is bench/results/2026-10-17.json; the line beside a program's name is Vyrn's time across all records.
Operating systemWindows 11 10.0.26200
CPUAMD Ryzen 5 9600X 6-Core Processor (12 logical cores)
Memory31.1 GiB
clangclang version 22.1.0 (https://github.com/llvm/llvm-project 4434dabb69916856b824f68a64b029c67175e532)
rustcrustc 1.98.1 (48a229cea 2026-09-01)
nodev26.12.0
bun1.4.3
python3.13.13
vyrnvyrn 0.1.0-indev at 7942f7575cf03b4d9b5ba17147792fc7c53fdc2b
wasmtime49.0.3, sha256 bee8f02158458a5f360412b232543d4fea379b71b94380b806e7980050596c18
wasm-optwasm-opt version 133 (version_133), sha256 17a2cbeac6b5693c5fbafab3838d3c65fd9c1eb38b05f5baec6c657e8c84995b
C flagsclang -O2 -ffp-contract=off -std=c11
Rust flagsrustc -C opt-level=3
JavaScript on nodenode (no build step)
JavaScript on bunbun (no build step)
Vyrn nativevyrn build (the module through wasm2c, clang -O2 -ffp-contract=off with wasm-rt)
Vyrn wasmvyrn build --target wasm (the emitter's module, no optimizer) + wasmtime run
Vyrn wasm-optvyrn --wasm-opt build --target wasm (the emitter's module through wasm-opt -O3) + wasmtime run