1mod bottleneck;
29mod cpu_detect;
30mod regression;
31mod stats;
32mod suite;
33mod validator;
34
35pub use bottleneck::{AnalysisSummary, BottleneckAnalysis, BottleneckEntry, BottleneckSeverity};
36pub use cpu_detect::CpuCapabilities;
37pub use regression::{RegressionDetector, RegressionEntry, RegressionReport};
38pub use suite::{BaselineEntry, BaselineReport, OptimizationSuite, WorkloadConfig};
39pub use validator::{OptimizationValidator, ValidationResult};
40
41#[cfg(test)]
42mod tests {
43 use super::stats::{cv, mean, std_dev, t_test};
44 use super::*;
45
46 #[test]
47 fn test_mean() {
48 assert!((mean(&[1.0, 2.0, 3.0, 4.0, 5.0]) - 3.0).abs() < 0.001);
49 assert_eq!(mean(&[]), 0.0);
50 }
51
52 #[test]
53 fn test_std_dev() {
54 let samples = vec![2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
55 let sd = std_dev(&samples);
56 assert!((sd - 2.138).abs() < 0.01);
57 }
58
59 #[test]
60 fn test_cv() {
61 let samples = vec![10.0, 10.0, 10.0, 10.0, 10.0];
62 assert_eq!(cv(&samples), 0.0);
63
64 let samples = vec![10.0, 20.0, 30.0, 40.0, 50.0];
65 let c = cv(&samples);
66 assert!(c > 0.0);
67 }
68
69 #[test]
70 fn test_t_test_same_distribution() {
71 let a = vec![10.0, 11.0, 10.5, 10.2, 10.8];
72 let b = vec![10.1, 10.9, 10.3, 10.6, 10.4];
73 let p = t_test(&a, &b);
74 assert!(p > 0.05);
76 }
77
78 #[test]
79 fn test_t_test_different_distribution() {
80 let a = vec![10.0, 10.1, 9.9, 10.2, 9.8];
82 let b = vec![20.0, 20.1, 19.9, 20.2, 19.8];
83 let p = t_test(&a, &b);
84 assert!(p < 0.05, "p-value {} should be < 0.05", p);
86 }
87
88 #[test]
89 fn test_baseline_entry_serialization() {
90 let entry = BaselineEntry {
91 workload: "dot_product".to_string(),
92 size: 1000000,
93 backend: "Simd".to_string(),
94 gflops: 50.0,
95 efficiency: 0.5,
96 cv_percent: 5.0,
97 score: 85,
98 };
99
100 let json = serde_json::to_string(&entry).unwrap();
101 let parsed: BaselineEntry = serde_json::from_str(&json).unwrap();
102 assert_eq!(parsed.workload, "dot_product");
103 assert_eq!(parsed.gflops, 50.0);
104 }
105
106 #[test]
107 fn test_optimization_suite_quick() {
108 let suite = OptimizationSuite::quick();
109 assert_eq!(suite.workloads.len(), 2);
110 assert_eq!(suite.sizes.len(), 2);
111 assert_eq!(suite.duration, std::time::Duration::from_secs(1));
112 }
113
114 #[test]
115 fn test_bottleneck_severity() {
116 assert_eq!(
117 serde_json::to_string(&BottleneckSeverity::Critical).unwrap(),
118 "\"Critical\""
119 );
120 }
121
122 #[test]
123 fn test_regression_report_exit_code() {
124 let passing = RegressionReport {
125 passed: true,
126 regressions: vec![],
127 improvements: vec![],
128 summary: "OK".to_string(),
129 };
130 assert_eq!(passing.exit_code(), 0);
131
132 let failing = RegressionReport {
133 passed: false,
134 regressions: vec![RegressionEntry {
135 workload: "test".to_string(),
136 size: 1000,
137 baseline_gflops: 100.0,
138 current_gflops: 80.0,
139 change_percent: -20.0,
140 }],
141 improvements: vec![],
142 summary: "FAILED".to_string(),
143 };
144 assert_eq!(failing.exit_code(), 1);
145 }
146
147 #[test]
148 fn test_validation_result_format() {
149 let result = ValidationResult {
150 passed: true,
151 improvement_percent: 15.0,
152 before_gflops: 50.0,
153 after_gflops: 57.5,
154 before_cv: 3.0,
155 after_cv: 2.5,
156 p_value: 0.01,
157 statistically_significant: true,
158 };
159
160 let report = result.format_report();
161 assert!(report.contains("PASSED"));
162 assert!(report.contains("15.0%"));
163 }
164}