03 / Evals

Measured, not claimed.

neo is our proprietary C++ engine. Every number below was printed by a script, on one machine, against the same input, and checked for the same output. The same kernels were ported to four other languages and told to beat it. Where something else is quicker, it is shown quicker.

Progress since the saved language comparison

Finish small jobs without waiting on sleeping threads

94.7% less paired time · Small pipeline · Full command: startup through exit.

All 23 controls passed. See the saved language results alongside the improvements to aggregation, verification and command completion →

Earlier research and experiment history

V13 · accepted follow-up

Command completion without idle shutdown waits.

The complete release decision includes both clocks, every control and exact-output checks →

V11 · retained improvement

Less repeated result verification.

The earlier accepted study compares C++ workflows under its own fixed protocol and timing boundary →

V12 · earlier trial rejected

The shutdown-only experiment.

This earlier candidate missed its combined gate. The accepted follow-up passed every control; both studies keep their original decisions and measurements →

33×
the median speed-up over the JavaScript it replaces

57 cases over 23 nodes at 250,000 rows; the least 4.7×, the most 1,356×

627 / 627
cases where old and new give the same output

the original JavaScript and the C++ on the same input, output for output (tools/eval/eval.py)

9.11 mJ
of energy to total a column by group, 1,000,000 rows, one run from rest

the same in Polars 3× · DuckDB 4× · pandas 6× · Spark 86× as much

0.020 ms
to total a column by group, 1,000,000 rows

the same in Polars 77× · DuckDB 112× · pandas 612× · Spark 1,948× as long

Lower is better · the measurement, with each column's multiple of neo in gray · click an engine for its comparison, or a kernel for its chart

The same kernels, in other languages

1,000,000 rows · ms · 2026-10-15 08:22

neo (C++)GoRustSwiftZig
load (parse + type + dictionary)2.894.981.7×3.531.2×3.291.1×4.031.4×
filter amount > 5000.0180.0643.6×0.0372.1×0.0422.3×0.0301.7×
sort into a new table2.855.852.1×3.891.4×7.502.6×4.171.5×
sum by region0.0200.0794.0×0.0422.1×0.0311.6×0.0241.2×

The same kernels, at a hundred million rows

100,000,000 rows · ms · 2026-10-15 08:50

load (parse + type + dictionary)

neo (C++)
326
Go
495 · 1.5×
Rust
441 · 1.4×
Swift
416 · 1.3×
Zig
416 · 1.3×

Bars to scale: each kernel from zero to its slowest engine.

neo (C++)GoRustSwiftZig
load (parse + type + dictionary)3264951.5×4411.4×4161.3×4161.3×
filter amount > 5003.007.572.5×7.122.4×8.032.7×6.842.3×
sort into a new table7591,4882.0×1,0911.4×1,1221.5×1,2381.6×
sum by region4.204.351.0×5.191.2×4.761.1×4.961.2×

Against the libraries people reach for first

1,000,000 rows · ms · 2026-10-11 21:23

neoPolarsDuckDBpandasSpark
load the CSV (parse + type)2.7715.25.5×51.819×22983×359130×
filter amount > 500, count0.0180.1799.9×0.60233×0.32818×36.92,049×
sort into a new table2.7212.24.5×23.48.6×11040×12245×
sum(amount) by region0.0201.5577×2.24112×12.2612×39.01,948×

The same run, in energy

1,000,000 rows · mJ · 2026-10-11 21:23

neoPolarsDuckDBpandasSpark
load the CSV (parse + type)1724942.9×1,4218.3×1,6369.5×14,30283×
filter amount > 500, count1.082.071.9×14.814×2.612.4×1,4131,313×
sort into a new table1443172.2×9006.3×6374.4×6,35044×
sum(amount) by region1.5550.933×72.347×90.659×2,3521,518×

Public data, from a path to a table

loads after the first, as text · ms · 2026-10-11 16:43

neoArrowPolarsDuckDBpandas
worldcitiespop11.423.02.0×39.93.5×91.88.1×1,05393×
NYC taxi · 1M52.990.71.7×95.31.8×66112×3,10359×
NYC taxi · 10M4189592.3×1,0982.6×2,5396.1×31,51275×
ClickBench · 1M96.03733.9×1892.0×1,43815×5,87661×
ClickBench · 10M1,0563,8293.6×2,6962.6×4,6824.4×——

Over time

The same kernels at every run the ledgers kept. neo in white, the engine closest to it dashed.

Every run, every kernel

Load a CSV, 1,000,000 rows

10.4 → 2.77 ms

3.8× quicker over 11 runs, 10-08 to 10-11 · Polars 15.2 ms at the last

neo 2.77Polars 15.210-0810-112026-10-08 19:52 · busy machine · neo 10.4 ms · Polars 17.2 ms · c138ccb2026-10-08 20:08 · busy machine · neo 8.78 ms · Polars 15.6 ms · ab951ac2026-10-10 11:52 · busy machine · neo 8.31 ms · Polars 15.6 ms · afeb06c2026-10-10 12:00 · neo 8.89 ms · Polars 15.5 ms · afeb06c2026-10-11 10:29 · neo 4.31 ms · Polars 16.6 ms · f1d835a2026-10-11 16:03 · neo 2.95 ms · Polars 16.9 ms · f1d835a2026-10-11 17:08 · neo 2.89 ms · Polars 15.6 ms · f1d835a2026-10-11 17:31 · neo 2.92 ms · Polars 15.3 ms · f1d835a2026-10-11 21:01 · neo 2.83 ms · Polars 15.1 ms · f1d835a2026-10-11 21:13 · neo 2.93 ms · Polars 14.8 ms · f1d835a2026-10-11 21:23 · neo 2.77 ms · Polars 15.2 ms · f1d835a

Load a CSV, 10,000,000 rows

78.8 → 21.7 ms

3.6× quicker over 11 runs, 10-08 to 10-11 · Polars 114 ms at the last

neo 21.7Polars 11410-0810-112026-10-08 19:53 · busy machine · neo 78.8 ms · Polars 348 ms · c138ccb2026-10-08 20:09 · busy machine · neo 90.7 ms · Polars 130 ms · ab951ac2026-10-10 11:52 · busy machine · neo 85.8 ms · Polars 120 ms · afeb06c2026-10-10 12:01 · neo 81.8 ms · Polars 119 ms · afeb06c2026-10-11 10:30 · neo 34.8 ms · Polars 129 ms · f1d835a2026-10-11 16:04 · neo 23.6 ms · Polars 128 ms · f1d835a2026-10-11 17:09 · neo 23.9 ms · Polars 132 ms · f1d835a2026-10-11 17:31 · neo 24.1 ms · Polars 130 ms · f1d835a2026-10-11 21:02 · neo 21.9 ms · Polars 117 ms · f1d835a2026-10-11 21:14 · neo 22.3 ms · Polars 114 ms · f1d835a2026-10-11 21:24 · neo 21.7 ms · Polars 114 ms · f1d835a

Load a CSV, 100,000,000 rows

1,465 → 249 ms

5.9× quicker over 10 runs, 10-08 to 10-11 · Polars 1,186 ms at the last

neo 249Polars 1,18610-0810-112026-10-08 20:16 · busy machine · neo 1,465 ms · Polars 1,715 ms · ab951ac2026-10-10 11:58 · busy machine · neo 909 ms · Polars 1,203 ms · afeb06c2026-10-10 12:08 · neo 861 ms · Polars 1,227 ms · afeb06c2026-10-11 10:38 · neo 409 ms · Polars 1,340 ms · f1d835a2026-10-11 16:09 · neo 299 ms · Polars 1,210 ms · f1d835a2026-10-11 17:15 · neo 285 ms · Polars 1,203 ms · f1d835a2026-10-11 17:38 · neo 279 ms · Polars 1,206 ms · f1d835a2026-10-11 21:07 · neo 244 ms · Polars 1,165 ms · f1d835a2026-10-11 21:20 · neo 244 ms · Polars 1,132 ms · f1d835a2026-10-11 21:29 · neo 249 ms · Polars 1,186 ms · f1d835a

Sort into a new table, 100,000,000 rows

1,483 → 744 ms

2.0× quicker over 10 runs, 10-08 to 10-11 · Polars 1,542 ms at the last

neo 744Polars 1,54210-0810-112026-10-08 20:16 · busy machine · neo 1,483 ms · Polars 2,490 ms · ab951ac2026-10-10 11:58 · busy machine · neo 752 ms · Polars 1,716 ms · afeb06c2026-10-10 12:08 · neo 750 ms · Polars 1,677 ms · afeb06c2026-10-11 10:38 · neo 771 ms · Polars 1,833 ms · f1d835a2026-10-11 16:09 · neo 759 ms · Polars 1,693 ms · f1d835a2026-10-11 17:15 · neo 750 ms · Polars 1,658 ms · f1d835a2026-10-11 17:38 · neo 747 ms · Polars 1,614 ms · f1d835a2026-10-11 21:07 · neo 745 ms · Polars 1,547 ms · f1d835a2026-10-11 21:20 · neo 744 ms · Polars 1,522 ms · f1d835a2026-10-11 21:29 · neo 744 ms · Polars 1,542 ms · f1d835a

Measured on Apple M5 Max, 18 cores, 26.4.1. Polars, DuckDB, pandas, Spark and Arrow at their current releases, written the way their users write them; the Go, Rust, Swift and Zig ports on 16 or 18 threads, the better of the two.