surrealpatch/lib/benches/hash_trie_btree.rs
2024-03-08 10:58:07 +00:00

200 lines
5.3 KiB
Rust

use criterion::measurement::WallTime;
use criterion::{criterion_group, criterion_main, BenchmarkGroup, Criterion, Throughput};
use radix_trie::{Trie, TrieCommon, TrieKey};
use std::collections::{BTreeMap, HashMap};
use std::hash::Hash;
use std::time::Duration;
use surrealdb::key::table::ix;
use surrealdb_core::sql::{value, Array, Id, Thing};
// Common use case: VectorSearch
fn bench_hash_trie_btree_large_vector(c: &mut Criterion) {
const N: usize = 10_000;
let mut samples = Vec::with_capacity(N);
for i in 0..N {
let key = vec![i as u64; 1536];
samples.push((key, i));
}
let mut g = new_group(c, "bench_hash_trie_btree_large_vector", N);
bench_hash(&mut g, &samples);
bench_trie(&mut g, &samples);
bench_btree(&mut g, &samples);
g.finish();
}
fn bench_hash_trie_btree_ix_key(c: &mut Criterion) {
const N: usize = 100_000;
let mut samples = Vec::with_capacity(N);
for i in 0..N {
let key = ix::new("test", "test", "test", &format!("test{i}")).encode().unwrap();
samples.push((key, i));
}
let mut g = new_group(c, "bench_hash_trie_btree_ix_key", N);
bench_hash(&mut g, &samples);
bench_trie(&mut g, &samples);
bench_btree(&mut g, &samples);
g.finish();
}
fn bench_hash_trie_btree_small_string(c: &mut Criterion) {
const N: usize = 100_000;
let mut samples = Vec::with_capacity(N);
for i in 0..N {
let key = format!("test{i}");
samples.push((key, i));
}
let mut g = new_group(c, "bench_hash_trie_btree_string", N);
bench_hash(&mut g, &samples);
bench_trie(&mut g, &samples);
bench_btree(&mut g, &samples);
g.finish();
}
fn bench_hash_trie_btree_value(c: &mut Criterion) {
const N: usize = 100_000;
let mut samples = Vec::with_capacity(N);
for i in 0..N {
let key = value(&format!("{{ test: {{ something: [1, 'two', null, test:{i}, {{ trueee: false, noneee: nulll }}] }} }}")).unwrap();
samples.push((key, i));
}
let mut g = new_group(c, "bench_hash_trie_btree_value", N);
bench_hash(&mut g, &samples);
bench_btree(&mut g, &samples);
g.finish();
}
fn bench_hash_trie_btree_thing(c: &mut Criterion) {
const N: usize = 50_000;
let mut samples = Vec::with_capacity(N);
for i in 0..N {
let key = Thing::from(("test", Id::Array(Array::from(vec![i as i32; 5]))));
samples.push((key, i));
}
let mut g = new_group(c, "bench_hash_trie_btree_thing", N);
bench_hash(&mut g, &samples);
bench_btree(&mut g, &samples);
g.finish();
}
fn new_group<'a>(c: &'a mut Criterion, group: &str, n: usize) -> BenchmarkGroup<'a, WallTime> {
let mut group = c.benchmark_group(group);
group.throughput(Throughput::Elements(n as u64));
group.sample_size(10);
group.measurement_time(Duration::from_secs(10));
group
}
fn bench_hash<K: Hash + Eq + Clone, V: Clone>(
group: &mut BenchmarkGroup<WallTime>,
samples: &[(K, V)],
) {
group.bench_function("hash_insert", |b| {
b.iter(|| bench_hash_insert(samples));
});
group.bench_function("hash_get", |b| {
let map = build_hash(samples);
b.iter(|| bench_hash_get(samples, &map));
});
}
fn bench_trie<K: TrieKey + Clone, V: Clone>(
group: &mut BenchmarkGroup<WallTime>,
samples: &[(K, V)],
) {
group.bench_function("trie_insert", |b| {
b.iter(|| bench_trie_insert(samples));
});
group.bench_function("trie_get", |b| {
let map = build_trie(samples);
b.iter(|| bench_trie_get(samples, &map));
});
}
fn bench_btree<K: Eq + Ord + Clone, V: Clone>(
group: &mut BenchmarkGroup<WallTime>,
samples: &[(K, V)],
) {
group.bench_function("btree_insert", |b| {
b.iter(|| bench_btree_insert(samples));
});
group.bench_function("btree_get", |b| {
let map = build_btree(samples);
b.iter(|| bench_btree_get(samples, &map));
});
}
fn build_hash<K: Hash + Eq + Clone, V: Clone>(samples: &[(K, V)]) -> HashMap<K, V> {
let mut map = HashMap::default();
for (key, val) in samples {
map.insert(key.clone(), val.clone());
}
map
}
fn bench_hash_insert<K: Hash + Eq + Clone, V: Clone>(samples: &[(K, V)]) {
let map = build_hash(samples);
assert_eq!(map.len(), samples.len());
}
fn bench_hash_get<K: Hash + Eq, V>(samples: &[(K, V)], map: &HashMap<K, V>) {
for (key, _) in samples {
assert!(map.get(key).is_some());
}
assert_eq!(map.len(), samples.len());
}
fn build_trie<K: TrieKey + Clone, V: Clone>(samples: &[(K, V)]) -> Trie<K, V> {
let mut map = Trie::default();
for (key, val) in samples {
map.insert(key.clone(), val.clone());
}
map
}
fn bench_trie_insert<K: TrieKey + Clone, V: Clone>(samples: &[(K, V)]) {
let map = build_trie(samples);
assert_eq!(map.len(), samples.len());
}
fn bench_trie_get<K: TrieKey, V>(samples: &[(K, V)], map: &Trie<K, V>) {
for (key, _) in samples {
assert!(map.get(key).is_some());
}
assert_eq!(map.len(), samples.len());
}
fn build_btree<K: Ord + Clone, V: Clone>(samples: &[(K, V)]) -> BTreeMap<K, V> {
let mut map = BTreeMap::default();
for (key, val) in samples {
map.insert(key.clone(), val.clone());
}
map
}
fn bench_btree_insert<K: Ord + Clone, V: Clone>(samples: &[(K, V)]) {
let map = build_btree(samples);
assert_eq!(map.len(), samples.len());
}
fn bench_btree_get<K: Ord, V>(samples: &[(K, V)], map: &BTreeMap<K, V>) {
for (key, _) in samples {
assert!(map.get(key).is_some());
}
assert_eq!(map.len(), samples.len());
}
criterion_group!(
benches,
bench_hash_trie_btree_large_vector,
bench_hash_trie_btree_ix_key,
bench_hash_trie_btree_small_string,
bench_hash_trie_btree_thing,
bench_hash_trie_btree_value
);
criterion_main!(benches);