use std::sync::{
LazyLock,
atomic::{AtomicUsize, Ordering, fence},
};
use enum_map::{Enum, EnumMap};
use tracing::*;
#[derive(Debug, Copy, Clone, Enum)]
pub enum Op {
SnapshotLoad,
IndexLoad,
BackendRead,
BackendWrite,
BackendDelete,
BackendCacheHit,
BackendCacheSpill,
FileToBuffer,
FileToMmap,
TreeCacheHit,
TreeCacheMiss,
ChunkCacheHit,
ChunkCacheMiss,
PackRereads,
}
static COUNTER_MAP: LazyLock<EnumMap<Op, AtomicUsize>> = LazyLock::new(EnumMap::default);
#[inline]
pub fn bump(which: Op) {
add(which, 1);
}
pub fn add(to: Op, amount: usize) {
COUNTER_MAP[to].fetch_add(amount, Ordering::Relaxed);
}
pub fn log_counts() {
fence(Ordering::SeqCst);
let counts = COUNTER_MAP
.iter()
.map(|(k, v)| (k, v.load(Ordering::Relaxed)))
.filter(|(_k, v)| *v > 0) .collect::<Vec<_>>();
if counts.is_empty() {
return;
}
let opname = |op| match op {
Op::SnapshotLoad => "snapshots loaded",
Op::IndexLoad => "indexes loaded",
Op::BackendRead => "backend reads",
Op::BackendWrite => "backend writes",
Op::BackendDelete => "backend delete (and cache evictions)",
Op::BackendCacheHit => "backend cache hits",
Op::BackendCacheSpill => "backend cache spills",
Op::FileToBuffer => "input files buffered",
Op::FileToMmap => "input files memory mapped",
Op::TreeCacheHit => "tree cache hits",
Op::TreeCacheMiss => "tree cache misses",
Op::ChunkCacheHit => "chunk cache hits",
Op::ChunkCacheMiss => "chunk cache misses",
Op::PackRereads => "packs reread",
};
debug!("Counters:");
for (op, count) in &counts {
debug!("{:6} {}", count, opname(*op),);
}
}