232 lines
8.1 KiB
Rust
232 lines
8.1 KiB
Rust
//! 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);
|