Skip to content

Instantly share code, notes, and snippets.

@navahas
Last active August 7, 2025 14:43
Show Gist options
  • Select an option

  • Save navahas/18e947c88d2f4f203dc310503250cd64 to your computer and use it in GitHub Desktop.

Select an option

Save navahas/18e947c88d2f4f203dc310503250cd64 to your computer and use it in GitHub Desktop.
Benchmark: Indexing vs Iterator in Rust
use std::hint::black_box;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
// Indexing approaches
pub fn sum_indexing(v: &[u64]) -> u64 {
let mut sum = 0;
for i in 0..v.len() {
sum += v[i];
}
sum
}
pub fn sum_indexing_unchecked(v: &[u64]) -> u64 {
let mut sum = 0;
for i in 0..v.len() {
unsafe { sum += *v.get_unchecked(i) };
}
sum
}
// Iterator approaches
pub fn sum_iter(v: &[u64]) -> u64 {
let mut sum = 0;
for value in v.iter() {
sum += *value;
}
sum
}
pub fn sum_iter_copied(v: &[u64]) -> u64 {
let mut sum = 0;
for value in v.iter().copied() {
sum += value;
}
sum
}
pub fn sum_fold(v: &[u64]) -> u64 {
v.iter().fold(0, |acc, &x| acc + x)
}
pub fn sum_reduce(v: &[u64]) -> u64 {
v.iter().copied().reduce(|acc, x| acc + x).unwrap_or(0)
}
// Functional approaches
pub fn sum_functional(v: &[u64]) -> u64 {
v.iter().sum()
}
// Memory access patterns test
pub fn sum_indexing_strided(v: &[u64], stride: usize) -> u64 {
let mut sum = 0;
let mut i = 0;
while i < v.len() {
sum += v[i];
i += stride;
}
sum
}
pub fn sum_iter_strided(v: &[u64], stride: usize) -> u64 {
let mut sum = 0;
for value in v.iter().step_by(stride) {
sum += *value;
}
sum
}
// Complex operations to test beyond simple addition
pub fn complex_indexing(v: &[u64]) -> u64 {
let mut result = 0;
for i in 0..v.len() {
let val = v[i];
result += val.wrapping_mul(val).wrapping_add(1);
}
result
}
pub fn complex_iter(v: &[u64]) -> u64 {
let mut result = 0;
for &val in v.iter() {
result += val.wrapping_mul(val).wrapping_add(1);
}
result
}
fn bench_basic_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("basic_sum");
// Test different sizes to see scaling behavior
let sizes = [100, 1_000, 10_000, 100_000, 1_000_000];
for size in sizes.iter() {
let vec: Vec<u64> = (0..*size).collect();
group.throughput(Throughput::Elements(*size as u64));
group.bench_with_input(
BenchmarkId::new("indexing", size),
&vec,
|b, v| b.iter(|| sum_indexing(black_box(v)))
);
group.bench_with_input(
BenchmarkId::new("iterator", size),
&vec,
|b, v| b.iter(|| sum_iter(black_box(v)))
);
group.bench_with_input(
BenchmarkId::new("iterator_copied", size),
&vec,
|b, v| b.iter(|| sum_iter_copied(black_box(v)))
);
group.bench_with_input(
BenchmarkId::new("fold", size),
&vec,
|b, v| b.iter(|| sum_fold(black_box(v)))
);
group.bench_with_input(
BenchmarkId::new("functional_sum", size),
&vec,
|b, v| b.iter(|| sum_functional(black_box(v)))
);
}
group.finish();
}
fn bench_unsafe_vs_safe(c: &mut Criterion) {
let mut group = c.benchmark_group("unsafe_comparison");
let vec: Vec<u64> = (0..1_000_000).collect();
group.throughput(Throughput::Elements(1_000_000));
group.bench_function("safe_indexing", |b| {
b.iter(|| sum_indexing(black_box(&vec)))
});
group.bench_function("unsafe_indexing", |b| {
b.iter(|| sum_indexing_unchecked(black_box(&vec)))
});
group.bench_function("iterator", |b| {
b.iter(|| sum_iter(black_box(&vec)))
});
group.finish();
}
fn bench_memory_patterns(c: &mut Criterion) {
let mut group = c.benchmark_group("memory_access_patterns");
let vec: Vec<u64> = (0..1_000_000).collect();
let strides = [1, 2, 4, 8, 16];
for stride in strides.iter() {
group.throughput(Throughput::Elements(1_000_000 / *stride as u64));
group.bench_with_input(
BenchmarkId::new("indexing_stride", stride),
stride,
|b, &s| b.iter(|| sum_indexing_strided(black_box(&vec), s))
);
group.bench_with_input(
BenchmarkId::new("iterator_stride", stride),
stride,
|b, &s| b.iter(|| sum_iter_strided(black_box(&vec), s))
);
}
group.finish();
}
fn bench_complex_operations(c: &mut Criterion) {
let mut group = c.benchmark_group("complex_operations");
let vec: Vec<u64> = (0..1_000_000).collect();
group.throughput(Throughput::Elements(1_000_000));
group.bench_function("complex_indexing", |b| {
b.iter(|| complex_indexing(black_box(&vec)))
});
group.bench_function("complex_iterator", |b| {
b.iter(|| complex_iter(black_box(&vec)))
});
group.finish();
}
fn bench_different_types(c: &mut Criterion) {
let mut group = c.benchmark_group("different_types");
// Test with different data types
let vec_u64: Vec<u64> = (0..1_000_000u64).cycle().take(1_000_000).collect();
let vec_f64: Vec<f64> = (0..1_000_000).map(|x| x as f64).collect();
group.throughput(Throughput::Elements(1_000_000));
// u64 benchmarks
group.bench_function("u64_indexing", |b| {
b.iter(|| {
let mut sum = 0u64;
for i in 0..vec_u64.len() {
sum += vec_u64[i] as u64;
}
sum
})
});
group.bench_function("u64_iterator", |b| {
b.iter(|| {
let mut sum = 0u64;
for &value in vec_u64.iter() {
sum += value as u64;
}
sum
})
});
// f64 benchmarks
group.bench_function("f64_indexing", |b| {
b.iter(|| {
let mut sum = 0.0;
for i in 0..vec_f64.len() {
sum += vec_f64[i];
}
sum
})
});
group.bench_function("f64_iterator", |b| {
b.iter(|| {
let mut sum = 0.0;
for &value in vec_f64.iter() {
sum += value;
}
sum
})
});
group.finish();
}
fn bench_cache_behavior(c: &mut Criterion) {
let mut group = c.benchmark_group("cache_behavior");
// Small data that fits in L1 cache
let small_vec: Vec<u64> = (0..1000).collect();
// Large data that doesn't fit in cache
let large_vec: Vec<u64> = (0..10_000_000).collect();
group.bench_function("small_data_indexing", |b| {
b.iter(|| sum_indexing(black_box(&small_vec)))
});
group.bench_function("small_data_iterator", |b| {
b.iter(|| sum_iter(black_box(&small_vec)))
});
group.bench_function("large_data_indexing", |b| {
b.iter(|| sum_indexing(black_box(&large_vec)))
});
group.bench_function("large_data_iterator", |b| {
b.iter(|| sum_iter(black_box(&large_vec)))
});
group.finish();
}
criterion_group!(
benches,
bench_basic_operations,
bench_unsafe_vs_safe,
bench_memory_patterns,
bench_complex_operations,
bench_different_types,
bench_cache_behavior
);
criterion_main!(benches);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment