Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions oscars/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@ default = ["mark_sweep"]
std = []
mark_sweep = []
gc_allocator = ["dep:allocator-api2", "mark_sweep"]

[[bench]]
name = "arena3_alloc"
harness = false
63 changes: 63 additions & 0 deletions oscars/benches/arena3_alloc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use criterion::{Criterion, criterion_group, criterion_main};
use oscars::alloc::arena3::ArenaAllocator;
use std::hint::black_box as bb;

fn bench_arena3_alloc(c: &mut Criterion) {
let mut group = c.benchmark_group("Arena3 Allocation");

group.bench_function("Scenario A: Pure Bump Allocation", |b| {
b.iter_batched(
|| {
let alloc = ArenaAllocator::default().with_arena_size(1024 * 64);
alloc
},
|mut alloc| {
for i in 0..1000 {
let ptr = alloc.try_alloc(bb(i)).unwrap();
bb(ptr);
}
},
criterion::BatchSize::SmallInput,
);
});

group.bench_function("Scenario B: Bulk Allocation Loop", |b| {
let mut alloc = ArenaAllocator::default().with_arena_size(1024 * 1024 * 10);
b.iter(|| {
for i in 0..1000 {
let ptr = alloc.try_alloc(bb(i)).unwrap();
bb(ptr);
}
});
Comment on lines +25 to +31
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Scenario B, the allocator is created outside b.iter, so each iteration keeps allocating additional objects into the same ArenaAllocator. Over many Criterion iterations this can continuously grow memory usage (and may eventually OOM / change behavior once new pools are allocated), which will skew results and make the benchmark unstable. Consider using iter_batched/iter_batched_ref to construct a fresh allocator per measured iteration, or otherwise reset/free between iterations so each sample measures the same fixed workload.

Suggested change
let mut alloc = ArenaAllocator::default().with_arena_size(1024 * 1024 * 10);
b.iter(|| {
for i in 0..1000 {
let ptr = alloc.try_alloc(bb(i)).unwrap();
bb(ptr);
}
});
b.iter_batched(
|| {
ArenaAllocator::default().with_arena_size(1024 * 1024 * 10)
},
|mut alloc| {
for i in 0..1000 {
let ptr = alloc.try_alloc(bb(i)).unwrap();
bb(ptr);
}
},
criterion::BatchSize::SmallInput,
);

Copilot uses AI. Check for mistakes.
});

group.bench_function("Scenario C: Free List Reuse", |b| {
b.iter_batched(
|| {
let mut alloc = ArenaAllocator::default().with_arena_size(1024 * 64);
let mut ptrs = Vec::new();
for i in 0..1000 {
ptrs.push(alloc.try_alloc(i).unwrap());
}
for ptr in ptrs {
unsafe {
alloc.free_slot_typed(ptr.as_ptr());
}
}
alloc
},
|mut alloc| {
for i in 0..1000 {
let ptr = alloc.try_alloc(bb(i)).unwrap();
bb(ptr);
}
},
criterion::BatchSize::SmallInput,
);
});

group.finish();
}

criterion_group!(benches, bench_arena3_alloc);
criterion_main!(benches);
1 change: 1 addition & 0 deletions oscars/src/alloc/arena3/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ impl From<LayoutError> for ArenaAllocError {

const SIZE_CLASSES: &[usize] = &[16, 24, 32, 48, 64, 96, 128, 192, 256, 512, 1024, 2048];

#[inline(always)]
fn size_class_index_for(size: usize) -> usize {
let idx = SIZE_CLASSES.iter().copied().position(|sc| sc >= size);
debug_assert!(
Expand Down