From 1dae104ef46f3c82eaef5a97443b708c99760cc5 Mon Sep 17 00:00:00 2001 From: Zachary Dremann Date: Sun, 28 Jan 2024 02:41:38 -0500 Subject: [PATCH] Try using serialzation to speed up bitmap/treemap compare --- fuzz/fuzz_targets/arbitrary_ops64/mod.rs | 57 +++++++++++++----------- fuzz/fuzz_targets/fuzz_ops64.rs | 16 +++++-- 2 files changed, 43 insertions(+), 30 deletions(-) diff --git a/fuzz/fuzz_targets/arbitrary_ops64/mod.rs b/fuzz/fuzz_targets/arbitrary_ops64/mod.rs index d61075d..c923ae2 100644 --- a/fuzz/fuzz_targets/arbitrary_ops64/mod.rs +++ b/fuzz/fuzz_targets/arbitrary_ops64/mod.rs @@ -15,7 +15,7 @@ impl<'a> Arbitrary<'a> for Num { } } -#[derive(Arbitrary, Debug)] +#[derive(Arbitrary, Debug, PartialEq, Eq)] pub enum MutableBitmapOperation { Add(Num), AddChecked(Num), @@ -33,13 +33,13 @@ pub enum MutableBitmapOperation { AddToMax(u16), } -#[derive(Arbitrary, Debug)] +#[derive(Arbitrary, Debug, PartialEq, Eq)] pub enum MutableRhsBitmapOperation { MutateSelf(MutableBitmapOperation), MutBinaryOp(BitmapMutBinop), } -#[derive(Arbitrary, Debug)] +#[derive(Arbitrary, Debug, PartialEq, Eq)] pub enum BitmapMutBinop { And, Or, @@ -91,7 +91,7 @@ impl BitmapMutBinop { } } -#[derive(Arbitrary, Debug)] +#[derive(Arbitrary, Debug, PartialEq, Eq)] pub enum BitmapCompOperation { Eq, IsSubset, @@ -104,11 +104,11 @@ pub enum BitmapCompOperation { AndNot, } -#[derive(Arbitrary, Debug)] +#[derive(Arbitrary, Debug, PartialEq, Eq)] pub enum ReadBitmapOp { - ContainsRange(RangeInclusive), - Contains(Num), - RangeCardinality(RangeInclusive), + ContainsRange(RangeInclusive), + Contains(u64), + RangeCardinality(RangeInclusive), Cardinality, ToVec, GetPortableSerializedSizeInBytes, @@ -118,13 +118,12 @@ pub enum ReadBitmapOp { GetFrozenSerializedSizeInBytes, */ IsEmpty, - AddOffset(i64), - IntersectWithRange(RangeInclusive), + IntersectWithRange(RangeInclusive), Minimum, Maximum, - Rank(Num), - Index(Num), - Select(Num), + Rank(u64), + Index(u64), + Select(u64), Clone, Debug, } @@ -132,18 +131,18 @@ pub enum ReadBitmapOp { impl ReadBitmapOp { pub fn check_against_tree(&self, b: &Bitmap64, t: &Treemap) { match *self { - ReadBitmapOp::Contains(Num(i)) => { + ReadBitmapOp::Contains(i) => { assert_eq!(b.contains(i), t.contains(i)); } ReadBitmapOp::RangeCardinality(ref r) => { // Tree doesn't implement directly, but we can do it manually let mut t_with_range = t.clone(); if !r.is_empty() { - t_with_range.remove_range(0..r.start().0); - t_with_range.remove_range(r.end().0 + 1..); + t_with_range.remove_range(0..*r.start()); + t_with_range.remove_range(r.end() + 1..); } assert_eq!( - b.range_cardinality(r.start().0..=r.end().0), + b.range_cardinality(r.start()..=r.end()), t_with_range.cardinality() ); } @@ -160,13 +159,13 @@ impl ReadBitmapOp { ReadBitmapOp::Maximum => { assert_eq!(b.maximum(), t.maximum()); } - ReadBitmapOp::Rank(Num(i)) => { + ReadBitmapOp::Rank(i) => { assert_eq!(b.rank(i), t.rank(i)); } - ReadBitmapOp::Index(Num(i)) => { + ReadBitmapOp::Index(i) => { assert_eq!(b.position(i), t.position(i)); } - ReadBitmapOp::Select(Num(i)) => { + ReadBitmapOp::Select(i) => { assert_eq!(b.select(i), t.select(i)); } ReadBitmapOp::Clone => { @@ -192,14 +191,11 @@ impl ReadBitmapOp { } ReadBitmapOp::ContainsRange(ref range) => { // Unsupported by treemaps - _ = b.contains_range(range.start().0..=range.end().0); - } - ReadBitmapOp::AddOffset(_) => { - // Unsupported + _ = b.contains_range(range.start()..=range.end()); } ReadBitmapOp::IntersectWithRange(ref range) => { // Unsupported by treemaps - _ = b.intersect_with_range(range.start().0..=range.end().0); + _ = b.intersect_with_range(range.start()..=range.end()); } } } @@ -414,5 +410,14 @@ impl BitmapCompOperation { pub fn assert_64_eq(lhs: &Bitmap64, rhs: &Treemap) { assert_eq!(lhs.cardinality(), rhs.cardinality()); - assert!(lhs.iter().eq(rhs.iter())); + if lhs.serialize::() != rhs.serialize::() { + let mut lhs = lhs.iter().enumerate(); + let mut rhs = rhs.iter(); + while let Some((i, l)) = lhs.next() { + let r = rhs.next().unwrap(); + assert_eq!(l, r, "{l} != {r} at {i}"); + } + assert!(rhs.next().is_none()); + panic!("Serialize not equal, but all items equal?") + } } diff --git a/fuzz/fuzz_targets/fuzz_ops64.rs b/fuzz/fuzz_targets/fuzz_ops64.rs index ccdaf01..fcd1e98 100644 --- a/fuzz/fuzz_targets/fuzz_ops64.rs +++ b/fuzz/fuzz_targets/fuzz_ops64.rs @@ -9,11 +9,19 @@ use libfuzzer_sys::fuzz_target; mod arbitrary_ops64; fuzz_target!(|input: FuzzInput| { - let mut lhs64 = Bitmap64::deserialize::(input.initial_input); + // TODO: Deserialization isn't safe yet without internal validate + // let mut lhs64 = Bitmap64::deserialize::(input.initial_input); + // let mut lhs_tree = Treemap::from_iter(lhs64.iter()); + let mut lhs64 = Bitmap64::new(); let mut rhs64 = Bitmap64::new(); - let mut lhs_tree = Treemap::from_iter(lhs64.iter()); + let mut lhs_tree = Treemap::new(); let mut rhs_tree = Treemap::new(); + let mut input = input; + // Only dedup read-only ops + input.compares.dedup(); + input.view_ops.dedup(); + for op in input.lhs_ops.iter().take(10) { op.on_bitmap64(&mut lhs64); op.on_treemap(&mut lhs_tree); @@ -34,10 +42,10 @@ fuzz_target!(|input: FuzzInput| { }); #[derive(Arbitrary, Debug)] -struct FuzzInput<'a> { +struct FuzzInput { lhs_ops: Vec, rhs_ops: Vec, compares: Vec, view_ops: Vec, - initial_input: &'a [u8], + // initial_input: &'a [u8], }