concurrent_counters/
concurrent_counters.rs1use micromeasure::{
2 ConcurrentBenchContext, ConcurrentBenchControl, ConcurrentWorker, ConcurrentWorkerResult,
3 benchmark_main, black_box,
4};
5use std::sync::RwLock;
6use std::time::Duration;
7
8#[derive(Default)]
9struct CounterLatch {
10 value: RwLock<u64>,
11}
12
13impl ConcurrentBenchContext for CounterLatch {
14 fn prepare(_num_threads: usize) -> Self {
15 Self::default()
16 }
17}
18
19fn optimistic_reader(
20 ctx: &CounterLatch,
21 control: &ConcurrentBenchControl,
22) -> ConcurrentWorkerResult {
23 let mut operations = 0_u64;
24 let mut read_misses = 0_u64;
25
26 while !control.should_stop() {
27 if let Ok(guard) = ctx.value.try_read() {
28 black_box(*guard ^ control.thread_index() as u64 ^ control.role_thread_index() as u64);
29 operations = operations.wrapping_add(1);
30 } else {
31 read_misses = read_misses.wrapping_add(1);
32 }
33 }
34
35 ConcurrentWorkerResult::operations(operations).with_counter("read_misses", read_misses)
36}
37
38fn exclusive_writer(
39 ctx: &CounterLatch,
40 control: &ConcurrentBenchControl,
41) -> ConcurrentWorkerResult {
42 let mut operations = 0_u64;
43
44 while !control.should_stop() {
45 let mut guard = ctx.value.write().expect("rwlock poisoned");
46 *guard = guard.wrapping_add(control.thread_index() as u64 + 1);
47 black_box(*guard);
48 operations = operations.wrapping_add(1);
49 }
50
51 ConcurrentWorkerResult::operations(operations)
52}
53
54benchmark_main!(|runner| {
55 let workers = [
56 ConcurrentWorker {
57 name: "optimistic_reader",
58 threads: 3,
59 run: optimistic_reader,
60 },
61 ConcurrentWorker {
62 name: "exclusive_writer",
63 threads: 1,
64 run: exclusive_writer,
65 },
66 ];
67
68 runner.concurrent_group::<CounterLatch>("Contention", |g| {
69 g.bench(
70 "rwlock_readers_vs_writer_with_counters",
71 Duration::from_millis(50),
72 &workers,
73 );
74 });
75});