use compressed_intvec::prelude::*;
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
use rand::{rngs::SmallRng, RngExt, SeedableRng};
use std::time::Duration;
use succinct::int_vec::{IntVecMut, IntVector};
use sux::prelude::BitFieldVec;
use value_traits::slices::SliceByValueMut;
fn generate_random_vec(size: usize, max_val_exclusive: u64) -> Vec<u64> {
let mut rng = SmallRng::seed_from_u64(42);
if max_val_exclusive == 0 {
return (0..size).map(|_| rng.random::<u64>()).collect();
}
(0..size)
.map(|_| rng.random_range(0..max_val_exclusive))
.collect()
}
fn benchmark_mutable_ops(c: &mut Criterion) {
const VECTOR_SIZE: usize = 1_000_000;
const BIT_WIDTH: u32 = 16;
let mut group = c.benchmark_group(format!("MutableOps/{}bit", BIT_WIDTH));
group.throughput(Throughput::Elements(VECTOR_SIZE as u64));
group.sample_size(20);
let data = generate_random_vec(VECTOR_SIZE, 1u64 << BIT_WIDTH);
group.bench_function("LEFixedVec/build_from_slice", |b| {
b.iter(|| {
black_box(
LEFixedVec::builder()
.bit_width(BitWidth::Explicit(BIT_WIDTH as usize))
.build(black_box(&data))
.unwrap(),
);
})
});
group.bench_function("sux::BitFieldVec/from_slice", |b| {
b.iter(|| {
black_box(BitFieldVec::<u64>::from_slice(black_box(&data)).unwrap());
})
});
group.bench_function("Baseline_Vec<u64>/push_loop", |b| {
b.iter(|| {
let mut vec = Vec::with_capacity(VECTOR_SIZE);
for &val in black_box(&data) {
vec.push(val);
}
black_box(vec);
})
});
group.bench_function("LEFixedVec/push_loop", |b| {
b.iter(|| {
let mut vec = LEFixedVec::with_capacity(BIT_WIDTH as usize, VECTOR_SIZE).unwrap();
for &val in black_box(&data) {
vec.push(val);
}
black_box(vec);
})
});
group.bench_function("sux::BitFieldVec/push_loop", |b| {
b.iter(|| {
let mut vec = BitFieldVec::<u64>::with_capacity(BIT_WIDTH as usize, VECTOR_SIZE);
for &val in black_box(&data) {
vec.push(val);
}
black_box(vec);
})
});
group.bench_function("succinct::IntVector/push_loop", |b| {
b.iter(|| {
let mut vec = IntVector::<u64>::with_capacity(BIT_WIDTH as usize, VECTOR_SIZE as u64);
for &val in black_box(&data) {
vec.push(val);
}
black_box(vec);
})
});
const RESIZE_FROM: usize = VECTOR_SIZE / 2;
const RESIZE_TO: usize = VECTOR_SIZE;
let resize_value = data[0];
group.bench_function("Baseline_Vec<u64>/resize", |b| {
b.iter_batched(
|| data[..RESIZE_FROM].to_vec(),
|mut vec| {
vec.resize(RESIZE_TO, resize_value);
black_box(vec);
},
criterion::BatchSize::LargeInput,
);
});
group.bench_function("LEFixedVec/resize", |b| {
b.iter_batched(
|| {
LEFixedVec::builder()
.bit_width(BitWidth::Explicit(BIT_WIDTH as usize))
.build(&data[..RESIZE_FROM])
.unwrap()
},
|mut vec| {
vec.resize(RESIZE_TO, resize_value);
black_box(vec);
},
criterion::BatchSize::LargeInput,
);
});
group.bench_function("sux::BitFieldVec/resize", |b| {
b.iter_batched(
|| {
let mut vec = BitFieldVec::<u64>::with_capacity(BIT_WIDTH as usize, RESIZE_FROM);
for &val in &data[..RESIZE_FROM] {
vec.push(val);
}
vec
},
|mut vec| {
vec.resize(RESIZE_TO, resize_value);
black_box(vec);
},
criterion::BatchSize::LargeInput,
);
});
group.bench_function("succinct::VarVector/resize", |b| {
b.iter_batched(
|| {
let mut vec =
IntVector::<u64>::with_capacity(BIT_WIDTH as usize, RESIZE_FROM as u64);
for &val in &data[..RESIZE_FROM] {
vec.push(val);
}
vec
},
|mut vec| {
vec.resize(RESIZE_TO as u64, resize_value);
black_box(vec);
},
criterion::BatchSize::LargeInput,
);
});
const NUM_SETS: usize = 100_000;
let mut rng = SmallRng::seed_from_u64(1338);
let set_indices: Vec<usize> = (0..NUM_SETS)
.map(|_| rng.random_range(0..VECTOR_SIZE))
.collect();
let set_values: Vec<u64> = generate_random_vec(NUM_SETS, 1u64 << BIT_WIDTH);
let base_le_fixed_vec = LEFixedVec::builder()
.bit_width(BitWidth::Explicit(BIT_WIDTH as usize))
.build(&data)
.unwrap();
let base_sux_bfv = BitFieldVec::<u64>::from_slice(&data).unwrap();
let mut base_succinct_iv =
IntVector::<u64>::with_capacity(BIT_WIDTH as usize, VECTOR_SIZE as u64);
for &val in &data {
base_succinct_iv.push(val);
}
group.bench_function("LEFixedVec/set_unchecked_random", |b| {
b.iter_batched(
|| base_le_fixed_vec.clone(),
|mut vec| {
for i in 0..NUM_SETS {
unsafe { vec.set_unchecked(set_indices[i], set_values[i]) };
}
black_box(vec);
},
criterion::BatchSize::LargeInput,
);
});
group.bench_function("sux::BitFieldVec/set_unchecked_random", |b| {
b.iter_batched(
|| base_sux_bfv.clone(),
|mut vec| {
for i in 0..NUM_SETS {
unsafe { vec.set_value_unchecked(set_indices[i], set_values[i]) };
}
black_box(vec);
},
criterion::BatchSize::LargeInput,
);
});
group.bench_function("succinct::VarVector/set_random", |b| {
b.iter_batched(
|| base_succinct_iv.clone(),
|mut vec| {
for i in 0..NUM_SETS {
vec.set(set_indices[i] as u64, set_values[i]);
}
black_box(vec);
},
criterion::BatchSize::LargeInput,
);
});
group.finish();
}
criterion_group! {
name = benches;
config = Criterion::default()
.sample_size(20)
.warm_up_time(Duration::from_millis(100))
.measurement_time(Duration::from_secs(3));
targets = benchmark_mutable_ops
}
criterion_main!(benches);