//! 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);