Skip to main content

voirs_cli/performance/
optimizer.rs

1//! Performance optimizer for automated tuning and recommendations
2//!
3//! This module analyzes performance metrics and applies optimizations automatically
4//! or provides detailed recommendations for manual optimization.
5
6use super::{
7    GpuMetrics, MemoryMetrics, OptimizationCategory, OptimizationRecommendation,
8    PerformanceMetrics, SynthesisMetrics, SystemMetrics,
9};
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12use std::time::Duration;
13
14/// Performance optimizer configuration
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct OptimizerConfig {
17    /// Enable automatic optimizations
18    pub auto_optimize: bool,
19    /// Minimum improvement threshold to trigger optimization
20    pub min_improvement_threshold: f64,
21    /// Maximum optimization attempts per session
22    pub max_optimization_attempts: u32,
23    /// Optimization target priority
24    pub optimization_targets: Vec<OptimizationTarget>,
25    /// Resource constraints
26    pub resource_constraints: ResourceConstraints,
27    /// Optimization aggressiveness (1-10)
28    pub aggressiveness: u8,
29}
30
31/// Optimization targets with priorities
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct OptimizationTarget {
34    /// Target category
35    pub category: OptimizationCategory,
36    /// Priority weight (0.0-1.0)
37    pub weight: f64,
38    /// Enable automatic optimization for this target
39    pub auto_optimize: bool,
40}
41
42/// Resource constraints for optimization
43#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct ResourceConstraints {
45    /// Maximum memory usage in MB
46    pub max_memory_mb: Option<u64>,
47    /// Maximum CPU usage percentage
48    pub max_cpu_percent: Option<f64>,
49    /// Maximum GPU memory usage in MB
50    pub max_gpu_memory_mb: Option<u64>,
51    /// Minimum disk space in MB
52    pub min_disk_space_mb: Option<u64>,
53    /// Target latency in milliseconds
54    pub target_latency_ms: Option<f64>,
55}
56
57/// Optimization result
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct OptimizationResult {
60    /// Applied optimizations
61    pub applied: Vec<AppliedOptimization>,
62    /// Performance improvement achieved
63    pub improvement: PerformanceImprovement,
64    /// Time taken to apply optimizations
65    pub optimization_time: Duration,
66    /// Whether optimization was successful
67    pub success: bool,
68    /// Error message if optimization failed
69    pub error: Option<String>,
70}
71
72/// Details of an applied optimization
73#[derive(Debug, Clone, Serialize, Deserialize)]
74pub struct AppliedOptimization {
75    /// Optimization category
76    pub category: OptimizationCategory,
77    /// Description of what was changed
78    pub description: String,
79    /// Previous value/setting
80    pub previous_value: String,
81    /// New value/setting
82    pub new_value: String,
83    /// Expected improvement
84    pub expected_improvement: f64,
85    /// Actual improvement measured
86    pub actual_improvement: Option<f64>,
87}
88
89/// Performance improvement metrics
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct PerformanceImprovement {
92    /// CPU usage improvement (positive = better)
93    pub cpu_improvement: f64,
94    /// Memory usage improvement (positive = better)
95    pub memory_improvement: f64,
96    /// Synthesis speed improvement (positive = better)
97    pub speed_improvement: f64,
98    /// Overall performance score improvement
99    pub overall_improvement: f64,
100    /// Real-time factor improvement
101    pub rtf_improvement: f64,
102}
103
104/// Performance optimizer
105pub struct PerformanceOptimizer {
106    /// Optimizer configuration
107    config: OptimizerConfig,
108    /// Applied optimizations history
109    optimization_history: Vec<OptimizationResult>,
110    /// Current optimization settings
111    current_settings: HashMap<String, String>,
112    /// Performance baseline
113    baseline_metrics: Option<PerformanceMetrics>,
114}
115
116impl PerformanceOptimizer {
117    /// Create a new performance optimizer
118    pub fn new(config: OptimizerConfig) -> Self {
119        Self {
120            config,
121            optimization_history: Vec::new(),
122            current_settings: HashMap::new(),
123            baseline_metrics: None,
124        }
125    }
126
127    /// Set performance baseline
128    pub fn set_baseline(&mut self, metrics: PerformanceMetrics) {
129        self.baseline_metrics = Some(metrics);
130    }
131
132    /// Analyze metrics and generate optimization recommendations
133    pub async fn analyze_and_recommend(
134        &self,
135        current_metrics: &PerformanceMetrics,
136    ) -> Vec<OptimizationRecommendation> {
137        let mut recommendations = Vec::new();
138
139        // Analyze each optimization target
140        for target in &self.config.optimization_targets {
141            match target.category {
142                OptimizationCategory::Memory => {
143                    self.analyze_memory_optimization(
144                        &mut recommendations,
145                        &current_metrics.memory,
146                        &current_metrics.system,
147                        target.weight,
148                    )
149                    .await;
150                }
151                OptimizationCategory::Cpu => {
152                    self.analyze_cpu_optimization(
153                        &mut recommendations,
154                        &current_metrics.system,
155                        &current_metrics.synthesis,
156                        target.weight,
157                    )
158                    .await;
159                }
160                OptimizationCategory::Gpu => {
161                    if let Some(ref gpu_metrics) = current_metrics.gpu {
162                        self.analyze_gpu_optimization(
163                            &mut recommendations,
164                            gpu_metrics,
165                            &current_metrics.synthesis,
166                            target.weight,
167                        )
168                        .await;
169                    }
170                }
171                OptimizationCategory::Parallelization => {
172                    self.analyze_parallelization_optimization(
173                        &mut recommendations,
174                        &current_metrics.synthesis,
175                        &current_metrics.system,
176                        target.weight,
177                    )
178                    .await;
179                }
180                OptimizationCategory::Caching => {
181                    self.analyze_caching_optimization(
182                        &mut recommendations,
183                        &current_metrics.memory,
184                        &current_metrics.synthesis,
185                        target.weight,
186                    )
187                    .await;
188                }
189                OptimizationCategory::ModelOptimization => {
190                    self.analyze_model_optimization(
191                        &mut recommendations,
192                        &current_metrics.synthesis,
193                        &current_metrics.system,
194                        target.weight,
195                    )
196                    .await;
197                }
198                _ => {
199                    // Handle other categories
200                    self.analyze_general_optimization(
201                        &mut recommendations,
202                        current_metrics,
203                        &target.category,
204                        target.weight,
205                    )
206                    .await;
207                }
208            }
209        }
210
211        // Sort by priority and filter by improvement threshold
212        recommendations.sort_by(|a, b| {
213            b.priority.cmp(&a.priority).then(
214                b.performance_impact
215                    .partial_cmp(&a.performance_impact)
216                    .unwrap_or(std::cmp::Ordering::Equal),
217            )
218        });
219
220        recommendations
221            .into_iter()
222            .filter(|r| r.performance_impact >= self.config.min_improvement_threshold)
223            .take(10) // Limit to top 10 recommendations
224            .collect()
225    }
226
227    /// Apply automatic optimizations
228    pub async fn apply_optimizations(
229        &mut self,
230        recommendations: &[OptimizationRecommendation],
231    ) -> OptimizationResult {
232        let start_time = std::time::Instant::now();
233        let mut applied = Vec::new();
234        let mut total_improvement = 0.0;
235
236        for recommendation in recommendations {
237            // Check if auto-optimization is enabled for this category
238            let auto_optimize = self
239                .config
240                .optimization_targets
241                .iter()
242                .find(|t| t.category == recommendation.category)
243                .map(|t| t.auto_optimize)
244                .unwrap_or(false);
245
246            if !auto_optimize || !self.config.auto_optimize {
247                continue;
248            }
249
250            if let Ok(optimization) = self.apply_single_optimization(recommendation).await {
251                total_improvement += optimization.expected_improvement;
252                applied.push(optimization);
253            }
254        }
255
256        let optimization_time = start_time.elapsed();
257
258        OptimizationResult {
259            applied,
260            improvement: PerformanceImprovement {
261                cpu_improvement: total_improvement * 0.3,
262                memory_improvement: total_improvement * 0.2,
263                speed_improvement: total_improvement * 0.4,
264                overall_improvement: total_improvement,
265                rtf_improvement: total_improvement * 0.5,
266            },
267            optimization_time,
268            success: total_improvement > 0.0,
269            error: None,
270        }
271    }
272
273    /// Apply a single optimization
274    async fn apply_single_optimization(
275        &mut self,
276        recommendation: &OptimizationRecommendation,
277    ) -> Result<AppliedOptimization, Box<dyn std::error::Error>> {
278        let (setting_key, previous_value, new_value) = match recommendation.category {
279            OptimizationCategory::Memory => self.apply_memory_optimization(recommendation).await?,
280            OptimizationCategory::Cpu => self.apply_cpu_optimization(recommendation).await?,
281            OptimizationCategory::Gpu => self.apply_gpu_optimization(recommendation).await?,
282            OptimizationCategory::Parallelization => {
283                self.apply_parallelization_optimization(recommendation)
284                    .await?
285            }
286            OptimizationCategory::Caching => {
287                self.apply_caching_optimization(recommendation).await?
288            }
289            OptimizationCategory::ModelOptimization => {
290                self.apply_model_optimization(recommendation).await?
291            }
292            OptimizationCategory::Io => self.apply_io_optimization(recommendation).await?,
293            OptimizationCategory::Network => {
294                self.apply_network_optimization(recommendation).await?
295            }
296            OptimizationCategory::Configuration => {
297                self.apply_configuration_optimization(recommendation)
298                    .await?
299            }
300            OptimizationCategory::ResourceAllocation => {
301                self.apply_resource_allocation_optimization(recommendation)
302                    .await?
303            }
304        };
305
306        // Update current settings
307        self.current_settings
308            .insert(setting_key.clone(), new_value.clone());
309
310        Ok(AppliedOptimization {
311            category: recommendation.category.clone(),
312            description: recommendation.recommendation.clone(),
313            previous_value,
314            new_value,
315            expected_improvement: recommendation.performance_impact,
316            actual_improvement: None, // Will be measured later
317        })
318    }
319
320    /// Memory optimization analysis
321    async fn analyze_memory_optimization(
322        &self,
323        recommendations: &mut Vec<OptimizationRecommendation>,
324        memory: &MemoryMetrics,
325        system: &SystemMetrics,
326        weight: f64,
327    ) {
328        let memory_usage_percent = (memory.heap_used as f64
329            / (system.memory_used + system.memory_available) as f64)
330            * 100.0;
331
332        if memory_usage_percent > 75.0 {
333            recommendations.push(OptimizationRecommendation {
334                category: OptimizationCategory::Memory,
335                priority: (8.0 * weight) as u8,
336                description: format!("High memory usage: {:.1}%", memory_usage_percent),
337                recommendation:
338                    "Enable memory optimization: reduce batch size, enable streaming processing"
339                        .to_string(),
340                expected_improvement: format!("{:.0}% memory reduction", 30.0 * weight),
341                difficulty: 2,
342                performance_impact: 0.3 * weight,
343            });
344        }
345
346        if memory.fragmentation_percent > 20.0 {
347            recommendations.push(OptimizationRecommendation {
348                category: OptimizationCategory::Memory,
349                priority: (6.0 * weight) as u8,
350                description: format!("Memory fragmentation: {:.1}%", memory.fragmentation_percent),
351                recommendation: "Enable memory pool allocation".to_string(),
352                expected_improvement: format!("{:.0}% fragmentation reduction", 50.0 * weight),
353                difficulty: 3,
354                performance_impact: 0.15 * weight,
355            });
356        }
357
358        if memory.cache_hit_rate < 60.0 {
359            recommendations.push(OptimizationRecommendation {
360                category: OptimizationCategory::Caching,
361                priority: (7.0 * weight) as u8,
362                description: format!("Low cache hit rate: {:.1}%", memory.cache_hit_rate),
363                recommendation: "Increase cache size and enable aggressive caching".to_string(),
364                expected_improvement: format!(
365                    "{:.0}% cache performance improvement",
366                    40.0 * weight
367                ),
368                difficulty: 2,
369                performance_impact: 0.25 * weight,
370            });
371        }
372    }
373
374    /// CPU optimization analysis
375    async fn analyze_cpu_optimization(
376        &self,
377        recommendations: &mut Vec<OptimizationRecommendation>,
378        system: &SystemMetrics,
379        synthesis: &SynthesisMetrics,
380        weight: f64,
381    ) {
382        if system.cpu_usage > 90.0 {
383            recommendations.push(OptimizationRecommendation {
384                category: OptimizationCategory::Cpu,
385                priority: (9.0 * weight) as u8,
386                description: format!("CPU overload: {:.1}%", system.cpu_usage),
387                recommendation:
388                    "Reduce parallel threads, enable GPU acceleration, or use lower quality"
389                        .to_string(),
390                expected_improvement: format!("{:.0}% CPU usage reduction", 40.0 * weight),
391                difficulty: 2,
392                performance_impact: 0.4 * weight,
393            });
394        } else if system.cpu_usage < 30.0 && synthesis.real_time_factor > 2.0 {
395            recommendations.push(OptimizationRecommendation {
396                category: OptimizationCategory::Parallelization,
397                priority: (6.0 * weight) as u8,
398                description: format!("CPU underutilization: {:.1}%", system.cpu_usage),
399                recommendation: "Increase parallel processing threads".to_string(),
400                expected_improvement: format!("{:.0}% throughput increase", 30.0 * weight),
401                difficulty: 1,
402                performance_impact: 0.3 * weight,
403            });
404        }
405
406        if synthesis.real_time_factor < 1.0 {
407            recommendations.push(OptimizationRecommendation {
408                category: OptimizationCategory::ModelOptimization,
409                priority: (8.0 * weight) as u8,
410                description: format!(
411                    "Poor real-time performance: {:.2}x RTF",
412                    synthesis.real_time_factor
413                ),
414                recommendation: "Use quantized models or enable GPU acceleration".to_string(),
415                expected_improvement: "Achieve real-time synthesis".to_string(),
416                difficulty: 4,
417                performance_impact: 0.5 * weight,
418            });
419        }
420    }
421
422    /// GPU optimization analysis
423    async fn analyze_gpu_optimization(
424        &self,
425        recommendations: &mut Vec<OptimizationRecommendation>,
426        gpu: &GpuMetrics,
427        synthesis: &SynthesisMetrics,
428        weight: f64,
429    ) {
430        if gpu.utilization < 40.0 && synthesis.real_time_factor < 2.0 {
431            recommendations.push(OptimizationRecommendation {
432                category: OptimizationCategory::Gpu,
433                priority: (7.0 * weight) as u8,
434                description: format!("Low GPU utilization: {:.1}%", gpu.utilization),
435                recommendation: "Increase batch size or use larger models".to_string(),
436                expected_improvement: format!("{:.0}% GPU utilization improvement", 50.0 * weight),
437                difficulty: 2,
438                performance_impact: 0.3 * weight,
439            });
440        }
441
442        let gpu_memory_usage = (gpu.memory_used as f64 / gpu.memory_total as f64) * 100.0;
443        if gpu_memory_usage > 85.0 {
444            recommendations.push(OptimizationRecommendation {
445                category: OptimizationCategory::Gpu,
446                priority: (8.0 * weight) as u8,
447                description: format!("High GPU memory usage: {:.1}%", gpu_memory_usage),
448                recommendation: "Reduce batch size or enable model quantization".to_string(),
449                expected_improvement: format!("{:.0}% GPU memory reduction", 30.0 * weight),
450                difficulty: 3,
451                performance_impact: 0.2 * weight,
452            });
453        }
454
455        if gpu.temperature > 80.0 {
456            recommendations.push(OptimizationRecommendation {
457                category: OptimizationCategory::Gpu,
458                priority: (9.0 * weight) as u8,
459                description: format!("High GPU temperature: {:.1}°C", gpu.temperature),
460                recommendation: "Reduce GPU workload or improve cooling".to_string(),
461                expected_improvement: "Prevent thermal throttling".to_string(),
462                difficulty: 4,
463                performance_impact: 0.25 * weight,
464            });
465        }
466    }
467
468    /// Parallelization optimization analysis
469    async fn analyze_parallelization_optimization(
470        &self,
471        recommendations: &mut Vec<OptimizationRecommendation>,
472        synthesis: &SynthesisMetrics,
473        system: &SystemMetrics,
474        weight: f64,
475    ) {
476        let available_cores = system.thread_count;
477        let estimated_utilization = system.cpu_usage / 100.0;
478
479        if estimated_utilization < 0.6 && synthesis.queue_depth > 5 {
480            recommendations.push(OptimizationRecommendation {
481                category: OptimizationCategory::Parallelization,
482                priority: (7.0 * weight) as u8,
483                description: format!(
484                    "Suboptimal parallelization: {} cores available",
485                    available_cores
486                ),
487                recommendation: format!(
488                    "Increase worker threads to {}",
489                    (available_cores as f64 * 0.8) as usize
490                ),
491                expected_improvement: format!("{:.0}% throughput improvement", 40.0 * weight),
492                difficulty: 2,
493                performance_impact: 0.35 * weight,
494            });
495        }
496
497        if synthesis.avg_synthesis_time_ms > 1000.0 && synthesis.queue_depth < 2 {
498            recommendations.push(OptimizationRecommendation {
499                category: OptimizationCategory::Parallelization,
500                priority: (6.0 * weight) as u8,
501                description: "Sequential processing detected".to_string(),
502                recommendation: "Enable batch processing for improved efficiency".to_string(),
503                expected_improvement: format!("{:.0}% processing time reduction", 25.0 * weight),
504                difficulty: 2,
505                performance_impact: 0.25 * weight,
506            });
507        }
508    }
509
510    /// Caching optimization analysis
511    async fn analyze_caching_optimization(
512        &self,
513        recommendations: &mut Vec<OptimizationRecommendation>,
514        memory: &MemoryMetrics,
515        synthesis: &SynthesisMetrics,
516        weight: f64,
517    ) {
518        if memory.cache_hit_rate < 70.0 {
519            recommendations.push(OptimizationRecommendation {
520                category: OptimizationCategory::Caching,
521                priority: (7.0 * weight) as u8,
522                description: format!(
523                    "Low cache efficiency: {:.1}% hit rate",
524                    memory.cache_hit_rate
525                ),
526                recommendation: "Increase cache size and implement model preloading".to_string(),
527                expected_improvement: format!("{:.0}% cache hit rate improvement", 30.0 * weight),
528                difficulty: 3,
529                performance_impact: 0.3 * weight,
530            });
531        }
532
533        if synthesis.avg_synthesis_time_ms > 500.0 && memory.cache_hit_rate > 80.0 {
534            recommendations.push(OptimizationRecommendation {
535                category: OptimizationCategory::Caching,
536                priority: (5.0 * weight) as u8,
537                description: "Opportunity for aggressive caching".to_string(),
538                recommendation: "Enable result caching for repeated synthesis".to_string(),
539                expected_improvement: format!("{:.0}% synthesis speed improvement", 50.0 * weight),
540                difficulty: 3,
541                performance_impact: 0.4 * weight,
542            });
543        }
544    }
545
546    /// Model optimization analysis
547    async fn analyze_model_optimization(
548        &self,
549        recommendations: &mut Vec<OptimizationRecommendation>,
550        synthesis: &SynthesisMetrics,
551        system: &SystemMetrics,
552        weight: f64,
553    ) {
554        if synthesis.real_time_factor < 1.0 {
555            recommendations.push(OptimizationRecommendation {
556                category: OptimizationCategory::ModelOptimization,
557                priority: (9.0 * weight) as u8,
558                description: format!(
559                    "Below real-time performance: {:.2}x",
560                    synthesis.real_time_factor
561                ),
562                recommendation: "Use quantized models (INT8/FP16) for faster inference".to_string(),
563                expected_improvement: format!("{:.0}x speed improvement", 2.0 * weight),
564                difficulty: 4,
565                performance_impact: 0.6 * weight,
566            });
567        }
568
569        if synthesis.memory_per_operation_mb > 1000.0 {
570            recommendations.push(OptimizationRecommendation {
571                category: OptimizationCategory::ModelOptimization,
572                priority: (7.0 * weight) as u8,
573                description: format!(
574                    "High memory per operation: {:.0} MB",
575                    synthesis.memory_per_operation_mb
576                ),
577                recommendation: "Use model pruning or distillation for smaller footprint"
578                    .to_string(),
579                expected_improvement: format!("{:.0}% memory reduction", 40.0 * weight),
580                difficulty: 5,
581                performance_impact: 0.3 * weight,
582            });
583        }
584
585        let memory_usage_percent =
586            (synthesis.memory_per_operation_mb * synthesis.queue_depth as f64 * 1024.0 * 1024.0)
587                / (system.memory_used + system.memory_available) as f64
588                * 100.0;
589
590        if memory_usage_percent > 50.0 {
591            recommendations.push(OptimizationRecommendation {
592                category: OptimizationCategory::ModelOptimization,
593                priority: (8.0 * weight) as u8,
594                description: "Models consuming excessive memory".to_string(),
595                recommendation: "Use smaller model variants or enable model streaming".to_string(),
596                expected_improvement: format!(
597                    "{:.0}% memory efficiency improvement",
598                    35.0 * weight
599                ),
600                difficulty: 4,
601                performance_impact: 0.35 * weight,
602            });
603        }
604    }
605
606    /// General optimization analysis for other categories
607    async fn analyze_general_optimization(
608        &self,
609        recommendations: &mut Vec<OptimizationRecommendation>,
610        metrics: &PerformanceMetrics,
611        category: &OptimizationCategory,
612        weight: f64,
613    ) {
614        match category {
615            OptimizationCategory::Io => {
616                if metrics.system.disk_read_bps > 50_000_000
617                    || metrics.system.disk_write_bps > 50_000_000
618                {
619                    recommendations.push(OptimizationRecommendation {
620                        category: OptimizationCategory::Io,
621                        priority: (6.0 * weight) as u8,
622                        description: "High disk I/O detected".to_string(),
623                        recommendation: "Use SSD storage or enable I/O optimization".to_string(),
624                        expected_improvement: format!(
625                            "{:.0}% I/O performance improvement",
626                            40.0 * weight
627                        ),
628                        difficulty: 3,
629                        performance_impact: 0.3 * weight,
630                    });
631                }
632            }
633            OptimizationCategory::Network => {
634                if metrics.system.network_bps > 100_000_000 {
635                    recommendations.push(OptimizationRecommendation {
636                        category: OptimizationCategory::Network,
637                        priority: (5.0 * weight) as u8,
638                        description: "High network usage detected".to_string(),
639                        recommendation: "Enable compression or local caching".to_string(),
640                        expected_improvement: format!(
641                            "{:.0}% network efficiency improvement",
642                            25.0 * weight
643                        ),
644                        difficulty: 3,
645                        performance_impact: 0.2 * weight,
646                    });
647                }
648            }
649            OptimizationCategory::Configuration => {
650                recommendations.push(OptimizationRecommendation {
651                    category: OptimizationCategory::Configuration,
652                    priority: (4.0 * weight) as u8,
653                    description: "Configuration optimization available".to_string(),
654                    recommendation: "Review and optimize system configuration".to_string(),
655                    expected_improvement: format!("{:.0}% overall improvement", 15.0 * weight),
656                    difficulty: 2,
657                    performance_impact: 0.15 * weight,
658                });
659            }
660            OptimizationCategory::ResourceAllocation => {
661                if metrics.synthesis.queue_depth > 10 {
662                    recommendations.push(OptimizationRecommendation {
663                        category: OptimizationCategory::ResourceAllocation,
664                        priority: (7.0 * weight) as u8,
665                        description: format!("High queue depth: {}", metrics.synthesis.queue_depth),
666                        recommendation: "Optimize resource allocation and scheduling".to_string(),
667                        expected_improvement: format!("{:.0}% latency reduction", 30.0 * weight),
668                        difficulty: 3,
669                        performance_impact: 0.25 * weight,
670                    });
671                }
672            }
673            _ => {} // Already handled in specific methods
674        }
675    }
676
677    /// Apply memory optimization
678    async fn apply_memory_optimization(
679        &mut self,
680        recommendation: &OptimizationRecommendation,
681    ) -> Result<(String, String, String), Box<dyn std::error::Error>> {
682        if recommendation.description.contains("High memory usage") {
683            let key = "batch_size".to_string();
684            let previous = self
685                .current_settings
686                .get(&key)
687                .unwrap_or(&"32".to_string())
688                .clone();
689            let new_value = (previous.parse::<u32>()? / 2).to_string();
690            Ok((key, previous, new_value))
691        } else if recommendation.description.contains("fragmentation") {
692            let key = "memory_pool".to_string();
693            let previous = self
694                .current_settings
695                .get(&key)
696                .unwrap_or(&"false".to_string())
697                .clone();
698            let new_value = "true".to_string();
699            Ok((key, previous, new_value))
700        } else {
701            Err("Unknown memory optimization".into())
702        }
703    }
704
705    /// Apply CPU optimization
706    async fn apply_cpu_optimization(
707        &mut self,
708        recommendation: &OptimizationRecommendation,
709    ) -> Result<(String, String, String), Box<dyn std::error::Error>> {
710        if recommendation.description.contains("CPU overload") {
711            let key = "max_threads".to_string();
712            let previous = self
713                .current_settings
714                .get(&key)
715                .unwrap_or(&"8".to_string())
716                .clone();
717            let new_value = (previous.parse::<u32>()?.saturating_sub(2)).to_string();
718            Ok((key, previous, new_value))
719        } else {
720            Err("Unknown CPU optimization".into())
721        }
722    }
723
724    /// Apply GPU optimization
725    async fn apply_gpu_optimization(
726        &mut self,
727        recommendation: &OptimizationRecommendation,
728    ) -> Result<(String, String, String), Box<dyn std::error::Error>> {
729        if recommendation.description.contains("Low GPU utilization") {
730            let key = "gpu_batch_size".to_string();
731            let previous = self
732                .current_settings
733                .get(&key)
734                .unwrap_or(&"16".to_string())
735                .clone();
736            let new_value = (previous.parse::<u32>()? * 2).to_string();
737            Ok((key, previous, new_value))
738        } else if recommendation.description.contains("High GPU memory") {
739            let key = "gpu_batch_size".to_string();
740            let previous = self
741                .current_settings
742                .get(&key)
743                .unwrap_or(&"16".to_string())
744                .clone();
745            let new_value = (previous.parse::<u32>()? / 2).to_string();
746            Ok((key, previous, new_value))
747        } else {
748            Err("Unknown GPU optimization".into())
749        }
750    }
751
752    /// Apply parallelization optimization
753    async fn apply_parallelization_optimization(
754        &mut self,
755        recommendation: &OptimizationRecommendation,
756    ) -> Result<(String, String, String), Box<dyn std::error::Error>> {
757        if recommendation.recommendation.contains("worker threads") {
758            let key = "worker_threads".to_string();
759            let previous = self
760                .current_settings
761                .get(&key)
762                .unwrap_or(&"4".to_string())
763                .clone();
764            let new_value = (previous.parse::<u32>()? + 2).to_string();
765            Ok((key, previous, new_value))
766        } else {
767            Err("Unknown parallelization optimization".into())
768        }
769    }
770
771    /// Apply caching optimization
772    async fn apply_caching_optimization(
773        &mut self,
774        recommendation: &OptimizationRecommendation,
775    ) -> Result<(String, String, String), Box<dyn std::error::Error>> {
776        if recommendation.description.contains("cache") {
777            let key = "cache_size_mb".to_string();
778            let previous = self
779                .current_settings
780                .get(&key)
781                .unwrap_or(&"256".to_string())
782                .clone();
783            let new_value = (previous.parse::<u32>()? * 2).to_string();
784            Ok((key, previous, new_value))
785        } else {
786            Err("Unknown caching optimization".into())
787        }
788    }
789
790    /// Apply model optimization
791    async fn apply_model_optimization(
792        &mut self,
793        recommendation: &OptimizationRecommendation,
794    ) -> Result<(String, String, String), Box<dyn std::error::Error>> {
795        if recommendation.recommendation.contains("quantized") {
796            let key = "model_precision".to_string();
797            let previous = self
798                .current_settings
799                .get(&key)
800                .unwrap_or(&"fp32".to_string())
801                .clone();
802            let new_value = "fp16".to_string();
803            Ok((key, previous, new_value))
804        } else {
805            Err("Unknown model optimization".into())
806        }
807    }
808
809    /// Apply I/O optimization
810    async fn apply_io_optimization(
811        &mut self,
812        recommendation: &OptimizationRecommendation,
813    ) -> Result<(String, String, String), Box<dyn std::error::Error>> {
814        if recommendation.description.contains("buffering") {
815            let key = "io_buffer_size".to_string();
816            let previous = self
817                .current_settings
818                .get(&key)
819                .unwrap_or(&"8192".to_string())
820                .clone();
821            let new_value = (previous.parse::<u32>()? * 2).to_string();
822            Ok((key, previous, new_value))
823        } else if recommendation.description.contains("async") {
824            let key = "async_io".to_string();
825            let previous = self
826                .current_settings
827                .get(&key)
828                .unwrap_or(&"false".to_string())
829                .clone();
830            let new_value = "true".to_string();
831            Ok((key, previous, new_value))
832        } else {
833            Err("Unknown I/O optimization".into())
834        }
835    }
836
837    /// Apply network optimization
838    async fn apply_network_optimization(
839        &mut self,
840        recommendation: &OptimizationRecommendation,
841    ) -> Result<(String, String, String), Box<dyn std::error::Error>> {
842        if recommendation.description.contains("compression") {
843            let key = "network_compression".to_string();
844            let previous = self
845                .current_settings
846                .get(&key)
847                .unwrap_or(&"none".to_string())
848                .clone();
849            let new_value = "gzip".to_string();
850            Ok((key, previous, new_value))
851        } else if recommendation.description.contains("connection pool") {
852            let key = "connection_pool_size".to_string();
853            let previous = self
854                .current_settings
855                .get(&key)
856                .unwrap_or(&"10".to_string())
857                .clone();
858            let new_value = (previous.parse::<u32>()? * 2).to_string();
859            Ok((key, previous, new_value))
860        } else {
861            Err("Unknown network optimization".into())
862        }
863    }
864
865    /// Apply configuration optimization
866    async fn apply_configuration_optimization(
867        &mut self,
868        recommendation: &OptimizationRecommendation,
869    ) -> Result<(String, String, String), Box<dyn std::error::Error>> {
870        if recommendation.description.contains("sample rate") {
871            let key = "sample_rate".to_string();
872            let previous = self
873                .current_settings
874                .get(&key)
875                .unwrap_or(&"22050".to_string())
876                .clone();
877            let new_value = "16000".to_string();
878            Ok((key, previous, new_value))
879        } else if recommendation.description.contains("quality") {
880            let key = "quality_preset".to_string();
881            let previous = self
882                .current_settings
883                .get(&key)
884                .unwrap_or(&"high".to_string())
885                .clone();
886            let new_value = "medium".to_string();
887            Ok((key, previous, new_value))
888        } else {
889            Err("Unknown configuration optimization".into())
890        }
891    }
892
893    /// Apply resource allocation optimization
894    async fn apply_resource_allocation_optimization(
895        &mut self,
896        recommendation: &OptimizationRecommendation,
897    ) -> Result<(String, String, String), Box<dyn std::error::Error>> {
898        if recommendation.description.contains("worker threads") {
899            let key = "worker_threads".to_string();
900            let previous = self
901                .current_settings
902                .get(&key)
903                .unwrap_or(&"4".to_string())
904                .clone();
905            let cpu_count = num_cpus::get();
906            let new_value = cpu_count.to_string();
907            Ok((key, previous, new_value))
908        } else if recommendation.description.contains("memory limit") {
909            let key = "memory_limit_mb".to_string();
910            let previous = self
911                .current_settings
912                .get(&key)
913                .unwrap_or(&"1024".to_string())
914                .clone();
915            let new_value = (previous.parse::<u32>()? * 2).to_string();
916            Ok((key, previous, new_value))
917        } else {
918            Err("Unknown resource allocation optimization".into())
919        }
920    }
921
922    /// Get optimization history
923    pub fn get_optimization_history(&self) -> &[OptimizationResult] {
924        &self.optimization_history
925    }
926
927    /// Get current settings
928    pub fn get_current_settings(&self) -> &HashMap<String, String> {
929        &self.current_settings
930    }
931
932    /// Update configuration
933    pub fn update_config(&mut self, config: OptimizerConfig) {
934        self.config = config;
935    }
936}
937
938impl Default for OptimizerConfig {
939    fn default() -> Self {
940        Self {
941            auto_optimize: false,
942            min_improvement_threshold: 0.1,
943            max_optimization_attempts: 5,
944            optimization_targets: vec![
945                OptimizationTarget {
946                    category: OptimizationCategory::Memory,
947                    weight: 0.8,
948                    auto_optimize: true,
949                },
950                OptimizationTarget {
951                    category: OptimizationCategory::Cpu,
952                    weight: 0.9,
953                    auto_optimize: true,
954                },
955                OptimizationTarget {
956                    category: OptimizationCategory::Gpu,
957                    weight: 0.7,
958                    auto_optimize: false,
959                },
960            ],
961            resource_constraints: ResourceConstraints::default(),
962            aggressiveness: 5,
963        }
964    }
965}
966
967impl Default for ResourceConstraints {
968    fn default() -> Self {
969        Self {
970            max_memory_mb: Some(8192),
971            max_cpu_percent: Some(80.0),
972            max_gpu_memory_mb: Some(6144),
973            min_disk_space_mb: Some(1024),
974            target_latency_ms: Some(500.0),
975        }
976    }
977}
978
979#[cfg(test)]
980mod tests {
981    use super::*;
982
983    #[test]
984    fn test_optimizer_config_default() {
985        let config = OptimizerConfig::default();
986        assert!(!config.auto_optimize);
987        assert_eq!(config.aggressiveness, 5);
988        assert!(config.optimization_targets.len() > 0);
989    }
990
991    #[tokio::test]
992    async fn test_performance_optimizer_creation() {
993        let config = OptimizerConfig::default();
994        let optimizer = PerformanceOptimizer::new(config);
995        assert_eq!(optimizer.optimization_history.len(), 0);
996        assert_eq!(optimizer.current_settings.len(), 0);
997    }
998
999    #[tokio::test]
1000    async fn test_memory_optimization_analysis() {
1001        let config = OptimizerConfig::default();
1002        let optimizer = PerformanceOptimizer::new(config);
1003
1004        let mut recommendations = Vec::new();
1005        let memory = MemoryMetrics {
1006            heap_used: 8_000_000_000, // 8GB
1007            fragmentation_percent: 25.0,
1008            cache_hit_rate: 50.0,
1009            ..Default::default()
1010        };
1011        let system = SystemMetrics {
1012            memory_used: 8_000_000_000,
1013            memory_available: 2_000_000_000,
1014            ..Default::default()
1015        };
1016
1017        optimizer
1018            .analyze_memory_optimization(&mut recommendations, &memory, &system, 1.0)
1019            .await;
1020
1021        assert!(recommendations.len() > 0);
1022        assert!(recommendations
1023            .iter()
1024            .any(|r| r.category == OptimizationCategory::Memory));
1025    }
1026
1027    #[tokio::test]
1028    async fn test_cpu_optimization_analysis() {
1029        let config = OptimizerConfig::default();
1030        let optimizer = PerformanceOptimizer::new(config);
1031
1032        let mut recommendations = Vec::new();
1033        let system = SystemMetrics {
1034            cpu_usage: 95.0, // High CPU usage
1035            ..Default::default()
1036        };
1037        let synthesis = SynthesisMetrics {
1038            real_time_factor: 0.5, // Poor RTF
1039            ..Default::default()
1040        };
1041
1042        optimizer
1043            .analyze_cpu_optimization(&mut recommendations, &system, &synthesis, 1.0)
1044            .await;
1045
1046        assert!(recommendations.len() > 0);
1047        assert!(recommendations
1048            .iter()
1049            .any(|r| r.category == OptimizationCategory::Cpu
1050                || r.category == OptimizationCategory::ModelOptimization));
1051    }
1052
1053    #[tokio::test]
1054    async fn test_optimization_recommendation_sorting() {
1055        let config = OptimizerConfig::default();
1056        let optimizer = PerformanceOptimizer::new(config);
1057
1058        let metrics = PerformanceMetrics {
1059            system: SystemMetrics {
1060                cpu_usage: 95.0,
1061                memory_used: 8_000_000_000,
1062                memory_available: 2_000_000_000,
1063                ..Default::default()
1064            },
1065            memory: MemoryMetrics {
1066                heap_used: 8_000_000_000,
1067                cache_hit_rate: 50.0,
1068                ..Default::default()
1069            },
1070            synthesis: SynthesisMetrics {
1071                real_time_factor: 0.5,
1072                ..Default::default()
1073            },
1074            ..Default::default()
1075        };
1076
1077        let recommendations = optimizer.analyze_and_recommend(&metrics).await;
1078
1079        assert!(!recommendations.is_empty());
1080
1081        // Check that recommendations are sorted by priority
1082        for i in 1..recommendations.len() {
1083            assert!(recommendations[i - 1].priority >= recommendations[i].priority);
1084        }
1085    }
1086}