use batpak::prelude::*;
use batpak::store::{IndexTopology, Store, StoreConfig};
use batpak_bench_support::{apply_profile, BenchProfile};
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion, Throughput};
use std::hint::black_box;
use tempfile::TempDir;
const KINDS: [EventKind; 8] = [
EventKind::custom(0x1, 1),
EventKind::custom(0x1, 2),
EventKind::custom(0x1, 3),
EventKind::custom(0x1, 4),
EventKind::custom(0x2, 1),
EventKind::custom(0x2, 2),
EventKind::custom(0x2, 3),
EventKind::custom(0x2, 4),
];
const QUERY_KIND: EventKind = KINDS[0];
fn build_store(events_per_kind: u32) -> (Store, TempDir) {
let dir = TempDir::new().expect("temp dir");
let store = Store::open(
StoreConfig::new(dir.path())
.with_index_topology(IndexTopology::scan())
.with_sync_every_n_events(100_000),
)
.expect("open");
let coords: Vec<Coordinate> = KINDS
.iter()
.enumerate()
.map(|(i, _)| Coordinate::new(format!("bench:entity:{i}"), "bench:scope").expect("coord"))
.collect();
for seq in 0..events_per_kind {
for (i, &kind) in KINDS.iter().enumerate() {
store
.append(&coords[i], kind, &serde_json::json!({"seq": seq}))
.expect("append");
}
}
(store, dir)
}
fn close_store(store: Store) {
store.close().expect("close");
}
fn bench_cursor_poll_batch(c: &mut Criterion) {
const EVENTS_PER_KIND: u32 = 1_000; let (store, _dir) = build_store(EVENTS_PER_KIND);
let region = Region::all().with_fact(KindFilter::Exact(QUERY_KIND));
let batch_sizes: &[usize] = &[1, 16, 64, 256];
let mut group = c.benchmark_group("cursor/poll_batch");
apply_profile(&mut group, BenchProfile::Heavy);
for &batch_size in batch_sizes {
group.throughput(Throughput::Elements(batch_size as u64));
group.bench_function(BenchmarkId::new("soa", batch_size), |b| {
b.iter(|| {
let mut cursor = store.cursor_guaranteed(®ion);
black_box(cursor.poll_batch(batch_size))
});
});
}
group.finish();
close_store(store);
}
fn bench_by_kind(c: &mut Criterion) {
let corpus_sizes: &[u32] = &[100, 500, 1_000, 4_000];
let mut group = c.benchmark_group("query/by_kind");
apply_profile(&mut group, BenchProfile::Heavy);
for &events_per_kind in corpus_sizes {
let (store, _dir) = build_store(events_per_kind);
group.throughput(Throughput::Elements(events_per_kind as u64));
group.bench_function(BenchmarkId::new("soa", events_per_kind), |b| {
b.iter(|| black_box(store.by_fact(QUERY_KIND)));
});
close_store(store);
}
group.finish();
}
fn bench_query_region(c: &mut Criterion) {
let corpus_sizes: &[u32] = &[100, 500, 1_000];
let mut group = c.benchmark_group("query/region_all");
apply_profile(&mut group, BenchProfile::Heavy);
for &events_per_kind in corpus_sizes {
let total = events_per_kind as u64 * KINDS.len() as u64;
let (store, _dir) = build_store(events_per_kind);
group.throughput(Throughput::Elements(total));
group.bench_function(BenchmarkId::new("soa", events_per_kind), |b| {
b.iter(|| black_box(store.query(&Region::all())));
});
close_store(store);
}
group.finish();
}
criterion_group!(
benches,
bench_cursor_poll_batch,
bench_by_kind,
bench_query_region
);
criterion_main!(benches);