use announcement::Announcement; use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput}; use std::collections::HashMap; use std::hint::black_box; use std::sync::Arc; // Small type: 4 bytes fn bench_small_type(c: &mut Criterion) { let mut group = c.benchmark_group("small_type_i32"); for n in [1, 10, 100, 500].iter() { group.throughput(Throughput::Elements(*n as u64)); // Direct Clone group.bench_with_input(BenchmarkId::new("direct_clone", n), n, |b, &n| { b.iter(|| { let (tx, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..n { listeners.push(announcement.listener()); } tx.announce(42i32).unwrap(); for listener in listeners { black_box(listener.try_listen()); } }); }); // Arc Clone group.bench_with_input(BenchmarkId::new("arc_clone", n), n, |b, &n| { b.iter(|| { let (tx, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..n { listeners.push(announcement.listener()); } tx.announce(Arc::new(42i32)).unwrap(); for listener in listeners { black_box(listener.try_listen()); } }); }); } group.finish(); } // Medium type: 1KB fn bench_medium_type(c: &mut Criterion) { let mut group = c.benchmark_group("medium_type_1kb"); for n in [1, 10, 100, 500].iter() { group.throughput(Throughput::Elements(*n as u64)); // Direct Clone group.bench_with_input(BenchmarkId::new("direct_clone", n), n, |b, &n| { b.iter(|| { let (tx, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..n { listeners.push(announcement.listener()); } tx.announce([0u8; 1024]).unwrap(); for listener in listeners { black_box(listener.try_listen()); } }); }); // Arc Clone group.bench_with_input(BenchmarkId::new("arc_clone", n), n, |b, &n| { b.iter(|| { let (tx, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..n { listeners.push(announcement.listener()); } tx.announce(Arc::new([0u8; 1024])).unwrap(); for listener in listeners { black_box(listener.try_listen()); } }); }); } group.finish(); } // Large type: 1MB fn bench_large_type(c: &mut Criterion) { let mut group = c.benchmark_group("large_type_1mb"); group.sample_size(10); // Reduce sample size for large data for n in [1, 10, 100, 500].iter() { group.throughput(Throughput::Elements(*n as u64)); // Direct Clone group.bench_with_input(BenchmarkId::new("direct_clone", n), n, |b, &n| { b.iter(|| { let (tx, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..n { listeners.push(announcement.listener()); } tx.announce(vec![0u8; 1024 * 1024]).unwrap(); for listener in listeners { black_box(listener.try_listen()); } }); }); // Arc Clone group.bench_with_input(BenchmarkId::new("arc_clone", n), n, |b, &n| { b.iter(|| { let (tx, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..n { listeners.push(announcement.listener()); } tx.announce(Arc::new(vec![0u8; 1024 * 1024])).unwrap(); for listener in listeners { black_box(listener.try_listen()); } }); }); } group.finish(); } // Complex type: Config with String, Vec, HashMap #[derive(Clone, Debug)] #[allow(dead_code)] struct Config { name: String, tags: Vec, settings: HashMap, data: Vec, } impl Config { fn new() -> Self { let mut settings = HashMap::new(); settings.insert("key1".to_string(), "value1".to_string()); settings.insert("key2".to_string(), "value2".to_string()); settings.insert("key3".to_string(), "value3".to_string()); Config { name: "MyConfig".to_string(), tags: vec!["tag1".to_string(), "tag2".to_string(), "tag3".to_string()], settings, data: vec![0u8; 1024], } } } fn bench_complex_type(c: &mut Criterion) { let mut group = c.benchmark_group("complex_type_config"); for n in [1, 10, 100, 500].iter() { group.throughput(Throughput::Elements(*n as u64)); // Direct Clone group.bench_with_input(BenchmarkId::new("direct_clone", n), n, |b, &n| { b.iter(|| { let (tx, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..n { listeners.push(announcement.listener()); } tx.announce(Config::new()).unwrap(); for listener in listeners { black_box(listener.try_listen()); } }); }); // Arc Clone group.bench_with_input(BenchmarkId::new("arc_clone", n), n, |b, &n| { b.iter(|| { let (tx, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..n { listeners.push(announcement.listener()); } tx.announce(Arc::new(Config::new())).unwrap(); for listener in listeners { black_box(listener.try_listen()); } }); }); } group.finish(); } // Comparison benchmark showing the crossover point fn bench_crossover_analysis(c: &mut Criterion) { let mut group = c.benchmark_group("crossover_analysis"); // Test various type sizes to find where Arc becomes beneficial let sizes = [4, 8, 16, 32, 64, 128, 256, 512]; for size in sizes.iter() { group.throughput(Throughput::Bytes(*size as u64)); // Direct clone with 10 listeners group.bench_with_input( BenchmarkId::new("direct_10_listeners", size), size, |b, &size| { b.iter(|| { let (tx, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..10 { listeners.push(announcement.listener()); } let data = vec![0u8; size]; tx.announce(data).unwrap(); for listener in listeners { black_box(listener.try_listen()); } }); }, ); // Arc clone with 10 listeners group.bench_with_input( BenchmarkId::new("arc_10_listeners", size), size, |b, &size| { b.iter(|| { let (tx, announcement) = Announcement::new(); let mut listeners = Vec::new(); for _ in 0..10 { listeners.push(announcement.listener()); } let data = Arc::new(vec![0u8; size]); tx.announce(data).unwrap(); for listener in listeners { black_box(listener.try_listen()); } }); }, ); } group.finish(); } criterion_group!( benches, bench_small_type, bench_medium_type, bench_large_type, bench_complex_type, bench_crossover_analysis, ); criterion_main!(benches);