#![cfg(feature = "alloc-global")]
#![allow(
clippy::cast_possible_truncation,
clippy::needless_pass_by_value,
clippy::semicolon_if_nothing_returned
)]
use std::alloc::{GlobalAlloc, Layout, System};
use std::hint::black_box;
use std::time::Duration;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use sefer_alloc::SeferAlloc;
#[inline]
fn alloc_free_one<A: GlobalAlloc>(a: &A, layout: Layout) {
let ptr = unsafe { a.alloc(layout) };
black_box(ptr);
if !ptr.is_null() {
unsafe { a.dealloc(ptr, layout) };
}
}
#[inline]
fn realloc_grow<A: GlobalAlloc>(a: &A, start: usize, doublings: u32) -> usize {
let align = 8_usize;
let init_layout = Layout::from_size_align(start, align).unwrap();
let mut ptr = unsafe { a.alloc(init_layout) };
if ptr.is_null() {
return 0;
}
let mut current_size = start;
for _ in 0..doublings {
let new_size = current_size * 2;
let old_layout = Layout::from_size_align(current_size, align).unwrap();
let new_ptr = unsafe { a.realloc(ptr, old_layout, new_size) };
if new_ptr.is_null() {
unsafe { a.dealloc(ptr, old_layout) };
return current_size;
}
ptr = new_ptr;
current_size = new_size;
}
black_box(ptr);
let final_layout = Layout::from_size_align(current_size, align).unwrap();
unsafe { a.dealloc(ptr, final_layout) };
current_size
}
#[inline]
fn realloc_unfavorable<A: GlobalAlloc>(
a: &A,
start: usize,
step_size: usize,
steps: usize,
neighbours: usize,
) {
let align = 8_usize;
let start_layout = Layout::from_size_align(start, align).unwrap();
let noise_layout = Layout::from_size_align(64, align).unwrap();
let mut subject = unsafe { a.alloc(start_layout) };
if subject.is_null() {
return;
}
let mut subject_size = start;
let mut noise: Vec<*mut u8> = Vec::with_capacity(neighbours);
for _ in 0..neighbours {
let p = unsafe { a.alloc(noise_layout) };
noise.push(p);
}
for _ in 0..steps {
let new_size = subject_size + step_size;
let old_layout = Layout::from_size_align(subject_size, align).unwrap();
let new_ptr = unsafe { a.realloc(subject, old_layout, new_size) };
if new_ptr.is_null() {
let cur_layout = Layout::from_size_align(subject_size, align).unwrap();
unsafe { a.dealloc(subject, cur_layout) };
subject = core::ptr::null_mut();
break;
}
subject = new_ptr;
subject_size = new_size;
}
black_box(subject);
for &p in &noise {
if !p.is_null() {
unsafe { a.dealloc(p, noise_layout) };
}
}
if !subject.is_null() {
let final_layout = Layout::from_size_align(subject_size, align).unwrap();
unsafe { a.dealloc(subject, final_layout) };
}
}
fn bench_large_alloc_free(c: &mut Criterion) {
let mut group = c.benchmark_group("large_alloc_free");
group.sample_size(10);
group.warm_up_time(Duration::from_secs(1));
group.measurement_time(Duration::from_secs(2));
const LARGE_SIZES: &[(usize, &str)] = &[
(4 * 1024 * 1024, "4MiB"),
(16 * 1024 * 1024, "16MiB"),
(64 * 1024 * 1024, "64MiB"),
];
let sefer = SeferAlloc::new();
let mi = mimalloc::MiMalloc;
let sys = System;
for &(size, label) in LARGE_SIZES {
let layout = Layout::from_size_align(size, 8).unwrap();
group.bench_with_input(BenchmarkId::new("SeferAlloc", label), &layout, |b, &l| {
b.iter(|| alloc_free_one(&sefer, l))
});
group.bench_with_input(BenchmarkId::new("mimalloc", label), &layout, |b, &l| {
b.iter(|| alloc_free_one(&mi, l))
});
group.bench_with_input(BenchmarkId::new("System", label), &layout, |b, &l| {
b.iter(|| alloc_free_one(&sys, l))
});
}
group.finish();
}
fn bench_realloc_grow_geometric(c: &mut Criterion) {
let mut group = c.benchmark_group("realloc_grow_geometric");
group.sample_size(10);
group.warm_up_time(Duration::from_secs(1));
group.measurement_time(Duration::from_secs(2));
const START: usize = 64;
const DOUBLINGS: u32 = 16;
let sefer = SeferAlloc::new();
let mi = mimalloc::MiMalloc;
let sys = System;
group.bench_function("SeferAlloc", |b| {
b.iter(|| black_box(realloc_grow(&sefer, START, DOUBLINGS)))
});
group.bench_function("mimalloc", |b| {
b.iter(|| black_box(realloc_grow(&mi, START, DOUBLINGS)))
});
group.bench_function("System", |b| {
b.iter(|| black_box(realloc_grow(&sys, START, DOUBLINGS)))
});
group.finish();
}
fn bench_realloc_in_place_unfavorable(c: &mut Criterion) {
let mut group = c.benchmark_group("realloc_in_place_unfavorable");
group.sample_size(10);
group.warm_up_time(Duration::from_secs(1));
group.measurement_time(Duration::from_secs(3));
const START: usize = 512 * 1024; const STEP: usize = 256 * 1024; const STEPS: usize = 8; const NEIGHBOURS: usize = 32;
let sefer = SeferAlloc::new();
let mi = mimalloc::MiMalloc;
let sys = System;
group.bench_function("SeferAlloc", |b| {
b.iter(|| realloc_unfavorable(&sefer, START, STEP, STEPS, NEIGHBOURS))
});
group.bench_function("mimalloc", |b| {
b.iter(|| realloc_unfavorable(&mi, START, STEP, STEPS, NEIGHBOURS))
});
group.bench_function("System", |b| {
b.iter(|| realloc_unfavorable(&sys, START, STEP, STEPS, NEIGHBOURS))
});
group.finish();
}
criterion_group!(
benches,
bench_large_alloc_free,
bench_realloc_grow_geometric,
bench_realloc_in_place_unfavorable,
);
criterion_main!(benches);