use std::sync::Arc;
use std::time::Duration;
use criterion::{Criterion, Throughput, black_box, criterion_group, criterion_main};
use logdb::LogDb;
use logdb::{Config, DurabilityMode};
fn bench_db(ring_size: usize) -> LogDb {
let dir = tempfile::tempdir().unwrap().keep();
let mut config = Config::default();
config.data_dir = dir;
config.ring_size = ring_size;
config.durability_mode = DurabilityMode::Async;
config.flush_timeout = Duration::from_secs(5);
LogDb::open(config).unwrap()
}
fn bench_append_64b_single(c: &mut Criterion) {
let db = bench_db(8192);
let content = vec![0u8; 64];
c.bench_function("append/64B/1t", |b| {
b.iter(|| {
db.append(black_box(&content)).unwrap();
});
});
}
fn bench_append_256b_single(c: &mut Criterion) {
let db = bench_db(8192);
let content = vec![0u8; 256];
c.bench_function("append/256B/1t", |b| {
b.iter(|| {
db.append(black_box(&content)).unwrap();
});
});
}
fn bench_append_1k_single(c: &mut Criterion) {
let db = bench_db(8192);
let content = vec![0u8; 1024];
c.bench_function("append/1024B/1t", |b| {
b.iter(|| {
db.append(black_box(&content)).unwrap();
});
});
}
fn bench_append_256b_throughput(c: &mut Criterion) {
let mut group = c.benchmark_group("append-throughput/256B");
for threads in [1, 2, 4, 8].iter() {
group.throughput(Throughput::Elements(1));
group.bench_function(format!("{}t-rec/s", threads), |b| {
b.iter_custom(|iters| {
let db = Arc::new(bench_db(65536));
let content = vec![0x42u8; 256];
let mut handles = vec![];
let per_thread = iters / *threads as u64;
let start = std::time::Instant::now();
for _ in 0..*threads {
let db = Arc::clone(&db);
let c = content.clone();
handles.push(std::thread::spawn(move || {
for _ in 0..per_thread {
black_box(db.append(&c).unwrap());
}
}));
}
for h in handles {
h.join().unwrap();
}
start.elapsed()
});
});
}
group.finish();
}
fn bench_append_varying_sizes(c: &mut Criterion) {
for &size in &[0, 16, 64, 128, 256, 512, 1024] {
let db = bench_db(8192);
let content = vec![0u8; size];
c.bench_function(&format!("append/{}B/1t", size), |b| {
b.iter(|| {
db.append(black_box(&content)).unwrap();
});
});
}
}
#[cfg(feature = "encryption")]
fn bench_db_encrypted(ring_size: usize) -> LogDb {
let dir = tempfile::tempdir().unwrap().keep();
let mut config = Config::default();
config.data_dir = dir;
config.ring_size = ring_size;
config.durability_mode = DurabilityMode::Async;
config.flush_timeout = Duration::from_secs(5);
config.encryption_keys = Some(logdb::KeyRing::single([0x42u8; 32]));
LogDb::open(config).unwrap()
}
#[cfg(feature = "encryption")]
fn bench_append_encrypted_256b(c: &mut Criterion) {
let db = bench_db_encrypted(8192);
let content = vec![0u8; 256];
c.bench_function("append/256B/1t/encrypted", |b| {
b.iter(|| {
db.append(black_box(&content)).unwrap();
});
});
}
const SCAN_RECORDS: u64 = 10_000;
fn populate(db: &LogDb, n: u64, size: usize) {
let content = vec![0u8; size];
for _ in 0..n {
db.append(&content).unwrap();
}
db.flush().unwrap();
while db.durable_cursor() < n {
std::thread::sleep(Duration::from_millis(1));
}
}
fn bench_scan_plaintext(c: &mut Criterion) {
let db = bench_db(65536);
populate(&db, SCAN_RECORDS, 256);
c.bench_function("scan/10k/256B/plaintext", |b| {
b.iter(|| {
let n = db.scan(0, u64::MAX).unwrap().filter_map(|r| r.ok()).count();
black_box(n);
});
});
}
#[cfg(feature = "encryption")]
fn bench_scan_encrypted(c: &mut Criterion) {
let db = bench_db_encrypted(65536);
populate(&db, SCAN_RECORDS, 256);
c.bench_function("scan/10k/256B/encrypted", |b| {
b.iter(|| {
let n = db.scan(0, u64::MAX).unwrap().filter_map(|r| r.ok()).count();
black_box(n);
});
});
}
criterion_group!(
benches,
bench_append_64b_single,
bench_append_256b_single,
bench_append_1k_single,
bench_append_256b_throughput,
bench_append_varying_sizes,
bench_scan_plaintext,
);
#[cfg(feature = "encryption")]
criterion_group!(
enc_benches,
bench_append_encrypted_256b,
bench_scan_encrypted,
);
#[cfg(not(feature = "encryption"))]
criterion_main!(benches);
#[cfg(feature = "encryption")]
criterion_main!(benches, enc_benches);