blob: 2316aa96fa4d1a11f0debde197bc90af824f9fab [file] [log] [blame]
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use std::{
sync::{Arc, Barrier, RwLock},
thread,
time::{Duration, Instant},
};
#[derive(Clone)]
struct MultithreadedBench<T> {
start: Arc<Barrier>,
end: Arc<Barrier>,
slab: Arc<T>,
}
impl<T: Send + Sync + 'static> MultithreadedBench<T> {
fn new(slab: Arc<T>) -> Self {
Self {
start: Arc::new(Barrier::new(5)),
end: Arc::new(Barrier::new(5)),
slab,
}
}
fn thread(&self, f: impl FnOnce(&Barrier, &T) + Send + 'static) -> &Self {
let start = self.start.clone();
let end = self.end.clone();
let slab = self.slab.clone();
thread::spawn(move || {
f(&*start, &*slab);
end.wait();
});
self
}
fn run(&self) -> Duration {
self.start.wait();
let t0 = Instant::now();
self.end.wait();
t0.elapsed()
}
}
const N_INSERTIONS: &'static [usize] = &[100, 300, 500, 700, 1000, 3000, 5000];
fn insert_remove_local(c: &mut Criterion) {
// the 10000-insertion benchmark takes the `slab` crate about an hour to
// run; don't run this unless you're prepared for that...
// const N_INSERTIONS: &'static [usize] = &[100, 500, 1000, 5000, 10000];
let mut group = c.benchmark_group("insert_remove_local");
let g = group.measurement_time(Duration::from_secs(15));
for i in N_INSERTIONS {
g.bench_with_input(BenchmarkId::new("sharded_slab", i), i, |b, &i| {
b.iter_custom(|iters| {
let mut total = Duration::from_secs(0);
for _ in 0..iters {
let bench = MultithreadedBench::new(Arc::new(sharded_slab::Slab::new()));
let elapsed = bench
.thread(move |start, slab| {
start.wait();
let v: Vec<_> = (0..i).map(|i| slab.insert(i).unwrap()).collect();
for i in v {
slab.remove(i);
}
})
.thread(move |start, slab| {
start.wait();
let v: Vec<_> = (0..i).map(|i| slab.insert(i).unwrap()).collect();
for i in v {
slab.remove(i);
}
})
.thread(move |start, slab| {
start.wait();
let v: Vec<_> = (0..i).map(|i| slab.insert(i).unwrap()).collect();
for i in v {
slab.remove(i);
}
})
.thread(move |start, slab| {
start.wait();
let v: Vec<_> = (0..i).map(|i| slab.insert(i).unwrap()).collect();
for i in v {
slab.remove(i);
}
})
.run();
total += elapsed;
}
total
})
});
g.bench_with_input(BenchmarkId::new("slab_biglock", i), i, |b, &i| {
b.iter_custom(|iters| {
let mut total = Duration::from_secs(0);
let i = i;
for _ in 0..iters {
let bench = MultithreadedBench::new(Arc::new(RwLock::new(slab::Slab::new())));
let elapsed = bench
.thread(move |start, slab| {
start.wait();
let v: Vec<_> =
(0..i).map(|i| slab.write().unwrap().insert(i)).collect();
for i in v {
slab.write().unwrap().remove(i);
}
})
.thread(move |start, slab| {
start.wait();
let v: Vec<_> =
(0..i).map(|i| slab.write().unwrap().insert(i)).collect();
for i in v {
slab.write().unwrap().remove(i);
}
})
.thread(move |start, slab| {
start.wait();
let v: Vec<_> =
(0..i).map(|i| slab.write().unwrap().insert(i)).collect();
for i in v {
slab.write().unwrap().remove(i);
}
})
.thread(move |start, slab| {
start.wait();
let v: Vec<_> =
(0..i).map(|i| slab.write().unwrap().insert(i)).collect();
for i in v {
slab.write().unwrap().remove(i);
}
})
.run();
total += elapsed;
}
total
})
});
}
group.finish();
}
fn insert_remove_single_thread(c: &mut Criterion) {
// the 10000-insertion benchmark takes the `slab` crate about an hour to
// run; don't run this unless you're prepared for that...
// const N_INSERTIONS: &'static [usize] = &[100, 500, 1000, 5000, 10000];
let mut group = c.benchmark_group("insert_remove_single_threaded");
for i in N_INSERTIONS {
group.bench_with_input(BenchmarkId::new("sharded_slab", i), i, |b, &i| {
let slab = sharded_slab::Slab::new();
b.iter(|| {
let v: Vec<_> = (0..i).map(|i| slab.insert(i).unwrap()).collect();
for i in v {
slab.remove(i);
}
});
});
group.bench_with_input(BenchmarkId::new("slab_no_lock", i), i, |b, &i| {
let mut slab = slab::Slab::new();
b.iter(|| {
let v: Vec<_> = (0..i).map(|i| slab.insert(i)).collect();
for i in v {
slab.remove(i);
}
});
});
group.bench_with_input(BenchmarkId::new("slab_uncontended", i), i, |b, &i| {
let slab = RwLock::new(slab::Slab::new());
b.iter(|| {
let v: Vec<_> = (0..i).map(|i| slab.write().unwrap().insert(i)).collect();
for i in v {
slab.write().unwrap().remove(i);
}
});
});
}
group.finish();
}
criterion_group!(benches, insert_remove_local, insert_remove_single_thread);
criterion_main!(benches);