Skip to main content

concurrent_scenario/
concurrent_scenario.rs

1// Copyright 2026 Ryan Daum
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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});