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); bench_concurrent(&mut group, *size); }
group.finish();
}
fn bench_enqueue(group: &mut BenchmarkGroup<WallTime>, size: usize) {
#[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;
});
});
#[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")]
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<WallTime>, size: usize) {
#[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,
);
});
#[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")]
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<WallTime>, size: usize) {
#[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());
}
});
});
#[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")]
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<WallTime>, size: usize) {
#[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);
}
});
});
#[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")]
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<WallTime>, size: usize) {
use std::sync::Arc;
use std::thread;
#[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![];
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);
}
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);
}
for handle in handles {
handle.join().unwrap();
}
});
});
#[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![];
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);
}
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);
}
for handle in handles {
handle.join().unwrap();
}
});
});
#[cfg(feature = "std")]
group.bench_function(BenchmarkId::new("SyncQueue/concurrent", size), |b| {
b.iter(|| {
let queue = Arc::new(Queue::new());
let mut handles = vec![];
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);
}
for _ in 0..4 {
let queue = Arc::clone(&queue);
let handle = thread::spawn(move || {
for _ in 0..(size / 4) {
queue.dequeue();
}
});
handles.push(handle);
}
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);