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

232 lines
8.1 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! Stress test benchmarks for extreme scenarios
//!
//! Tests announcement under extreme conditions:
//! - Million-scale operations (1M+ listeners/announcements)
//! - Fully connected networks (N announcements × N listeners)
//! - Cascade patterns (chain reactions and trees)
use announcement::Announcement;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use std::hint::black_box;
use std::sync::Arc;
use std::time::Duration;
/// Benchmark: Million scale stress - 1M announcements × 10 listeners
fn bench_million_announcements(c: &mut Criterion) {
let mut group = c.benchmark_group("stress/million_scale");
group.sample_size(10);
group.measurement_time(Duration::from_secs(30));
group.bench_function("10K_announcements_x_10_listeners", |b| {
b.iter(|| {
let num_announcements = 10_000;
let listeners_per_announcement = 10;
let mut announcements = Vec::with_capacity(num_announcements);
let mut announcers = Vec::with_capacity(num_announcements);
// Create 10K announcement channels
for _ in 0..num_announcements {
let (tx, announcement) = Announcement::<Arc<i32>>::new();
announcers.push(tx);
announcements.push(announcement);
}
// Create 10 listeners for each announcement (100K total)
let mut all_listeners =
Vec::with_capacity(num_announcements * listeners_per_announcement);
for announcement in &announcements {
for _ in 0..listeners_per_announcement {
all_listeners.push(announcement.listener());
}
}
// Announce on all channels
for (i, announcer) in announcers.into_iter().enumerate() {
announcer.announce(Arc::new(i as i32)).unwrap();
}
// Verify delivery (sampling for performance)
for i in (0..all_listeners.len()).step_by(1000) {
black_box(all_listeners[i].try_listen());
}
});
});
group.finish();
}
/// Benchmark: Single announcement to 10K listeners
fn bench_one_to_million(c: &mut Criterion) {
let mut group = c.benchmark_group("stress/one_to_ten_thousand");
group.sample_size(10);
group.bench_function("1_announcement_x_10K_listeners", |b| {
b.iter(|| {
let (tx, announcement) = Announcement::new();
let num_listeners = 10_000;
let mut listeners = Vec::with_capacity(num_listeners);
for _ in 0..num_listeners {
listeners.push(announcement.listener());
}
tx.announce(Arc::new(42)).unwrap();
// Sample retrieval
for i in (0..listeners.len()).step_by(1000) {
black_box(listeners[i].try_listen());
}
});
});
group.finish();
}
/// Benchmark: Fully connected network - N announcements × N listeners
fn bench_fully_connected(c: &mut Criterion) {
let mut group = c.benchmark_group("stress/fully_connected");
group.sample_size(10);
group.measurement_time(Duration::from_secs(10));
// N announcements each received by N listeners = N² connections
for n in [10, 100, 500].iter() {
let total_connections = n * n;
group.throughput(Throughput::Elements(total_connections as u64));
group.bench_with_input(BenchmarkId::from_parameter(n), n, |b, &n| {
b.iter(|| {
// Create N announcement channels
let mut announcements = Vec::with_capacity(n);
let mut announcers = Vec::with_capacity(n);
for _ in 0..n {
let (tx, announcement) = Announcement::<Arc<i32>>::new();
announcers.push(tx);
announcements.push(announcement);
}
// Create N listeners for each announcement (N² total listeners)
let mut all_listeners = Vec::with_capacity(n * n);
for announcement in &announcements {
for _ in 0..n {
all_listeners.push(announcement.listener());
}
}
// Announce on all channels
for (i, announcer) in announcers.into_iter().enumerate() {
announcer.announce(Arc::new(i as i32)).unwrap();
}
// Retrieve all values
for listener in &all_listeners {
black_box(listener.try_listen());
}
});
});
}
group.finish();
}
/// Benchmark: Cascade chain - A triggers B triggers C...
fn bench_cascade_chain(c: &mut Criterion) {
let mut group = c.benchmark_group("stress/cascade_chain");
for chain_length in [10, 100, 500].iter() {
group.bench_with_input(
BenchmarkId::from_parameter(chain_length),
chain_length,
|b, &n| {
b.iter(|| {
let mut announcements = Vec::with_capacity(n);
let mut announcers = Vec::with_capacity(n);
// Create chain of announcements
for _ in 0..n {
let (tx, announcement) = Announcement::<Arc<i32>>::new();
announcers.push(tx);
announcements.push(announcement);
}
// Link chain: each announcement triggers next
let listeners: Vec<_> = announcements
.iter()
.take(n - 1)
.map(|a| a.listener())
.collect();
// Trigger cascade
for (i, announcer) in announcers.into_iter().enumerate() {
announcer.announce(Arc::new(i as i32)).unwrap();
}
// Verify propagation
for listener in &listeners {
black_box(listener.try_listen());
}
});
},
);
}
group.finish();
}
/// Benchmark: Cascade tree - A triggers B1, B2, B3... (tree fanout)
fn bench_cascade_tree(c: &mut Criterion) {
let mut group = c.benchmark_group("stress/cascade_tree");
for fanout in [2, 5, 10, 50].iter() {
group.throughput(Throughput::Elements(*fanout as u64));
group.bench_with_input(BenchmarkId::from_parameter(fanout), fanout, |b, &fanout| {
b.iter(|| {
// Root announcement
let (root_tx, root_announcement) = Announcement::<Arc<i32>>::new();
// Create fanout child announcements
let mut child_announcers = Vec::with_capacity(fanout);
let mut child_announcements = Vec::with_capacity(fanout);
for _ in 0..fanout {
let (tx, announcement) = Announcement::<Arc<i32>>::new();
child_announcers.push(tx);
child_announcements.push(announcement);
}
// Root listener triggers all children
let _root_listener = root_announcement.listener();
// Create listeners for all children
let mut child_listeners = Vec::with_capacity(fanout);
for announcement in &child_announcements {
child_listeners.push(announcement.listener());
}
// Trigger cascade
root_tx.announce(Arc::new(0)).unwrap();
for (i, announcer) in child_announcers.into_iter().enumerate() {
announcer.announce(Arc::new(i as i32)).unwrap();
}
// Verify all children received
for listener in &child_listeners {
black_box(listener.try_listen());
}
});
});
}
group.finish();
}
criterion_group!(
benches,
bench_million_announcements,
bench_one_to_million,
bench_fully_connected,
bench_cascade_chain,
bench_cascade_tree,
);
criterion_main!(benches);