1 #[macro_use]
2 extern crate criterion;
3 
4 use criterion::{Criterion, Bencher, black_box};
5 use std::{
6     ops::DerefMut,
7     sync::Arc,
8 };
9 
10 trait Mutex<T>: Send + Sync + 'static {
11     type Guard<'a>: DerefMut<Target = T> where Self: 'a;
new(x: T) -> Self12     fn new(x: T) -> Self;
lock(&self) -> Self::Guard<'_>13     fn lock(&self) -> Self::Guard<'_>;
14 }
15 
16 impl<T: Send + 'static> Mutex<T> for spin::mutex::SpinMutex<T> {
17     type Guard<'a> = spin::mutex::SpinMutexGuard<'a, T> where Self: 'a;
new(x: T) -> Self18     fn new(x: T) -> Self { spin::mutex::SpinMutex::new(x) }
lock(&self) -> Self::Guard<'_>19     fn lock(&self) -> Self::Guard<'_> { self.lock() }
20 }
21 
22 impl<T: Send + 'static> Mutex<T> for spin::mutex::TicketMutex<T> {
23     type Guard<'a> = spin::mutex::TicketMutexGuard<'a, T> where Self: 'a;
new(x: T) -> Self24     fn new(x: T) -> Self { spin::mutex::TicketMutex::new(x) }
lock(&self) -> Self::Guard<'_>25     fn lock(&self) -> Self::Guard<'_> { self.lock() }
26 }
27 
28 impl<T: Send + 'static> Mutex<T> for std::sync::Mutex<T> {
29     type Guard<'a> = std::sync::MutexGuard<'a, T> where Self: 'a;
new(x: T) -> Self30     fn new(x: T) -> Self { std::sync::Mutex::new(x) }
lock(&self) -> Self::Guard<'_>31     fn lock(&self) -> Self::Guard<'_> { self.lock().unwrap() }
32 }
33 
gen_create<M: Mutex<u32>>(b: &mut Bencher)34 fn gen_create<M: Mutex<u32>>(b: &mut Bencher) {
35     b.iter(|| {
36         let n = black_box(42);
37         M::new(n)
38     });
39 }
40 
gen_lock_unlock<M: Mutex<u32>>(b: &mut Bencher)41 fn gen_lock_unlock<M: Mutex<u32>>(b: &mut Bencher) {
42     let m = M::new(0);
43     b.iter(|| {
44         let mut m = m.lock();
45         *m = m.wrapping_add(1);
46         drop(m);
47     });
48 }
49 
gen_lock_unlock_read_contention<M: Mutex<u32>>(b: &mut Bencher)50 fn gen_lock_unlock_read_contention<M: Mutex<u32>>(b: &mut Bencher) {
51     let m = Arc::new(M::new(0));
52     let thread = std::thread::spawn({
53         let m = m.clone();
54         move || {
55             while Arc::strong_count(&m) > 1 {
56                 for _ in 0..1000 {
57                     black_box(*m.lock());
58                 }
59             }
60         }
61     });
62     b.iter(|| {
63         let mut m = m.lock();
64         *m = m.wrapping_add(1);
65         drop(m);
66     });
67     drop(m);
68     thread.join().unwrap();
69 }
70 
gen_lock_unlock_write_contention<M: Mutex<u32>>(b: &mut Bencher)71 fn gen_lock_unlock_write_contention<M: Mutex<u32>>(b: &mut Bencher) {
72     let m = Arc::new(M::new(0));
73     let thread = std::thread::spawn({
74         let m = m.clone();
75         move || {
76             while Arc::strong_count(&m) > 1 {
77                 for _ in 0..1000 {
78                     let mut m = m.lock();
79                     *m = m.wrapping_add(1);
80                     drop(m);
81                 }
82             }
83         }
84     });
85     b.iter(|| {
86         let mut m = m.lock();
87         *m = m.wrapping_add(1);
88         drop(m);
89     });
90     drop(m);
91     thread.join().unwrap();
92 }
93 
create(b: &mut Criterion)94 fn create(b: &mut Criterion) {
95     b.bench_function("create-spin-spinmutex", |b| gen_create::<spin::mutex::SpinMutex<u32>>(b));
96     b.bench_function("create-spin-ticketmutex", |b| gen_create::<spin::mutex::TicketMutex<u32>>(b));
97     b.bench_function("create-std", |b| gen_create::<std::sync::Mutex<u32>>(b));
98 }
99 
lock_unlock(b: &mut Criterion)100 fn lock_unlock(b: &mut Criterion) {
101     b.bench_function("lock_unlock-spin-spinmutex", |b| gen_lock_unlock::<spin::mutex::SpinMutex<u32>>(b));
102     b.bench_function("lock_unlock-spin-ticketmutex", |b| gen_lock_unlock::<spin::mutex::TicketMutex<u32>>(b));
103     b.bench_function("lock_unlock-std", |b| gen_lock_unlock::<std::sync::Mutex<u32>>(b));
104 }
105 
lock_unlock_read_contention(b: &mut Criterion)106 fn lock_unlock_read_contention(b: &mut Criterion) {
107     b.bench_function("lock_unlock_read_contention-spin-spinmutex", |b| gen_lock_unlock_read_contention::<spin::mutex::SpinMutex<u32>>(b));
108     b.bench_function("lock_unlock_read_contention-spin-ticketmutex", |b| gen_lock_unlock_read_contention::<spin::mutex::TicketMutex<u32>>(b));
109     b.bench_function("lock_unlock_read_contention-std", |b| gen_lock_unlock_read_contention::<std::sync::Mutex<u32>>(b));
110 }
111 
lock_unlock_write_contention(b: &mut Criterion)112 fn lock_unlock_write_contention(b: &mut Criterion) {
113     b.bench_function("lock_unlock_write_contention-spin-spinmutex", |b| gen_lock_unlock_write_contention::<spin::mutex::SpinMutex<u32>>(b));
114     b.bench_function("lock_unlock_write_contention-spin-ticketmutex", |b| gen_lock_unlock_write_contention::<spin::mutex::TicketMutex<u32>>(b));
115     b.bench_function("lock_unlock_write_contention-std", |b| gen_lock_unlock_write_contention::<std::sync::Mutex<u32>>(b));
116 }
117 
118 criterion_group!(
119     mutex,
120     create,
121     lock_unlock,
122     lock_unlock_read_contention,
123     lock_unlock_write_contention,
124 );
125 
126 criterion_main!(mutex);
127