memscope_rs/export/
config_optimizer.rs

1//! configuration optimization tool module
2//!
3//! This module provides automated configuration optimization and validation tools.
4
5use crate::core::types::TrackingResult;
6use crate::export::fast_export_coordinator::FastExportConfigBuilder;
7// use crate::export::performance_testing::OptimizationTarget; // Removed - using local definition
8
9/// Optimization target for configuration
10#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
11pub enum OptimizationTarget {
12    Speed,
13    Memory,
14    Balanced,
15}
16use crate::export::system_optimizer::SystemOptimizer;
17use serde::{Deserialize, Serialize};
18
19/// configuration optimizer
20pub struct ConfigOptimizer {
21    system_optimizer: SystemOptimizer,
22    optimization_history: Vec<OptimizationRecord>,
23}
24
25/// optimization record
26#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct OptimizationRecord {
28    /// optimization timestamp
29    pub timestamp: u64,
30    /// optimization target
31    pub target: OptimizationTarget,
32    /// original configuration
33    pub original_config: ConfigSnapshot,
34    /// optimized configuration
35    pub optimized_config: ConfigSnapshot,
36    /// performance improvement
37    pub performance_improvement: f64,
38    /// optimization success rate
39    pub success_rate: f64,
40}
41
42/// configuration snapshot
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct ConfigSnapshot {
45    /// shard size
46    pub shard_size: usize,
47    /// thread count
48    pub thread_count: usize,
49    /// buffer size
50    pub buffer_size: usize,
51    /// configuration hash
52    pub config_hash: String,
53}
54
55impl ConfigOptimizer {
56    /// create new configuration optimizer
57    pub fn new() -> TrackingResult<Self> {
58        Ok(Self {
59            system_optimizer: SystemOptimizer::new()?,
60            optimization_history: Vec::new(),
61        })
62    }
63
64    /// auto optimize configuration
65    pub fn auto_optimize(
66        &mut self,
67        target: OptimizationTarget,
68        dataset_size: Option<usize>,
69    ) -> TrackingResult<FastExportConfigBuilder> {
70        // generate configuration recommendation
71        let recommendation = self
72            .system_optimizer
73            .generate_configuration_recommendation(target, dataset_size);
74
75        // create configuration
76        let config_builder = FastExportConfigBuilder::new()
77            .shard_size(recommendation.recommended_shard_size)
78            .max_threads(Some(recommendation.recommended_thread_count))
79            .buffer_size(recommendation.recommended_buffer_size)
80            .performance_monitoring(true);
81
82        // validate configuration
83        let validation_result = self
84            .system_optimizer
85            .validate_configuration(&config_builder);
86
87        if !validation_result.is_valid {
88            tracing::warn!("⚠️ configuration validation failed, using default configuration");
89            for error in &validation_result.errors {
90                tracing::warn!(" Error : {}", error);
91            }
92            return Ok(FastExportConfigBuilder::new());
93        }
94
95        // record optimization history
96        let record = OptimizationRecord {
97            timestamp: std::time::SystemTime::now()
98                .duration_since(std::time::UNIX_EPOCH)
99                .unwrap_or_default()
100                .as_secs(),
101            target,
102            original_config: ConfigSnapshot {
103                shard_size: 1000,
104                thread_count: 4,
105                buffer_size: 256 * 1024,
106                config_hash: "default".to_string(),
107            },
108            optimized_config: ConfigSnapshot {
109                shard_size: recommendation.recommended_shard_size,
110                thread_count: recommendation.recommended_thread_count,
111                buffer_size: recommendation.recommended_buffer_size,
112                config_hash: format!(
113                    "{:x}",
114                    recommendation.recommended_shard_size
115                        ^ recommendation.recommended_thread_count
116                        ^ recommendation.recommended_buffer_size
117                ),
118            },
119            performance_improvement: recommendation.expected_performance_gain,
120            success_rate: recommendation.confidence,
121        };
122
123        self.optimization_history.push(record);
124
125        Ok(config_builder)
126    }
127
128    /// get optimization history
129    pub fn get_optimization_history(&self) -> &[OptimizationRecord] {
130        &self.optimization_history
131    }
132
133    /// clear optimization history
134    pub fn clear_history(&mut self) {
135        self.optimization_history.clear();
136    }
137}
138
139impl Default for ConfigOptimizer {
140    fn default() -> Self {
141        Self::new().unwrap_or_else(|_| Self {
142            system_optimizer: SystemOptimizer::default(),
143            optimization_history: Vec::new(),
144        })
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use super::*;
151
152    #[test]
153    fn test_config_optimizer_new() {
154        // Test creation of new ConfigOptimizer
155        let optimizer = ConfigOptimizer::new();
156        assert!(optimizer.is_ok());
157
158        let optimizer = optimizer.unwrap();
159        assert!(optimizer.optimization_history.is_empty());
160    }
161
162    #[test]
163    fn test_config_optimizer_default() {
164        // Test default implementation
165        let optimizer = ConfigOptimizer::default();
166        assert!(optimizer.optimization_history.is_empty());
167    }
168
169    #[test]
170    fn test_optimization_target_equality() {
171        // Test OptimizationTarget enum equality
172        assert_eq!(OptimizationTarget::Speed, OptimizationTarget::Speed);
173        assert_ne!(OptimizationTarget::Speed, OptimizationTarget::Memory);
174        assert_ne!(OptimizationTarget::Memory, OptimizationTarget::Balanced);
175    }
176
177    #[test]
178    fn test_auto_optimize_speed() {
179        // Test auto optimize with Speed target
180        let mut optimizer = ConfigOptimizer::new().unwrap();
181        let result = optimizer.auto_optimize(OptimizationTarget::Speed, Some(10000));
182
183        assert!(result.is_ok());
184        let config_builder = result.unwrap();
185        // Verify config builder was created (it should have some default values)
186        // We can't test exact values as they depend on SystemOptimizer implementation
187        let config = config_builder.build();
188        // Just verify that the config was built successfully by checking a field
189        assert!(config.shard_config.shard_size > 0);
190    }
191
192    #[test]
193    fn test_auto_optimize_memory() {
194        // Test auto optimize with Memory target
195        let mut optimizer = ConfigOptimizer::new().unwrap();
196        let result = optimizer.auto_optimize(OptimizationTarget::Memory, Some(5000));
197
198        assert!(result.is_ok());
199        assert!(!optimizer.optimization_history.is_empty());
200    }
201
202    #[test]
203    fn test_auto_optimize_balanced() {
204        // Test auto optimize with Balanced target
205        let mut optimizer = ConfigOptimizer::new().unwrap();
206        let result = optimizer.auto_optimize(OptimizationTarget::Balanced, None);
207
208        assert!(result.is_ok());
209        // Check that optimization history was recorded
210        assert_eq!(optimizer.optimization_history.len(), 1);
211
212        let record = &optimizer.optimization_history[0];
213        assert_eq!(record.target, OptimizationTarget::Balanced);
214        assert!(record.timestamp > 0);
215    }
216
217    #[test]
218    fn test_optimization_history() {
219        // Test optimization history tracking
220        let mut optimizer = ConfigOptimizer::new().unwrap();
221
222        // Perform multiple optimizations
223        let _ = optimizer.auto_optimize(OptimizationTarget::Speed, Some(1000));
224        let _ = optimizer.auto_optimize(OptimizationTarget::Memory, Some(2000));
225        let _ = optimizer.auto_optimize(OptimizationTarget::Balanced, Some(3000));
226
227        // Check history
228        let history = optimizer.get_optimization_history();
229        assert_eq!(history.len(), 3);
230
231        // Verify each record has correct target
232        assert_eq!(history[0].target, OptimizationTarget::Speed);
233        assert_eq!(history[1].target, OptimizationTarget::Memory);
234        assert_eq!(history[2].target, OptimizationTarget::Balanced);
235
236        // All records should have valid timestamps
237        for record in history {
238            assert!(record.timestamp > 0);
239            assert!(!record.optimized_config.config_hash.is_empty());
240        }
241    }
242
243    #[test]
244    fn test_clear_history() {
245        // Test clearing optimization history
246        let mut optimizer = ConfigOptimizer::new().unwrap();
247
248        // Add some history
249        let _ = optimizer.auto_optimize(OptimizationTarget::Speed, Some(1000));
250        let _ = optimizer.auto_optimize(OptimizationTarget::Memory, Some(2000));
251
252        assert!(!optimizer.optimization_history.is_empty());
253
254        // Clear history
255        optimizer.clear_history();
256        assert!(optimizer.optimization_history.is_empty());
257        assert_eq!(optimizer.get_optimization_history().len(), 0);
258    }
259
260    #[test]
261    fn test_config_snapshot_fields() {
262        // Test ConfigSnapshot structure
263        let snapshot = ConfigSnapshot {
264            shard_size: 1000,
265            thread_count: 8,
266            buffer_size: 512 * 1024,
267            config_hash: "test_hash".to_string(),
268        };
269
270        assert_eq!(snapshot.shard_size, 1000);
271        assert_eq!(snapshot.thread_count, 8);
272        assert_eq!(snapshot.buffer_size, 512 * 1024);
273        assert_eq!(snapshot.config_hash, "test_hash");
274    }
275
276    #[test]
277    fn test_optimization_record_fields() {
278        // Test OptimizationRecord structure
279        let original = ConfigSnapshot {
280            shard_size: 500,
281            thread_count: 4,
282            buffer_size: 256 * 1024,
283            config_hash: "original".to_string(),
284        };
285
286        let optimized = ConfigSnapshot {
287            shard_size: 1000,
288            thread_count: 8,
289            buffer_size: 512 * 1024,
290            config_hash: "optimized".to_string(),
291        };
292
293        let record = OptimizationRecord {
294            timestamp: 1234567890,
295            target: OptimizationTarget::Speed,
296            original_config: original.clone(),
297            optimized_config: optimized.clone(),
298            performance_improvement: 25.5,
299            success_rate: 0.95,
300        };
301
302        assert_eq!(record.timestamp, 1234567890);
303        assert_eq!(record.target, OptimizationTarget::Speed);
304        assert_eq!(record.original_config.shard_size, 500);
305        assert_eq!(record.optimized_config.shard_size, 1000);
306        assert_eq!(record.performance_improvement, 25.5);
307        assert_eq!(record.success_rate, 0.95);
308    }
309
310    #[test]
311    fn test_multiple_optimizations_different_sizes() {
312        // Test multiple optimizations with different dataset sizes
313        let mut optimizer = ConfigOptimizer::new().unwrap();
314
315        let sizes = vec![Some(100), Some(1000), Some(10000), Some(100000), None];
316        for size in sizes {
317            let result = optimizer.auto_optimize(OptimizationTarget::Balanced, size);
318            assert!(result.is_ok());
319        }
320
321        // Should have 5 records in history
322        assert_eq!(optimizer.get_optimization_history().len(), 5);
323    }
324
325    #[test]
326    fn test_optimization_with_validation_scenario() {
327        // Test optimization that might trigger validation warnings
328        // This tests the validation path in auto_optimize
329        let mut optimizer = ConfigOptimizer::new().unwrap();
330
331        // Use very large dataset size that might trigger different optimization path
332        let result = optimizer.auto_optimize(OptimizationTarget::Speed, Some(usize::MAX / 2));
333        assert!(result.is_ok());
334
335        // Even with extreme values, we should get a valid config
336        let config_builder = result.unwrap();
337        let config = config_builder.build();
338        assert!(config.shard_config.shard_size > 0);
339    }
340
341    #[test]
342    fn test_serialization_of_types() {
343        // Test that our types can be serialized/deserialized
344        let target = OptimizationTarget::Memory;
345        let serialized = serde_json::to_string(&target).unwrap();
346        let deserialized: OptimizationTarget = serde_json::from_str(&serialized).unwrap();
347        assert_eq!(target, deserialized);
348
349        let snapshot = ConfigSnapshot {
350            shard_size: 2000,
351            thread_count: 16,
352            buffer_size: 1024 * 1024,
353            config_hash: "hash123".to_string(),
354        };
355        let serialized = serde_json::to_string(&snapshot).unwrap();
356        let deserialized: ConfigSnapshot = serde_json::from_str(&serialized).unwrap();
357        assert_eq!(snapshot.shard_size, deserialized.shard_size);
358        assert_eq!(snapshot.config_hash, deserialized.config_hash);
359    }
360}