chore: initial release v0.1.0
Runtime-agnostic oneshot broadcast channel for Rust.
This commit is contained in:
64 files changed
+23966
No files matched your search
@@ -0,0 +1,231 @@
|
||||
//! 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);
|
||||
Reference in new issue
Block a user