use criterion::{ black_box, criterion_group, criterion_main, measurement::WallTime, BenchmarkGroup, BenchmarkId, Criterion, Throughput, }; #[cfg(feature = "std")] use nimbusqueue::synchronous_queue::Queue; #[cfg(feature = "no_std")] use nimbusqueue::crossbeam_queue::Queue; use std::time::Duration; fn bench_queues(c: &mut Criterion) { let mut group = c.benchmark_group("queue_operations"); for size in [100, 1000, 10000].iter() { group.throughput(Throughput::Elements(*size as u64)); bench_enqueue(&mut group, *size); bench_dequeue(&mut group, *size); bench_mixed(&mut group, *size); bench_iterator(&mut group, *size); // Call iterator benchmark bench_concurrent(&mut group, *size); // Call concurrent benchmark } group.finish(); } fn bench_enqueue(group: &mut BenchmarkGroup, size: usize) { // SegQueue enqueue #[cfg(feature = "no_std")] group.bench_function(BenchmarkId::new("SegQueue/enqueue", size), |b| { let queue = Queue::new_segmented(); let mut i = 0; b.iter(|| { queue.enqueue(black_box(i)).unwrap(); i = (i + 1) % size; }); }); // ArrayQueue enqueue #[cfg(feature = "no_std")] group.bench_function(BenchmarkId::new("ArrayQueue/enqueue", size), |b| { let queue = Queue::new_array(size); let mut i = 0; b.iter(|| { let _ = queue.enqueue(black_box(i)); i = (i + 1) % size; }); }); #[cfg(feature = "std")] // SyncQueue enqueue group.bench_function(BenchmarkId::new("SyncQueue/enqueue", size), |b| { let queue = Queue::new(); let mut i = 0; b.iter(|| { queue.enqueue(black_box(i)); i = (i + 1) % size; }); }); } fn bench_dequeue(group: &mut BenchmarkGroup, size: usize) { // SegQueue dequeue #[cfg(feature = "no_std")] group.bench_function(BenchmarkId::new("SegQueue/dequeue", size), |b| { b.iter_batched( || { let queue = Queue::new_segmented(); for i in 0..size { queue.enqueue(i).unwrap(); } queue }, |queue| { for _ in 0..size { black_box(queue.dequeue()); } }, criterion::BatchSize::LargeInput, ); }); // ArrayQueue dequeue #[cfg(feature = "no_std")] group.bench_function(BenchmarkId::new("ArrayQueue/dequeue", size), |b| { b.iter_batched( || { let queue = Queue::new_array(size); for i in 0..size { queue.enqueue(i).unwrap(); } queue }, |queue| { for _ in 0..size { black_box(queue.dequeue()); } }, criterion::BatchSize::LargeInput, ); }); #[cfg(feature = "std")] // SyncQueue dequeue group.bench_function(BenchmarkId::new("SyncQueue/dequeue", size), |b| { b.iter_batched( || { let queue = Queue::new(); for i in 0..size { queue.enqueue(i); } queue }, |queue| { for _ in 0..size { black_box(queue.dequeue()); } }, criterion::BatchSize::LargeInput, ); }); } fn bench_mixed(group: &mut BenchmarkGroup, size: usize) { // SegQueue mixed operations #[cfg(feature = "no_std")] group.bench_function(BenchmarkId::new("SegQueue/mixed", size), |b| { let queue = Queue::new_segmented(); b.iter(|| { for i in 0..(size / 2) { queue.enqueue(black_box(i)).unwrap(); } for _ in 0..(size / 2) { black_box(queue.dequeue()); } }); }); // ArrayQueue mixed operations #[cfg(feature = "no_std")] group.bench_function(BenchmarkId::new("ArrayQueue/mixed", size), |b| { let queue = Queue::new_array(size); b.iter(|| { for i in 0..(size / 2) { queue.enqueue(black_box(i)).unwrap(); } for _ in 0..(size / 2) { black_box(queue.dequeue()); } }); }); #[cfg(feature = "std")] // SyncQueue mixed operations group.bench_function(BenchmarkId::new("SyncQueue/mixed", size), |b| { let queue = Queue::new(); b.iter(|| { for i in 0..(size / 2) { queue.enqueue(black_box(i)); } for _ in 0..(size / 2) { black_box(queue.dequeue()); } }); }); } fn bench_iterator(group: &mut BenchmarkGroup, size: usize) { // SegQueue iterator #[cfg(feature = "no_std")] group.bench_function(BenchmarkId::new("SegQueue/iter", size), |b| { let queue = Queue::new_segmented(); for i in 0..size { queue.enqueue(i).unwrap(); } b.iter(|| { for item in queue.iter() { black_box(item); } }); }); // ArrayQueue iterator #[cfg(feature = "no_std")] group.bench_function(BenchmarkId::new("ArrayQueue/iter", size), |b| { let queue = Queue::new_array(size); for i in 0..size { queue.enqueue(i).unwrap(); } b.iter(|| { for item in queue.iter() { black_box(item); } }); }); #[cfg(feature = "std")] // SyncQueue iterator group.bench_function(BenchmarkId::new("SyncQueue/iter", size), |b| { let queue = Queue::new(); for i in 0..size { queue.enqueue(i); } b.iter(|| { for item in queue.iter() { black_box(item); } }); }); } fn bench_concurrent(group: &mut BenchmarkGroup, size: usize) { use std::sync::Arc; use std::thread; // SegQueue concurrent operations #[cfg(feature = "no_std")] group.bench_function(BenchmarkId::new("SegQueue/concurrent", size), |b| { b.iter(|| { let queue = Arc::new(Queue::new_segmented()); let mut handles = vec![]; // Spawn producer threads for i in 0..4 { let queue = Arc::clone(&queue); let handle = thread::spawn(move || { for j in 0..(size / 4) { queue.enqueue(i * (size / 4) + j).unwrap(); } }); handles.push(handle); } // Spawn consumer threads for _ in 0..4 { let queue = Arc::clone(&queue); let handle = thread::spawn(move || { for _ in 0..(size / 4) { while queue.dequeue().is_none() { thread::yield_now(); } } }); handles.push(handle); } // Wait for all threads to complete for handle in handles { handle.join().unwrap(); } }); }); // ArrayQueue concurrent operations #[cfg(feature = "no_std")] group.bench_function(BenchmarkId::new("ArrayQueue/concurrent", size), |b| { b.iter(|| { let queue = Arc::new(Queue::new_array(size)); let mut handles = vec![]; // Spawn producer threads for i in 0..4 { let queue = Arc::clone(&queue); let handle = thread::spawn(move || { for j in 0..(size / 4) { while queue.enqueue(i * (size / 4) + j).is_err() { thread::yield_now(); } } }); handles.push(handle); } // Spawn consumer threads for _ in 0..4 { let queue = Arc::clone(&queue); let handle = thread::spawn(move || { for _ in 0..(size / 4) { while queue.dequeue().is_none() { thread::yield_now(); } } }); handles.push(handle); } // Wait for all threads to complete for handle in handles { handle.join().unwrap(); } }); }); #[cfg(feature = "std")] // SyncQueue concurrent operations group.bench_function(BenchmarkId::new("SyncQueue/concurrent", size), |b| { b.iter(|| { let queue = Arc::new(Queue::new()); let mut handles = vec![]; // Spawn producer threads for i in 0..4 { let queue = Arc::clone(&queue); let handle = thread::spawn(move || { for j in 0..(size / 4) { queue.enqueue(i * (size / 4) + j); } }); handles.push(handle); } // Spawn consumer threads for _ in 0..4 { let queue = Arc::clone(&queue); let handle = thread::spawn(move || { for _ in 0..(size / 4) { queue.dequeue(); } }); handles.push(handle); } // Wait for all threads to complete for handle in handles { handle.join().unwrap(); } }); }); } criterion_group!( name = benches; config = Criterion::default() .with_plots() .sample_size(100) .measurement_time(Duration::from_secs(10)) .warm_up_time(Duration::from_secs(1)) .confidence_level(0.95) .noise_threshold(0.02); targets = bench_queues ); criterion_main!(benches);