#[macro_use]
extern crate alloc;
#[macro_use]
extern crate ctor;
use std::sync::Arc;
use std::thread;
use std::thread::sleep;
use std::time::Duration;
use alloc::alloc::GlobalAlloc;
use alloc::alloc::Layout;
use buddy_system_allocator::LockedHeap;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use rand::{Rng, SeedableRng};
const SMALL_SIZE: usize = 8;
const LARGE_SIZE: usize = 1024 * 1024; const ALIGN: usize = 8;
#[inline]
pub fn small_alloc<const ORDER: usize>(heap: &LockedHeap<ORDER>) {
let layout = unsafe { Layout::from_size_align_unchecked(SMALL_SIZE, ALIGN) };
unsafe {
let addr = heap.alloc(layout);
heap.dealloc(addr, layout);
}
}
#[inline]
pub fn large_alloc<const ORDER: usize>(heap: &LockedHeap<ORDER>) {
let layout = unsafe { Layout::from_size_align_unchecked(LARGE_SIZE, ALIGN) };
unsafe {
let addr = heap.alloc(layout);
heap.dealloc(addr, layout);
}
}
#[inline]
pub fn mutil_thread_random_size<const ORDER: usize>(heap: &'static LockedHeap<ORDER>) {
const THREAD_SIZE: usize = 10;
let mut threads = Vec::with_capacity(THREAD_SIZE);
let alloc = Arc::new(heap);
for i in 0..THREAD_SIZE {
let prethread_alloc = alloc.clone();
let handle = thread::spawn(move || {
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(i as u64);
let layout = unsafe {
Layout::from_size_align_unchecked(rng.gen_range(SMALL_SIZE..=LARGE_SIZE), ALIGN)
};
let addr = unsafe { prethread_alloc.alloc(layout) };
sleep(Duration::from_nanos((THREAD_SIZE - i) as u64));
unsafe { prethread_alloc.dealloc(addr, layout) }
});
threads.push(handle);
}
drop(alloc);
for t in threads {
t.join().unwrap();
}
}
#[inline]
pub fn thread_test() {
const N_ITERATIONS: usize = 50;
const N_OBJECTS: usize = 30000;
const N_THREADS: usize = 10;
const OBJECT_SIZE: usize = 1;
#[derive(Clone)]
struct Foo {
pub a: i32,
pub b: i32,
}
let mut threads = Vec::with_capacity(N_THREADS);
for _i in 0..N_THREADS {
let handle = thread::spawn(move || {
let mut a = Vec::with_capacity(N_OBJECTS / N_THREADS);
for j in 0..N_ITERATIONS {
for k in 0..(N_OBJECTS / N_THREADS) {
a.push(vec![
Foo {
a: k as i32,
b: j as i32
};
OBJECT_SIZE
]);
a[k][0].a += a[k][0].b;
}
}
});
threads.push(handle);
}
for t in threads {
t.join().unwrap();
}
}
const ORDER: usize = 32;
const MACHINE_ALIGN: usize = core::mem::size_of::<usize>();
const KERNEL_HEAP_SIZE: usize = 128 * 1024 * 1024;
const HEAP_BLOCK: usize = KERNEL_HEAP_SIZE / MACHINE_ALIGN;
static mut HEAP: [usize; HEAP_BLOCK] = [0; HEAP_BLOCK];
#[global_allocator]
static HEAP_ALLOCATOR: LockedHeap<ORDER> = LockedHeap::<ORDER>::new();
#[ctor]
fn init_heap() {
let heap_start = unsafe { HEAP.as_ptr() as usize };
unsafe {
HEAP_ALLOCATOR
.lock()
.init(heap_start, HEAP_BLOCK * MACHINE_ALIGN);
}
}
pub fn criterion_benchmark(c: &mut Criterion) {
c.bench_function("small alloc", |b| {
b.iter(|| small_alloc(black_box(&HEAP_ALLOCATOR)))
});
c.bench_function("large alloc", |b| {
b.iter(|| large_alloc(black_box(&HEAP_ALLOCATOR)))
});
c.bench_function("mutil thread random size", |b| {
b.iter(|| mutil_thread_random_size(black_box(&HEAP_ALLOCATOR)))
});
c.bench_function("threadtest", |b| b.iter(|| thread_test()));
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);