diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 0d51309..0d2c683 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -11,6 +11,7 @@ env: CARGO_INCREMENTAL: 0 jobs: + # Ensure the crate builds build: runs-on: ubuntu-latest @@ -32,6 +33,7 @@ jobs: cargo test --verbose --features "$FEATURES" && cargo test --verbose --release --features "$FEATURES" + # Use clippy to lint for code smells clippy: runs-on: ubuntu-latest @@ -52,6 +54,7 @@ jobs: run: | cargo clippy + # Enforce rustfmt formatting formatting: runs-on: ubuntu-latest @@ -70,4 +73,26 @@ jobs: override: true - name: Run Clippy run: | - cargo fmt --all --check \ No newline at end of file + cargo fmt --all --check + + # Ensure the benchmarks compile + benchmark_compiles: + + runs-on: ubuntu-latest + strategy: + matrix: + # Check builds only on stable + rust: [stable] + + steps: + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@stable + with: + profile: minimal + toolchain: ${{ matrix.rust }} + components: clippy + override: true + - name: Run Clippy + run: | + cd benches + cargo bench --bench benches --no-run \ No newline at end of file diff --git a/benches/Cargo.toml b/benches/Cargo.toml new file mode 100644 index 0000000..76f2fe6 --- /dev/null +++ b/benches/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "benches" +version = "0.1.0" +edition = "2021" +description = "Benchmarks for FixedBitset" +publish = false +license = "MIT OR Apache-2.0" + +[dev-dependencies] +fixedbitset = { path = ".." } +criterion = { version = "0.4", features = ["html_reports"] } + +[[bench]] +name = "benches" +harness = false \ No newline at end of file diff --git a/benches/benches.rs b/benches/benches.rs deleted file mode 100644 index 12fcb77..0000000 --- a/benches/benches.rs +++ /dev/null @@ -1,131 +0,0 @@ -#![feature(test)] - -extern crate fixedbitset; -extern crate test; -use fixedbitset::{Block, FixedBitSet}; -use std::mem::size_of; -use test::Bencher; - -#[inline] -fn iter_ones_using_contains(fb: &FixedBitSet, f: &mut F) { - for bit in 0..fb.len() { - if fb.contains(bit) { - f(bit); - } - } -} - -#[inline] -fn iter_ones_using_slice_directly(fb: &FixedBitSet, f: &mut F) { - for (block_idx, &block) in fb.as_slice().iter().enumerate() { - let mut bit_pos = block_idx * size_of::() * 8; - let mut block: Block = block; - - while block != 0 { - if (block & 1) == 1 { - f(bit_pos); - } - block = block >> 1; - bit_pos += 1; - } - } -} - -#[bench] -fn bench_iter_ones_using_contains_all_zeros(b: &mut Bencher) { - const N: usize = 1_000_000; - let fb = FixedBitSet::with_capacity(N); - - b.iter(|| { - let mut count = 0; - iter_ones_using_contains(&fb, &mut |_bit| count += 1); - count - }); -} - -#[bench] -fn bench_iter_ones_using_contains_all_ones(b: &mut Bencher) { - const N: usize = 1_000_000; - let mut fb = FixedBitSet::with_capacity(N); - fb.insert_range(..); - - b.iter(|| { - let mut count = 0; - iter_ones_using_contains(&fb, &mut |_bit| count += 1); - count - }); -} - -#[bench] -fn bench_iter_ones_using_slice_directly_all_zero(b: &mut Bencher) { - const N: usize = 1_000_000; - let fb = FixedBitSet::with_capacity(N); - - b.iter(|| { - let mut count = 0; - iter_ones_using_slice_directly(&fb, &mut |_bit| count += 1); - count - }); -} - -#[bench] -fn bench_iter_ones_using_slice_directly_all_ones(b: &mut Bencher) { - const N: usize = 1_000_000; - let mut fb = FixedBitSet::with_capacity(N); - fb.insert_range(..); - - b.iter(|| { - let mut count = 0; - iter_ones_using_slice_directly(&fb, &mut |_bit| count += 1); - count - }); -} - -#[bench] -fn bench_iter_ones_all_zeros(b: &mut Bencher) { - const N: usize = 1_000_000; - let fb = FixedBitSet::with_capacity(N); - - b.iter(|| { - let mut count = 0; - for _ in fb.ones() { - count += 1; - } - count - }); -} - -#[bench] -fn bench_iter_ones_all_ones(b: &mut Bencher) { - const N: usize = 1_000_000; - let mut fb = FixedBitSet::with_capacity(N); - fb.insert_range(..); - - b.iter(|| { - let mut count = 0; - for _ in fb.ones() { - count += 1; - } - count - }); -} - -#[bench] -fn bench_insert_range(b: &mut Bencher) { - const N: usize = 1_000_000; - let mut fb = FixedBitSet::with_capacity(N); - - b.iter(|| fb.insert_range(..)); -} - -#[bench] -fn bench_insert_range_using_loop(b: &mut Bencher) { - const N: usize = 1_000_000; - let mut fb = FixedBitSet::with_capacity(N); - - b.iter(|| { - for i in 0..N { - fb.insert(i); - } - }); -} diff --git a/benches/benches/benches.rs b/benches/benches/benches.rs new file mode 100644 index 0000000..b8c4ba6 --- /dev/null +++ b/benches/benches/benches.rs @@ -0,0 +1,163 @@ +extern crate criterion; +extern crate fixedbitset; +use criterion::{criterion_group, criterion_main, Criterion}; +use fixedbitset::FixedBitSet; +use std::hint::black_box; + +#[inline] +fn iter_ones_using_contains(fb: &FixedBitSet, f: &mut F) { + for bit in 0..fb.len() { + if fb.contains(bit) { + f(bit); + } + } +} + +fn iter_ones_using_contains_all_zeros(c: &mut Criterion) { + const N: usize = 1_000_000; + let fb = FixedBitSet::with_capacity(N); + + c.bench_function("iter_ones/contains_all_zeros", |b| { + b.iter(|| { + let mut count = 0; + iter_ones_using_contains(&fb, &mut |_bit| count += 1); + count + }) + }); +} + +fn iter_ones_using_contains_all_ones(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb = FixedBitSet::with_capacity(N); + fb.insert_range(..); + + c.bench_function("iter_ones/contains_all_ones", |b| { + b.iter(|| { + let mut count = 0; + iter_ones_using_contains(&fb, &mut |_bit| count += 1); + count + }) + }); +} + +fn iter_ones_all_zeros(c: &mut Criterion) { + const N: usize = 1_000_000; + let fb = FixedBitSet::with_capacity(N); + + c.bench_function("iter_ones/all_zeros", |b| { + b.iter(|| { + let mut count = 0; + for _ in fb.ones() { + count += 1; + } + count + }) + }); +} + +fn iter_ones_all_ones(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb = FixedBitSet::with_capacity(N); + fb.insert_range(..); + + c.bench_function("iter_ones/all_ones", |b| { + b.iter(|| { + let mut count = 0; + for _ in fb.ones() { + count += 1; + } + count + }) + }); +} + +fn insert_range(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb = FixedBitSet::with_capacity(N); + + c.bench_function("insert_range/1m", |b| b.iter(|| fb.insert_range(..))); +} + +fn insert(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb = FixedBitSet::with_capacity(N); + + c.bench_function("insert/1m", |b| { + b.iter(|| { + for i in 0..N { + fb.insert(i); + } + }) + }); +} + +fn union_with(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb_a = FixedBitSet::with_capacity(N); + let fb_b = FixedBitSet::with_capacity(N); + + c.bench_function("union_with/1m", |b| b.iter(|| fb_a.union_with(&fb_b))); +} + +fn intersect_with(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb_a = FixedBitSet::with_capacity(N); + let fb_b = FixedBitSet::with_capacity(N); + + c.bench_function("intersect_with/1m", |b| { + b.iter(|| fb_a.intersect_with(&fb_b)) + }); +} + +fn difference_with(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb_a = FixedBitSet::with_capacity(N); + let fb_b = FixedBitSet::with_capacity(N); + + c.bench_function("difference_with/1m", |b| { + b.iter(|| fb_a.difference_with(&fb_b)) + }); +} + +fn symmetric_difference_with(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb_a = FixedBitSet::with_capacity(N); + let fb_b = FixedBitSet::with_capacity(N); + + c.bench_function("symmetric_difference_with/1m", |b| { + b.iter(|| fb_a.symmetric_difference_with(&fb_b)) + }); +} + +fn clear(c: &mut Criterion) { + const N: usize = 1_000_000; + let mut fb_a = FixedBitSet::with_capacity(N); + + c.bench_function("clear/1m", |b| b.iter(|| fb_a.clear())); +} + +fn count_ones(c: &mut Criterion) { + const N: usize = 1_000_000; + let fb_a = FixedBitSet::with_capacity(N); + + c.bench_function("count_ones/1m", |b| { + b.iter(|| black_box(fb_a.count_ones(..))) + }); +} + +criterion_group!( + benches, + iter_ones_using_contains_all_zeros, + iter_ones_using_contains_all_ones, + iter_ones_all_zeros, + iter_ones_all_ones, + insert_range, + insert, + intersect_with, + difference_with, + union_with, + symmetric_difference_with, + count_ones, + clear, +); +criterion_main!(benches);