use micromeasure::{
ConcurrentBenchContext, ConcurrentBenchControl, ConcurrentWorker, ConcurrentWorkerResult,
benchmark_main, black_box,
};
use std::sync::RwLock;
use std::time::Duration;
#[derive(Default)]
struct CounterLatch {
value: RwLock<u64>,
}
impl ConcurrentBenchContext for CounterLatch {
fn prepare(_num_threads: usize) -> Self {
Self::default()
}
}
fn optimistic_reader(
ctx: &CounterLatch,
control: &ConcurrentBenchControl,
) -> ConcurrentWorkerResult {
let mut operations = 0_u64;
let mut read_misses = 0_u64;
while !control.should_stop() {
if let Ok(guard) = ctx.value.try_read() {
black_box(*guard ^ control.thread_index() as u64 ^ control.role_thread_index() as u64);
operations = operations.wrapping_add(1);
} else {
read_misses = read_misses.wrapping_add(1);
}
}
ConcurrentWorkerResult::operations(operations).with_counter("read_misses", read_misses)
}
fn exclusive_writer(
ctx: &CounterLatch,
control: &ConcurrentBenchControl,
) -> ConcurrentWorkerResult {
let mut operations = 0_u64;
while !control.should_stop() {
let mut guard = ctx.value.write().expect("rwlock poisoned");
*guard = guard.wrapping_add(control.thread_index() as u64 + 1);
black_box(*guard);
operations = operations.wrapping_add(1);
}
ConcurrentWorkerResult::operations(operations)
}
benchmark_main!(|runner| {
let workers = [
ConcurrentWorker {
name: "optimistic_reader",
threads: 3,
run: optimistic_reader,
},
ConcurrentWorker {
name: "exclusive_writer",
threads: 1,
run: exclusive_writer,
},
];
runner.concurrent_group::<CounterLatch>("Contention", |g| {
g.bench(
"rwlock_readers_vs_writer_with_counters",
Duration::from_millis(50),
&workers,
);
});
});