| //! 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<R, W>( |
| 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<R, W>(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)); |
| }, |
| ); |
| } |