Summary
I ported the full LangArena benchmark suite (50 tasks) to Aether — it's up as aether-lang-dev/LangArena#add-aether-benchmarks, all 50 checksums matching on both the small (test.js) and production (run.js) inputs. This issue is the performance read-out, filed as an optimization opportunity rather than a bug: Aether comes out Go-class overall, with one clearly-localized weak spot worth attacking.
Method (and the honest caveats)
- Aether was measured on a Chromebook-class Intel i7-1265U (2 P-core + 8 E-core, 15 W, single-channel-ish memory — a laptop, thermally throttled).
- The other 24 languages come from the published LangArena results (
results/2026-09-03), measured on the author's AMD Ryzen 7 3800X desktop (8 full cores, ~105 W).
- Different machines → absolute seconds aren't comparable. So every number below is a ratio to Go, with Go measured on each machine. Go is the common yardstick and the machine delta largely cancels. Lower = faster;
1.00 = same speed as Go.
- I sanity-checked the machine delta directly (Go vs Go, same code+inputs): this Chromebook is ~1.17× slower than the reference desktop on geomean, but ±2× per benchmark — memory-bound/threaded work up to 2.5× slower here, single-threaded cache-resident bursts sometimes faster. That variance is exactly why the ratio-to-Go framing matters.
- Single run, no repeat-averaging. Directional, not a leaderboard.
Headline: Aether is Go-class on this suite
Go-anchored geomean across all 50 benchmarks:
| Language |
geomean vs Go |
| C / Gcc |
0.58 |
| Rust |
0.63 |
| Java / OpenJDK |
0.86 |
| Crystal |
0.89 |
| Zig |
0.92 |
| C# / JIT |
0.93 |
| Go |
1.00 |
| Nim |
1.02 |
| Aether |
1.12 |
| Swift |
1.78 |
| Dart / AOT |
1.98 |
| Python |
3.05 |
| Ruby |
10.92 |
1.12× Go over 50 tasks — right next to Nim, ahead of Swift/Dart and every scripting language. For a young language compiling through C, that's a strong baseline. Aether is actually faster than Go on ~20 of the 50 (binarytrees-arena 0.37, calculator-interpreter 0.36 — beat everything measured, maze family 0.54–0.65, base64-encode 0.50, sha256 0.74, raytracer 0.71, and the parse/regex tasks).
The opportunity: packed-float-array throughput
The geomean is dragged almost entirely by a single, coherent cluster — dense std.floatarr inner loops:
| Benchmark |
Aether / Go |
Aether (s) |
Go (s) |
note |
| Matmul::Single |
3.51× |
14.42 |
4.11 |
sequential dense matmul |
| Matmul::T4 |
11.18× |
18.73 |
1.68 |
← see "no parallelism" below |
| Matmul::T8 |
13.28× |
15.50 |
1.17 |
|
| Matmul::T16 |
14.50× |
15.36 |
1.06 |
|
| CLBG::Nbody |
4.96× |
5.53 |
1.12 |
float struct-of-arrays, tight loop |
| Etc::NeuralNet |
7.67× |
10.32 |
1.35 |
dense weight×output sums |
| CLBG::Spectralnorm |
1.58× |
1.46 |
0.93 |
milder, same shape |
Two distinct root causes, both addressable:
1. floatarr element access doesn't lower to a vectorizable load/store.
Every read/write goes through floatarr.floatarr_get_unchecked(a, i) / _set_unchecked(a, i, v) — a call on an untyped ptr handle. The C backend (and thus LLVM/gcc behind it) can't prove aliasing/stride the way it can for a raw double[], so the matmul/nbody/nn inner loops don't auto-vectorize the way C/Zig/Java's do. The milder Spectralnorm (1.58×) is the same loop shape at smaller scale, which is consistent with "constant per-element overhead not amortized," i.e. the accessor call itself.
This is the same root the deferred index-sugar ask names (asks/REPLY-index-sugar-for-intarr-floatarr-longarr.md): the handle is a bare ptr with no element type. A distinct floatarr/intarr/longarr handle type carrying its element kind would let the front end lower a[i] (and the accessors) to a typed, aliasing-friendly load/store — enabling both the ergonomic sugar and the codegen that vectorizes. The perf table is the concrete payoff argument for doing that type-system change.
2. The parallel Matmul variants aren't parallel in Aether.
Look at T4/T8/T16: Go scales 1.68 → 1.17 → 1.06 s as it uses more cores; Aether is flat at ~15–19 s. The port runs those variants sequentially (the checksum only reads one output cell, so I didn't parallelize them). That's a port limitation, not a language one — but it's a natural showcase for Aether's actor scheduler: a worker-pool matmul over spawn + typed messages would be the idiomatic Aether answer, and a much better demo of what the runtime is actually built for than a bare loop. Worth having as a canonical example regardless of the accessor work.
One genuine outlier to look at separately
Distance::NGram = 26.6× Go (24.9 s vs 0.94 s). Not float — this is the map-heavy path. My port keys an std.map by 4-grams rendered with string.from_int, so every n-gram does an int→string alloc + string-hash. Go/Rust/Zig use a native integer-keyed map. An integer-keyed map (or letting std.map take non-string keys) would close most of this. Filing as a note because it's a different subsystem from the float story.
What I'm not claiming
- Not a machine-fair leaderboard (Chromebook vs desktop; ratio-to-Go is the mitigation, not a substitute for running on identical hardware).
- The parse/regex tasks that show
0.00× (Json::ParseDom/Mapping, CSV) are partly too fast because my port takes shortcuts on those (documented in the port); don't read those as headline wins.
- Single run, no warmup-averaging.
Suggested follow-ups (in impact order)
- Distinct handle types for
intarr/floatarr/longarr carrying element kind → typed, vectorizable element access (fixes the whole Matmul/Nbody/NeuralNet cluster and unlocks a[i] sugar). This is the big one.
- Integer-keyed maps (or non-string keys in
std.map) → fixes Distance::NGram and any hot integer-keyed lookup.
- A canonical actor-parallel matmul example — turns the T4/T8/T16 "weakness" into a runtime showcase.
Happy to re-run on desktop-class hardware for machine-fair numbers, add absolute-time tables, or drill into the generated C for any of these. Raw data and the analysis script are in the LangArena port branch.
(Filed from the LangArena port line; numbers reproducible from aether-lang-dev/LangArena@add-aether-benchmarks + the results/2026-09-03 reference set.)
Summary
I ported the full LangArena benchmark suite (50 tasks) to Aether — it's up as
aether-lang-dev/LangArena#add-aether-benchmarks, all 50 checksums matching on both the small (test.js) and production (run.js) inputs. This issue is the performance read-out, filed as an optimization opportunity rather than a bug: Aether comes out Go-class overall, with one clearly-localized weak spot worth attacking.Method (and the honest caveats)
results/2026-09-03), measured on the author's AMD Ryzen 7 3800X desktop (8 full cores, ~105 W).1.00= same speed as Go.Headline: Aether is Go-class on this suite
Go-anchored geomean across all 50 benchmarks:
1.12× Go over 50 tasks — right next to Nim, ahead of Swift/Dart and every scripting language. For a young language compiling through C, that's a strong baseline. Aether is actually faster than Go on ~20 of the 50 (binarytrees-arena 0.37, calculator-interpreter 0.36 — beat everything measured, maze family 0.54–0.65, base64-encode 0.50, sha256 0.74, raytracer 0.71, and the parse/regex tasks).
The opportunity: packed-float-array throughput
The geomean is dragged almost entirely by a single, coherent cluster — dense
std.floatarrinner loops:Two distinct root causes, both addressable:
1.
floatarrelement access doesn't lower to a vectorizable load/store.Every read/write goes through
floatarr.floatarr_get_unchecked(a, i)/_set_unchecked(a, i, v)— a call on an untypedptrhandle. The C backend (and thus LLVM/gcc behind it) can't prove aliasing/stride the way it can for a rawdouble[], so the matmul/nbody/nn inner loops don't auto-vectorize the way C/Zig/Java's do. The milder Spectralnorm (1.58×) is the same loop shape at smaller scale, which is consistent with "constant per-element overhead not amortized," i.e. the accessor call itself.This is the same root the deferred index-sugar ask names (
asks/REPLY-index-sugar-for-intarr-floatarr-longarr.md): the handle is a bareptrwith no element type. A distinctfloatarr/intarr/longarrhandle type carrying its element kind would let the front end lowera[i](and the accessors) to a typed, aliasing-friendly load/store — enabling both the ergonomic sugar and the codegen that vectorizes. The perf table is the concrete payoff argument for doing that type-system change.2. The parallel Matmul variants aren't parallel in Aether.
Look at T4/T8/T16: Go scales 1.68 → 1.17 → 1.06 s as it uses more cores; Aether is flat at ~15–19 s. The port runs those variants sequentially (the checksum only reads one output cell, so I didn't parallelize them). That's a port limitation, not a language one — but it's a natural showcase for Aether's actor scheduler: a worker-pool matmul over
spawn+ typed messages would be the idiomatic Aether answer, and a much better demo of what the runtime is actually built for than a bare loop. Worth having as a canonical example regardless of the accessor work.One genuine outlier to look at separately
Distance::NGram = 26.6× Go (24.9 s vs 0.94 s). Not float — this is the map-heavy path. My port keys an
std.mapby 4-grams rendered withstring.from_int, so every n-gram does an int→string alloc + string-hash. Go/Rust/Zig use a native integer-keyed map. An integer-keyed map (or lettingstd.maptake non-string keys) would close most of this. Filing as a note because it's a different subsystem from the float story.What I'm not claiming
0.00×(Json::ParseDom/Mapping, CSV) are partly too fast because my port takes shortcuts on those (documented in the port); don't read those as headline wins.Suggested follow-ups (in impact order)
intarr/floatarr/longarrcarrying element kind → typed, vectorizable element access (fixes the whole Matmul/Nbody/NeuralNet cluster and unlocksa[i]sugar). This is the big one.std.map) → fixes Distance::NGram and any hot integer-keyed lookup.Happy to re-run on desktop-class hardware for machine-fair numbers, add absolute-time tables, or drill into the generated C for any of these. Raw data and the analysis script are in the LangArena port branch.
(Filed from the LangArena port line; numbers reproducible from
aether-lang-dev/LangArena@add-aether-benchmarks+ theresults/2026-09-03reference set.)