Files
foxhunt/crates/ml-stress-testing/src/performance_analyzer.rs
jgrusewski 7ef92983f9 fix(clippy): apply cargo clippy --fix across workspace
Mechanical auto-fixes: redundant borrows, clone on Copy, or_insert_with,
single-char push_str, get(0) → first(), needless borrow, let_and_return.
150 files, no behavior changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 11:17:51 +01:00

146 lines
3.7 KiB
Rust

//! Performance analysis for ML stress testing
use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::{Duration, SystemTime};
use super::{PhaseResult, RequirementsCheck, StressTestConfig};
/// Latency statistics
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct LatencyStats {
pub mean: f64,
pub min: u64,
pub max: u64,
pub p50: u64,
pub p95: u64,
pub p99: u64,
pub count: u64,
}
/// Comprehensive stress test report
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StressTestReport {
pub config: StressTestConfig,
pub total_duration: Duration,
pub phase_results: Vec<PhaseResult>,
pub total_predictions: u64,
pub total_errors: u64,
pub error_rate: f64,
pub latency_stats: LatencyStats,
pub requirements_met: RequirementsCheck,
pub throughput_achieved: f64,
pub recommendations: Vec<String>,
}
/// Performance analyzer for stress testing
#[derive(Debug, Clone)]
pub struct PerformanceAnalyzer {
start_time: Option<SystemTime>,
measurements: Vec<PerformanceMeasurement>,
}
#[derive(Debug, Clone)]
struct PerformanceMeasurement {
timestamp: SystemTime,
metric_name: String,
value: f64,
labels: HashMap<String, String>,
}
impl PerformanceAnalyzer {
pub fn new() -> Self {
Self {
start_time: None,
measurements: Vec::new(),
}
}
pub async fn start_monitoring(&self) -> Result<()> {
// Implementation would start background monitoring
// For now, this is a placeholder
Ok(())
}
pub fn record_measurement(
&mut self,
metric_name: &str,
value: f64,
labels: HashMap<String, String>,
) {
self.measurements.push(PerformanceMeasurement {
timestamp: SystemTime::now(),
metric_name: metric_name.to_owned(),
value,
labels,
});
}
pub fn generate_summary(&self) -> PerformanceSummary {
let mut latencies = Vec::new();
let mut errors = 0;
let mut total_requests = 0;
for measurement in &self.measurements {
match measurement.metric_name.as_str() {
"latency" => latencies.push(measurement.value as u64),
"error" => errors += 1,
"request" => total_requests += 1,
_ => {},
}
}
let latency_stats = if latencies.is_empty() {
LatencyStats::default()
} else {
self.calculate_latency_stats(&latencies)
};
let error_rate = if total_requests > 0 {
errors as f64 / total_requests as f64
} else {
0.0
};
PerformanceSummary {
latency_stats,
error_rate,
total_requests: total_requests as u64,
total_errors: errors as u64,
}
}
fn calculate_latency_stats(&self, latencies: &[u64]) -> LatencyStats {
let mut sorted = latencies.to_vec();
sorted.sort_unstable();
let len = sorted.len();
let mean = sorted.iter().sum::<u64>() as f64 / len as f64;
LatencyStats {
mean,
min: sorted[0],
max: sorted[len - 1],
p50: sorted[len * 50 / 100],
p95: sorted[len * 95 / 100],
p99: sorted[len * 99 / 100],
count: len as u64,
}
}
}
#[derive(Debug, Clone)]
pub struct PerformanceSummary {
pub latency_stats: LatencyStats,
pub error_rate: f64,
pub total_requests: u64,
pub total_errors: u64,
}
impl Default for PerformanceAnalyzer {
fn default() -> Self {
Self::new()
}
}