aboutsummaryrefslogtreecommitdiff
path: root/benches/mutex.rs
blob: 83897bb09f1591e4e20a565578abba4f03f7bcc3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#[macro_use]
extern crate criterion;

use criterion::{Criterion, Bencher, black_box};
use std::{
    ops::DerefMut,
    sync::Arc,
};

trait Mutex<T>: Send + Sync + 'static {
    type Guard<'a>: DerefMut<Target = T> where Self: 'a;
    fn new(x: T) -> Self;
    fn lock(&self) -> Self::Guard<'_>;
}

impl<T: Send + 'static> Mutex<T> for spin::mutex::SpinMutex<T> {
    type Guard<'a> = spin::mutex::SpinMutexGuard<'a, T> where Self: 'a;
    fn new(x: T) -> Self { spin::mutex::SpinMutex::new(x) }
    fn lock(&self) -> Self::Guard<'_> { self.lock() }
}

impl<T: Send + 'static> Mutex<T> for spin::mutex::TicketMutex<T> {
    type Guard<'a> = spin::mutex::TicketMutexGuard<'a, T> where Self: 'a;
    fn new(x: T) -> Self { spin::mutex::TicketMutex::new(x) }
    fn lock(&self) -> Self::Guard<'_> { self.lock() }
}

impl<T: Send + 'static> Mutex<T> for std::sync::Mutex<T> {
    type Guard<'a> = std::sync::MutexGuard<'a, T> where Self: 'a;
    fn new(x: T) -> Self { std::sync::Mutex::new(x) }
    fn lock(&self) -> Self::Guard<'_> { self.lock().unwrap() }
}

fn gen_create<M: Mutex<u32>>(b: &mut Bencher) {
    b.iter(|| {
        let n = black_box(42);
        M::new(n)
    });
}

fn gen_lock_unlock<M: Mutex<u32>>(b: &mut Bencher) {
    let m = M::new(0);
    b.iter(|| {
        let mut m = m.lock();
        *m = m.wrapping_add(1);
        drop(m);
    });
}

fn gen_lock_unlock_read_contention<M: Mutex<u32>>(b: &mut Bencher) {
    let m = Arc::new(M::new(0));
    let thread = std::thread::spawn({
        let m = m.clone();
        move || {
            while Arc::strong_count(&m) > 1 {
                for _ in 0..1000 {
                    black_box(*m.lock());
                }
            }
        }
    });
    b.iter(|| {
        let mut m = m.lock();
        *m = m.wrapping_add(1);
        drop(m);
    });
    drop(m);
    thread.join().unwrap();
}

fn gen_lock_unlock_write_contention<M: Mutex<u32>>(b: &mut Bencher) {
    let m = Arc::new(M::new(0));
    let thread = std::thread::spawn({
        let m = m.clone();
        move || {
            while Arc::strong_count(&m) > 1 {
                for _ in 0..1000 {
                    let mut m = m.lock();
                    *m = m.wrapping_add(1);
                    drop(m);
                }
            }
        }
    });
    b.iter(|| {
        let mut m = m.lock();
        *m = m.wrapping_add(1);
        drop(m);
    });
    drop(m);
    thread.join().unwrap();
}

fn create(b: &mut Criterion) {
    b.bench_function("create-spin-spinmutex", |b| gen_create::<spin::mutex::SpinMutex<u32>>(b));
    b.bench_function("create-spin-ticketmutex", |b| gen_create::<spin::mutex::TicketMutex<u32>>(b));
    b.bench_function("create-std", |b| gen_create::<std::sync::Mutex<u32>>(b));
}

fn lock_unlock(b: &mut Criterion) {
    b.bench_function("lock_unlock-spin-spinmutex", |b| gen_lock_unlock::<spin::mutex::SpinMutex<u32>>(b));
    b.bench_function("lock_unlock-spin-ticketmutex", |b| gen_lock_unlock::<spin::mutex::TicketMutex<u32>>(b));
    b.bench_function("lock_unlock-std", |b| gen_lock_unlock::<std::sync::Mutex<u32>>(b));
}

fn lock_unlock_read_contention(b: &mut Criterion) {
    b.bench_function("lock_unlock_read_contention-spin-spinmutex", |b| gen_lock_unlock_read_contention::<spin::mutex::SpinMutex<u32>>(b));
    b.bench_function("lock_unlock_read_contention-spin-ticketmutex", |b| gen_lock_unlock_read_contention::<spin::mutex::TicketMutex<u32>>(b));
    b.bench_function("lock_unlock_read_contention-std", |b| gen_lock_unlock_read_contention::<std::sync::Mutex<u32>>(b));
}

fn lock_unlock_write_contention(b: &mut Criterion) {
    b.bench_function("lock_unlock_write_contention-spin-spinmutex", |b| gen_lock_unlock_write_contention::<spin::mutex::SpinMutex<u32>>(b));
    b.bench_function("lock_unlock_write_contention-spin-ticketmutex", |b| gen_lock_unlock_write_contention::<spin::mutex::TicketMutex<u32>>(b));
    b.bench_function("lock_unlock_write_contention-std", |b| gen_lock_unlock_write_contention::<std::sync::Mutex<u32>>(b));
}

criterion_group!(
    mutex,
    create,
    lock_unlock,
    lock_unlock_read_contention,
    lock_unlock_write_contention,
);

criterion_main!(mutex);