diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6753492..b486142 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,8 @@ jobs: - uses: actions-rs/cargo@v1 with: command: build - args: --all-features + # --all-targets ensures that we also build the benchmarks and tests already. + args: --all-features --all-targets - uses: actions-rs/cargo@v1 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index d3264fd..06233fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,13 +7,15 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Added -- Added generic support for wrapping mutexes that implement the traits provided by the +- Generic support for wrapping mutexes that implement the traits provided by the [`lock_api`][lock_api] crate. This can be used for creating support for other mutex providers that implement it. -- Added support for [`parking_lot`][parking_lot] mutexes. Support includes type aliases for all +- Support for [`parking_lot`][parking_lot] mutexes. Support includes type aliases for all provided mutex types as well as a dedicated `Once` wrapper. +- Simple benchmark to track the rough performance penalty incurred by dependency tracking. + ## [0.1.2] - 2021-05-27 ### Added diff --git a/Cargo.toml b/Cargo.toml index d48a6b4..47bcb36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,13 @@ lock_api = { version = "0.4", optional = true } parking_lot = { version = "0.11", optional = true } [dev-dependencies] +criterion = "0.3" rand = "0.8" +[[bench]] +name = "mutex" +harness = false + [features] # Feature names do not match crate names pending namespaced features. lockapi = ["lock_api"] diff --git a/benches/mutex.rs b/benches/mutex.rs new file mode 100644 index 0000000..0c75198 --- /dev/null +++ b/benches/mutex.rs @@ -0,0 +1,82 @@ +use std::sync::Arc; +use std::sync::Mutex; + +use criterion::criterion_group; +use criterion::criterion_main; +use criterion::BenchmarkId; +use criterion::Criterion; +use criterion::Throughput; +use rand::prelude::*; +use tracing_mutex::stdsync::TracingMutex; + +const SAMPLE_SIZES: [usize; 5] = [10, 30, 100, 300, 1000]; + +/// Reproducibly generate random combinations a, b where the index(a) < index(b) +/// +/// All combinations are generated +fn generate_combinations(options: &[Arc]) -> Vec<(Arc, Arc)> { + let mut combinations = Vec::new(); + + for (i, first) in options.iter().enumerate() { + for second in options.iter().skip(i + 1) { + combinations.push((Arc::clone(first), Arc::clone(second))); + } + } + + let mut rng = StdRng::seed_from_u64(42); + + combinations.shuffle(&mut rng); + + combinations +} + +/// Take two arbitrary mutexes, lock the first, lock the second while holding the first. +fn benchmark_baseline(c: &mut Criterion) { + let mut group = c.benchmark_group("baseline"); + + for nodes in SAMPLE_SIZES { + group.throughput(Throughput::Elements((nodes * (nodes - 1) / 2) as u64)); + group.bench_with_input(BenchmarkId::from_parameter(nodes), &nodes, |b, &s| { + b.iter_batched( + || { + let mutexes: Vec<_> = (0..s).map(|_| Arc::new(Mutex::new(()))).collect(); + generate_combinations(&mutexes) + }, + |combinations| { + for (first, second) in combinations { + let _first = first.lock(); + let _second = second.lock(); + } + }, + criterion::BatchSize::SmallInput, + ) + }); + } +} + +/// Same as [`benchmark_baseline`] but now while tracking dependencies. +fn benchmark_tracing_mutex(c: &mut Criterion) { + let mut group = c.benchmark_group("tracing_mutex"); + + for nodes in SAMPLE_SIZES { + group.throughput(Throughput::Elements((nodes * (nodes - 1) / 2) as u64)); + group.bench_with_input(BenchmarkId::from_parameter(nodes), &nodes, |b, &s| { + b.iter_batched( + || { + let mutexes: Vec<_> = (0..s).map(|_| Arc::new(TracingMutex::new(()))).collect(); + generate_combinations(&mutexes) + }, + |combinations| { + for (first, second) in combinations { + let _first = first.lock(); + let _second = second.lock(); + } + }, + criterion::BatchSize::SmallInput, + ) + }); + } +} + +criterion_group!(benches, benchmark_baseline, benchmark_tracing_mutex); +criterion_main!(benches);