use std::alloc::{GlobalAlloc, Layout, System};
use std::println;
use std::time::Instant;
use std::vec;
use std::vec::Vec;
use crate::memory::{Arena, InlineVec, MemTag, Pool, Realm, TrackingAlloc};
const FRAME_ITEMS: usize = 4_096;
const POOL_CHURN: usize = 1_024;
const LEDGER_PAIRS: usize = 1_024;
const TARGET_NS: u128 = 200_000_000;
const MAX_ITERS: u64 = 1 << 20;
fn bench<R>(name: &str, items: u64, mut body: impl FnMut() -> R) {
let mut iters: u64 = 1;
loop {
let start = Instant::now();
for _ in 0..iters {
core::hint::black_box(body());
}
if start.elapsed().as_nanos() >= TARGET_NS || iters >= MAX_ITERS {
break;
}
iters = iters.saturating_mul(4).min(MAX_ITERS);
}
let start = Instant::now();
for _ in 0..iters {
core::hint::black_box(body());
}
let elapsed = start.elapsed();
let per_item_ns = elapsed.as_secs_f64() * 1e9 / (iters * items.max(1)) as f64;
println!(" {name:<40} {per_item_ns:>10.2} ns/item");
}
#[test]
#[ignore = "benchmark; run with --ignored --test-threads=1"]
fn bench_allocation_layer() {
{
let mut arena = Arena::with_capacity(64 * 1024);
bench(
"memory/arena_frame_slice/4k",
FRAME_ITEMS as u64,
move || {
arena.reset();
let slab = arena
.alloc_slice(FRAME_ITEMS, 0u64)
.expect("arena sized for the frame");
for (i, v) in slab.iter_mut().enumerate() {
*v = i as u64;
}
slab.iter().sum::<u64>()
},
);
}
bench("memory/heap_frame_vec/4k", FRAME_ITEMS as u64, || {
let v: Vec<u64> = (0..FRAME_ITEMS as u64).collect();
v.iter().sum::<u64>()
});
{
let mut pool: Pool<[u64; 4]> = Pool::with_capacity(POOL_CHURN);
let mut handles = Vec::with_capacity(POOL_CHURN);
bench("memory/pool_churn/1k", POOL_CHURN as u64, move || {
for i in 0..POOL_CHURN {
handles.push(
pool.insert([i as u64; 4])
.expect("pool sized for the churn"),
);
}
for handle in handles.drain(..) {
pool.remove(handle);
}
pool.len()
});
}
bench("memory/inline_vec_single/1", 1, || {
let mut v: InlineVec<u64> = InlineVec::default();
v.push(7);
core::hint::black_box(&v);
v.as_slice()[0]
});
bench("memory/vec_single/1", 1, || {
let v: Vec<u64> = vec![7];
core::hint::black_box(&v);
v[0]
});
{
let tracked = TrackingAlloc::new(System);
let layout = Layout::from_size_align(64, 16).expect("valid layout");
bench("memory/alloc_tracked/64B", 1, || {
unsafe {
let ptr = core::hint::black_box(tracked.alloc(layout));
assert!(!ptr.is_null(), "system allocator returned null");
tracked.dealloc(ptr, layout);
}
});
bench("memory/alloc_untracked/64B", 1, || {
unsafe {
let ptr = core::hint::black_box(System.alloc(layout));
assert!(!ptr.is_null(), "system allocator returned null");
System.dealloc(ptr, layout);
}
});
}
{
let ledger = crate::memory::ledger();
bench("memory/ledger_report_pair/1k", LEDGER_PAIRS as u64, || {
for _ in 0..LEDGER_PAIRS {
ledger.add(MemTag::Meshes, Realm::Device, 4_096);
ledger.release(MemTag::Meshes, Realm::Device, 4_096);
}
});
}
}