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