use std::hint::black_box; use portable_atomic::{AtomicU64, Ordering}; use std::sync::{Mutex, RwLock}; use std::thread; use std::time::SystemTime; const ITERATIONS: usize = 1000 * 1000; fn baseline(num_threads: usize) { let start = SystemTime::now(); for _ in 0..num_threads { thread::scope(|s| { s.spawn(|| { let mut value = 0u64; for _ in 0..ITERATIONS { let value = black_box(&mut value); *value += 1; } for _ in 0..ITERATIONS { let value = black_box(&mut value); *value -= 1; } }); }); } let end = SystemTime::now(); let duration = end.duration_since(start).unwrap(); println!( "baseline (NOT atomic) ({} threads): {} ops in {}ms", num_threads, 2 * ITERATIONS, duration.as_millis(), ); } fn atomics(num_threads: usize) { let start = SystemTime::now(); let value = AtomicU64::new(0); for _ in 0..num_threads { thread::scope(|s| { s.spawn(|| { for _ in 0..ITERATIONS { let value = black_box(&value); value.fetch_add(1, Ordering::Release); } for _ in 0..ITERATIONS { let value = black_box(&value); value.fetch_sub(1, Ordering::Release); } }); }); } assert_eq!(0, value.load(Ordering::Acquire)); let end = SystemTime::now(); let duration = end.duration_since(start).unwrap(); println!( "atomics ({} threads): {} ops in {}ms", num_threads, 2 * ITERATIONS, duration.as_millis(), ); } fn mutex(num_threads: usize) { let start = SystemTime::now(); let value = Mutex::new(0u64); for _ in 0..num_threads { thread::scope(|s| { s.spawn(|| { for _ in 0..ITERATIONS { let value = black_box(&value); *value.lock().unwrap() += 1; } for _ in 0..ITERATIONS { let value = black_box(&value); *value.lock().unwrap() -= 1; } }); }); } assert_eq!(0u64, *value.lock().unwrap()); let end = SystemTime::now(); let duration = end.duration_since(start).unwrap(); println!( "mutex ({} threads): {} ops in {}ms", num_threads, 2 * ITERATIONS, duration.as_millis(), ); } fn rw_lock(num_threads: usize) { let start = SystemTime::now(); let value = RwLock::new(0u64); for _ in 0..num_threads { thread::scope(|s| { s.spawn(|| { for _ in 0..ITERATIONS { let value = black_box(&value); *value.write().unwrap() += 1; } for _ in 0..ITERATIONS { let value = black_box(&value); *value.write().unwrap() -= 1; } }); }); } assert_eq!(0u64, *value.read().unwrap()); let end = SystemTime::now(); let duration = end.duration_since(start).unwrap(); println!( "rwlock ({} threads): {} ops in {}ms", num_threads, 2 * ITERATIONS, duration.as_millis(), ); } fn main() { for threads in [1, 2, 4, 8, 16, 32, 64] { baseline(threads); atomics(threads); mutex(threads); rw_lock(threads); println!(); } }