use criterion::{criterion_group, criterion_main, BatchSize, BenchmarkId, Criterion};
use libdd_tinybytes::BytesString;
use libdd_trace_utils::span::vec_map::VecMap;
use std::hint::black_box;
const SIZES: &[usize] = &[8, 16, 64, 128];
const PREFIXES: &[&str] = &["", "http.", "db.", "aws.", "_dd."];
const DUP_PERIODS: &[usize] = &[2, 4, 10];
fn keys(n: usize) -> Vec<BytesString> {
(0..n)
.map(|i| {
let prefix = PREFIXES[i % PREFIXES.len()];
BytesString::from_string(format!("{prefix}{i:03}-nth-key"))
})
.collect()
}
fn values(n: usize) -> Vec<BytesString> {
(0..n)
.map(|i| BytesString::from_string(format!("value-{i:03}")))
.collect()
}
fn populated_meta(n: usize) -> VecMap<BytesString, BytesString> {
keys(n).into_iter().zip(values(n)).collect()
}
fn populated_metrics(n: usize) -> VecMap<BytesString, f64> {
keys(n)
.into_iter()
.enumerate()
.map(|(i, k)| (k, i as f64))
.collect()
}
fn bench_insert(c: &mut Criterion) {
let mut group = c.benchmark_group("vec_map/insert");
for &n in SIZES {
group.throughput(criterion::Throughput::Elements(n as u64));
group.bench_with_input(BenchmarkId::from_parameter(n), &n, |b, &n| {
let ks = keys(n);
let vs = values(n);
b.iter_batched(
|| (ks.clone(), vs.clone()),
|(ks, vs)| {
let mut map = VecMap::with_capacity(n);
for (k, v) in ks.into_iter().zip(vs) {
map.insert(black_box(k), black_box(v));
}
map
},
BatchSize::SmallInput,
)
});
}
group.finish();
}
fn bench_get_hit(c: &mut Criterion) {
let mut group = c.benchmark_group("vec_map/get_hit");
for &n in SIZES {
group.throughput(criterion::Throughput::Elements(n as u64));
let map = populated_meta(n);
let lookups = keys(n);
group.bench_with_input(BenchmarkId::from_parameter(n), &n, |b, _| {
b.iter(|| {
for k in &lookups {
black_box(map.get(black_box(k.as_str())));
}
})
});
}
group.finish();
}
fn bench_get_miss(c: &mut Criterion) {
let mut group = c.benchmark_group("vec_map/get_miss");
for &n in SIZES {
let map = populated_meta(n);
group.bench_with_input(BenchmarkId::from_parameter(n), &n, |b, _| {
b.iter(|| {
black_box(map.get(black_box("this.key.is.absent")));
})
});
}
group.finish();
}
fn bench_get_mut(c: &mut Criterion) {
let mut group = c.benchmark_group("vec_map/get_mut");
for &n in SIZES {
group.throughput(criterion::Throughput::Elements(n as u64));
let lookups = keys(n);
group.bench_with_input(BenchmarkId::from_parameter(n), &n, |b, _| {
b.iter_batched_ref(
|| populated_metrics(n),
|map| {
for k in &lookups {
if let Some(v) = map.get_mut(black_box(k.as_str())) {
*v += 1.0;
}
}
},
BatchSize::SmallInput,
)
});
}
group.finish();
}
fn bench_contains_key(c: &mut Criterion) {
let mut group = c.benchmark_group("vec_map/contains_key");
for &n in SIZES {
group.throughput(criterion::Throughput::Elements(n as u64));
let map = populated_meta(n);
let lookups = keys(n);
group.bench_with_input(BenchmarkId::from_parameter(n), &n, |b, _| {
b.iter(|| {
for k in &lookups {
black_box(map.contains_key(black_box(k.as_str())));
}
black_box(map.contains_key(black_box("this.key.is.absent")));
})
});
}
group.finish();
}
fn bench_iter(c: &mut Criterion) {
let mut group = c.benchmark_group("vec_map/iter");
for &n in SIZES {
group.throughput(criterion::Throughput::Elements(n as u64));
let map = populated_meta(n);
group.bench_with_input(BenchmarkId::from_parameter(n), &n, |b, _| {
b.iter(|| {
for (k, v) in map.iter() {
black_box((k, v));
}
})
});
}
group.finish();
}
fn meta_with_duplicates(n: usize, period: usize) -> VecMap<BytesString, BytesString> {
let mut map = VecMap::with_capacity(n + n / period);
for (i, (k, v)) in keys(n).into_iter().zip(values(n)).enumerate() {
if i % period == 0 {
map.insert(k.clone(), BytesString::from_static("stale"));
}
map.insert(k, v);
}
map
}
fn bench_dedup(c: &mut Criterion) {
let mut group = c.benchmark_group("vec_map/dedup");
for &n in SIZES {
group.bench_with_input(BenchmarkId::new("no_duplicates", n), &n, |b, &n| {
b.iter_batched_ref(
|| populated_meta(n),
|map| {
map.dedup();
black_box(&*map);
},
BatchSize::SmallInput,
)
});
for &period in DUP_PERIODS {
group.bench_with_input(
BenchmarkId::new(format!("dup_1_in_{period}"), n),
&n,
|b, &n| {
b.iter_batched_ref(
|| meta_with_duplicates(n, period),
|map| {
map.dedup();
black_box(&*map);
},
BatchSize::SmallInput,
)
},
);
}
}
group.finish();
}
fn bench_as_deduped_map(c: &mut Criterion) {
let mut group = c.benchmark_group("vec_map/as_deduped_map");
for &n in SIZES {
let mut deduped = populated_meta(n);
deduped.dedup();
group.bench_with_input(BenchmarkId::new("already_deduped", n), &n, |b, _| {
b.iter(|| {
let map = black_box(deduped.as_deduped_map());
for (k, v) in map.iter() {
black_box((k, v));
}
})
});
for &period in DUP_PERIODS {
let dirty = meta_with_duplicates(n, period);
group.bench_with_input(
BenchmarkId::new(format!("needs_dedup_1_in_{period}"), n),
&n,
|b, _| {
b.iter(|| {
let map = black_box(dirty.as_deduped_map());
for (k, v) in map.iter() {
black_box((k, v));
}
})
},
);
}
}
group.finish();
}
criterion_group!(
benches,
bench_insert,
bench_get_hit,
bench_get_miss,
bench_get_mut,
bench_contains_key,
bench_iter,
bench_dedup,
bench_as_deduped_map,
);
criterion_main!(benches);