| 1 | use std::sync::atomic::{AtomicUsize, Ordering}; |
| 2 | use std::sync::Arc; |
| 3 | |
| 4 | use tokio::sync::Notify; |
| 5 | |
| 6 | use criterion::measurement::WallTime; |
| 7 | use criterion::{criterion_group, criterion_main, BenchmarkGroup, Criterion}; |
| 8 | |
| 9 | fn rt() -> tokio::runtime::Runtime { |
| 10 | tokio::runtime::Builder::new_multi_thread() |
| 11 | .worker_threads(6) |
| 12 | .build() |
| 13 | .unwrap() |
| 14 | } |
| 15 | |
| 16 | fn notify_waiters<const N_WAITERS: usize>(g: &mut BenchmarkGroup<WallTime>) { |
| 17 | let rt = rt(); |
| 18 | let notify = Arc::new(Notify::new()); |
| 19 | let counter = Arc::new(AtomicUsize::new(0)); |
| 20 | for _ in 0..N_WAITERS { |
| 21 | rt.spawn({ |
| 22 | let notify = notify.clone(); |
| 23 | let counter = counter.clone(); |
| 24 | async move { |
| 25 | loop { |
| 26 | notify.notified().await; |
| 27 | counter.fetch_add(1, Ordering::Relaxed); |
| 28 | } |
| 29 | } |
| 30 | }); |
| 31 | } |
| 32 | |
| 33 | const N_ITERS: usize = 500; |
| 34 | g.bench_function(N_WAITERS.to_string(), |b| { |
| 35 | b.iter(|| { |
| 36 | counter.store(0, Ordering::Relaxed); |
| 37 | loop { |
| 38 | notify.notify_waiters(); |
| 39 | if counter.load(Ordering::Relaxed) >= N_ITERS { |
| 40 | break; |
| 41 | } |
| 42 | } |
| 43 | }) |
| 44 | }); |
| 45 | } |
| 46 | |
| 47 | fn notify_one<const N_WAITERS: usize>(g: &mut BenchmarkGroup<WallTime>) { |
| 48 | let rt = rt(); |
| 49 | let notify = Arc::new(Notify::new()); |
| 50 | let counter = Arc::new(AtomicUsize::new(0)); |
| 51 | for _ in 0..N_WAITERS { |
| 52 | rt.spawn({ |
| 53 | let notify = notify.clone(); |
| 54 | let counter = counter.clone(); |
| 55 | async move { |
| 56 | loop { |
| 57 | notify.notified().await; |
| 58 | counter.fetch_add(1, Ordering::Relaxed); |
| 59 | } |
| 60 | } |
| 61 | }); |
| 62 | } |
| 63 | |
| 64 | const N_ITERS: usize = 500; |
| 65 | g.bench_function(N_WAITERS.to_string(), |b| { |
| 66 | b.iter(|| { |
| 67 | counter.store(0, Ordering::Relaxed); |
| 68 | loop { |
| 69 | notify.notify_one(); |
| 70 | if counter.load(Ordering::Relaxed) >= N_ITERS { |
| 71 | break; |
| 72 | } |
| 73 | } |
| 74 | }) |
| 75 | }); |
| 76 | } |
| 77 | |
| 78 | fn bench_notify_one(c: &mut Criterion) { |
| 79 | let mut group = c.benchmark_group("notify_one" ); |
| 80 | notify_one::<10>(&mut group); |
| 81 | notify_one::<50>(&mut group); |
| 82 | notify_one::<100>(&mut group); |
| 83 | notify_one::<200>(&mut group); |
| 84 | notify_one::<500>(&mut group); |
| 85 | group.finish(); |
| 86 | } |
| 87 | |
| 88 | fn bench_notify_waiters(c: &mut Criterion) { |
| 89 | let mut group = c.benchmark_group("notify_waiters" ); |
| 90 | notify_waiters::<10>(&mut group); |
| 91 | notify_waiters::<50>(&mut group); |
| 92 | notify_waiters::<100>(&mut group); |
| 93 | notify_waiters::<200>(&mut group); |
| 94 | notify_waiters::<500>(&mut group); |
| 95 | group.finish(); |
| 96 | } |
| 97 | |
| 98 | criterion_group!( |
| 99 | notify_waiters_simple, |
| 100 | bench_notify_one, |
| 101 | bench_notify_waiters |
| 102 | ); |
| 103 | |
| 104 | criterion_main!(notify_waiters_simple); |
| 105 | |