#[macro_use] extern crate criterion; use criterion::{Criterion, Bencher, black_box}; use std::{ ops::DerefMut, sync::Arc, }; trait Mutex: Send + Sync + 'static { type Guard<'a>: DerefMut where Self: 'a; fn new(x: T) -> Self; fn lock(&self) -> Self::Guard<'_>; } impl Mutex for spin::mutex::SpinMutex { 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 Mutex for spin::mutex::TicketMutex { 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 Mutex for std::sync::Mutex { 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>(b: &mut Bencher) { b.iter(|| { let n = black_box(42); M::new(n) }); } fn gen_lock_unlock>(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>(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>(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::>(b)); b.bench_function("create-spin-ticketmutex", |b| gen_create::>(b)); b.bench_function("create-std", |b| gen_create::>(b)); } fn lock_unlock(b: &mut Criterion) { b.bench_function("lock_unlock-spin-spinmutex", |b| gen_lock_unlock::>(b)); b.bench_function("lock_unlock-spin-ticketmutex", |b| gen_lock_unlock::>(b)); b.bench_function("lock_unlock-std", |b| gen_lock_unlock::>(b)); } fn lock_unlock_read_contention(b: &mut Criterion) { b.bench_function("lock_unlock_read_contention-spin-spinmutex", |b| gen_lock_unlock_read_contention::>(b)); b.bench_function("lock_unlock_read_contention-spin-ticketmutex", |b| gen_lock_unlock_read_contention::>(b)); b.bench_function("lock_unlock_read_contention-std", |b| gen_lock_unlock_read_contention::>(b)); } fn lock_unlock_write_contention(b: &mut Criterion) { b.bench_function("lock_unlock_write_contention-spin-spinmutex", |b| gen_lock_unlock_write_contention::>(b)); b.bench_function("lock_unlock_write_contention-spin-ticketmutex", |b| gen_lock_unlock_write_contention::>(b)); b.bench_function("lock_unlock_write_contention-std", |b| gen_lock_unlock_write_contention::>(b)); } criterion_group!( mutex, create, lock_unlock, lock_unlock_read_contention, lock_unlock_write_contention, ); criterion_main!(mutex);