1 use criterion
::{criterion_group, criterion_main, BenchmarkId, Criterion}
;
3 sync
::{Arc, Barrier, RwLock}
,
5 time
::{Duration, Instant}
,
9 struct MultithreadedBench
<T
> {
15 impl<T
: Send
+ Sync
+ '
static> MultithreadedBench
<T
> {
16 fn new(slab
: Arc
<T
>) -> Self {
18 start
: Arc
::new(Barrier
::new(5)),
19 end
: Arc
::new(Barrier
::new(5)),
24 fn thread(&self, f
: impl FnOnce(&Barrier
, &T
) + Send
+ '
static) -> &Self {
25 let start
= self.start
.clone();
26 let end
= self.end
.clone();
27 let slab
= self.slab
.clone();
28 thread
::spawn(move || {
35 fn run(&self) -> Duration
{
37 let t0
= Instant
::now();
43 const N_INSERTIONS
: &'
static [usize] = &[100, 300, 500, 700, 1000, 3000, 5000];
45 fn insert_remove_local(c
: &mut Criterion
) {
46 // the 10000-insertion benchmark takes the `slab` crate about an hour to
47 // run; don't run this unless you're prepared for that...
48 // const N_INSERTIONS: &'static [usize] = &[100, 500, 1000, 5000, 10000];
49 let mut group
= c
.benchmark_group("insert_remove_local");
50 let g
= group
.measurement_time(Duration
::from_secs(15));
52 for i
in N_INSERTIONS
{
53 g
.bench_with_input(BenchmarkId
::new("sharded_slab", i
), i
, |b
, &i
| {
54 b
.iter_custom(|iters
| {
55 let mut total
= Duration
::from_secs(0);
57 let bench
= MultithreadedBench
::new(Arc
::new(sharded_slab
::Slab
::new()));
59 .thread(move |start
, slab
| {
61 let v
: Vec
<_
> = (0..i
).map(|i
| slab
.insert(i
).unwrap()).collect();
66 .thread(move |start
, slab
| {
68 let v
: Vec
<_
> = (0..i
).map(|i
| slab
.insert(i
).unwrap()).collect();
73 .thread(move |start
, slab
| {
75 let v
: Vec
<_
> = (0..i
).map(|i
| slab
.insert(i
).unwrap()).collect();
80 .thread(move |start
, slab
| {
82 let v
: Vec
<_
> = (0..i
).map(|i
| slab
.insert(i
).unwrap()).collect();
93 g
.bench_with_input(BenchmarkId
::new("slab_biglock", i
), i
, |b
, &i
| {
94 b
.iter_custom(|iters
| {
95 let mut total
= Duration
::from_secs(0);
98 let bench
= MultithreadedBench
::new(Arc
::new(RwLock
::new(slab
::Slab
::new())));
100 .thread(move |start
, slab
| {
103 (0..i
).map(|i
| slab
.write().unwrap().insert(i
)).collect();
105 slab
.write().unwrap().remove(i
);
108 .thread(move |start
, slab
| {
111 (0..i
).map(|i
| slab
.write().unwrap().insert(i
)).collect();
113 slab
.write().unwrap().remove(i
);
116 .thread(move |start
, slab
| {
119 (0..i
).map(|i
| slab
.write().unwrap().insert(i
)).collect();
121 slab
.write().unwrap().remove(i
);
124 .thread(move |start
, slab
| {
127 (0..i
).map(|i
| slab
.write().unwrap().insert(i
)).collect();
129 slab
.write().unwrap().remove(i
);
142 fn insert_remove_single_thread(c
: &mut Criterion
) {
143 // the 10000-insertion benchmark takes the `slab` crate about an hour to
144 // run; don't run this unless you're prepared for that...
145 // const N_INSERTIONS: &'static [usize] = &[100, 500, 1000, 5000, 10000];
146 let mut group
= c
.benchmark_group("insert_remove_single_threaded");
148 for i
in N_INSERTIONS
{
149 group
.bench_with_input(BenchmarkId
::new("sharded_slab", i
), i
, |b
, &i
| {
150 let slab
= sharded_slab
::Slab
::new();
152 let v
: Vec
<_
> = (0..i
).map(|i
| slab
.insert(i
).unwrap()).collect();
158 group
.bench_with_input(BenchmarkId
::new("slab_no_lock", i
), i
, |b
, &i
| {
159 let mut slab
= slab
::Slab
::new();
161 let v
: Vec
<_
> = (0..i
).map(|i
| slab
.insert(i
)).collect();
167 group
.bench_with_input(BenchmarkId
::new("slab_uncontended", i
), i
, |b
, &i
| {
168 let slab
= RwLock
::new(slab
::Slab
::new());
170 let v
: Vec
<_
> = (0..i
).map(|i
| slab
.write().unwrap().insert(i
)).collect();
172 slab
.write().unwrap().remove(i
);
180 criterion_group
!(benches
, insert_remove_local
, insert_remove_single_thread
);
181 criterion_main
!(benches
);