130 lines
3.3 KiB
Rust
130 lines
3.3 KiB
Rust
//! These are very minimal benchmarks ‒ reading and writing an integer shared in
|
||
//! different ways. You can compare the times and see the characteristics.
|
||
|
||
use std::io::{self, Write};
|
||
use std::sync::{Arc, Mutex, RwLock};
|
||
use std::time::Instant;
|
||
|
||
use arc_swap::ArcSwap;
|
||
use criterion::black_box;
|
||
use crossbeam_utils::thread;
|
||
|
||
fn test_run<R, W>(
|
||
name: &str,
|
||
read_threads: usize,
|
||
write_threads: usize,
|
||
iterations: usize,
|
||
r: R,
|
||
w: W,
|
||
) where
|
||
R: Fn() -> usize + Sync + Send,
|
||
W: Fn(usize) + Sync + Send,
|
||
{
|
||
print!(
|
||
"{:20} ({} + {}) x {}: ",
|
||
name, read_threads, write_threads, iterations
|
||
);
|
||
io::stdout().flush().unwrap();
|
||
let before = Instant::now();
|
||
thread::scope(|scope| {
|
||
for _ in 0..read_threads {
|
||
scope.spawn(|_| {
|
||
for _ in 0..iterations {
|
||
black_box(r());
|
||
}
|
||
});
|
||
}
|
||
for _ in 0..write_threads {
|
||
scope.spawn(|_| {
|
||
for i in 0..iterations {
|
||
black_box(w(i));
|
||
}
|
||
});
|
||
}
|
||
})
|
||
.unwrap();
|
||
let duration = Instant::now() - before;
|
||
println!(
|
||
"{:03}.{:03}s",
|
||
duration.as_secs(),
|
||
duration.subsec_nanos() / 100_000
|
||
);
|
||
}
|
||
|
||
fn test_round<R, W>(name: &str, iterations: usize, r: R, w: W)
|
||
where
|
||
R: Fn() -> usize + Sync + Send,
|
||
W: Fn(usize) + Sync + Send,
|
||
{
|
||
test_run(name, 1, 0, iterations, &r, &w);
|
||
test_run(name, 2, 0, iterations, &r, &w);
|
||
test_run(name, 4, 0, iterations, &r, &w);
|
||
test_run(name, 8, 0, iterations, &r, &w);
|
||
test_run(name, 1, 1, iterations, &r, &w);
|
||
test_run(name, 4, 1, iterations, &r, &w);
|
||
test_run(name, 4, 2, iterations, &r, &w);
|
||
test_run(name, 4, 4, iterations, &r, &w);
|
||
test_run(name, 8, 1, iterations, &r, &w);
|
||
test_run(name, 8, 2, iterations, &r, &w);
|
||
test_run(name, 8, 4, iterations, &r, &w);
|
||
test_run(name, 0, 1, iterations, &r, &w);
|
||
test_run(name, 0, 4, iterations, &r, &w);
|
||
}
|
||
|
||
fn main() {
|
||
let mutex = Mutex::new(42);
|
||
test_round(
|
||
"mutex",
|
||
100_000,
|
||
|| *mutex.lock().unwrap(),
|
||
|i| *mutex.lock().unwrap() = i,
|
||
);
|
||
let mutex = Mutex::new(Arc::new(42));
|
||
test_round(
|
||
"mutex-arc",
|
||
100_000,
|
||
|| **mutex.lock().unwrap(),
|
||
|i| *mutex.lock().unwrap() = Arc::new(i),
|
||
);
|
||
test_round(
|
||
"mutex-arc-clone",
|
||
100_000,
|
||
|| *Arc::clone(&*mutex.lock().unwrap()),
|
||
|i| *mutex.lock().unwrap() = Arc::new(i),
|
||
);
|
||
let lock = RwLock::new(42);
|
||
test_round(
|
||
"rw",
|
||
100_000,
|
||
|| *lock.read().unwrap(),
|
||
|i| *lock.write().unwrap() = i,
|
||
);
|
||
let lock = RwLock::new(Arc::new(42));
|
||
test_round(
|
||
"rw-arc",
|
||
100_000,
|
||
|| **lock.read().unwrap(),
|
||
|i| *lock.write().unwrap() = Arc::new(i),
|
||
);
|
||
test_round(
|
||
"rw-arc-clone",
|
||
100_000,
|
||
|| *Arc::clone(&*lock.read().unwrap()),
|
||
|i| *lock.write().unwrap() = Arc::new(i),
|
||
);
|
||
let arc = ArcSwap::from(Arc::new(42));
|
||
test_round(
|
||
"arc-load-store",
|
||
100_000,
|
||
|| **arc.load(),
|
||
|i| arc.store(Arc::new(i)),
|
||
);
|
||
test_round(
|
||
"arc-rcu",
|
||
100_000,
|
||
|| *arc.load_full(),
|
||
|i| {
|
||
arc.rcu(|_| Arc::new(i));
|
||
},
|
||
);
|
||
}
|