1use crate::error::Result;
7use crate::regression_tester::config::TestEnvironment;
8use scirs2_core::numeric::Float;
9use serde::{Deserialize, Serialize};
10use std::collections::{HashMap, VecDeque};
11use std::fmt::Debug;
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct PerformanceMetrics<A: Float> {
16 pub timing: TimingMetrics,
18 pub memory: MemoryMetrics,
20 pub efficiency: EfficiencyMetrics<A>,
22 pub convergence: ConvergenceMetrics<A>,
24 pub custom: HashMap<String, f64>,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, Default)]
30pub struct TimingMetrics {
31 pub mean_time_ns: u64,
33 pub std_time_ns: u64,
35 pub median_time_ns: u64,
37 pub p95_time_ns: u64,
39 pub p99_time_ns: u64,
41 pub min_time_ns: u64,
43 pub max_time_ns: u64,
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct MemoryMetrics {
50 pub peak_memory_bytes: usize,
52 pub avg_memory_bytes: usize,
54 pub allocation_count: usize,
56 pub fragmentation_ratio: f64,
58 pub efficiency_score: f64,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct EfficiencyMetrics<A: Float> {
65 pub flops: f64,
67 pub arithmetic_intensity: f64,
69 pub cache_hit_ratio: f64,
71 pub cpu_utilization: f64,
73 pub efficiency_score: f64,
75 pub custom_metrics: HashMap<String, A>,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
81pub struct ConvergenceMetrics<A: Float> {
82 pub final_objective: A,
84 pub convergence_rate: f64,
86 pub iterations_to_convergence: Option<usize>,
88 pub quality_score: f64,
90 pub stability_score: f64,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
96pub struct PerformanceRecord<A: Float> {
97 pub timestamp: u64,
99 pub commit_hash: Option<String>,
101 pub branch: Option<String>,
103 pub environment: TestEnvironment,
105 pub metrics: PerformanceMetrics<A>,
107 pub metadata: HashMap<String, String>,
109}
110
111#[derive(Debug, Serialize, Deserialize)]
113pub struct DatabaseMetadata {
114 pub version: String,
116 pub created_at: u64,
118 pub last_updated: u64,
120 pub total_records: usize,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct PerformanceBaseline<A: Float> {
127 pub name: String,
129 pub baseline_stats: BaselineStatistics<A>,
131 pub confidence_intervals: ConfidenceIntervals,
133 pub sample_count: usize,
135 pub created_at: u64,
137 pub updated_at: u64,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct BaselineStatistics<A: Float> {
144 pub timing: TimingStatistics,
146 pub memory: MemoryStatistics,
148 pub efficiency: EfficiencyStatistics<A>,
150 pub convergence: ConvergenceStatistics<A>,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct TimingStatistics {
157 pub mean: f64,
159 pub std_dev: f64,
161 pub median: f64,
163 pub iqr: f64,
165 pub coefficient_of_variation: f64,
167}
168
169#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct MemoryStatistics {
172 pub mean_memory: f64,
174 pub std_dev_memory: f64,
176 pub peak_memory_percentiles: HashMap<String, f64>,
178 pub fragmentation_stats: FragmentationStatistics,
180}
181
182#[derive(Debug, Clone, Serialize, Deserialize)]
184pub struct FragmentationStatistics {
185 pub mean_ratio: f64,
187 pub std_dev_ratio: f64,
189 pub trend: f64,
191}
192
193#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct EfficiencyStatistics<A: Float> {
196 pub mean_flops: f64,
198 pub flops_cv: f64,
200 pub mean_efficiency: f64,
202 pub custom_efficiency: HashMap<String, A>,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct ConvergenceStatistics<A: Float> {
209 pub mean_objective: A,
211 pub std_objective: A,
213 pub mean_convergence_rate: f64,
215 pub convergence_consistency: f64,
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct ConfidenceIntervals {
222 pub timing_ci_95: (f64, f64),
224 pub memory_ci_95: (f64, f64),
226 pub timing_ci_99: (f64, f64),
228 pub memory_ci_99: (f64, f64),
230}
231
232#[derive(Debug, Clone, Serialize, Deserialize)]
234pub struct RegressionResult<A: Float> {
235 pub test_id: String,
237 pub regression_detected: bool,
239 pub severity: f64,
241 pub confidence: f64,
243 pub performance_change_percent: f64,
245 pub memory_change_percent: f64,
247 pub affected_metrics: Vec<String>,
249 pub statistical_tests: Vec<StatisticalTestResult>,
251 pub analysis: RegressionAnalysis<A>,
253 pub recommendations: Vec<String>,
255}
256
257#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct StatisticalTestResult {
260 pub test_name: String,
262 pub test_statistic: f64,
264 pub p_value: f64,
266 pub degrees_of_freedom: Option<usize>,
268 pub conclusion: String,
270}
271
272#[derive(Debug, Clone, Serialize, Deserialize)]
274pub struct RegressionAnalysis<A: Float> {
275 pub trend_analysis: TrendAnalysis,
277 pub change_point_analysis: ChangePointAnalysis,
279 pub outlier_analysis: OutlierAnalysis<A>,
281 pub root_cause_hints: Vec<String>,
283}
284
285#[derive(Debug, Clone, Serialize, Deserialize)]
287pub struct TrendAnalysis {
288 pub direction: TrendDirection,
290 pub magnitude: f64,
292 pub significance: f64,
294 pub start_point: Option<usize>,
296}
297
298#[derive(Debug, Clone, Serialize, Deserialize)]
300pub enum TrendDirection {
301 Improving,
303 Stable,
305 Degrading,
307 Volatile,
309}
310
311#[derive(Debug, Clone, Serialize, Deserialize)]
313pub struct ChangePointAnalysis {
314 pub change_points: Vec<usize>,
316 pub magnitudes: Vec<f64>,
318 pub confidences: Vec<f64>,
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize)]
324pub struct OutlierAnalysis<A: Float> {
325 pub outlier_indices: Vec<usize>,
327 pub outlier_scores: Vec<A>,
329 pub outlier_types: Vec<OutlierType>,
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
335pub enum OutlierType {
336 Point,
338 Shift,
340 Trend,
342 Variance,
344}
345
346pub trait RegressionDetector<A: Float>: Debug {
348 fn detect_regression(
350 &self,
351 baseline: &PerformanceBaseline<A>,
352 current_metrics: &PerformanceMetrics<A>,
353 history: &VecDeque<PerformanceRecord<A>>,
354 ) -> Result<RegressionResult<A>>;
355
356 fn name(&self) -> &str;
358
359 fn config(&self) -> HashMap<String, String>;
361}
362
363pub trait StatisticalAnalyzer<A: Float>: Debug {
365 fn analyze(
367 &self,
368 data: &VecDeque<PerformanceRecord<A>>,
369 ) -> Result<StatisticalAnalysisResult<A>>;
370
371 fn name(&self) -> &str;
373}
374
375#[derive(Debug, Clone, Serialize, Deserialize)]
377pub struct StatisticalAnalysisResult<A: Float> {
378 pub summary: String,
380 pub tests: Vec<StatisticalTestResult>,
382 pub patterns: Vec<String>,
384 pub anomalies: Vec<A>,
386}
387
388impl<A: Float + Send + Sync> Default for PerformanceMetrics<A> {
389 fn default() -> Self {
390 Self {
391 timing: TimingMetrics::default(),
392 memory: MemoryMetrics::default(),
393 efficiency: EfficiencyMetrics::default(),
394 convergence: ConvergenceMetrics::default(),
395 custom: HashMap::new(),
396 }
397 }
398}
399
400impl Default for MemoryMetrics {
401 fn default() -> Self {
402 Self {
403 peak_memory_bytes: 0,
404 avg_memory_bytes: 0,
405 allocation_count: 0,
406 fragmentation_ratio: 0.0,
407 efficiency_score: 0.0,
408 }
409 }
410}
411
412impl<A: Float + Send + Sync> Default for EfficiencyMetrics<A> {
413 fn default() -> Self {
414 Self {
415 flops: 0.0,
416 arithmetic_intensity: 0.0,
417 cache_hit_ratio: 0.0,
418 cpu_utilization: 0.0,
419 efficiency_score: 0.0,
420 custom_metrics: HashMap::new(),
421 }
422 }
423}
424
425impl<A: Float + Send + Sync> Default for ConvergenceMetrics<A> {
426 fn default() -> Self {
427 Self {
428 final_objective: A::zero(),
429 convergence_rate: 0.0,
430 iterations_to_convergence: None,
431 quality_score: 0.0,
432 stability_score: 0.0,
433 }
434 }
435}
436
437impl Default for DatabaseMetadata {
438 fn default() -> Self {
439 use std::time::{SystemTime, UNIX_EPOCH};
440
441 let now = SystemTime::now()
442 .duration_since(UNIX_EPOCH)
443 .unwrap_or_default()
444 .as_secs();
445
446 Self {
447 version: "1.0.0".to_string(),
448 created_at: now,
449 last_updated: now,
450 total_records: 0,
451 }
452 }
453}
454
455#[cfg(test)]
456mod tests {
457 use super::*;
458
459 #[test]
460 fn test_performance_metrics_default() {
461 let metrics: PerformanceMetrics<f64> = PerformanceMetrics::default();
462 assert_eq!(metrics.timing.mean_time_ns, 0);
463 assert_eq!(metrics.memory.peak_memory_bytes, 0);
464 assert_eq!(metrics.efficiency.flops, 0.0);
465 assert_eq!(metrics.convergence.final_objective, 0.0);
466 assert!(metrics.custom.is_empty());
467 }
468
469 #[test]
470 fn test_database_metadata_default() {
471 let metadata = DatabaseMetadata::default();
472 assert_eq!(metadata.version, "1.0.0");
473 assert_eq!(metadata.total_records, 0);
474 assert!(metadata.created_at > 0);
475 assert!(metadata.last_updated > 0);
476 }
477
478 #[test]
479 fn test_trend_direction_variants() {
480 assert!(matches!(
481 TrendDirection::Improving,
482 TrendDirection::Improving
483 ));
484 assert!(matches!(TrendDirection::Stable, TrendDirection::Stable));
485 assert!(matches!(
486 TrendDirection::Degrading,
487 TrendDirection::Degrading
488 ));
489 assert!(matches!(TrendDirection::Volatile, TrendDirection::Volatile));
490 }
491
492 #[test]
493 fn test_outlier_type_variants() {
494 assert!(matches!(OutlierType::Point, OutlierType::Point));
495 assert!(matches!(OutlierType::Shift, OutlierType::Shift));
496 assert!(matches!(OutlierType::Trend, OutlierType::Trend));
497 assert!(matches!(OutlierType::Variance, OutlierType::Variance));
498 }
499}