Skip to content

Commit f747405

Browse files
committed
feat: add support of global allocator in std enviroment and simplify benchmark
1 parent eb1329d commit f747405

File tree

2 files changed

+48
-36
lines changed

2 files changed

+48
-36
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ optional = true
2121

2222
[dev-dependencies]
2323
criterion = "0.3"
24+
ctor = "0.1.23"
2425

2526
[[bench]]
2627
name = "memory_allocator_benchmark"

benches/memory_allocator_benchmark.rs

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
#[macro_use]
22
extern crate alloc;
33

4+
#[macro_use]
5+
extern crate ctor;
6+
47
use std::sync::Arc;
58
use std::thread;
69
use std::thread::sleep;
@@ -11,23 +14,23 @@ use alloc::alloc::Layout;
1114
use buddy_system_allocator::LockedHeap;
1215
use criterion::{black_box, criterion_group, criterion_main, Criterion};
1316

14-
const LARGE_SIZE: usize = 1024;
15-
const SMALL_SIZE: usize = 8;
16-
const THREAD_SIZE: usize = 10;
17+
// use for first three benchmark
1718
const ALIGN: usize = 8;
1819

1920
#[inline]
20-
pub fn large_alloc<const ORDER: usize>(heap: &LockedHeap<ORDER>) {
21-
let layout = unsafe { Layout::from_size_align_unchecked(LARGE_SIZE, ALIGN) };
21+
pub fn small_alloc<const ORDER: usize>(heap: &LockedHeap<ORDER>) {
22+
const SMALL_SIZE: usize = 8;
23+
let layout = unsafe { Layout::from_size_align_unchecked(SMALL_SIZE, ALIGN) };
2224
unsafe {
2325
let addr = heap.alloc(layout);
2426
heap.dealloc(addr, layout);
2527
}
2628
}
2729

2830
#[inline]
29-
pub fn small_alloc<const ORDER: usize>(heap: &LockedHeap<ORDER>) {
30-
let layout = unsafe { Layout::from_size_align_unchecked(SMALL_SIZE, ALIGN) };
31+
pub fn large_alloc<const ORDER: usize>(heap: &LockedHeap<ORDER>) {
32+
const LARGE_SIZE: usize = 1024;
33+
let layout = unsafe { Layout::from_size_align_unchecked(LARGE_SIZE, ALIGN) };
3134
unsafe {
3235
let addr = heap.alloc(layout);
3336
heap.dealloc(addr, layout);
@@ -36,6 +39,7 @@ pub fn small_alloc<const ORDER: usize>(heap: &LockedHeap<ORDER>) {
3639

3740
#[inline]
3841
pub fn mutil_thread_alloc<const ORDER: usize>(heap: &'static LockedHeap<ORDER>) {
42+
const THREAD_SIZE: usize = 10;
3943
let mut threads = Vec::with_capacity(THREAD_SIZE);
4044
let alloc = Arc::new(heap);
4145
for i in 0..THREAD_SIZE {
@@ -80,63 +84,72 @@ pub fn mutil_thread_alloc<const ORDER: usize>(heap: &'static LockedHeap<ORDER>)
8084
/// ----------------------------------------------------------------------
8185
///
8286
#[inline]
83-
pub fn thread_test<const ORDER: usize>(heap: &'static LockedHeap<ORDER>) {
87+
pub fn thread_test() {
8488
const N_ITERATIONS: usize = 50;
85-
const N_OBJECTS: usize = 30000;
89+
const N_OBJECTS: usize = 3000;
8690
const N_THREADS: usize = 10;
8791
const OBJECT_SIZE: usize = 1;
8892

89-
let mut threads = Vec::with_capacity(THREAD_SIZE);
90-
let alloc = Arc::new(heap);
93+
#[derive(Clone)]
94+
struct Foo {
95+
pub a: i32,
96+
pub b: i32,
97+
}
9198

92-
for i in 0..THREAD_SIZE {
93-
let prethread_alloc = alloc.clone();
99+
let mut threads = Vec::with_capacity(N_THREADS);
100+
101+
for _i in 0..N_THREADS {
94102
let handle = thread::spawn(move || {
95-
// a = new Foo * [nobjects / nthreads];
96-
let layout = unsafe {
97-
Layout::from_size_align_unchecked(SMALL_SIZE * (N_OBJECTS / N_THREADS), ALIGN)
98-
};
99-
let addr = unsafe { prethread_alloc.alloc(layout) };
100-
for j in 0..N_ITERATIONS {
103+
// let a = new Foo * [nobjects / nthreads];
104+
let mut a = Vec::with_capacity(N_OBJECTS / N_THREADS);
105+
for _j in 0..N_ITERATIONS {
101106
// inner object:
102107
// a[i] = new Foo[objSize];
103-
let mut addrs = vec![];
104-
let layout =
105-
unsafe { Layout::from_size_align_unchecked(SMALL_SIZE * OBJECT_SIZE, ALIGN) };
106-
for i in 0..(N_OBJECTS / N_THREADS) {
107-
addrs.push(unsafe { prethread_alloc.alloc(layout) });
108-
}
109-
for addr in addrs {
110-
unsafe { prethread_alloc.dealloc(addr, layout) }
108+
for _k in 0..(N_OBJECTS / N_THREADS) {
109+
a.push(vec![Foo { a: 0, b: 1 }; OBJECT_SIZE]);
111110
}
112111
}
113-
unsafe { prethread_alloc.dealloc(addr, layout) }
112+
// auto drop here
114113
});
115114
threads.push(handle);
116115
}
117-
drop(alloc);
118116

119117
for t in threads {
120118
t.join().unwrap();
121119
}
122120
}
123121

124122
const ORDER: usize = 32;
125-
static HEAP_ALLOCATOR: LockedHeap<ORDER> = LockedHeap::<ORDER>::new();
126-
const KERNEL_HEAP_SIZE: usize = 16 * 1024 * 1024;
127123
const MACHINE_ALIGN: usize = core::mem::size_of::<usize>();
124+
const KERNEL_HEAP_SIZE: usize = 16 * 1024 * 1024;
128125
const HEAP_BLOCK: usize = KERNEL_HEAP_SIZE / MACHINE_ALIGN;
129126
static mut HEAP: [usize; HEAP_BLOCK] = [0; HEAP_BLOCK];
130127

131-
pub fn criterion_benchmark(c: &mut Criterion) {
132-
// init heap
128+
/// Use `LockedHeap` as global allocator
129+
#[global_allocator]
130+
static HEAP_ALLOCATOR: LockedHeap<ORDER> = LockedHeap::<ORDER>::new();
131+
132+
/// # Init heap
133+
///
134+
/// We need `ctor` here because benchmark is running behind the std enviroment,
135+
/// which means std will do some initialization before execute `fn main()`.
136+
/// However, our memory allocator must be init in runtime(use linkedlist, which
137+
/// can not be evaluated in compile time). And in the initialization phase, heap
138+
/// memory is needed.
139+
///
140+
/// So the solution in this dilemma is to run `fn init_heap()` in initialization phase
141+
/// rather than in `fn main()`. We need `ctor` to do this.
142+
#[ctor]
143+
fn init_heap() {
133144
let heap_start = unsafe { HEAP.as_ptr() as usize };
134145
unsafe {
135146
HEAP_ALLOCATOR
136147
.lock()
137148
.init(heap_start, HEAP_BLOCK * MACHINE_ALIGN);
138149
}
150+
}
139151

152+
pub fn criterion_benchmark(c: &mut Criterion) {
140153
// run benchmark
141154
c.bench_function("small alloc", |b| {
142155
b.iter(|| small_alloc(black_box(&HEAP_ALLOCATOR)))
@@ -147,9 +160,7 @@ pub fn criterion_benchmark(c: &mut Criterion) {
147160
c.bench_function("mutil thread alloc", |b| {
148161
b.iter(|| mutil_thread_alloc(black_box(&HEAP_ALLOCATOR)))
149162
});
150-
c.bench_function("threadtest", |b| {
151-
b.iter(|| thread_test(black_box(&HEAP_ALLOCATOR)))
152-
});
163+
c.bench_function("threadtest", |b| b.iter(|| thread_test()));
153164
}
154165

155166
criterion_group!(benches, criterion_benchmark);

0 commit comments

Comments
 (0)