//! These are very minimal benchmarks ‒ reading and writing an integer shared in //! different ways. You can compare the times and see the characteristics. use std::io::{self, Write}; use std::sync::{Arc, Mutex, RwLock}; use std::time::Instant; use arc_swap::ArcSwap; use criterion::black_box; use crossbeam_utils::thread; fn test_run( name: &str, read_threads: usize, write_threads: usize, iterations: usize, r: R, w: W, ) where R: Fn() -> usize + Sync + Send, W: Fn(usize) + Sync + Send, { print!( "{:20} ({} + {}) x {}: ", name, read_threads, write_threads, iterations ); io::stdout().flush().unwrap(); let before = Instant::now(); thread::scope(|scope| { for _ in 0..read_threads { scope.spawn(|_| { for _ in 0..iterations { black_box(r()); } }); } for _ in 0..write_threads { scope.spawn(|_| { for i in 0..iterations { black_box(w(i)); } }); } }) .unwrap(); let duration = Instant::now() - before; println!( "{:03}.{:03}s", duration.as_secs(), duration.subsec_nanos() / 100_000 ); } fn test_round(name: &str, iterations: usize, r: R, w: W) where R: Fn() -> usize + Sync + Send, W: Fn(usize) + Sync + Send, { test_run(name, 1, 0, iterations, &r, &w); test_run(name, 2, 0, iterations, &r, &w); test_run(name, 4, 0, iterations, &r, &w); test_run(name, 8, 0, iterations, &r, &w); test_run(name, 1, 1, iterations, &r, &w); test_run(name, 4, 1, iterations, &r, &w); test_run(name, 4, 2, iterations, &r, &w); test_run(name, 4, 4, iterations, &r, &w); test_run(name, 8, 1, iterations, &r, &w); test_run(name, 8, 2, iterations, &r, &w); test_run(name, 8, 4, iterations, &r, &w); test_run(name, 0, 1, iterations, &r, &w); test_run(name, 0, 4, iterations, &r, &w); } fn main() { let mutex = Mutex::new(42); test_round( "mutex", 100_000, || *mutex.lock().unwrap(), |i| *mutex.lock().unwrap() = i, ); let mutex = Mutex::new(Arc::new(42)); test_round( "mutex-arc", 100_000, || **mutex.lock().unwrap(), |i| *mutex.lock().unwrap() = Arc::new(i), ); test_round( "mutex-arc-clone", 100_000, || *Arc::clone(&*mutex.lock().unwrap()), |i| *mutex.lock().unwrap() = Arc::new(i), ); let lock = RwLock::new(42); test_round( "rw", 100_000, || *lock.read().unwrap(), |i| *lock.write().unwrap() = i, ); let lock = RwLock::new(Arc::new(42)); test_round( "rw-arc", 100_000, || **lock.read().unwrap(), |i| *lock.write().unwrap() = Arc::new(i), ); test_round( "rw-arc-clone", 100_000, || *Arc::clone(&*lock.read().unwrap()), |i| *lock.write().unwrap() = Arc::new(i), ); let arc = ArcSwap::from(Arc::new(42)); test_round( "arc-load-store", 100_000, || **arc.load(), |i| arc.store(Arc::new(i)), ); test_round( "arc-rcu", 100_000, || *arc.load_full(), |i| { arc.rcu(|_| Arc::new(i)); }, ); }