use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::OnceLock;
#[derive(Debug, Default)]
pub struct PerfMetrics {
simd_hits: AtomicU64,
simd_misses: AtomicU64,
simd_speedup_micros: AtomicU64,
zero_copy_hits: AtomicU64,
zero_copy_misses: AtomicU64,
zero_copy_alloc_reduction: AtomicU64,
pool_acquire_count: AtomicU64,
pool_acquire_failed_count: AtomicU64,
pool_throughput_ops: AtomicU64,
plan_cache_hits: AtomicU64,
plan_cache_misses: AtomicU64,
}
impl PerfMetrics {
pub fn global() -> &'static PerfMetrics {
static METRICS: OnceLock<PerfMetrics> = OnceLock::new();
METRICS.get_or_init(PerfMetrics::default)
}
pub fn record_simd_hit(&self) {
self.simd_hits.fetch_add(1, Ordering::Relaxed);
}
pub fn record_simd_miss(&self) {
self.simd_misses.fetch_add(1, Ordering::Relaxed);
}
pub fn record_zero_copy_hit(&self) {
self.zero_copy_hits.fetch_add(1, Ordering::Relaxed);
}
pub fn record_zero_copy_miss(&self) {
self.zero_copy_misses.fetch_add(1, Ordering::Relaxed);
}
pub fn record_alloc_reduction(&self, bytes: u64) {
self.zero_copy_alloc_reduction.fetch_add(bytes, Ordering::Relaxed);
}
pub fn record_pool_acquire(&self) {
self.pool_acquire_count.fetch_add(1, Ordering::Relaxed);
}
pub fn record_pool_acquire_failed(&self) {
self.pool_acquire_failed_count.fetch_add(1, Ordering::Relaxed);
}
pub fn record_pool_throughput(&self, ops: u64) {
self.pool_throughput_ops.store(ops, Ordering::Relaxed);
}
pub fn record_plan_cache_hit(&self) {
self.plan_cache_hits.fetch_add(1, Ordering::Relaxed);
}
pub fn record_plan_cache_miss(&self) {
self.plan_cache_misses.fetch_add(1, Ordering::Relaxed);
}
pub fn record_simd_speedup(&self, speedup: f64) {
let micros = (speedup * 1_000_000.0) as u64;
self.simd_speedup_micros.store(micros, Ordering::Relaxed);
}
pub fn snapshot(&self) -> PerfMetricsSnapshot {
let simd_hits = self.simd_hits.load(Ordering::Relaxed);
let simd_misses = self.simd_misses.load(Ordering::Relaxed);
let plan_cache_hits = self.plan_cache_hits.load(Ordering::Relaxed);
let plan_cache_misses = self.plan_cache_misses.load(Ordering::Relaxed);
let pool_acquire_count = self.pool_acquire_count.load(Ordering::Relaxed);
let zero_copy_hits = self.zero_copy_hits.load(Ordering::Relaxed);
let zero_copy_misses = self.zero_copy_misses.load(Ordering::Relaxed);
PerfMetricsSnapshot {
simd_hits,
simd_misses,
simd_speedup_avg: self.simd_speedup_micros.load(Ordering::Relaxed) as f64 / 1_000_000.0,
zero_copy_hits,
zero_copy_misses,
zero_copy_alloc_reduction: self.zero_copy_alloc_reduction.load(Ordering::Relaxed),
pool_acquire_count,
pool_acquire_failed_count: self.pool_acquire_failed_count.load(Ordering::Relaxed),
pool_throughput_ops: self.pool_throughput_ops.load(Ordering::Relaxed),
plan_cache_hits,
plan_cache_misses,
plan_cache_hit_rate: {
let total = plan_cache_hits + plan_cache_misses;
if total == 0 { 0.0 } else { plan_cache_hits as f64 / total as f64 }
},
simd_hit_rate: {
let total = simd_hits + simd_misses;
if total == 0 { 0.0 } else { simd_hits as f64 / total as f64 }
},
zero_copy_hit_rate: {
let total = zero_copy_hits + zero_copy_misses;
if total == 0 { 0.0 } else { zero_copy_hits as f64 / total as f64 }
},
pool_acquire_success_rate: {
let total = pool_acquire_count + self.pool_acquire_failed_count.load(Ordering::Relaxed);
if total == 0 { 0.0 } else { pool_acquire_count as f64 / total as f64 }
},
}
}
pub fn to_prometheus(&self) -> String {
let s = self.snapshot();
format!(
"# HELP sz_orm_simd_hits Total SIMD hits\n\
# TYPE sz_orm_simd_hits counter\n\
sz_orm_simd_hits {}\n\
# HELP sz_orm_simd_misses Total SIMD misses (fallback to scalar)\n\
# TYPE sz_orm_simd_misses counter\n\
sz_orm_simd_misses {}\n\
# HELP sz_orm_zero_copy_hits Total zero-copy hits\n\
# TYPE sz_orm_zero_copy_hits counter\n\
sz_orm_zero_copy_hits {}\n\
# HELP sz_orm_zero_copy_misses Total zero-copy misses\n\
# TYPE sz_orm_zero_copy_misses counter\n\
sz_orm_zero_copy_misses {}\n\
# HELP sz_orm_plan_cache_hits Total plan cache hits\n\
# TYPE sz_orm_plan_cache_hits counter\n\
sz_orm_plan_cache_hits {}\n\
# HELP sz_orm_plan_cache_misses Total plan cache misses\n\
# TYPE sz_orm_plan_cache_misses counter\n\
sz_orm_plan_cache_misses {}\n\
# HELP sz_orm_plan_cache_hit_rate Plan cache hit rate\n\
# TYPE sz_orm_plan_cache_hit_rate gauge\n\
sz_orm_plan_cache_hit_rate {}\n\
# HELP sz_orm_pool_acquire_count Total pool acquire count\n\
# TYPE sz_orm_pool_acquire_count counter\n\
sz_orm_pool_acquire_count {}\n\
# HELP sz_orm_pool_throughput_ops Pool throughput (ops/s)\n\
# TYPE sz_orm_pool_throughput_ops gauge\n\
sz_orm_pool_throughput_ops {}\n",
s.simd_hits, s.simd_misses,
s.zero_copy_hits, s.zero_copy_misses,
s.plan_cache_hits, s.plan_cache_misses, s.plan_cache_hit_rate,
s.pool_acquire_count, s.pool_throughput_ops,
)
}
}
#[derive(Debug, Clone)]
pub struct PerfMetricsSnapshot {
pub simd_hits: u64,
pub simd_misses: u64,
pub simd_speedup_avg: f64,
pub simd_hit_rate: f64,
pub zero_copy_hits: u64,
pub zero_copy_misses: u64,
pub zero_copy_hit_rate: f64,
pub zero_copy_alloc_reduction: u64,
pub pool_acquire_count: u64,
pub pool_acquire_failed_count: u64,
pub pool_acquire_success_rate: f64,
pub pool_throughput_ops: u64,
pub plan_cache_hits: u64,
pub plan_cache_misses: u64,
pub plan_cache_hit_rate: f64,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_global_singleton() {
let m1 = PerfMetrics::global();
let m2 = PerfMetrics::global();
m1.record_simd_hit();
assert!(m2.snapshot().simd_hits >= 1);
}
#[test]
fn test_snapshot() {
let m = PerfMetrics::default();
m.record_simd_hit();
m.record_simd_hit();
m.record_simd_miss();
m.record_plan_cache_hit();
m.record_plan_cache_miss();
let s = m.snapshot();
assert_eq!(s.simd_hits, 2);
assert_eq!(s.simd_misses, 1);
assert_eq!(s.plan_cache_hits, 1);
assert_eq!(s.plan_cache_misses, 1);
assert!((s.simd_hit_rate - 2.0 / 3.0).abs() < 1e-9);
assert!((s.plan_cache_hit_rate - 0.5).abs() < 1e-9);
}
#[test]
fn test_prometheus_format() {
let m = PerfMetrics::default();
m.record_simd_hit();
m.record_zero_copy_hit();
m.record_plan_cache_hit();
let prom = m.to_prometheus();
assert!(prom.contains("sz_orm_simd_hits 1"));
assert!(prom.contains("sz_orm_zero_copy_hits 1"));
assert!(prom.contains("sz_orm_plan_cache_hits 1"));
}
#[test]
fn test_simd_speedup() {
let m = PerfMetrics::default();
m.record_simd_speedup(1.5);
let s = m.snapshot();
assert!((s.simd_speedup_avg - 1.5).abs() < 1e-6);
}
#[test]
fn test_pool_metrics() {
let m = PerfMetrics::default();
m.record_pool_acquire();
m.record_pool_acquire();
m.record_pool_acquire_failed();
m.record_pool_throughput(10000);
let s = m.snapshot();
assert_eq!(s.pool_acquire_count, 2);
assert_eq!(s.pool_acquire_failed_count, 1);
assert_eq!(s.pool_throughput_ops, 10000);
assert!((s.pool_acquire_success_rate - 2.0 / 3.0).abs() < 1e-9);
}
}