use std::io::{self, Write};
use subms::{SubMsPerfHarness, SubMsStageKind, summarize, summary_to_json};
const ITERATIONS: usize = 50_000;
const SEED: u64 = 0;
const BATCH: usize = 256;
fn main() -> io::Result<()> {
let mut h = SubMsPerfHarness::new("arena-allocator-features", "rust");
h.input("iterations", &ITERATIONS.to_string());
h.input("seed", &SEED.to_string());
h.input("batch", &BATCH.to_string());
h.add_meta("subms.recipe.slug", "subms-arena-allocator");
h.add_meta("subms.recipe.category", "memory");
base(&mut h);
#[cfg(feature = "typed")]
typed(&mut h);
#[cfg(feature = "growable")]
growable(&mut h);
#[cfg(feature = "stats")]
stats(&mut h);
#[cfg(feature = "aligned")]
aligned(&mut h);
#[cfg(feature = "freelist")]
freelist(&mut h);
let summary = summarize(&h);
let mut stdout = io::stdout();
summary_to_json(&summary, &mut stdout)?;
writeln!(stdout)?;
Ok(())
}
fn base(h: &mut SubMsPerfHarness) {
use subms_arena_allocator::Bump;
h.add_meta("subms.workload.feature", "base");
let mut a = Bump::with_capacity(4096);
let mut counter = 0u64;
{
let alloc_stage = h
.stage("base_allocate", ITERATIONS)
.with_kind(SubMsStageKind::HotPath);
for i in 0..ITERATIONS {
counter = counter.wrapping_add(1);
alloc_stage.time(|| {
let _ = a.alloc_copy(counter);
});
if (i + 1) % BATCH == 0 {
a.reset();
}
}
}
let reset_stage = h
.stage("base_reset", ITERATIONS / BATCH + 1)
.with_kind(SubMsStageKind::HotPath);
a.reset();
for _ in 0..(ITERATIONS / BATCH) {
let _ = a.alloc_copy(counter);
reset_stage.time(|| a.reset());
}
}
#[cfg(feature = "typed")]
fn typed(h: &mut SubMsPerfHarness) {
use subms_arena_allocator::TypedArena;
h.add_meta("subms.workload.feature", "typed");
let mut a = TypedArena::<u64>::with_capacity(BATCH);
let mut counter = 0u64;
{
let alloc_stage = h
.stage("typed_allocate", ITERATIONS)
.with_kind(SubMsStageKind::HotPath);
for i in 0..ITERATIONS {
counter = counter.wrapping_add(1);
alloc_stage.time(|| {
let _ = a.alloc(counter);
});
if (i + 1) % BATCH == 0 {
a.reset();
}
}
}
let reset_stage = h
.stage("typed_reset", ITERATIONS / BATCH + 1)
.with_kind(SubMsStageKind::HotPath);
a.reset();
for _ in 0..(ITERATIONS / BATCH) {
let _ = a.alloc(counter);
reset_stage.time(|| a.reset());
}
}
#[cfg(feature = "growable")]
fn growable(h: &mut SubMsPerfHarness) {
use subms_arena_allocator::GrowableBump;
h.add_meta("subms.workload.feature", "growable");
let mut a = GrowableBump::with_capacity(512);
let mut counter = 0u64;
{
let alloc_stage = h
.stage("growable_allocate", ITERATIONS)
.with_kind(SubMsStageKind::HotPath);
for i in 0..ITERATIONS {
counter = counter.wrapping_add(1);
alloc_stage.time(|| {
let _ = a.alloc_copy(counter);
});
if (i + 1) % BATCH == 0 {
a.reset();
}
}
}
let reset_stage = h
.stage("growable_reset", ITERATIONS / BATCH + 1)
.with_kind(SubMsStageKind::HotPath);
a.reset();
for _ in 0..(ITERATIONS / BATCH) {
let _ = a.alloc_copy(counter);
reset_stage.time(|| a.reset());
}
}
#[cfg(feature = "stats")]
fn stats(h: &mut SubMsPerfHarness) {
use subms_arena_allocator::StatsBump;
h.add_meta("subms.workload.feature", "stats");
let mut a = StatsBump::with_capacity(4096);
let mut counter = 0u64;
{
let alloc_stage = h
.stage("stats_allocate", ITERATIONS)
.with_kind(SubMsStageKind::HotPath);
for i in 0..ITERATIONS {
counter = counter.wrapping_add(1);
alloc_stage.time(|| {
let _ = a.alloc_copy(counter);
});
if (i + 1) % BATCH == 0 {
a.reset();
}
}
}
let snap_stage = h
.stage("stats_snapshot", ITERATIONS)
.with_kind(SubMsStageKind::HotPath);
for _ in 0..ITERATIONS {
snap_stage.time(|| {
let _ = std::hint::black_box(a.stats());
});
}
}
#[cfg(feature = "aligned")]
fn aligned(h: &mut SubMsPerfHarness) {
use subms_arena_allocator::AlignedBump;
h.add_meta("subms.workload.feature", "aligned");
let chunk = BATCH * 64 + 64;
let mut a = AlignedBump::with_capacity(chunk);
{
let alloc_stage = h
.stage("aligned_allocate_aligned", ITERATIONS)
.with_kind(SubMsStageKind::HotPath);
for i in 0..ITERATIONS {
alloc_stage.time(|| {
let s = a.alloc_aligned(64, 64);
std::hint::black_box(s.as_ptr());
});
if (i + 1) % BATCH == 0 {
a.reset();
}
}
}
}
#[cfg(feature = "freelist")]
fn freelist(h: &mut SubMsPerfHarness) {
use std::alloc::Layout;
use subms_arena_allocator::FreelistBump;
h.add_meta("subms.workload.feature", "freelist");
let layout = Layout::new::<u64>();
let mut a = FreelistBump::with_capacity(4096);
let primed = a.alloc_raw(layout);
unsafe { a.free(primed, layout) };
let mut held: *mut u8 = std::ptr::null_mut();
{
let alloc_stage = h
.stage("freelist_allocate", ITERATIONS)
.with_kind(SubMsStageKind::HotPath);
for _ in 0..ITERATIONS {
alloc_stage.time(|| {
held = a.alloc_raw(layout);
});
unsafe { a.free(held, layout) };
}
}
let p = a.alloc_raw(layout);
let free_stage = h
.stage("freelist_free", ITERATIONS)
.with_kind(SubMsStageKind::HotPath);
let mut cur = p;
for _ in 0..ITERATIONS {
free_stage.time(|| unsafe { a.free(cur, layout) });
cur = a.alloc_raw(layout);
}
}