167 lines
5.3 KiB
Rust
167 lines
5.3 KiB
Rust
use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput};
|
|
use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner};
|
|
use rangemap::*;
|
|
use std::{any::type_name, fmt::Debug, ops::*};
|
|
use test_strategy::Arbitrary;
|
|
|
|
type Key = i64;
|
|
type Value = i64;
|
|
|
|
const COUNT: usize = 100000;
|
|
const OPERATIONS: usize = 100000;
|
|
const LOOKUPS: usize = 1000000;
|
|
|
|
#[derive(Debug, Clone, Arbitrary)]
|
|
enum Operation<K, V> {
|
|
Insert(K, V),
|
|
Delete(K),
|
|
}
|
|
|
|
fn range_inclusive_map<K: Ord + StepLite + Debug + Clone, V: Eq + Clone + Debug>(
|
|
values: impl Strategy<Value = (RangeInclusive<K>, V)>,
|
|
size: usize,
|
|
) -> impl Strategy<Value = RangeInclusiveMap<K, V>> {
|
|
prop::collection::vec(values, size)
|
|
.prop_map(|ranges| ranges.into_iter().collect::<RangeInclusiveMap<K, V>>())
|
|
}
|
|
|
|
fn range_map<K: Ord + StepLite + Debug + Clone, V: Eq + Clone + Debug>(
|
|
values: impl Strategy<Value = (Range<K>, V)>,
|
|
size: usize,
|
|
) -> impl Strategy<Value = RangeMap<K, V>> {
|
|
prop::collection::vec(values, size)
|
|
.prop_map(|ranges| ranges.into_iter().collect::<RangeMap<K, V>>())
|
|
}
|
|
|
|
fn criterion_benchmark(c: &mut Criterion) {
|
|
let mut runner = TestRunner::deterministic();
|
|
|
|
let mut group = c.benchmark_group(format!(
|
|
"RangeMap<{}, {}>",
|
|
type_name::<Key>(),
|
|
type_name::<Value>()
|
|
));
|
|
|
|
group.throughput(Throughput::Elements(COUNT as u64));
|
|
group.bench_function("insert", |b| {
|
|
let entries = prop::collection::vec(any::<(Range<Key>, Value)>(), COUNT)
|
|
.new_tree(&mut runner)
|
|
.unwrap()
|
|
.current();
|
|
b.iter_with_large_drop(|| {
|
|
let mut map = RangeMap::new();
|
|
for (range, value) in entries.clone().into_iter() {
|
|
map.insert(range, value);
|
|
}
|
|
map
|
|
})
|
|
});
|
|
|
|
group.throughput(Throughput::Elements(OPERATIONS as u64));
|
|
group.bench_function("operations", |b| {
|
|
let map = range_map(any::<(Range<Key>, Value)>(), COUNT)
|
|
.new_tree(&mut runner)
|
|
.unwrap()
|
|
.current();
|
|
let operations = prop::collection::vec(any::<Operation<Range<Key>, Value>>(), OPERATIONS)
|
|
.new_tree(&mut runner)
|
|
.unwrap()
|
|
.current();
|
|
b.iter_with_large_drop(|| {
|
|
let mut map = map.clone();
|
|
for operation in operations.clone().into_iter() {
|
|
match operation {
|
|
Operation::Insert(key, value) => map.insert(key, value),
|
|
Operation::Delete(key) => map.remove(key),
|
|
}
|
|
}
|
|
map
|
|
})
|
|
});
|
|
|
|
group.throughput(Throughput::Elements(LOOKUPS as u64));
|
|
group.bench_function("lookups", |b| {
|
|
let map = range_map(any::<(Range<Key>, Value)>(), COUNT)
|
|
.new_tree(&mut runner)
|
|
.unwrap()
|
|
.current();
|
|
let lookups = prop::collection::vec(any::<Key>(), LOOKUPS)
|
|
.new_tree(&mut runner)
|
|
.unwrap()
|
|
.current();
|
|
b.iter(|| {
|
|
for lookup in lookups.iter() {
|
|
black_box(map.get(lookup));
|
|
}
|
|
})
|
|
});
|
|
|
|
group.finish();
|
|
|
|
let mut group = c.benchmark_group(format!(
|
|
"RangeInclusiveMap<{}, {}>",
|
|
type_name::<Key>(),
|
|
type_name::<Value>()
|
|
));
|
|
|
|
group.throughput(Throughput::Elements(COUNT as u64));
|
|
group.bench_function("insert", |b| {
|
|
let entries = prop::collection::vec(any::<(RangeInclusive<Key>, Value)>(), COUNT)
|
|
.new_tree(&mut runner)
|
|
.unwrap()
|
|
.current();
|
|
b.iter_with_large_drop(|| {
|
|
let mut map = RangeInclusiveMap::new();
|
|
for (range, value) in entries.clone().into_iter() {
|
|
map.insert(range, value);
|
|
}
|
|
map
|
|
})
|
|
});
|
|
|
|
group.throughput(Throughput::Elements(OPERATIONS as u64));
|
|
group.bench_function("operations", |b| {
|
|
let map = range_inclusive_map(any::<(RangeInclusive<Key>, Value)>(), COUNT)
|
|
.new_tree(&mut runner)
|
|
.unwrap()
|
|
.current();
|
|
let operations =
|
|
prop::collection::vec(any::<Operation<RangeInclusive<Key>, Value>>(), OPERATIONS)
|
|
.new_tree(&mut runner)
|
|
.unwrap()
|
|
.current();
|
|
b.iter_with_large_drop(|| {
|
|
let mut map = map.clone();
|
|
for operation in operations.clone().into_iter() {
|
|
match operation {
|
|
Operation::Insert(key, value) => map.insert(key, value),
|
|
Operation::Delete(key) => map.remove(key),
|
|
}
|
|
}
|
|
map
|
|
})
|
|
});
|
|
|
|
group.throughput(Throughput::Elements(LOOKUPS as u64));
|
|
group.bench_function("lookups", |b| {
|
|
let map = range_inclusive_map(any::<(RangeInclusive<Key>, Value)>(), COUNT)
|
|
.new_tree(&mut runner)
|
|
.unwrap()
|
|
.current();
|
|
let lookups = prop::collection::vec(any::<Key>(), LOOKUPS)
|
|
.new_tree(&mut runner)
|
|
.unwrap()
|
|
.current();
|
|
b.iter(|| {
|
|
for lookup in lookups.iter() {
|
|
black_box(map.get(lookup));
|
|
}
|
|
})
|
|
});
|
|
|
|
group.finish();
|
|
}
|
|
|
|
criterion_group!(benches, criterion_benchmark);
|
|
criterion_main!(benches);
|