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