Every number comes from axle bench: run time, CPU time, peak RAM at compile and run, and binary size — with the exact source for each language.
Benchmarks for v0.14.0
StringBuilder append throughput — building one large string.
| Variant | Run | Compile | Output | |||
|---|---|---|---|---|---|---|
| Run time | CPU time | RAM | Compile time | RAM | Binary | |
| Rust -O2 | 5 ms | 5 ms | 45.9 MB | 104 ms | 0 KB | 3863 KB |
| Rust -O3 | 5 ms | 5 ms | 45.9 MB | 105 ms | 0 KB | 3863 KB |
| Rust -O1 | 6 ms | 5 ms | 45.9 MB | 100 ms | 0 KB | 3863 KB |
| Axle -O0 | 7 ms | 7 ms | 45.9 MB | 70 ms | 0 KB | 305 KB |
| Axle -O1 | 7 ms | 7 ms | 45.9 MB | 71 ms | 0 KB | 305 KB |
| Axle -O2 | 7 ms | 7 ms | 45.9 MB | 80 ms | 0 KB | 305 KB |
| Axle -O3 | 7 ms | 7 ms | 45.9 MB | 79 ms | 0 KB | 305 KB |
| C++ -O1 | 12 ms | 12 ms | 45.9 MB | 444 ms | 0 KB | 17 KB |
| C++ -O2 | 12 ms | 12 ms | 45.9 MB | 448 ms | 0 KB | 17 KB |
| C++ -O3 | 12 ms | 12 ms | 45.9 MB | 456 ms | 0 KB | 17 KB |
| Rust -O0 | 34 ms | 34 ms | 45.9 MB | 100 ms | 0 KB | 3869 KB |
| C++ -O0 | 51 ms | 51 ms | 45.9 MB | 424 ms | 0 KB | 30 KB |
// EXPECTED_EXIT: 0
// StringBuilder benchmark #1 — raw append throughput.
// Shared logic with append.cpp / append.rs
// (run via `axle bench --compare cpp,rust`).
//
// Workload: append a fixed 16-byte ASCII chunk 1,000,000 times,
// building a 16 MB buffer (~20 capacity-doubling reallocations).
// Output: total length + 3 sampled bytes (start / middle / end) so
// the three languages cross-check byte-identically without an
// O(n^2) full-string walk.
use std::text::StringBuilder;
fn main() : i32 {
let n : i64 = 1000000;
let chunk : string = "abcdefghijklmnop"; // 16 ASCII bytes
let sb : StringBuilder = new StringBuilder();
let i : i64 = 0;
while (i < n) {
sb.append(chunk);
i = i + 1;
}
// O(1) byte length as the cross-impl correctness signal (the
// workload is deterministic, so identical length ⇒ identical
// bytes). Reading individual bytes back via `byteAt` would be
// O(n) per call (AxleString carries no length → `strlen`), which
// would measure the string ABI, not the builder.
println(sb.byteLength());
sb.dispose();
return 0;
}StringBuilder grow / reset churn across many small builders.
| Variant | Run | Compile | Output | |||
|---|---|---|---|---|---|---|
| Run time | CPU time | RAM | Compile time | RAM | Binary | |
| Rust -O2 | 9 ms | 9 ms | 45.9 MB | 113 ms | 0 KB | 3863 KB |
| Rust -O3 | 9 ms | 9 ms | 45.9 MB | 110 ms | 0 KB | 3863 KB |
| Axle -O1 | 11 ms | 11 ms | 45.9 MB | 80 ms | 0 KB | 312 KB |
| Rust -O1 | 11 ms | 11 ms | 45.9 MB | 103 ms | 0 KB | 3863 KB |
| Axle -O0 | 12 ms | 12 ms | 45.9 MB | 78 ms | 0 KB | 312 KB |
| Axle -O2 | 12 ms | 12 ms | 45.9 MB | 91 ms | 0 KB | 312 KB |
| Axle -O3 | 12 ms | 12 ms | 45.9 MB | 92 ms | 0 KB | 312 KB |
| C++ -O2 | 20 ms | 20 ms | 45.9 MB | 455 ms | 0 KB | 17 KB |
| C++ -O1 | 21 ms | 21 ms | 45.9 MB | 450 ms | 0 KB | 17 KB |
| C++ -O3 | 27 ms | 27 ms | 45.9 MB | 455 ms | 0 KB | 17 KB |
| Rust -O0 | 138 ms | 138 ms | 45.9 MB | 100 ms | 0 KB | 3870 KB |
| C++ -O0 | 193 ms | 193 ms | 45.9 MB | 432 ms | 0 KB | 32 KB |
// EXPECTED_EXIT: 0
// StringBuilder benchmark #3 — build / materialize / reset churn.
// Shared logic with churn.cpp / churn.rs (run via `axle bench --compare cpp,rust`).
//
// Workload: 200,000 outer rounds; each appends a 3-byte chunk 20
// times, materialises the result to a `string` (one alloc + copy),
// reads its first byte into an accumulator (so the build can't be
// optimised away), then clear()s for reuse. Stresses the
// append + toString + clear hot loop with buffer reuse. Output:
// the accumulated first-byte sum.
use std::text::StringBuilder;
fn main() : i32 {
let outer : i64 = 200000;
let inner : i64 = 20;
let chunk : string = "xyz";
let sb : StringBuilder = new StringBuilder();
let acc : i64 = 0;
let o : i64 = 0;
while (o < outer) {
let k : i64 = 0;
while (k < inner) {
sb.append(chunk);
k = k + 1;
}
let s : string = sb.toString();
acc = acc + (s.byteAt(0) as i64);
sb.clear();
o = o + 1;
}
println(acc);
sb.dispose();
return 0;
}Integer-to-string formatting via StringBuilder.
| Variant | Run | Compile | Output | |||
|---|---|---|---|---|---|---|
| Run time | CPU time | RAM | Compile time | RAM | Binary | |
| Axle -O3 | 9 ms | 9 ms | 46.2 MB | 87 ms | 0 KB | 305 KB |
| C++ -O2 | 9 ms | 9 ms | 46.2 MB | 460 ms | 0 KB | 17 KB |
| C++ -O3 | 9 ms | 9 ms | 46.2 MB | 462 ms | 0 KB | 17 KB |
| Axle -O0 | 10 ms | 10 ms | 46.2 MB | 75 ms | 0 KB | 305 KB |
| Axle -O1 | 10 ms | 9 ms | 46.2 MB | 75 ms | 0 KB | 305 KB |
| Axle -O2 | 10 ms | 10 ms | 46.2 MB | 89 ms | 0 KB | 305 KB |
| C++ -O1 | 10 ms | 10 ms | 46.2 MB | 461 ms | 0 KB | 17 KB |
| Rust -O2 | 15 ms | 15 ms | 46.2 MB | 114 ms | 0 KB | 3864 KB |
| Rust -O3 | 15 ms | 15 ms | 46.2 MB | 114 ms | 0 KB | 3863 KB |
| Rust -O1 | 18 ms | 18 ms | 46.2 MB | 105 ms | 0 KB | 3863 KB |
| Rust -O0 | 62 ms | 61 ms | 46.2 MB | 103 ms | 0 KB | 3874 KB |
| C++ -O0 | 94 ms | 94 ms | 46.2 MB | 435 ms | 0 KB | 30 KB |
// EXPECTED_EXIT: 0
// StringBuilder benchmark #2 — integer formatting throughput.
// Shared logic with int_format.cpp / int_format.rs
// (run via `axle bench --compare cpp,rust`).
//
// Workload: append 500,000 LCG-driven integers (each formatted to
// decimal) separated by commas — a CSV-style builder. Stresses
// `appendI64` (int→string conversion + bulk append) plus the
// comma separator append. Output: total length + first / last byte.
//
// Caveat: `appendI64` formats digits directly into the builder's
// buffer, so it pays no separate string allocation for the formatted
// number. `int_format.cpp`'s `std::to_string` and `int_format.rs`'s
// `to_string()` each materialise a temporary `std::string` / `String`
// per integer before appending it — real work this bench does not ask
// Axle to do, not a language-speed result.
use std::text::StringBuilder;
fn main() : i32 {
let n : i64 = 500000;
let sb : StringBuilder = new StringBuilder();
let seed : i64 = 12345;
let i : i64 = 0;
while (i < n) {
seed = (seed * 48271) % 2147483647;
sb.appendI64(seed % 100000);
sb.append(",");
i = i + 1;
}
// O(1) byte length as the cross-impl correctness signal (same
// LCG + same integer formatting ⇒ identical bytes ⇒ identical
// length). See append.axle for why per-byte readback is avoided.
println(sb.byteLength());
sb.dispose();
return 0;
}