use criterion::{
black_box, criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion, Throughput,
};
use std::sync::Arc;
use std::thread;
#[allow(clippy::single_component_path_imports)]
use auto_allocator;
fn bench_basic_allocation(c: &mut Criterion) {
let info = auto_allocator::get_allocator_info();
static SHOWN: std::sync::Once = std::sync::Once::new();
SHOWN.call_once(|| {
println!("Benchmarking with allocator: {:?}", info.allocator_type);
println!("Selection reason: {}", info.reason);
println!(
"System: {} cores, {} memory",
info.system_info.cpu_cores,
auto_allocator::format_memory_size(info.system_info.total_memory_bytes)
);
});
let mut group = c.benchmark_group("basic_allocation");
for size in [16, 64, 256, 1024, 4096, 16384].iter() {
group.throughput(Throughput::Bytes(*size as u64));
group.bench_with_input(BenchmarkId::new("raw_alloc", size), size, |b, &size| {
b.iter(|| {
let data = vec![0u8; size].into_boxed_slice();
black_box(data);
});
});
group.bench_with_input(BenchmarkId::new("vec_alloc", size), size, |b, &size| {
b.iter(|| {
let vec: Vec<u8> = vec![0; size];
black_box(vec);
});
});
}
group.finish();
}
fn bench_batch_allocation(c: &mut Criterion) {
let mut group = c.benchmark_group("batch_allocation");
group.bench_function("small_batch_1000", |b| {
b.iter_batched(
Vec::new,
|mut ptrs| {
for _ in 0..1000 {
let vec: Vec<u8> = vec![0; 64];
ptrs.push(vec);
}
ptrs.clear();
},
BatchSize::SmallInput,
);
});
group.bench_function("large_batch_100", |b| {
b.iter_batched(
Vec::new,
|mut ptrs| {
for _ in 0..100 {
let vec: Vec<u8> = vec![0; 8192];
ptrs.push(vec);
}
ptrs.clear();
},
BatchSize::SmallInput,
);
});
group.finish();
}
fn bench_real_world_scenarios(c: &mut Criterion) {
let mut group = c.benchmark_group("real_world");
group.bench_function("string_processing", |b| {
b.iter(|| {
let mut strings = Vec::new();
for i in 0..100 {
strings.push(format!("String number {}", i));
}
let mut result = String::new();
for s in strings {
result.push_str(&s);
result.push(' ');
}
black_box(result);
});
});
group.bench_function("data_structures", |b| {
b.iter(|| {
let mut vec = Vec::new();
for i in 0..1000 {
vec.push(i);
}
let mut map = std::collections::HashMap::new();
for i in 0..100 {
map.insert(format!("key_{}", i), i);
}
black_box((vec, map));
});
});
group.bench_function("json_like_serialization", |b| {
b.iter(|| {
let mut result = String::with_capacity(10000);
result.push('{');
for i in 0..100 {
if i > 0 {
result.push(',');
}
result.push_str(&format!("\"field_{}\": \"value_{}\"", i, i * 2));
}
result.push('}');
black_box(result);
});
});
group.finish();
}
fn bench_fragmentation(c: &mut Criterion) {
let mut group = c.benchmark_group("fragmentation");
group.bench_function("mixed_size_fragmentation", |b| {
b.iter(|| {
let mut small_ptrs = Vec::new();
let mut large_ptrs = Vec::new();
for i in 0..100 {
if i % 2 == 0 {
small_ptrs.push(vec![0u8; 64]);
} else {
large_ptrs.push(vec![0u8; 4096]);
}
}
for i in (0..small_ptrs.len()).step_by(2) {
small_ptrs[i].clear();
}
let mut medium_ptrs = Vec::new();
for _ in 0..50 {
medium_ptrs.push(vec![0u8; 1024]);
}
small_ptrs.clear();
large_ptrs.clear();
medium_ptrs.clear();
});
});
group.finish();
}
fn bench_concurrent_allocation(c: &mut Criterion) {
let mut group = c.benchmark_group("concurrent");
for thread_count in [2, 4, 8].iter() {
group.bench_with_input(
BenchmarkId::new("concurrent_alloc", thread_count),
thread_count,
|b, &thread_count| {
b.iter(|| {
let barrier = Arc::new(std::sync::Barrier::new(thread_count));
let handles: Vec<_> = (0..thread_count)
.map(|_| {
let barrier = Arc::clone(&barrier);
thread::spawn(move || {
barrier.wait();
let mut ptrs = Vec::new();
for _ in 0..250 {
ptrs.push(vec![0u8; 128]);
}
ptrs.clear();
})
})
.collect();
for handle in handles {
handle.join().unwrap();
}
});
},
);
}
group.finish();
}
criterion_group!(
benches,
bench_basic_allocation,
bench_batch_allocation,
bench_real_world_scenarios,
bench_fragmentation,
bench_concurrent_allocation
);
criterion_main!(benches);