use std::convert::TryInto as _;
use std::sync::{Arc, Barrier};
use criterion::{black_box, criterion_group, criterion_main};
use criterion::{AxisScale, PlotConfiguration};
use basedrop::{Collector, Handle};
use rtrb_basedrop::RingBuffer;
pub fn add_function
(
group: &mut criterion::BenchmarkGroup,
id: &str,
create: Create,
push: Push,
pop: Pop,
handle: &Handle,
) where
P: Send + 'static,
C: Send + 'static,
Create: Fn(usize, &Handle) -> (P, C),
Push: Fn(&mut P, u8) -> bool + Send + Copy + 'static,
Pop: Fn(&mut C) -> Option + Send + 'static,
M: criterion::measurement::Measurement,
{
// Just a quick check if the ring buffer works as expected:
let (mut p, mut c) = create(2, handle);
assert!(pop(&mut c).is_none());
assert!(push(&mut p, 1));
assert!(push(&mut p, 2));
assert!(!push(&mut p, 3));
assert_eq!(pop(&mut c).unwrap(), 1);
assert_eq!(pop(&mut c).unwrap(), 2);
assert!(pop(&mut c).is_none());
group.throughput(criterion::Throughput::Bytes(1));
group.plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic));
group.bench_function(["large", id].concat(), |b| {
b.iter_custom(|iters| {
// Queue is so long that there is no contention between threads.
let (mut p, mut c) = create((2 * iters).try_into().unwrap(), handle);
for _ in 0..iters {
push(&mut p, 42);
}
let barrier = Arc::new(Barrier::new(2));
let push_thread = {
let barrier = Arc::clone(&barrier);
std::thread::spawn(move || {
barrier.wait();
for _ in 0..iters {
push(&mut p, black_box(42));
}
barrier.wait();
})
};
barrier.wait();
let start = std::time::Instant::now();
for _ in 0..iters {
black_box(pop(&mut c));
}
barrier.wait();
let duration = start.elapsed();
push_thread.join().unwrap();
duration
});
});
group.bench_function(["small", id].concat(), |b| {
b.iter_custom(|iters| {
// Queue is very short in order to force a lot of contention between threads.
let (mut p, mut c) = create(2, handle);
let barrier = Arc::new(Barrier::new(2));
let push_thread = {
let barrier = Arc::clone(&barrier);
std::thread::spawn(move || {
barrier.wait();
for _ in 0..iters {
while !push(&mut p, black_box(42)) {}
}
barrier.wait();
})
};
barrier.wait();
let start = std::time::Instant::now();
for _ in 0..iters {
while pop(&mut c).is_none() {}
}
barrier.wait();
let duration = start.elapsed();
push_thread.join().unwrap();
duration
});
});
}
fn criterion_benchmark(criterion: &mut criterion::Criterion) {
let collector = Collector::new();
let mut group = criterion.benchmark_group("two-threads");
add_function(
&mut group,
"",
RingBuffer::new,
|p, i| p.push(i).is_ok(),
|c| c.pop().ok(),
&collector.handle(),
);
group.finish();
}
criterion_group!(benches, criterion_benchmark);
criterion_main!(benches);