use affinitypool::Threadpool;
use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main};
use std::hint::black_box;
use std::time::{Duration, Instant};
use tokio::runtime::Builder as TokioBuilder;
fn affinitypool_runtime() -> tokio::runtime::Runtime {
TokioBuilder::new_current_thread().enable_all().build().unwrap()
}
fn bench_spawn_overhead(c: &mut Criterion) {
let mut group = c.benchmark_group("vs_blocking_spawn_overhead");
group.measurement_time(Duration::from_secs(10));
for &count in &[1usize, 100, 1_000, 10_000] {
group.throughput(Throughput::Elements(count as u64));
for &workers in &[1usize, 4] {
group.bench_with_input(
BenchmarkId::new(format!("affinitypool_{}w", workers), count),
&(workers, count),
|b, &(workers, count)| {
let rt = affinitypool_runtime();
b.iter_custom(|iters| {
rt.block_on(async move {
let pool = Threadpool::new(workers);
let _ = pool.spawn(|| 0u32).await;
let mut total = Duration::ZERO;
for _ in 0..iters {
let start = Instant::now();
let mut handles = Vec::with_capacity(count);
for i in 0..count {
handles.push(pool.spawn(move || black_box(i)));
}
for h in handles {
black_box(h.await);
}
total += start.elapsed();
}
total
})
});
},
);
}
group.bench_with_input(BenchmarkId::new("blocking", count), &count, |b, &count| {
let rt = affinitypool_runtime();
b.iter_custom(|iters| {
rt.block_on(async move {
let _ = blocking::unblock(|| 0u32).await;
let mut total = Duration::ZERO;
for _ in 0..iters {
let start = Instant::now();
let mut handles = Vec::with_capacity(count);
for i in 0..count {
handles.push(blocking::unblock(move || black_box(i)));
}
for h in handles {
black_box(h.await);
}
total += start.elapsed();
}
total
})
});
});
}
group.finish();
}
fn bench_round_trip(c: &mut Criterion) {
let mut group = c.benchmark_group("vs_blocking_round_trip");
group.measurement_time(Duration::from_secs(10));
for &workers in &[1usize, 4, 8] {
group.bench_with_input(
BenchmarkId::new("affinitypool", workers),
&workers,
|b, &workers| {
let rt = affinitypool_runtime();
b.iter_custom(|iters| {
rt.block_on(async move {
let pool = Threadpool::new(workers);
let _ = pool.spawn(|| 0u32).await;
let start = Instant::now();
for i in 0..iters {
black_box(pool.spawn(move || black_box(i)).await);
}
start.elapsed()
})
});
},
);
}
group.bench_function("blocking", |b| {
let rt = affinitypool_runtime();
b.iter_custom(|iters| {
rt.block_on(async move {
let _ = blocking::unblock(|| 0u32).await;
let start = Instant::now();
for i in 0..iters {
black_box(blocking::unblock(move || black_box(i)).await);
}
start.elapsed()
})
});
});
group.finish();
}
fn bench_multi_producer(c: &mut Criterion) {
let mut group = c.benchmark_group("vs_blocking_multi_producer");
group.measurement_time(Duration::from_secs(10));
for &producers in &[2usize, 4, 8] {
let total_tasks = producers * 1_000;
group.throughput(Throughput::Elements(total_tasks as u64));
for &workers in &[1usize, 4] {
group.bench_with_input(
BenchmarkId::new(format!("affinitypool_{}p_{}w", producers, workers), total_tasks),
&(producers, workers),
|b, &(producers, workers)| {
let rt = TokioBuilder::new_multi_thread()
.worker_threads(producers)
.enable_all()
.build()
.unwrap();
b.iter_custom(|iters| {
rt.block_on(async move {
let pool = std::sync::Arc::new(Threadpool::new(workers));
let _ = pool.spawn(|| 0u32).await;
let per = 1_000usize;
let mut total = Duration::ZERO;
for _ in 0..iters {
let start = Instant::now();
let mut producer_handles = Vec::with_capacity(producers);
for _ in 0..producers {
let pool = pool.clone();
producer_handles.push(tokio::spawn(async move {
let mut hs = Vec::with_capacity(per);
for i in 0..per {
hs.push(pool.spawn(move || black_box(i)));
}
for h in hs {
black_box(h.await);
}
}));
}
for ph in producer_handles {
ph.await.unwrap();
}
total += start.elapsed();
}
total
})
});
},
);
}
group.bench_with_input(
BenchmarkId::new(format!("blocking_{}p", producers), total_tasks),
&producers,
|b, &producers| {
let rt = TokioBuilder::new_multi_thread()
.worker_threads(producers)
.enable_all()
.build()
.unwrap();
b.iter_custom(|iters| {
rt.block_on(async move {
let _ = blocking::unblock(|| 0u32).await;
let per = 1_000usize;
let mut total = Duration::ZERO;
for _ in 0..iters {
let start = Instant::now();
let mut producer_handles = Vec::with_capacity(producers);
for _ in 0..producers {
producer_handles.push(tokio::spawn(async move {
let mut hs = Vec::with_capacity(per);
for i in 0..per {
hs.push(blocking::unblock(move || black_box(i)));
}
for h in hs {
black_box(h.await);
}
}));
}
for ph in producer_handles {
ph.await.unwrap();
}
total += start.elapsed();
}
total
})
});
},
);
}
group.finish();
}
criterion_group!(benches, bench_spawn_overhead, bench_round_trip, bench_multi_producer);
criterion_main!(benches);