1 //! These are very minimal benchmarks ‒ reading and writing an integer shared in
2 //! different ways. You can compare the times and see the characteristics.
3
4 use std::io::{self, Write};
5 use std::sync::{Arc, Mutex, RwLock};
6 use std::time::Instant;
7
8 use arc_swap::ArcSwap;
9 use criterion::black_box;
10 use crossbeam_utils::thread;
11
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,12 fn test_run<R, W>(
13 name: &str,
14 read_threads: usize,
15 write_threads: usize,
16 iterations: usize,
17 r: R,
18 w: W,
19 ) where
20 R: Fn() -> usize + Sync + Send,
21 W: Fn(usize) + Sync + Send,
22 {
23 print!(
24 "{:20} ({} + {}) x {}: ",
25 name, read_threads, write_threads, iterations
26 );
27 io::stdout().flush().unwrap();
28 let before = Instant::now();
29 thread::scope(|scope| {
30 for _ in 0..read_threads {
31 scope.spawn(|_| {
32 for _ in 0..iterations {
33 black_box(r());
34 }
35 });
36 }
37 for _ in 0..write_threads {
38 scope.spawn(|_| {
39 for i in 0..iterations {
40 black_box(w(i));
41 }
42 });
43 }
44 })
45 .unwrap();
46 let duration = Instant::now() - before;
47 println!(
48 "{:03}.{:03}s",
49 duration.as_secs(),
50 duration.subsec_nanos() / 100_000
51 );
52 }
53
test_round<R, W>(name: &str, iterations: usize, r: R, w: W) where R: Fn() -> usize + Sync + Send, W: Fn(usize) + Sync + Send,54 fn test_round<R, W>(name: &str, iterations: usize, r: R, w: W)
55 where
56 R: Fn() -> usize + Sync + Send,
57 W: Fn(usize) + Sync + Send,
58 {
59 test_run(name, 1, 0, iterations, &r, &w);
60 test_run(name, 2, 0, iterations, &r, &w);
61 test_run(name, 4, 0, iterations, &r, &w);
62 test_run(name, 8, 0, iterations, &r, &w);
63 test_run(name, 1, 1, iterations, &r, &w);
64 test_run(name, 4, 1, iterations, &r, &w);
65 test_run(name, 4, 2, iterations, &r, &w);
66 test_run(name, 4, 4, iterations, &r, &w);
67 test_run(name, 8, 1, iterations, &r, &w);
68 test_run(name, 8, 2, iterations, &r, &w);
69 test_run(name, 8, 4, iterations, &r, &w);
70 test_run(name, 0, 1, iterations, &r, &w);
71 test_run(name, 0, 4, iterations, &r, &w);
72 }
73
main()74 fn main() {
75 let mutex = Mutex::new(42);
76 test_round(
77 "mutex",
78 100_000,
79 || *mutex.lock().unwrap(),
80 |i| *mutex.lock().unwrap() = i,
81 );
82 let mutex = Mutex::new(Arc::new(42));
83 test_round(
84 "mutex-arc",
85 100_000,
86 || **mutex.lock().unwrap(),
87 |i| *mutex.lock().unwrap() = Arc::new(i),
88 );
89 test_round(
90 "mutex-arc-clone",
91 100_000,
92 || *Arc::clone(&*mutex.lock().unwrap()),
93 |i| *mutex.lock().unwrap() = Arc::new(i),
94 );
95 let lock = RwLock::new(42);
96 test_round(
97 "rw",
98 100_000,
99 || *lock.read().unwrap(),
100 |i| *lock.write().unwrap() = i,
101 );
102 let lock = RwLock::new(Arc::new(42));
103 test_round(
104 "rw-arc",
105 100_000,
106 || **lock.read().unwrap(),
107 |i| *lock.write().unwrap() = Arc::new(i),
108 );
109 test_round(
110 "rw-arc-clone",
111 100_000,
112 || *Arc::clone(&*lock.read().unwrap()),
113 |i| *lock.write().unwrap() = Arc::new(i),
114 );
115 let arc = ArcSwap::from(Arc::new(42));
116 test_round(
117 "arc-load-store",
118 100_000,
119 || **arc.load(),
120 |i| arc.store(Arc::new(i)),
121 );
122 test_round(
123 "arc-rcu",
124 100_000,
125 || *arc.load_full(),
126 |i| {
127 arc.rcu(|_| Arc::new(i));
128 },
129 );
130 }
131