Files
swaits e8e55b7676 chore: initial release v0.1.0
Runtime-agnostic oneshot broadcast channel for Rust.
2025-10-13 19:36:37 -06:00

166 lines
5.2 KiB
Rust

//! Runtime comparison benchmarks
//!
//! Compares announcement performance across different async runtimes.
//! This verifies the runtime-agnostic design works consistently.
//!
//! Runtimes tested:
//! - tokio (most popular)
//! - smol (lightweight alternative)
//!
//! Expected result: Similar performance across runtimes since announcement
//! uses event-listener which abstracts runtime details.
#![allow(unused_must_use)]
use announcement::Announcement;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use std::hint::black_box;
use std::sync::Arc;
/// Benchmark: Basic announce and listen - tokio vs smol
fn bench_basic(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("runtimes/basic");
// Tokio version
group.bench_function("tokio", |b| {
b.to_async(&rt).iter(|| async {
let (announcer, announcement) = Announcement::new();
let listener = announcement.listener();
let handle = tokio::spawn(async move { listener.listen().await });
announcer.announce(Arc::new(42)).unwrap();
black_box(handle.await.unwrap());
});
});
// Smol version
group.bench_function("smol", |b| {
b.iter(|| {
smol::block_on(async {
let (announcer, announcement) = Announcement::new();
let listener = announcement.listener();
let handle = smol::spawn(async move { listener.listen().await });
announcer.announce(Arc::new(42)).unwrap();
black_box(handle.await);
});
});
});
group.finish();
}
/// Benchmark: Fanout to multiple listeners - tokio vs smol
fn bench_fanout(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("runtimes/fanout");
for n in [10, 100, 500].iter() {
group.throughput(Throughput::Elements(*n as u64));
// Tokio version
group.bench_with_input(BenchmarkId::new("tokio", n), n, |b, &n| {
b.to_async(&rt).iter(|| async move {
let (announcer, announcement) = Announcement::new();
let mut handles = Vec::with_capacity(n);
for _ in 0..n {
let listener = announcement.listener();
handles.push(tokio::spawn(async move { listener.listen().await }));
}
announcer.announce(Arc::new(42)).unwrap();
for h in handles {
black_box(h.await.unwrap());
}
});
});
// Smol version
group.bench_with_input(BenchmarkId::new("smol", n), n, |b, &n| {
b.iter(|| {
smol::block_on(async {
let (announcer, announcement) = Announcement::new();
let mut handles = Vec::with_capacity(n);
for _ in 0..n {
let listener = announcement.listener();
handles.push(smol::spawn(async move { listener.listen().await }));
}
announcer.announce(Arc::new(42)).unwrap();
for h in handles {
black_box(h.await);
}
});
});
});
}
group.finish();
}
/// Benchmark: Concurrent announcements - tokio vs smol
fn bench_concurrent(c: &mut Criterion) {
let rt = tokio::runtime::Runtime::new().unwrap();
let mut group = c.benchmark_group("runtimes/concurrent");
// Tokio version
group.bench_function("tokio", |b| {
b.to_async(&rt).iter(|| async {
let mut handles = Vec::with_capacity(100);
for i in 0..100 {
handles.push(tokio::spawn(async move {
let (announcer, announcement) = Announcement::new();
let listener = announcement.listener();
let recv_handle = tokio::spawn(async move { listener.listen().await });
announcer.announce(Arc::new(i)).unwrap();
recv_handle.await.unwrap()
}));
}
for h in handles {
black_box(h.await.unwrap());
}
});
});
// Smol version
group.bench_function("smol", |b| {
b.iter(|| {
smol::block_on(async {
let mut handles = Vec::with_capacity(100);
for i in 0..100 {
handles.push(smol::spawn(async move {
let (announcer, announcement) = Announcement::new();
let listener = announcement.listener();
let recv_handle = smol::spawn(async move { listener.listen().await });
announcer.announce(Arc::new(i)).unwrap();
recv_handle.await
}));
}
for h in handles {
black_box(h.await);
}
});
});
});
group.finish();
}
criterion_group!(benches, bench_basic, bench_fanout, bench_concurrent,);
criterion_main!(benches);