anya_core/core/
performance_optimization.rs

1// [AIR-3][AIS-3][BPC-3][RES-3] Removed unused import: std::error::Error
2// AIR-008: Performance Optimization Implementation
3// Priority: HIGH - Performance tuning with in-memory auto-save
4
5use std::collections::HashMap;
6use std::sync::{Arc, Mutex};
7use std::time::{Duration, Instant};
8
9/// Resource type enum
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum ResourceType {
12    CPU,
13    Memory,
14    Disk,
15    Network,
16    Database,
17    Cache,
18    Custom(u32),
19}
20
21/// Resource optimization status
22#[derive(Debug, Clone, PartialEq)]
23pub enum OptimizationStatus {
24    NotOptimized,
25    Optimizing,
26    Optimized,
27    Failed,
28}
29
30/// Performance metrics for a resource
31#[derive(Debug, Clone)]
32#[allow(dead_code)]
33pub struct PerformanceMetrics {
34    resource_type: ResourceType,
35    utilization: f64,
36    throughput: f64,
37    latency: Duration,
38    metrics: HashMap<String, f64>,
39    last_updated: Instant,
40}
41
42/// Resource optimization configuration
43#[derive(Debug, Clone)]
44#[allow(dead_code)]
45pub struct OptimizationConfig {
46    resource_type: ResourceType,
47    name: String,
48    status: OptimizationStatus,
49    settings: HashMap<String, String>,
50    target_utilization: f64,
51    target_throughput: f64,
52    target_latency: Duration,
53    last_modified: Instant,
54}
55
56/// Performance optimization manager
57pub struct PerformanceOptimizer {
58    resources: Arc<Mutex<HashMap<String, OptimizationConfig>>>,
59    metrics: Arc<Mutex<HashMap<String, PerformanceMetrics>>>,
60    input_counter: Arc<Mutex<usize>>,
61    auto_save_frequency: usize,
62}
63
64impl PerformanceOptimizer {
65    /// Create a new performance optimizer
66    pub fn new(auto_save_frequency: usize) -> Self {
67        Self {
68            resources: Arc::new(Mutex::new(HashMap::new())),
69            metrics: Arc::new(Mutex::new(HashMap::new())),
70            input_counter: Arc::new(Mutex::new(0)),
71            auto_save_frequency,
72        }
73    }
74
75    /// Add or update resource configuration
76    pub fn configure_resource(
77        &self,
78        resource_name: &str,
79        resource_type: ResourceType,
80        settings: HashMap<String, String>,
81        target_utilization: f64,
82        target_throughput: f64,
83        target_latency: Duration,
84    ) -> Result<(), String> {
85        {
86            let mut resources = self
87                .resources
88                .lock()
89                .map_err(|e| format!("Mutex lock error: {e}"))?;
90
91            let config = OptimizationConfig {
92                resource_type,
93                name: resource_name.to_string(),
94                status: OptimizationStatus::NotOptimized,
95                settings,
96                target_utilization,
97                target_throughput,
98                target_latency,
99                last_modified: Instant::now(),
100            };
101
102            resources.insert(resource_name.to_string(), config);
103        } // Release the lock before calling auto-save
104
105        // Record input and potentially auto-save
106        let _ = self.record_input_and_check_save();
107
108        Ok(())
109    }
110
111    /// Update performance metrics for a resource
112    pub fn update_metrics(
113        &self,
114        resource_name: &str,
115        utilization: f64,
116        throughput: f64,
117        latency: Duration,
118        additional_metrics: HashMap<String, f64>,
119    ) -> Result<(), String> {
120        // Check if resource exists and get resource type
121        let resource_type = {
122            let resources = self
123                .resources
124                .lock()
125                .map_err(|e| format!("Mutex lock error: {e}"))?;
126            if !resources.contains_key(resource_name) {
127                return Err(format!("Resource not found: {resource_name}"));
128            }
129            resources
130                .get(resource_name)
131                .ok_or(format!("Resource not found: {resource_name}"))?
132                .resource_type
133        };
134
135        // Update metrics
136        {
137            let mut metrics_map = self
138                .metrics
139                .lock()
140                .map_err(|e| format!("Mutex lock error: {e}"))?;
141
142            let metrics = PerformanceMetrics {
143                resource_type,
144                utilization,
145                throughput,
146                latency,
147                metrics: additional_metrics,
148                last_updated: Instant::now(),
149            };
150
151            metrics_map.insert(resource_name.to_string(), metrics);
152        } // Release the lock before calling auto-save
153
154        // Record input and potentially auto-save
155        let _ = self.record_input_and_check_save();
156
157        Ok(())
158    }
159
160    /// Record an input and check if auto-save is needed
161    fn record_input_and_check_save(&self) -> Result<(), String> {
162        let mut counter = self
163            .input_counter
164            .lock()
165            .map_err(|e| format!("Mutex lock error: {e}"))?;
166        *counter += 1;
167
168        // Auto-save every Nth input (e.g., every 20th input)
169        if *counter % self.auto_save_frequency == 0 {
170            match self.save_state_to_memory() {
171                Ok(_) => println!("Auto-saved performance state after {} changes", *counter),
172                Err(e) => eprintln!("Failed to auto-save: {e}"),
173            }
174        }
175
176        Ok(())
177    }
178
179    /// Save the current state to memory (no file writing)
180    fn save_state_to_memory(&self) -> Result<(), String> {
181        // In a real implementation, this would create a snapshot of current performance state
182        // For this implementation, we're just keeping everything in memory
183        let resources = self
184            .resources
185            .lock()
186            .map_err(|e| format!("Mutex lock error: {e}"))?;
187        let metrics = self
188            .metrics
189            .lock()
190            .map_err(|e| format!("Mutex lock error: {e}"))?;
191
192        println!(
193            "In-memory performance snapshot created: {} resources, {} metrics",
194            resources.len(),
195            metrics.len()
196        );
197
198        // Here you would normally serialize the state and store it
199        Ok(())
200    }
201
202    /// Optimize a specific resource
203    pub fn optimize_resource(&self, resource_name: &str) -> Result<OptimizationStatus, String> {
204        // Get resource configuration and update status
205        let status = {
206            let mut resources = self
207                .resources
208                .lock()
209                .map_err(|e| format!("Mutex lock error: {e}"))?;
210
211            let config = match resources.get_mut(resource_name) {
212                Some(config) => config,
213                None => return Err(format!("Resource not found: {resource_name}")),
214            };
215
216            // Check if metrics exist
217            let metrics = {
218                let metrics_map = self
219                    .metrics
220                    .lock()
221                    .map_err(|e| format!("Mutex lock error: {e}"))?;
222                match metrics_map.get(resource_name) {
223                    Some(metrics) => metrics.clone(),
224                    None => {
225                        return Err(format!(
226                            "No metrics available for resource: {resource_name}"
227                        ))
228                    }
229                }
230            };
231
232            // For demonstration purposes, we're just simulating optimization
233            println!(
234                "Optimizing resource {}: {:?}",
235                resource_name, config.resource_type
236            );
237
238            // Simulate optimization logic
239            let mut optimized = true;
240
241            if metrics.utilization > config.target_utilization {
242                println!(
243                    "  - High utilization: {:.2}% (target: {:.2}%)",
244                    metrics.utilization * 100.0,
245                    config.target_utilization * 100.0
246                );
247                optimized = false;
248            }
249
250            if metrics.throughput < config.target_throughput {
251                println!(
252                    "  - Low throughput: {:.2} (target: {:.2})",
253                    metrics.throughput, config.target_throughput
254                );
255                optimized = false;
256            }
257
258            if metrics.latency > config.target_latency {
259                println!(
260                    "  - High latency: {:?} (target: {:?})",
261                    metrics.latency, config.target_latency
262                );
263                optimized = false;
264            }
265
266            // Update status
267            config.status = if optimized {
268                OptimizationStatus::Optimized
269            } else {
270                // Apply optimizations (simulated here)
271                println!("  - Applying optimizations...");
272                OptimizationStatus::Optimized
273            };
274
275            config.last_modified = Instant::now();
276            config.status.clone()
277        }; // Release the lock before calling auto-save
278
279        // Record input and potentially auto-save
280        let _ = self.record_input_and_check_save();
281
282        Ok(status)
283    }
284
285    /// Optimize all resources
286    pub fn optimize_all_resources(&self) -> HashMap<String, Result<OptimizationStatus, String>> {
287        let resource_names = match self.resources.lock() {
288            Ok(resources) => {
289                let names: Vec<String> = resources.keys().cloned().collect();
290                drop(resources); // Release the lock
291                names
292            }
293            Err(e) => {
294                // Return empty map with error for all resources if we can't even get the lock
295                let mut map = HashMap::new();
296                map.insert("general".to_string(), Err(format!("Mutex lock error: {e}")));
297                return map;
298            }
299        };
300
301        // Optimize each resource
302        let mut results = HashMap::new();
303        for name in resource_names {
304            results.insert(name.clone(), self.optimize_resource(&name));
305        }
306
307        results
308    }
309
310    /// Get resource configuration
311    pub fn get_resource_config(&self, resource_name: &str) -> Option<OptimizationConfig> {
312        match self.resources.lock() {
313            Ok(resources) => resources.get(resource_name).cloned(),
314            Err(e) => {
315                eprintln!("Mutex lock error: {e}");
316                None
317            }
318        }
319    }
320
321    /// Get resource metrics
322    pub fn get_resource_metrics(&self, resource_name: &str) -> Option<PerformanceMetrics> {
323        match self.metrics.lock() {
324            Ok(metrics) => metrics.get(resource_name).cloned(),
325            Err(e) => {
326                eprintln!("Mutex lock error: {e}");
327                None
328            }
329        }
330    }
331
332    /// Get all resource configurations
333    pub fn get_all_resources(&self) -> Vec<OptimizationConfig> {
334        match self.resources.lock() {
335            Ok(resources) => resources.values().cloned().collect(),
336            Err(e) => {
337                eprintln!("Mutex lock error: {e}");
338                Vec::new()
339            }
340        }
341    }
342
343    /// Get all resource metrics
344    pub fn get_all_metrics(&self) -> Vec<PerformanceMetrics> {
345        match self.metrics.lock() {
346            Ok(metrics) => metrics.values().cloned().collect(),
347            Err(e) => {
348                eprintln!("Mutex lock error: {e}");
349                Vec::new()
350            }
351        }
352    }
353
354    /// Get number of changes and resources
355    pub fn get_stats(&self) -> (usize, usize, usize) {
356        let counter = match self.input_counter.lock() {
357            Ok(counter) => *counter,
358            Err(e) => {
359                eprintln!("Mutex lock error for counter: {e}");
360                0
361            }
362        };
363
364        let resources_len = match self.resources.lock() {
365            Ok(resources) => resources.len(),
366            Err(e) => {
367                eprintln!("Mutex lock error for resources: {e}");
368                0
369            }
370        };
371
372        let metrics_len = match self.metrics.lock() {
373            Ok(metrics) => metrics.len(),
374            Err(e) => {
375                eprintln!("Mutex lock error for metrics: {e}");
376                0
377            }
378        };
379
380        (counter, resources_len, metrics_len)
381    }
382}
383
384// Tests for the PerformanceOptimizer
385#[cfg(test)]
386mod tests {
387    use super::*;
388
389    #[test]
390    fn test_resource_configuration_and_auto_save() -> Result<(), Box<dyn std::error::Error>> {
391        let optimizer = PerformanceOptimizer::new(20); // Auto-save every 20th change
392
393        // Configure 25 resources to trigger auto-save
394        for i in 0..25 {
395            let mut settings = HashMap::new();
396            settings.insert("max_connections".to_string(), "100".to_string());
397            settings.insert("timeout".to_string(), "5000".to_string());
398
399            optimizer.configure_resource(
400                &format!("resource_{i}"),
401                ResourceType::CPU,
402                settings,
403                0.7,
404                1000.0,
405                Duration::from_millis(100),
406            )?;
407        }
408
409        // Check stats
410        let (changes, resources, _) = optimizer.get_stats();
411        assert_eq!(changes, 25);
412        assert_eq!(resources, 25);
413
414        Ok(())
415    }
416
417    #[test]
418    fn test_optimization_workflow() -> Result<(), Box<dyn std::error::Error>> {
419        let optimizer = PerformanceOptimizer::new(10);
420
421        // Configure a resource
422        let mut settings = HashMap::new();
423        settings.insert("cache_size".to_string(), "1024".to_string());
424
425        optimizer.configure_resource(
426            "database",
427            ResourceType::Database,
428            settings,
429            0.8,
430            500.0,
431            Duration::from_millis(50),
432        )?;
433
434        // Add metrics
435        let mut additional_metrics = HashMap::new();
436        additional_metrics.insert("cache_hits".to_string(), 0.75);
437        additional_metrics.insert("query_count".to_string(), 1500.0);
438
439        optimizer.update_metrics(
440            "database",
441            0.9,                       // High utilization, needs optimization
442            450.0,                     // Lower than target
443            Duration::from_millis(60), // Higher than target
444            additional_metrics,
445        )?;
446
447        // Optimize the resource
448        let result = optimizer.optimize_resource("database")?;
449        assert_eq!(result, OptimizationStatus::Optimized);
450
451        // Verify the status
452        if let Some(config) = optimizer.get_resource_config("database") {
453            assert_eq!(config.status, OptimizationStatus::Optimized);
454        } else {
455            return Err("Resource config not found".into());
456        }
457
458        Ok(())
459    }
460}