use atomic_waker::AtomicWaker; use criterion::{black_box, criterion_group, criterion_main, BenchmarkGroup, Criterion}; use std::sync::Arc; use std::task::{Wake, Waker}; enum Contention { Low, High, } impl Contention { fn bench( self, group: &mut BenchmarkGroup<'_, M>, f: impl Fn(&AtomicWaker) + Send + Sync + Clone, ) where M: criterion::measurement::Measurement, { let waker = AtomicWaker::new(); match self { Self::Low => { // Run the benchmark with low contention. group.bench_function("low contention", move |b| { b.iter(|| { for _ in 0..500 { f(&waker); } }) }); } Self::High => { // Run the benchmark with high contention. group.bench_function("high contention", move |b| { b.iter(|| { use rayon::prelude::*; (0..100_000).into_par_iter().for_each(|_| f(&waker)); }) }); } } } } fn run_lo_hi(c: &mut Criterion, name: &str, f: impl Fn(&AtomicWaker) + Send + Sync + Clone) { let mut group = c.benchmark_group(name); Contention::Low.bench(&mut group, f.clone()); Contention::High.bench(&mut group, f); group.finish(); } fn store_and_wake(c: &mut Criterion) { run_lo_hi(c, "store and wake", |waker| { let noop_waker = noop_waker(); waker.register(&noop_waker); waker.wake(); }); run_lo_hi(c, "store and take", |waker| { let noop_waker = noop_waker(); waker.register(&noop_waker); black_box(waker.take()); }); } fn wake_without_store(c: &mut Criterion) { run_lo_hi(c, "wake without store", |waker| { waker.wake(); }); run_lo_hi(c, "take without store", |waker| { black_box(waker.take()); }); } criterion_group!(benches, store_and_wake, wake_without_store); criterion_main!(benches); fn noop_waker() -> Waker { struct Noop; impl Wake for Noop { fn wake(self: Arc) { // Do nothing } fn wake_by_ref(self: &Arc) { // Do nothing } } Waker::from(Arc::new(Noop)) }