Skip to main content

cbtop/optimize/
mod.rs

1//! Optimization identification tooling for cbtop
2//!
3//! Provides systematic performance analysis using the cbtop Library API (HL-007).
4//!
5//! # Components
6//!
7//! - [`OptimizationSuite`]: Benchmark suite for baseline collection
8//! - [`BottleneckAnalysis`]: Identifies operations performing below expectations
9//! - [`RegressionDetector`]: Automated regression detection for CI/CD
10//! - [`OptimizationValidator`]: Statistical validation of optimizations
11//!
12//! # Example
13//!
14//! ```rust,no_run
15//! use cbtop::optimize::{OptimizationSuite, BottleneckAnalysis};
16//!
17//! // Collect baseline
18//! let suite = OptimizationSuite::standard();
19//! let baseline = suite.collect_baseline().unwrap();
20//!
21//! // Analyze bottlenecks
22//! let analysis = suite.analyze_bottlenecks(&baseline);
23//! for bottleneck in &analysis.severe {
24//!     println!("{}: {} - {}", bottleneck.workload, bottleneck.efficiency, bottleneck.recommendation);
25//! }
26//! ```
27
28mod 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        // Same distribution should have high p-value (not significant)
75        assert!(p > 0.05);
76    }
77
78    #[test]
79    fn test_t_test_different_distribution() {
80        // Use slightly varying values to have non-zero variance
81        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        // Different distributions should have low p-value (significant)
85        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}