1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
//! Benchmarks for VectorStorage insert performance.
//!
//! Run with: `cargo bench --bench storage_bench`
use criterion::{criterion_group, criterion_main, Criterion, Throughput};
use edgevec::hnsw::HnswConfig;
use edgevec::persistence::storage::file::FileBackend;
use edgevec::persistence::wal::WalAppender;
use edgevec::storage::VectorStorage;
use std::hint::black_box;
use tempfile::NamedTempFile;
fn bench_storage_insert(c: &mut Criterion) {
let mut group = c.benchmark_group("storage_insert");
let config = HnswConfig::new(128); // 128 dimensions
// Setup vector for insertion
let vector = vec![1.0f32; 128];
// Scenario A: In-Memory (No WAL)
group.throughput(Throughput::Elements(1));
group.bench_function("insert_memory_only", |b| {
// We need to re-create storage or reset it to avoid growing infinitely during bench loop,
// or we just measure the insert into an existing storage.
// Inserting into a `Vec` is amortized O(1).
// Let's create a storage and insert many times.
// To avoid allocation noise, we might pre-reserve, but standard usage is dynamic.
// However, Criterion runs many iterations.
// If we keep inserting, the storage grows.
// We want to measure the latency of a single insert.
// We can setup a fresh storage for each batch if possible, or just keep inserting.
// Let's reuse one storage instance to simulate steady state.
let mut storage = VectorStorage::new(&config, None);
b.iter(|| {
black_box(storage.insert(black_box(&vector))).unwrap();
});
});
// Scenario B: With WAL (Durable)
group.bench_function("insert_with_wal", |b| {
let temp_file = NamedTempFile::new().unwrap();
let path = temp_file.path().to_owned();
// We clone path because we re-open file in loop?
// No, WAL appender holds the file writer.
// We need a single storage with WAL.
// We need to be careful: if we keep inserting, the WAL grows on disk.
// IO performance might degrade if file gets huge, but for microbenchmark it's probably fine.
// We want to measure the sync overhead.
let backend = FileBackend::new(&path);
let wal = WalAppender::new(Box::new(backend), 0);
let mut storage = VectorStorage::new(&config, Some(wal));
b.iter(|| {
black_box(storage.insert(black_box(&vector))).unwrap();
});
});
group.finish();
}
criterion_group!(benches, bench_storage_insert);
criterion_main!(benches);