#[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);