Files
wifi-densepose/vendor/ruvector/crates/agentic-robotics-rt/src/latency.rs

146 lines
3.6 KiB
Rust

//! High-precision latency tracking using HDR histogram
use hdrhistogram::Histogram;
use parking_lot::Mutex;
use std::sync::Arc;
use std::time::{Duration, Instant};
/// Latency tracker with HDR histogram
pub struct LatencyTracker {
histogram: Arc<Mutex<Histogram<u64>>>,
name: String,
}
impl LatencyTracker {
/// Create a new latency tracker
pub fn new(name: impl Into<String>) -> Self {
// 3 significant digits, max value 1 hour in microseconds
let histogram = Histogram::<u64>::new(3)
.expect("Failed to create histogram");
Self {
histogram: Arc::new(Mutex::new(histogram)),
name: name.into(),
}
}
/// Record a latency measurement
pub fn record(&self, duration: Duration) {
let micros = duration.as_micros() as u64;
if let Some(mut hist) = self.histogram.try_lock() {
let _ = hist.record(micros);
}
}
/// Get latency statistics
pub fn stats(&self) -> LatencyStats {
let hist = self.histogram.lock();
LatencyStats {
name: self.name.clone(),
count: hist.len(),
min: hist.min(),
max: hist.max(),
mean: hist.mean(),
p50: hist.value_at_quantile(0.50),
p90: hist.value_at_quantile(0.90),
p99: hist.value_at_quantile(0.99),
p999: hist.value_at_quantile(0.999),
}
}
/// Reset the histogram
pub fn reset(&self) {
self.histogram.lock().reset();
}
/// Create a measurement guard
pub fn measure(&self) -> LatencyMeasurement {
LatencyMeasurement {
tracker: self.clone(),
start: Instant::now(),
}
}
}
impl Clone for LatencyTracker {
fn clone(&self) -> Self {
Self {
histogram: self.histogram.clone(),
name: self.name.clone(),
}
}
}
/// Latency statistics
#[derive(Debug, Clone)]
pub struct LatencyStats {
pub name: String,
pub count: u64,
pub min: u64,
pub max: u64,
pub mean: f64,
pub p50: u64,
pub p90: u64,
pub p99: u64,
pub p999: u64,
}
impl std::fmt::Display for LatencyStats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}: count={}, min={}µs, max={}µs, mean={:.2}µs, p50={}µs, p90={}µs, p99={}µs, p99.9={}µs",
self.name, self.count, self.min, self.max, self.mean, self.p50, self.p90, self.p99, self.p999
)
}
}
/// RAII guard for automatic latency measurement
pub struct LatencyMeasurement {
tracker: LatencyTracker,
start: Instant,
}
impl Drop for LatencyMeasurement {
fn drop(&mut self) {
let duration = self.start.elapsed();
self.tracker.record(duration);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_latency_tracker() {
let tracker = LatencyTracker::new("test");
// Record some measurements
tracker.record(Duration::from_micros(100));
tracker.record(Duration::from_micros(200));
tracker.record(Duration::from_micros(300));
let stats = tracker.stats();
assert_eq!(stats.count, 3);
assert!(stats.min >= 100);
assert!(stats.max <= 300);
assert!(stats.mean > 0.0);
}
#[test]
fn test_latency_measurement() {
let tracker = LatencyTracker::new("measurement");
{
let _measurement = tracker.measure();
std::thread::sleep(Duration::from_micros(100));
}
let stats = tracker.stats();
assert_eq!(stats.count, 1);
assert!(stats.min >= 100);
}
}