use std::collections::HashMap;
use std::hint::black_box;
use std::sync::Mutex;
use criterion::{criterion_group, criterion_main, Criterion};
use subetha_cxc::{SharedHashMap, InsertOutcome};
fn tmp(name: &str) -> std::path::PathBuf {
let mut p = std::env::temp_dir();
let pid = std::process::id();
p.push(format!("subetha-bench-map-compact-{name}-{pid}.bin"));
p
}
fn compact_overhead(c: &mut Criterion) {
let p = tmp("overhead");
let m: SharedHashMap<u32, u32> = SharedHashMap::create(&p, 1024).unwrap();
c.bench_function("map.compact_192_tombstones/mmf", |b| {
b.iter_with_setup(
|| {
m.clear();
for k in 0..256u32 {
m.insert(k, k).unwrap();
}
for k in 0..192u32 {
m.remove(&k);
}
},
|_| black_box(m.compact().unwrap()),
);
});
drop(m);
std::fs::remove_file(&p).ok();
}
fn churn_workload_with_compact(c: &mut Criterion) {
const CAP: usize = 256;
const LIVE: u32 = 64;
const ROUNDS: u32 = 200;
let p = tmp("churn-mmf");
let m: SharedHashMap<u32, u32> = SharedHashMap::create(&p, CAP).unwrap();
c.bench_function("map.churn_with_compact/mmf", |b| {
b.iter_with_setup(
|| {
m.clear();
for k in 0..LIVE { m.insert(k, k).unwrap(); }
},
|_| {
for (round, next_key) in (0..ROUNDS).zip(LIVE..) {
let oldest = round % LIVE;
m.remove(&oldest);
m.insert(black_box(next_key), next_key).expect("map insert failed");
if m.should_compact(0.30) {
m.compact().unwrap();
}
}
},
);
});
drop(m);
std::fs::remove_file(&p).ok();
let h: Mutex<HashMap<u32, u32>> = Mutex::new(HashMap::with_capacity(CAP));
c.bench_function("map.churn_with_compact/mutex_hashmap", |b| {
b.iter_with_setup(
|| {
let mut g = h.lock().unwrap();
g.clear();
for k in 0..LIVE { g.insert(k, k); }
},
|_| {
for (round, next_key) in (0..ROUNDS).zip(LIVE..) {
let oldest = round % LIVE;
let mut g = h.lock().unwrap();
g.remove(&oldest);
g.insert(black_box(next_key), next_key);
}
},
);
});
}
fn should_compact_query(c: &mut Criterion) {
let p = tmp("should");
let m: SharedHashMap<u32, u32> = SharedHashMap::create(&p, 1024).unwrap();
for k in 0..512u32 { m.insert(k, k).unwrap(); }
for k in 0..300u32 { m.remove(&k); }
c.bench_function("map.should_compact_query/mmf", |b| {
b.iter(|| black_box(m.should_compact(black_box(0.30))));
});
drop(m);
std::fs::remove_file(&p).ok();
}
fn insert_with_tombstone_bookkeeping(c: &mut Criterion) {
let p = tmp("remove-cost");
let m: SharedHashMap<u32, u32> = SharedHashMap::create(&p, 1 << 16).unwrap();
let mut next_key = 0u32;
c.bench_function("map.remove_with_tombstone_bookkeeping/mmf", |b| {
b.iter(|| {
m.insert(next_key, next_key).ok();
m.remove(&next_key);
next_key = next_key.wrapping_add(1);
});
});
drop(m);
std::fs::remove_file(&p).ok();
}
#[allow(dead_code)]
fn _unused() {
let _: InsertOutcome = InsertOutcome::Inserted;
}
criterion_group!(benches,
compact_overhead,
churn_workload_with_compact,
should_compact_query,
insert_with_tombstone_bookkeeping,
);
criterion_main!(benches);