Apsi

Benchmarks

Apsi, measured

Each category compares Apsi with the tool people use for that job today, on the same machine, with the command to reproduce it. Pick a category.

Apsi 2.4.4 against 2.0.0

Reproduce: python3 benchmarks/versions/compare.py --old ../apsi-2.0.0 --new . --web

The same programs on both versions, on the same machine, with the same results. On a GitHub Actions runner with the native compiler, 2.4.4 is 3.84× faster on the geometric mean of 12 measurements; on a small 2-core VM without the native compiler, 7.31×. The gains are where 2.0.0 was weakest: array code written as loops, objects, function calls and the web server. The CPU tab compares the heavy @native programs of both versions.

3.84×faster, geometric mean (runner)
2.72×more web requests per second
8.7×faster object creation
Apsi 2.4.4Apsi 2.0.0longer is faster
creating objects 8.65 × 1 ×recursive calls 3.37 × 1 ×@native matmul 512 2.56 × 1 ×web, 64 conn. 2.72 × 1 ×web, 256 conn. 2.4 × 1 ×dictionaries 1.56 × 1 ×start-up 1.34 × 1 ×strings 1.23 × 1 ×
ProgramApsi 2.0.0Apsi 2.4.4ChangeChange on a 2-core VM ¹
matmul 300, loops (compiled engine)38,157 ms5.0 ms7,708× faster6,374× faster
200k objects: create and sum3,758 ms434 ms8.65× faster9.26× faster
fib(25), recursive calls82.8 ms24.5 ms3.37× faster2.26× faster
web server, 64 connections5,124 req/s13,949 req/s2.72× more3.06× faster
matmul 512, @native loops24.7 ms9.6 ms2.56× faster300× faster
web server, 256 connections5,848 req/s14,052 req/s2.4× more3.18× faster
word count, 260k words320 ms205 ms1.56× faster1.41× faster
start-up: apsi run hello.apsi231 ms173 ms1.34× faster6.69× faster
200k f-strings and join236 ms192 ms1.23× faster1.26× faster
apsi check, 43 example programs (1,594 lines), empty cache9,865 ms9,526 ms1.04× faster4.90× faster
integer loop, 3M iterations171 ms168 ms1.02× fastersame
harmonic sum 50M, @native70.1 ms70.1 ms1.0× fastersame

¹ A 2-core cloud VM (Intel Xeon @ 2.30 GHz) without llvmlite: both versions ran the @native functions without the native compiler there, and 2.0.0 started much more slowly. Main columns: AMD EPYC 7763, GitHub Actions runner (4 vCPU), Linux, Python 3.13, llvmlite installed; best of 2 runs.

Every commit of the speed work, on one machine

Reproduce: python3 benchmarks/commits/measure.py --commits 1187386 7810294 040e971 --rounds 3

Numbers from different GitHub runs cannot be compared: GitHub picks the processor, and the same C program takes 14 ms on one runner model and 44 ms on another. So every commit was measured on one runner, in rotating rounds, against the ones before it. From the start of the work (1187386) to the release (040e971): n-body 4.0×, the ODE 1.5×, k-means 1.27×, compiling 1.21× faster, and no row slower.

4.0×faster n-body (SIMD lanes written by Apsi)
1.5×faster ODE integration
0measurements that got slower
Measurement1187386 (start)7810294040e971 (release)
heavy: nbody-dense 2000x10184.4 (1.00×)127.7 (1.44×)46.0 (4.01×)
heavy: jacobi-2d 1024x200156.4 (1.00×)156.9 (1.00×)152.5 (1.03×)
heavy: matmul 1024189.3 (1.00×)182.6 (1.04×)179.0 (1.06×)
heavy: lu-pivot 80041.4 (1.00×)41.2 (1.00×)41.4 (1.00×)
heavy: ising 512x5081.5 (1.00×)81.6 (1.00×)81.5 (1.00×)
heavy: levenshtein 10k194.8 (1.00×)195.1 (1.00×)195.1 (1.00×)
heavy: ode-rk4 20M533.4 (1.00×)355.0 (1.50×)355.0 (1.50×)
heavy: kmeans 200k k16 x2065.0 (1.00×)51.3 (1.27×)51.3 (1.27×)
programs: matmul 300, loops (compiled engine)38,245.6 (1.00×)38,307.7 (1.00×)38,642.7 (0.99×)
programs: matmul 512, @native loops25.9 (1.00×)24.8 (1.04×)26.0 (0.99×)
programs: harmonic sum 50M, @native70.0 (1.00×)70.0 (1.00×)70.1 (1.00×)
programs: fib(25), recursive calls24.8 (1.00×)24.6 (1.01×)24.1 (1.03×)
programs: 200k objects: create and sum431.8 (1.00×)434.8 (0.99×)435.1 (0.99×)
programs: word count, 260k words201.7 (1.00×)201.2 (1.00×)203.7 (0.99×)
programs: 200k f-strings and join193.9 (1.00×)190.4 (1.02×)188.2 (1.03×)
programs: integer loop, 3M iterations168.6 (1.00×)172.3 (0.98×)171.7 (0.98×)
start-up: apsi run hello.apsi173.0 (1.00×)173.3 (1.00×)172.3 (1.00×)
import apsi133.9 (1.00×)133.6 (1.00×)133.4 (1.00×)
cold heavy.apsi: compile + run, whole process7,290.7 (1.00×)6,617.3 (1.10×)6,031.9 (1.21×)
apsi check, 43 examples, empty cache9,900.8 (1.00×)9,788.9 (1.01×)9,628.6 (1.03×)

AMD EPYC 7763, GitHub Actions runner (4 threads), Linux, Python 3.13, llvmlite installed. Times in ms, best of 3 rounds; in brackets: time of the first commit / time of this commit.

Python, converted

Reproduce: benchmarks/python/cmp.sh · tests/test_stdlib_convert.py

Converted programs print byte-identical output. Object-heavy code runs 6 % faster than CPython; string and pure arithmetic code runs at about the same speed (within 4 %; use @native for machine code). Best of 5 runs each.

byte-identicaloutput of the converted standard library
6 % fasterobject-heavy code vs CPython
best of 5runs per program, same machine
Apsi (converted)CPython 3.13shorter is faster
objects 0.378 s 0.402 sstrings 0.377 s 0.363 sn-body 1.407 s 1.388 s
ProgramCPython 3.13Converted, apsi run
objects: trees, dataclasses, dicts, Counter0.402 s0.378 s
strings: regex, split, JSON, sets0.363 s0.377 s
n-body, 200,000 steps1.388 s1.407 s
Standard-library modules converted: identical output (tests/test_stdlib_convert.py)yesyes

Matrix multiplication

Reproduce: benchmarks/matmul/mm.apsi · mm.c · mm.py · tests/test_idioms.py

Three nested loops, written the obvious way, are recognised as a matrix product and run on the tuned BLAS kernel: 4–11× faster than the same loops in C with -O3, about 2,400× faster than Python loops. The loops stay as the fallback whenever the fast path would not give the loops' result. Best of 3 runs; BLAS uses all 4 vCPUs, the C loops one.

11×faster than C loops at 2048
89 GFLOP/sfrom three plain loops
0 bitsdifference from a @ b
Apsi loopsC loops (-O3)longer is faster
256 61 GFLOP/s 14.7 GFLOP/s512 79 GFLOP/s 14.2 GFLOP/s1024 88.5 GFLOP/s 13.8 GFLOP/s2048 89.3 GFLOP/s 8.1 GFLOP/s
Size (float64)C loops, gcc -O3 -march=nativeNumPy a @ bApsi loops (ikj)Apsi loops (dot form)Apsi a @ b
256 × 2562.28 ms · 14.7 GFLOP/s0.61 ms0.55 ms · 61.0 GFLOP/s0.45 ms0.46 ms
512 × 51218.85 ms · 14.2 GFLOP/s3.20 ms3.40 ms · 79.0 GFLOP/s3.20 ms3.17 ms
1024 × 1024155.2 ms · 13.8 GFLOP/s23.98 ms24.27 ms · 88.5 GFLOP/s23.77 ms23.49 ms
2048 × 20482,111 ms · 8.1 GFLOP/s190.7 ms192.4 ms · 89.3 GFLOP/s189.2 ms190.2 ms
Python loops, 128 × 128——114.0 ms in CPython (0.037 GFLOP/s)

Tables against pandas

Reproduce: benchmarks/dataframe/run.py

use dataframe on 2 million rows against pandas, results checked equal; best of 3 runs. Filters, group-bys and joins are several times faster; sorting is faster; reading CSV is about as fast as pandas.

21×faster filters than pandas
4×less memory
3.7×faster joins
Apsipandas 2shorter is faster
filter 4.6 ms 98.8 msgroup by 50k keys 35.6 ms 202.2 msgroup by 2 keys 39 ms 170.1 msleft join 45.1 ms 168.9 mssort 105.1 ms 168.4 ms
Operationpandas 2Apsi 2.4.4Speed-up
Filter with two conditions98.8 ms4.6 ms21.5×
Group by 50,000 string keys (sum, mean, count)202.2 ms35.6 ms5.7×
Group by two keys (std, max)170.1 ms39.0 ms4.4×
Left join 2M × 50k on a string key168.9 ms45.1 ms3.7×
Sort by a float column168.4 ms105.1 ms1.6×
Arithmetic on two columns2.8 ms2.7 mssame
Read a 1M-row CSV0.18 s0.20 s1.1× slower
Memory for the table262 MB65 MB4× less

HTTP server (synthetic)

Reproduce: benchmarks/web/

Synthetic benchmark: one route returning a fixed 25-byte JSON object, keep-alive, loopback, the Go load generator on the same 4-vCPU machine (it takes CPU time from the server too). It measures the server's own cost per request, not a real application (no database, no request parsing, no TLS). With processes="auto" Apsi answers 1.8× the requests of a single Node.js 22 process; a single Apsi process answers about two thirds of Node's. Three rounds of 5 seconds each; the range is shown.

44,269req/s with processes="auto" on 4 vCPUs
1.8×a single Node.js process on the same test
0errors at 1,000 connections
Setup64 connections256 connections
Apsi, 1 process (asyncio loop)14,008–14,978 req/s13,671–14,830 req/s
Apsi, 1 process, uvloop15,493–16,863 req/s14,958–15,392 req/s
Apsi, processes="auto" (4 processes)41,718–42,085 req/s44,042–44,269 req/s
Node.js 22, bare http module, 1 process19,872–22,198 req/s22,862–25,155 req/s
Fast route while 64 connections wait on a blocking 10 ms route (Apsi, 1 process)9,888 req/s, p99 7.9 ms—
1,000 connections at once (Apsi, 1 process)—15,454 req/s, 0 errors

Each Apsi process has its own memory: keep shared state in a database or memory.store(). Run: benchmarks/web/ (pip install uvloop for the uvloop rows).

Real-time video, CPU only

Reproduce: benchmarks/rt/

Gray conversion + motion detection on every frame, on the CPU only (one core of a 4-vCPU runner); a capped run holds its target while the frame work fits in the frame time — up to 2560×1440 at 60 fps here; 4K reaches 20 of 30 fps on this machine. A 2000 Hz control loop ran 6,000 of 6,000 ticks with p99 lateness 0.3–0.4 µs (worst single tick 26–48 µs).

8 sizes640×480 to 3840×2160
90 fps1080p capped, 7.6 ms latency
2,000 Hzcontrol loop, 0 missed, p99 0.4 µs
SizeUncapped fpsCapped fps (target)Latency p50
640×480708240.0 (240)1.82 ms
800×600506240.0 (240)1.80 ms
1280×720290120.0 (120)3.42 ms
1366×768251120.0 (120)3.86 ms
1600×90016990.0 (90)5.16 ms
1920×108010690.0 (90)7.61 ms
2560×14405057.1 (60)14.65 ms
3840×21602020.0 (30)36.46 ms

Models that learn

Reproduce: benchmarks/ai/learn.apsi

Trained from scratch on the CPU with use layers; held-out accuracy before → after training (the same in all 3 runs; time: best of 3).

100 %held-out accuracy, spiral MLP
100 %LSTM memory over 20 steps
0.019character transformer loss
TaskBeforeAfterTime
3-class spiral, MLP 64-6430.8 %100 %1.1 s
Remember the first of 20 steps, LSTM 3253.5 %100 %17.5 s
Character transformer (2 layers), loss1.6930.01910.3 s

Fewer AI tokens, nothing lost

Reproduce: docs/TOKENS.md

use tokens: every transform is exactly reversible. Token counts estimated.

63 %fewer tokens for record lists
99.7 %fewer for an edited document
0 byteslost: every transform reverses exactly
InputBeforeAfterSaved
200 orders as pretty JSON → pack()9,8023,62563 %
200 orders as minified JSON → pack()8,4013,62557 %
500-line log → dedupe()5,6892,33959 %
Edited 6,000-token document → diff()5,9511999.7 %

WebSocket and databases

Reproduce: benchmarks/websocket/ · benchmarks/db/

Built-in clients and servers, no drivers to install. PostgreSQL 16 and Redis 7 in Docker on the same machine; best of 3 runs.

225 µsWebSocket round trip
198 µsPostgreSQL point query
51kWebSocket messages per second
MeasurementResult
WebSocket round trip (Node.js 22 client)225 µs
WebSocket burst, in order50,591 messages/s
WebSocket: 1,000 concurrent connectionsall answered
PostgreSQL 16: 2,000 point queries397 ms (198 µs each)
PostgreSQL 16: insert 20,000 rows218 ms
PostgreSQL 16: read 20,000 rows70 ms
Redis 7: 10,000 pipelined pushes45 ms
Redis 7: 2,000 SET round trips257 ms (128 µs each)

CPU programs against compiled languages

Reproduce: python3 benchmarks/heavy/run.py
Apsi vs C (geometric mean)0.81×C-class speed
Fastest of all languages5of 8 programs
Sum of all programs (Apsi)1098 msC: 1700 ms
Results agreeYesevery language, same checksum
nbody-dense 2000x10lower is faster
jacobi-2d 1024x200lower is faster
matmul 1024lower is faster
lu-pivot 800lower is faster
ising 512x50lower is faster
levenshtein 10klower is faster
ode-rk4 20Mlower is faster
kmeans 200k k16 x20lower is faster

Results table · Apsi 2.4.4

ProgramApsiCC++RustGo
nbody-dense 2000x10All-pairs gravity for 2 000 bodies, 10 steps: 40 million interactions with a square root and a division each.47 ms44 ms44 ms182 ms317 ms
jacobi-2d 1024x200Heat equation on a 1024 × 1024 grid, 200 Jacobi sweeps of a 5-point stencil (memory-bandwidth bound).151 ms167 ms157 ms167 ms701 ms
matmul 1024Dense 1024 × 1024 matrix product, i-k-j loop order (2.1 GFLOP).178 ms200 ms165 ms182 ms479 ms
lu-pivot 800LU factorisation with partial pivoting of an 800 × 800 matrix, returning log |det A|.40 ms40 ms40 ms41 ms117 ms
ising 512x50Metropolis Monte Carlo of a 512 × 512 Ising model, 50 sweeps: 13 million random, branch-heavy updates.82 ms91 ms90 ms84 ms146 ms
levenshtein 10kEdit distance between two 10 000-symbol sequences: 100 million dynamic-programming cells.195 ms809 ms306 ms269 ms1737 ms
ode-rk4 20MVan der Pol oscillator, classic Runge–Kutta 4, 20 million steps: a long chain of dependent operations.355 ms289 ms289 ms355 ms355 ms
kmeans 200k k16 x20k-means clustering of 200 000 points into 16 clusters, 20 Lloyd iterations.51 ms61 ms59 ms64 ms213 ms
Sum of all programs1098 ms1700 ms1150 ms1343 ms4065 ms
Time relative to C (geometric mean)0.81×1.00×0.85×1.05×2.74×

Compare versions

On the same programs, Apsi 2.4.4 is 1.29× faster than Apsi 2.0.0 (geometric mean).

ProgramApsi 2.4.4Apsi 2.0.0ChangeTime, 2.4.4 vs 2.0.0
nbody-dense 2000x1047 ms183 ms3.93× faster
jacobi-2d 1024x200151 ms151 ms1.01× slower
matmul 1024178 ms179 ms1.01× faster
lu-pivot 80040 ms40 ms1.01× faster
ising 512x5082 ms82 ms1.00× faster
levenshtein 10k195 ms194 ms1.01× slower
ode-rk4 20M355 ms533 ms1.50× faster
kmeans 200k k16 x2051 ms65 ms1.27× faster

Bars use a log scale so very different times stay readable. Both versions measured on the same machine in one session. Apsi 2.0.0: apsi run (@native, strict IEEE).

How it was measured

  • Processor: AMD EPYC 7763 64-Core Processor (GitHub Actions runner), one core (all programs are single-threaded).
  • Operating system: Linux x86-64.
  • Method: best of 5 rounds; Apsi 2.4.4 and 2.0.0 measured in turn on the same runner, 2026-11-10.
  • Apsi: Apsi 2.4.4 — apsi run (@native, strict IEEE)
  • C: gcc (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0 — gcc -O3 -march=native
  • C++: g++ (Ubuntu 13.3.0-6ubuntu2~24.04.1) 13.3.0 — g++ -O3 -march=native
  • Rust: rustc 1.99.1 (58cf8f9c3 2026-10-13) — rustc -C opt-level=3 -C target-cpu=native
  • Go: go version go1.24.13 linux/amd64 — go build
  • Every program prints a checksum; results count only when all languages agree.

Run it yourself — one command

python3 benchmarks/heavy/run.py

Builds every installed language, runs all eight programs and shows a live table that fills in as each result arrives. Add --publish 2.4.4 and this page updates in real time while it runs. --apsi-root ../apsi-1.10.0 measures an older Apsi.

Results depend on the processor and compiler versions. Apsi keeps strict IEEE floating point (no fast-math reordering); its times include calling the compiled code from the Apsi runtime.

Machine for the 2.4.4 categories: AMD EPYC 7763, GitHub Actions runner (4 vCPU), Linux, Python 3.13, llvmlite installed; load generators and databases on the same machine; best of 3–5 rounds.