Which Language Wins the 1 Billion Loop Benchmark? C, Rust, and Zig Lead
Ben Dicken benchmarked a double‑nested loop of 10 000 × 100 000 iterations across dozens of languages, publishing the source code and fastest‑run results that show C, Zig and Rust consistently topping the performance chart, illustrated with an animated speed comparison.
Ben Dicken designed a performance test that runs a double‑nested loop of 10 000 outer iterations and 100 000 inner iterations (total 1 000 000 000 loop executions) to compare raw speed of several languages.
The test program accepts a single integer argument, uses it as divisor u, generates a random r in [0,9999], allocates an array a[10000] initialized to zero, executes the nested loops updating a[i] += j % u, then adds r to each element, and finally prints a[r] to prevent dead‑code elimination.
All implementations are in the public repository https://github.com/bddicken/languages.
C
#include "stdio.h"
#include "stdlib.h"
#include "stdint.h"
int main (int argc, char** argv) {
int u = atoi(argv[1]); // Get an input number from the command line
int r = rand() % 10000; // Random integer 0 ≤ r < 10 000
int32_t a[10000] = {0}; // Array of 10 000 zeros
for (int i = 0; i < 10000; i++) { // 10 k outer iterations
for (int j = 0; j < 100000; j++) { // 100 k inner iterations
a[i] = a[i] + j%u; // Simple sum
}
a[i] += r; // Add random value
}
printf("%d
", a[r]); // Output one element
}Rust
use rand::Rng;
fn main() {
let n: usize = std::env::args()
.nth(1)
.unwrap()
.parse()
.unwrap(); // input divisor
let r: usize = rand::thread_rng()
.gen_range(0..10000); // random 0 ≤ r < 10 k
let mut a = [0; 10000]; // zero‑initialized array
for i in 0..10000 { // outer loop
for j in 0..100000 { // inner loop
a[i] = a[i] + j % n; // sum
}
a[i] += r;
}
println!("{}", a[r]);
}Zig
const std = @import("std");
const rand = std.crypto.random;
const stdout = std.io.getStdOut().writer();
pub fn main() !void {
var args = std.process.args();
_ = args.next() else unreachable; // skip program name
const arg = args.next() else unreachable;
const u = try std.fmt.parseInt(usize, arg, 10);
const r = rand.intRangeAtMost(usize, 0, 10000);
var a: [10000]usize = undefined;
@memset(&a, 0);
for (0..10000) |i| {
for (0..100000) |j| {
a[i] += j % u;
}
a[i] += r;
}
try stdout.print("{d}\
", .{a[r]});
}Go
package main
import (
"fmt"
"math/rand"
"strconv"
"os"
)
func main() {
input, e := strconv.Atoi(os.Args[1])
if e != nil { panic(e) }
u := int(input)
r := int(rand.Intn(10000))
var a [10000]int
for i := 0; i < 10000; i++ {
for j := 0; j < 100000; j++ {
a[i] = a[i] + j%u
}
a[i] += r
}
fmt.Println(a[r])
}Each language was compiled with its typical release flags (e.g., -O3 for C, --release for Rust, default optimisations for Zig and Go). The program was run multiple times; the fastest execution per language was recorded.
The fastest runs, visualised as an animated GIF where ball speed reflects execution time, show that C, Zig, and Rust consistently achieve the shortest runtimes, placing them in the top performance tier. A secondary Fibonacci‑function benchmark produced the same ordering, confirming that the advantage holds across different computational patterns.
Reference:
1 Billion nested loop iterations: https://github.com/bddicken/languages
BirdNest Tech Talk
Author of the rpcx microservice framework, original book author, and chair of Baidu's Go CMC committee.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
