diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c46937b..832fb6f 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -28,7 +28,7 @@ jobs: - name: Install cargo tools uses: taiki-e/install-action@v2 with: - tool: cargo-hack,cargo-minimal-versions + tool: cargo-hack,cargo-minimal-versions${{ matrix.os == 'ubuntu-latest' && ',cargo-fuzz' || '' }} if: matrix.rust == 'nightly' && matrix.cargo_features == 'default' - uses: actions/checkout@v4 @@ -51,7 +51,7 @@ jobs: if: matrix.os == 'ubuntu-latest' && matrix.rust == 'nightly' && matrix.cargo_features == 'default' - name: Test - run: cargo +${{ matrix.rust }} test --no-default-features --features "${{ matrix.cargo_features }}" + run: cargo +${{ matrix.rust }} test --no-default-features --features "${{ matrix.cargo_features }}" --all-targets - name: Minimal versions # cargo-minimal-versions won't detach the path deps if we're using dev dependencies @@ -65,6 +65,21 @@ jobs: run: cargo update && cargo +${{ matrix.rust }} test --no-default-features --features "${{ matrix.cargo_features }}" if: matrix.rust == 'stable' && matrix.cargo_features == 'default' - - name: Benchmark - run: cargo +${{ matrix.rust }} bench --no-default-features --features "${{ matrix.cargo_features }}" + - name: Short Fuzz + run: | + cargo +${{ matrix.rust }} install cargo-fuzz --locked + cd fuzz || exit 1 + CFLAGS="-fsanitize=address -g -fno-omit-frame-pointer" + targets=( $(cargo metadata --format-version 1 --no-deps | jq -r ".packages[].targets[].name") ) + target_triple=$(cargo --version --verbose | grep 'host:' | cut -d ' ' -f 2) + for target in "${targets[@]}"; do + # https://github.com/rust-fuzz/cargo-fuzz/issues/355 + cargo +${{ matrix.rust }} fuzz run "$target" --target "${target_triple}" -- -max_total_time=10 + done + if: matrix.rust == 'nightly' && matrix.cargo_features == 'default' && matrix.os == 'ubuntu-latest' + + - name: Release Test + run: | + cargo +${{ matrix.rust }} test --no-default-features --features "${{ matrix.cargo_features }}" --release --all-targets if: matrix.rust == 'nightly' && matrix.cargo_features == 'default' + diff --git a/croaring/benches/benches.rs b/croaring/benches/benches.rs index e362f33..3717088 100644 --- a/croaring/benches/benches.rs +++ b/croaring/benches/benches.rs @@ -89,22 +89,36 @@ fn binops(c: &mut Criterion) { group }}; ($new:ident, $inplace:ident, $fast:ident) => {{ - let mut group = bench_op!($new, $inplace); + #[cfg(not(feature = "alloc"))] + { + bench_op!($new, $inplace) + } + #[cfg(feature = "alloc")] + { + let mut group = bench_op!($new, $inplace); - group.bench_function("fast", |b| { - b.iter(|| Bitmap::$fast(&[&bitmap1, &bitmap2])); - }); + group.bench_function("fast", |b| { + b.iter(|| Bitmap::$fast(&[&bitmap1, &bitmap2])); + }); - group + group + } }}; ($new:ident, $inplace:ident, $fast:ident, $fast_heap:ident) => {{ - let mut group = bench_op!($new, $inplace, $fast); + #[cfg(not(feature = "alloc"))] + { + bench_op!($new, $inplace, $fast) + } + #[cfg(feature = "alloc")] + { + let mut group = bench_op!($new, $inplace, $fast); - group.bench_function("fast_heap", |b| { - b.iter(|| Bitmap::$fast_heap(&[&bitmap1, &bitmap2])); - }); + group.bench_function("fast_heap", |b| { + b.iter(|| Bitmap::$fast_heap(&[&bitmap1, &bitmap2])); + }); - group + group + } }}; } @@ -134,6 +148,8 @@ fn to_vec(c: &mut Criterion) { const N: usize = 100_000; let bitmap: Bitmap = random_iter().take(N).collect(); let mut g = c.benchmark_group("collect"); + + #[cfg(feature = "alloc")] g.bench_function("to_vec", |b| { b.iter(|| bitmap.to_vec()); }); @@ -178,13 +194,20 @@ fn of(c: &mut Criterion) { } fn serialize(c: &mut Criterion) { - let mut group = c.benchmark_group("serialize"); - for &size in &[100_000, 1_000_000] { - let bitmap: Bitmap = (1..size).collect(); - group.throughput(Throughput::Elements(size.into())); - group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, _| { - b.iter(|| bitmap.serialize::()); - }); + #[cfg(not(feature = "alloc"))] + { + _ = c; + } + #[cfg(feature = "alloc")] + { + let mut group = c.benchmark_group("serialize"); + for &size in &[100_000, 1_000_000] { + let bitmap: Bitmap = (1..size).collect(); + group.throughput(Throughput::Elements(size.into())); + group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, _| { + b.iter(|| bitmap.serialize::()); + }); + } } } @@ -192,7 +215,10 @@ fn deserialize(c: &mut Criterion) { let mut group = c.benchmark_group("deserialize"); for &size in &[100_000, 1_000_000] { let bitmap: Bitmap = (1..size).collect(); - let serialized_buffer = bitmap.serialize::(); + let mut serialized_buffer = vec![0; bitmap.get_serialized_size_in_bytes::()]; + let serialized_buffer = bitmap + .try_serialize_into::(&mut serialized_buffer) + .unwrap(); group.throughput(Throughput::Elements(size.into())); group.bench_with_input(BenchmarkId::from_parameter(size), &size, |b, _| { b.iter(|| Bitmap::deserialize::(&serialized_buffer)); @@ -285,6 +311,8 @@ fn collect_bitmap64_to_vec(c: &mut Criterion) { let mut group = c.benchmark_group("collect_bitmap64_to_vec"); group.throughput(Throughput::Elements(N.into())); let bitmap = Bitmap64::from_range(0..N); + + #[cfg(feature = "alloc")] group.bench_function("to_vec", |b| { b.iter_batched(|| (), |()| bitmap.to_vec(), BatchSize::LargeInput); }); diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 43b434b..c46bc9b 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -25,18 +25,17 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.101" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac367972e516d45567c7eafc73d24e1c193dcf200a8d94e9db7b3d38b349572d" +checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" dependencies = [ "jobserver", "libc", - "once_cell", ] [[package]] name = "croaring" -version = "2.0.2" +version = "2.0.3" dependencies = [ "croaring-sys", ] @@ -52,7 +51,7 @@ dependencies = [ [[package]] name = "croaring-sys" -version = "4.1.0" +version = "4.1.1" dependencies = [ "cc", ]