Skip to content

Commit be99e7a

Browse files
authored
benches: add spawn_blocking concurrency benchmark (#7748)
1 parent 3bf2e53 commit be99e7a

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

benches/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,5 +96,10 @@ name = "time_timeout"
9696
path = "time_timeout.rs"
9797
harness = false
9898

99+
[[bench]]
100+
name = "spawn_blocking"
101+
path = "spawn_blocking.rs"
102+
harness = false
103+
99104
[lints]
100105
workspace = true

benches/spawn_blocking.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//! Benchmark spawn_blocking at different concurrency levels on the multi-threaded scheduler.
2+
//!
3+
//! For each parallelism level N (1, 2, 4, 8, 16, 32, 64, capped at available parallelism):
4+
//! - Spawns N regular async tasks
5+
//! - Each task spawns M batches of B spawn_blocking tasks (no-ops)
6+
//! - Each batch is awaited to completion before starting the next
7+
8+
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
9+
use tokio::runtime::{self, Runtime};
10+
use tokio::task::JoinSet;
11+
12+
/// Number of batches per task
13+
const NUM_BATCHES: usize = 100;
14+
/// Number of spawn_blocking calls per batch
15+
const BATCH_SIZE: usize = 16;
16+
17+
fn spawn_blocking_concurrency(c: &mut Criterion) {
18+
let max_parallelism = std::thread::available_parallelism()
19+
.map(|p| p.get())
20+
.unwrap_or(1);
21+
22+
let parallelism_levels: Vec<usize> = [1, 2, 4, 8, 16, 32, 64]
23+
.into_iter()
24+
.filter(|&n| n <= max_parallelism)
25+
.collect();
26+
27+
let mut group = c.benchmark_group("spawn_blocking");
28+
29+
for num_tasks in parallelism_levels {
30+
group.bench_with_input(
31+
BenchmarkId::new("concurrency", num_tasks),
32+
&num_tasks,
33+
|b, &num_tasks| {
34+
let rt = rt();
35+
36+
b.iter(|| {
37+
rt.block_on(async {
38+
let mut tasks = JoinSet::new();
39+
40+
for _ in 0..num_tasks {
41+
tasks.spawn(async {
42+
for _ in 0..NUM_BATCHES {
43+
let mut batch = JoinSet::new();
44+
45+
for _ in 0..BATCH_SIZE {
46+
batch.spawn_blocking(|| black_box(0));
47+
}
48+
49+
batch.join_all().await;
50+
}
51+
});
52+
}
53+
54+
tasks.join_all().await;
55+
});
56+
});
57+
},
58+
);
59+
}
60+
61+
group.finish();
62+
}
63+
64+
fn rt() -> Runtime {
65+
runtime::Builder::new_multi_thread()
66+
.enable_all()
67+
.build()
68+
.unwrap()
69+
}
70+
71+
criterion_group!(spawn_blocking_benches, spawn_blocking_concurrency);
72+
73+
criterion_main!(spawn_blocking_benches);

0 commit comments

Comments
 (0)