use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use std::time::Duration;
use std::sync::Arc;
use lite_sync::notify::SingleWaiterNotify;
use tokio::sync::Notify;
fn bench_notify_creation_comparison(c: &mut Criterion) {
let mut group = c.benchmark_group("notify_creation_comparison");
group.bench_function("custom_single_waiter_notify", |b| {
b.iter(|| {
let _notify = SingleWaiterNotify::new();
});
});
group.bench_function("tokio_notify", |b| {
b.iter(|| {
let _notify = Notify::new();
});
});
group.finish();
}
fn bench_notify_before_wait_comparison(c: &mut Criterion) {
let mut group = c.benchmark_group("notify_before_wait_comparison");
group.bench_function("custom_single_waiter_notify", |b| {
let runtime = tokio::runtime::Runtime::new().unwrap();
b.to_async(&runtime).iter_custom(|iters| async move {
let mut total_duration = Duration::from_secs(0);
for _ in 0..iters {
let notify = SingleWaiterNotify::new();
let start = std::time::Instant::now();
notify.notify_one();
notify.notified().await;
total_duration += start.elapsed();
}
total_duration
});
});
group.bench_function("tokio_notify", |b| {
let runtime = tokio::runtime::Runtime::new().unwrap();
b.to_async(&runtime).iter_custom(|iters| async move {
let mut total_duration = Duration::from_secs(0);
for _ in 0..iters {
let notify = Notify::new();
let start = std::time::Instant::now();
notify.notify_one();
notify.notified().await;
total_duration += start.elapsed();
}
total_duration
});
});
group.finish();
}
fn bench_notify_after_wait_comparison(c: &mut Criterion) {
let mut group = c.benchmark_group("notify_after_wait_comparison");
group.bench_function("custom_single_waiter_notify", |b| {
let runtime = tokio::runtime::Runtime::new().unwrap();
b.to_async(&runtime).iter_custom(|iters| async move {
let mut total_duration = Duration::from_secs(0);
for _ in 0..iters {
let notify = Arc::new(SingleWaiterNotify::new());
let notify_clone = notify.clone();
let start = std::time::Instant::now();
tokio::spawn(async move {
notify_clone.notify_one();
});
notify.notified().await;
total_duration += start.elapsed();
}
total_duration
});
});
group.bench_function("tokio_notify", |b| {
let runtime = tokio::runtime::Runtime::new().unwrap();
b.to_async(&runtime).iter_custom(|iters| async move {
let mut total_duration = Duration::from_secs(0);
for _ in 0..iters {
let notify = Arc::new(Notify::new());
let notify_clone = notify.clone();
let start = std::time::Instant::now();
tokio::spawn(async move {
notify_clone.notify_one();
});
notify.notified().await;
total_duration += start.elapsed();
}
total_duration
});
});
group.finish();
}
fn bench_notify_multiple_cycles_comparison(c: &mut Criterion) {
let mut group = c.benchmark_group("notify_multiple_cycles_comparison");
for cycles in [10, 100].iter() {
group.bench_with_input(
BenchmarkId::new("custom_single_waiter_notify", cycles),
cycles,
|b, &cycles| {
let runtime = tokio::runtime::Runtime::new().unwrap();
b.to_async(&runtime).iter_custom(|iters| async move {
let mut total_duration = Duration::from_secs(0);
for _ in 0..iters {
let notify = Arc::new(SingleWaiterNotify::new());
let start = std::time::Instant::now();
for _ in 0..cycles {
let notify_clone = notify.clone();
tokio::spawn(async move {
notify_clone.notify_one();
});
notify.notified().await;
}
total_duration += start.elapsed();
}
total_duration
});
},
);
group.bench_with_input(
BenchmarkId::new("tokio_notify", cycles),
cycles,
|b, &cycles| {
let runtime = tokio::runtime::Runtime::new().unwrap();
b.to_async(&runtime).iter_custom(|iters| async move {
let mut total_duration = Duration::from_secs(0);
for _ in 0..iters {
let notify = Arc::new(Notify::new());
let start = std::time::Instant::now();
for _ in 0..cycles {
let notify_clone = notify.clone();
tokio::spawn(async move {
notify_clone.notify_one();
});
notify.notified().await;
}
total_duration += start.elapsed();
}
total_duration
});
},
);
}
group.finish();
}
fn bench_notify_drop_comparison(c: &mut Criterion) {
let mut group = c.benchmark_group("notify_drop_comparison");
group.bench_function("custom_single_waiter_notify_drop_no_wait", |b| {
b.iter_batched(
|| {
SingleWaiterNotify::new()
},
|notify| {
drop(notify);
},
criterion::BatchSize::SmallInput,
);
});
group.bench_function("tokio_notify_drop_no_wait", |b| {
b.iter_batched(
|| {
Notify::new()
},
|notify| {
drop(notify);
},
criterion::BatchSize::SmallInput,
);
});
group.bench_function("custom_single_waiter_notify_drop_with_waker", |b| {
let runtime = tokio::runtime::Runtime::new().unwrap();
b.to_async(&runtime).iter_batched(
|| {
let notify = Arc::new(SingleWaiterNotify::new());
let notify_clone = notify.clone();
let wait_handle = tokio::spawn(async move {
let mut notified = Box::pin(notify_clone.notified());
tokio::select! {
_ = &mut notified => {},
_ = tokio::time::sleep(Duration::from_millis(100)) => {},
}
});
std::thread::sleep(Duration::from_micros(100));
(notify, wait_handle)
},
|(notify, wait_handle)| async move {
drop(notify);
wait_handle.abort();
},
criterion::BatchSize::SmallInput,
);
});
group.bench_function("tokio_notify_drop_with_waker", |b| {
let runtime = tokio::runtime::Runtime::new().unwrap();
b.to_async(&runtime).iter_batched(
|| {
let notify = Arc::new(Notify::new());
let notify_clone = notify.clone();
let wait_handle = tokio::spawn(async move {
let mut notified = Box::pin(notify_clone.notified());
tokio::select! {
_ = &mut notified => {},
_ = tokio::time::sleep(Duration::from_millis(100)) => {},
}
});
std::thread::sleep(Duration::from_micros(100));
(notify, wait_handle)
},
|(notify, wait_handle)| async move {
drop(notify);
wait_handle.abort();
},
criterion::BatchSize::SmallInput,
);
});
group.bench_function("custom_single_waiter_notify_batch_drop", |b| {
b.iter_batched(
|| {
let mut notifiers = Vec::new();
for _ in 0..100 {
notifiers.push(SingleWaiterNotify::new());
}
notifiers
},
|notifiers| {
drop(notifiers);
},
criterion::BatchSize::SmallInput,
);
});
group.bench_function("tokio_notify_batch_drop", |b| {
b.iter_batched(
|| {
let mut notifiers = Vec::new();
for _ in 0..100 {
notifiers.push(Notify::new());
}
notifiers
},
|notifiers| {
drop(notifiers);
},
criterion::BatchSize::SmallInput,
);
});
group.finish();
}
fn bench_notify_concurrent_comparison(c: &mut Criterion) {
let mut group = c.benchmark_group("notify_concurrent_comparison");
group.bench_function("custom_single_waiter_notify", |b| {
let runtime = tokio::runtime::Runtime::new().unwrap();
b.to_async(&runtime).iter_custom(|iters| async move {
let mut total_duration = Duration::from_secs(0);
for _ in 0..iters {
let notify = Arc::new(SingleWaiterNotify::new());
let start = std::time::Instant::now();
for _ in 0..5 {
let n = notify.clone();
tokio::spawn(async move {
n.notify_one();
});
}
notify.notified().await;
total_duration += start.elapsed();
}
total_duration
});
});
group.bench_function("tokio_notify", |b| {
let runtime = tokio::runtime::Runtime::new().unwrap();
b.to_async(&runtime).iter_custom(|iters| async move {
let mut total_duration = Duration::from_secs(0);
for _ in 0..iters {
let notify = Arc::new(Notify::new());
let start = std::time::Instant::now();
for _ in 0..5 {
let n = notify.clone();
tokio::spawn(async move {
n.notify_one();
});
}
notify.notified().await;
total_duration += start.elapsed();
}
total_duration
});
});
group.finish();
}
criterion_group!(
benches,
bench_notify_creation_comparison,
bench_notify_before_wait_comparison,
bench_notify_after_wait_comparison,
bench_notify_multiple_cycles_comparison,
bench_notify_drop_comparison,
bench_notify_concurrent_comparison,
);
criterion_main!(benches);