use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{Duration, Instant};
use parking_lot::RwLock;
use std::sync::Arc;
#[derive(Debug, Default)]
pub struct CryptoMetrics {
pub key_operations: AtomicU64,
pub key_cache_hits: AtomicU64,
pub key_cache_misses: AtomicU64,
pub encryption_ops: AtomicU64,
pub decryption_ops: AtomicU64,
pub avg_latency: RwLock<Duration>,
pub peak_latency: RwLock<Duration>,
latency_samples: RwLock<Vec<Duration>>,
}
impl CryptoMetrics {
pub fn new() -> Self {
Self {
key_operations: AtomicU64::new(0),
key_cache_hits: AtomicU64::new(0),
key_cache_misses: AtomicU64::new(0),
encryption_ops: AtomicU64::new(0),
decryption_ops: AtomicU64::new(0),
avg_latency: RwLock::new(Duration::default()),
peak_latency: RwLock::new(Duration::default()),
latency_samples: RwLock::new(Vec::with_capacity(100)),
}
}
pub fn record_key_op(&self, latency: Duration) {
self.key_operations.fetch_add(1, Ordering::Relaxed);
self.record_latency(latency);
}
pub fn record_cache_hit(&self) {
self.key_cache_hits.fetch_add(1, Ordering::Relaxed);
}
pub fn record_cache_miss(&self) {
self.key_cache_misses.fetch_add(1, Ordering::Relaxed);
}
pub fn record_encryption(&self, latency: Duration) {
self.encryption_ops.fetch_add(1, Ordering::Relaxed);
self.record_latency(latency);
}
pub fn record_decryption(&self, latency: Duration) {
self.decryption_ops.fetch_add(1, Ordering::Relaxed);
self.record_latency(latency);
}
fn record_latency(&self, latency: Duration) {
let mut avg = self.avg_latency.write();
let mut peak = self.peak_latency.write();
let mut samples = self.latency_samples.write();
*avg = if samples.is_empty() {
latency
} else {
Duration::from_nanos(
((avg.as_nanos() as f64 * samples.len() as f64) +
latency.as_nanos() as f64) as u64 / (samples.len() + 1) as f64 as u64
)
};
*peak = (*peak).max(latency);
if samples.len() >= 100 {
samples.remove(0);
}
samples.push(latency);
}
pub fn get_latency_percentile(&self, percentile: f64) -> Duration {
let samples = self.latency_samples.read();
if samples.is_empty() {
return Duration::default();
}
let mut sorted = samples.clone();
sorted.sort();
let index = ((sorted.len() as f64 * percentile / 100.0).round() as usize)
.min(sorted.len() - 1);
sorted[index]
}
pub fn get_summary(&self) -> CryptoMetricsSummary {
CryptoMetricsSummary {
total_operations: self.key_operations.load(Ordering::Relaxed),
cache_hit_ratio: self.key_cache_hits.load(Ordering::Relaxed) as f64 /
(self.key_cache_hits.load(Ordering::Relaxed) +
self.key_cache_misses.load(Ordering::Relaxed)) as f64,
avg_latency_us: self.avg_latency.read().as_micros() as f64,
peak_latency_us: self.peak_latency.read().as_micros() as f64,
p99_latency_us: self.get_latency_percentile(99.0).as_micros() as f64,
}
}
}
#[derive(Debug, Clone)]
pub struct CryptoMetricsSummary {
pub total_operations: u64,
pub cache_hit_ratio: f64,
pub avg_latency_us: f64,
pub peak_latency_us: f64,
pub p99_latency_us: f64,
}