1 | use std::sync::Arc; |
2 | use tokio::{sync::RwLock, task}; |
3 | |
4 | use criterion::measurement::WallTime; |
5 | use criterion::{black_box, criterion_group, criterion_main, BenchmarkGroup, Criterion}; |
6 | |
7 | fn read_uncontended(g: &mut BenchmarkGroup<WallTime>) { |
8 | let rt = tokio::runtime::Builder::new_multi_thread() |
9 | .worker_threads(6) |
10 | .build() |
11 | .unwrap(); |
12 | |
13 | let lock = Arc::new(RwLock::new(())); |
14 | g.bench_function("read" , |b| { |
15 | b.iter(|| { |
16 | let lock = lock.clone(); |
17 | rt.block_on(async move { |
18 | for _ in 0..6 { |
19 | let read = lock.read().await; |
20 | let _read = black_box(read); |
21 | } |
22 | }) |
23 | }) |
24 | }); |
25 | } |
26 | |
27 | fn read_concurrent_uncontended_multi(g: &mut BenchmarkGroup<WallTime>) { |
28 | let rt = tokio::runtime::Builder::new_multi_thread() |
29 | .worker_threads(6) |
30 | .build() |
31 | .unwrap(); |
32 | |
33 | async fn task(lock: Arc<RwLock<()>>) { |
34 | let read = lock.read().await; |
35 | let _read = black_box(read); |
36 | } |
37 | |
38 | let lock = Arc::new(RwLock::new(())); |
39 | g.bench_function("read_concurrent_multi" , |b| { |
40 | b.iter(|| { |
41 | let lock = lock.clone(); |
42 | rt.block_on(async move { |
43 | let j = tokio::try_join! { |
44 | task::spawn(task(lock.clone())), |
45 | task::spawn(task(lock.clone())), |
46 | task::spawn(task(lock.clone())), |
47 | task::spawn(task(lock.clone())), |
48 | task::spawn(task(lock.clone())), |
49 | task::spawn(task(lock.clone())) |
50 | }; |
51 | j.unwrap(); |
52 | }) |
53 | }) |
54 | }); |
55 | } |
56 | |
57 | fn read_concurrent_uncontended(g: &mut BenchmarkGroup<WallTime>) { |
58 | let rt = tokio::runtime::Builder::new_current_thread() |
59 | .build() |
60 | .unwrap(); |
61 | |
62 | async fn task(lock: Arc<RwLock<()>>) { |
63 | let read = lock.read().await; |
64 | let _read = black_box(read); |
65 | } |
66 | |
67 | let lock = Arc::new(RwLock::new(())); |
68 | g.bench_function("read_concurrent" , |b| { |
69 | b.iter(|| { |
70 | let lock = lock.clone(); |
71 | rt.block_on(async move { |
72 | tokio::join! { |
73 | task(lock.clone()), |
74 | task(lock.clone()), |
75 | task(lock.clone()), |
76 | task(lock.clone()), |
77 | task(lock.clone()), |
78 | task(lock.clone()) |
79 | }; |
80 | }) |
81 | }) |
82 | }); |
83 | } |
84 | |
85 | fn read_concurrent_contended_multi(g: &mut BenchmarkGroup<WallTime>) { |
86 | let rt = tokio::runtime::Builder::new_multi_thread() |
87 | .worker_threads(6) |
88 | .build() |
89 | .unwrap(); |
90 | |
91 | async fn task(lock: Arc<RwLock<()>>) { |
92 | let read = lock.read().await; |
93 | let _read = black_box(read); |
94 | } |
95 | |
96 | let lock = Arc::new(RwLock::new(())); |
97 | g.bench_function("read_concurrent_multi" , |b| { |
98 | b.iter(|| { |
99 | let lock = lock.clone(); |
100 | rt.block_on(async move { |
101 | let write = lock.write().await; |
102 | let j = tokio::try_join! { |
103 | async move { drop(write); Ok(()) }, |
104 | task::spawn(task(lock.clone())), |
105 | task::spawn(task(lock.clone())), |
106 | task::spawn(task(lock.clone())), |
107 | task::spawn(task(lock.clone())), |
108 | task::spawn(task(lock.clone())), |
109 | }; |
110 | j.unwrap(); |
111 | }) |
112 | }) |
113 | }); |
114 | } |
115 | |
116 | fn read_concurrent_contended(g: &mut BenchmarkGroup<WallTime>) { |
117 | let rt = tokio::runtime::Builder::new_current_thread() |
118 | .build() |
119 | .unwrap(); |
120 | |
121 | async fn task(lock: Arc<RwLock<()>>) { |
122 | let read = lock.read().await; |
123 | let _read = black_box(read); |
124 | } |
125 | |
126 | let lock = Arc::new(RwLock::new(())); |
127 | g.bench_function("read_concurrent" , |b| { |
128 | b.iter(|| { |
129 | let lock = lock.clone(); |
130 | rt.block_on(async move { |
131 | let write = lock.write().await; |
132 | tokio::join! { |
133 | async move { drop(write) }, |
134 | task(lock.clone()), |
135 | task(lock.clone()), |
136 | task(lock.clone()), |
137 | task(lock.clone()), |
138 | task(lock.clone()), |
139 | }; |
140 | }) |
141 | }) |
142 | }); |
143 | } |
144 | |
145 | fn bench_contention(c: &mut Criterion) { |
146 | let mut group = c.benchmark_group("contention" ); |
147 | read_concurrent_contended(&mut group); |
148 | read_concurrent_contended_multi(&mut group); |
149 | group.finish(); |
150 | } |
151 | |
152 | fn bench_uncontented(c: &mut Criterion) { |
153 | let mut group = c.benchmark_group("uncontented" ); |
154 | read_uncontended(&mut group); |
155 | read_concurrent_uncontended(&mut group); |
156 | read_concurrent_uncontended_multi(&mut group); |
157 | group.finish(); |
158 | } |
159 | |
160 | criterion_group!(contention, bench_contention); |
161 | criterion_group!(uncontented, bench_uncontented); |
162 | |
163 | criterion_main!(contention, uncontented); |
164 | |