1use crate::core::types::TrackingResult;
6use crate::export::fast_export_coordinator::{FastExportConfig, FastExportConfigBuilder};
7use crate::export::config_optimizer::OptimizationTarget;
9
10#[derive(Debug, Clone)]
12pub struct PerformanceTestResult {
13 pub duration_ms: u64,
14 pub memory_usage_mb: f64,
15 pub success: bool,
16}
17
18use serde::{Deserialize, Serialize};
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct SystemResources {
23 pub cpu_cores: usize,
25 pub available_memory_mb: usize,
27 pub system_load: f64,
29 pub disk_space_mb: usize,
31 pub system_type: SystemType,
33}
34
35#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37pub enum SystemType {
38 HighPerformanceServer,
40 DevelopmentWorkstation,
42 Desktop,
44 Laptop,
46 Embedded,
48 Unknown,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct ConfigurationRecommendation {
55 pub recommended_shard_size: usize,
57 pub recommended_thread_count: usize,
59 pub recommended_buffer_size: usize,
61 pub optimization_target: OptimizationTarget,
63 pub expected_performance_gain: f64,
65 pub expected_memory_usage_mb: f64,
67 pub reasoning: Vec<String>,
69 pub confidence: f64,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct PerformanceDiagnosis {
76 pub diagnosis_time: u64,
78 pub system_status: SystemResourceStatus,
80 pub bottlenecks: Vec<PerformanceBottleneck>,
82 pub optimization_suggestions: Vec<OptimizationSuggestion>,
84 pub health_score: u8,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct SystemResourceStatus {
91 pub cpu_usage_percent: f64,
93 pub memory_usage_percent: f64,
95 pub disk_usage_percent: f64,
97 pub load_status: LoadStatus,
99}
100
101#[derive(Debug, Clone, Serialize, Deserialize)]
103pub enum LoadStatus {
104 Low,
106 Medium,
108 High,
110 Overloaded,
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct PerformanceBottleneck {
117 pub bottleneck_type: BottleneckType,
119 pub severity: u8,
121 pub description: String,
123 pub impact: String,
125 pub suggested_solutions: Vec<String>,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize)]
131pub enum BottleneckType {
132 Cpu,
134 Memory,
136 Io,
138 Network,
140 Configuration,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
146pub struct OptimizationSuggestion {
147 pub suggestion_type: SuggestionType,
149 pub priority: u8,
151 pub title: String,
153 pub description: String,
155 pub expected_impact: String,
157 pub implementation_difficulty: u8,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
163pub enum SuggestionType {
164 ConfigurationTuning,
166 HardwareUpgrade,
168 SoftwareOptimization,
170 EnvironmentTuning,
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct OptimizationScore {
177 pub performance_score: u8,
179 pub memory_efficiency: u8,
181 pub stability_score: u8,
183 pub overall_score: u8,
185}
186
187#[derive(Debug)]
189pub struct SystemOptimizer {
190 system_resources: SystemResources,
192 performance_history: Vec<PerformanceTestResult>,
194 validation_rules: ConfigurationValidationRules,
196}
197
198#[derive(Debug, Clone)]
200pub struct ConfigurationValidationRules {
201 pub min_shard_size: usize,
203 pub max_shard_size: usize,
205 pub min_thread_count: usize,
207 pub max_thread_count: usize,
209 pub min_buffer_size: usize,
211 pub max_buffer_size: usize,
213 pub max_memory_limit_mb: usize,
215}
216
217impl Default for ConfigurationValidationRules {
218 fn default() -> Self {
219 Self {
220 min_shard_size: 100,
221 max_shard_size: 10000,
222 min_thread_count: 1,
223 max_thread_count: 32,
224 min_buffer_size: 16 * 1024, max_buffer_size: 16 * 1024 * 1024, max_memory_limit_mb: 512,
227 }
228 }
229}
230
231impl SystemOptimizer {
232 pub fn new() -> TrackingResult<Self> {
234 let system_resources = Self::detect_system_resources()?;
235
236 Ok(Self {
237 system_resources,
238 performance_history: Vec::new(),
239 validation_rules: ConfigurationValidationRules::default(),
240 })
241 }
242
243 pub fn detect_system_resources() -> TrackingResult<SystemResources> {
245 let cpu_cores = num_cpus::get();
246 let available_memory_mb = Self::get_available_memory_mb();
247 let system_load = Self::get_system_load();
248 let disk_space_mb = Self::get_disk_space_mb();
249 let system_type = Self::classify_system_type(cpu_cores, available_memory_mb);
250
251 Ok(SystemResources {
252 cpu_cores,
253 available_memory_mb,
254 system_load,
255 disk_space_mb,
256 system_type,
257 })
258 }
259
260 fn get_available_memory_mb() -> usize {
262 #[cfg(target_os = "linux")]
264 {
265 if let Ok(meminfo) = std::fs::read_to_string("/proc/meminfo") {
266 for line in meminfo.lines() {
267 if line.starts_with("MemAvailable:") {
268 if let Some(kb_str) = line.split_whitespace().nth(1) {
269 if let Ok(kb) = kb_str.parse::<usize>() {
270 return kb / 1024; }
272 }
273 }
274 }
275 }
276 }
277
278 4096 }
281
282 fn get_system_load() -> f64 {
284 #[cfg(target_os = "linux")]
286 {
287 if let Ok(loadavg) = std::fs::read_to_string("/proc/loadavg") {
288 if let Some(load_str) = loadavg.split_whitespace().next() {
289 if let Ok(load) = load_str.parse::<f64>() {
290 return load;
291 }
292 }
293 }
294 }
295
296 0.5 }
298
299 fn get_disk_space_mb() -> usize {
301 10240 }
304
305 fn classify_system_type(cpu_cores: usize, memory_mb: usize) -> SystemType {
307 match (cpu_cores, memory_mb) {
308 (cores, mem) if cores >= 16 && mem >= 32768 => SystemType::HighPerformanceServer,
309 (cores, mem) if cores >= 8 && mem >= 16384 => SystemType::DevelopmentWorkstation,
310 (cores, mem) if cores >= 4 && mem >= 8192 => SystemType::Desktop,
311 (cores, mem) if cores >= 2 && mem >= 4096 => SystemType::Laptop,
312 (cores, mem) if cores >= 1 && mem >= 1024 => SystemType::Embedded,
313 _ => SystemType::Unknown,
314 }
315 }
316
317 pub fn generate_configuration_recommendation(
319 &self,
320 target: OptimizationTarget,
321 dataset_size: Option<usize>,
322 ) -> ConfigurationRecommendation {
323 let dataset_size = dataset_size.unwrap_or(10000);
324
325 let (shard_size, thread_count, buffer_size, reasoning) = match target {
326 OptimizationTarget::Speed => self.optimize_for_speed(dataset_size),
327 OptimizationTarget::Memory => self.optimize_for_memory(dataset_size),
328 OptimizationTarget::Balanced => self.optimize_for_balance(dataset_size),
329 };
330
331 let expected_performance_gain =
332 self.estimate_performance_gain(&target, shard_size, thread_count);
333 let expected_memory_usage =
334 self.estimate_memory_usage(shard_size, thread_count, buffer_size);
335 let confidence = self.calculate_confidence(&target);
336
337 ConfigurationRecommendation {
338 recommended_shard_size: shard_size,
339 recommended_thread_count: thread_count,
340 recommended_buffer_size: buffer_size,
341 optimization_target: target,
342 expected_performance_gain,
343 expected_memory_usage_mb: expected_memory_usage,
344 reasoning,
345 confidence,
346 }
347 }
348
349 fn optimize_for_speed(&self, dataset_size: usize) -> (usize, usize, usize, Vec<String>) {
351 let mut reasoning = Vec::new();
352
353 let base_shard_size = match self.system_resources.system_type {
355 SystemType::HighPerformanceServer => 5000,
356 SystemType::DevelopmentWorkstation => 3000,
357 SystemType::Desktop => 2000,
358 SystemType::Laptop => 1500,
359 SystemType::Embedded => 500,
360 SystemType::Unknown => 1000,
361 };
362
363 let shard_size = if dataset_size > 50000 {
365 base_shard_size * 2
366 } else if dataset_size > 20000 {
367 (base_shard_size as f64 * 1.5) as usize
368 } else {
369 base_shard_size
370 }
371 .min(self.validation_rules.max_shard_size);
372
373 reasoning.push(format!(
374 "basic {:?} system type, recommended shard size: {}",
375 self.system_resources.system_type, shard_size
376 ));
377
378 let thread_count = match self.system_resources.system_load {
380 load if load < 0.5 => self.system_resources.cpu_cores,
381 load if load < 1.0 => (self.system_resources.cpu_cores * 3 / 4).max(1),
382 load if load < 2.0 => (self.system_resources.cpu_cores / 2).max(1),
383 _ => (self.system_resources.cpu_cores / 4).max(1),
384 }
385 .min(self.validation_rules.max_thread_count);
386
387 reasoning.push(format!(
388 "basic system load {:.2}, recommended thread count: {}",
389 self.system_resources.system_load, thread_count
390 ));
391
392 let buffer_size = match self.system_resources.available_memory_mb {
394 mem if mem >= 8192 => 2 * 1024 * 1024, mem if mem >= 4096 => 1024 * 1024, mem if mem >= 2048 => 512 * 1024, _ => 256 * 1024, }
399 .min(self.validation_rules.max_buffer_size);
400
401 reasoning.push(format!(
402 "basic available memory {} MB, recommended buffer size: {} KB",
403 self.system_resources.available_memory_mb,
404 buffer_size / 1024
405 ));
406
407 (shard_size, thread_count, buffer_size, reasoning)
408 }
409
410 fn optimize_for_memory(&self, _dataset_size: usize) -> (usize, usize, usize, Vec<String>) {
412 let mut reasoning = Vec::new();
413
414 let shard_size = match self.system_resources.available_memory_mb {
416 mem if mem >= 4096 => 1000,
417 mem if mem >= 2048 => 750,
418 mem if mem >= 1024 => 500,
419 _ => 250,
420 }
421 .max(self.validation_rules.min_shard_size);
422
423 reasoning.push(format!(
424 "basic available memory {} MB, recommended shard size: {shard_size}",
425 self.system_resources.available_memory_mb
426 ));
427
428 let thread_count = match self.system_resources.available_memory_mb {
430 mem if mem >= 4096 => 4,
431 mem if mem >= 2048 => 2,
432 _ => 1,
433 }
434 .min(self.system_resources.cpu_cores / 2)
435 .max(1);
436
437 reasoning.push(format!(
438 "basic available memory {} MB, recommended thread count: {thread_count}",
439 self.system_resources.available_memory_mb
440 ));
441
442 let buffer_size = match self.system_resources.available_memory_mb {
444 mem if mem >= 2048 => 256 * 1024, mem if mem >= 1024 => 128 * 1024, _ => 64 * 1024, }
448 .max(self.validation_rules.min_buffer_size);
449
450 reasoning.push(format!(
451 "basic available memory {} MB, recommended buffer size: {} KB",
452 self.system_resources.available_memory_mb,
453 buffer_size / 1024
454 ));
455
456 (shard_size, thread_count, buffer_size, reasoning)
457 }
458
459 fn optimize_for_balance(&self, dataset_size: usize) -> (usize, usize, usize, Vec<String>) {
461 let mut reasoning = Vec::new();
462
463 let shard_size = match (self.system_resources.cpu_cores, dataset_size) {
465 (cores, size) if cores >= 8 && size > 20000 => 2000,
466 (cores, size) if cores >= 4 && size > 10000 => 1500,
467 (cores, _) if cores >= 2 => 1000,
468 _ => 750,
469 }
470 .min(self.validation_rules.max_shard_size);
471
472 reasoning.push(format!(
473 "basic cpu cores {}, dataset size {dataset_size}, recommended shard size: {shard_size}",
474 self.system_resources.cpu_cores
475 ));
476
477 let thread_count = (self.system_resources.cpu_cores / 2)
479 .clamp(2, 6)
480 .min(self.validation_rules.max_thread_count);
481
482 reasoning.push(format!(
483 "basic cpu cores {}, dataset size {dataset_size}, recommended thread count: {thread_count}",
484 self.system_resources.cpu_cores,
485 ));
486
487 let buffer_size = match self.system_resources.available_memory_mb {
489 mem if mem >= 4096 => 512 * 1024, mem if mem >= 2048 => 256 * 1024, _ => 128 * 1024, };
493
494 reasoning.push(format!(
495 "basic available memory {} MB, recommended buffer size: {} KB",
496 self.system_resources.available_memory_mb,
497 buffer_size / 1024
498 ));
499
500 (shard_size, thread_count, buffer_size, reasoning)
501 }
502
503 fn estimate_performance_gain(
505 &self,
506 target: &OptimizationTarget,
507 shard_size: usize,
508 thread_count: usize,
509 ) -> f64 {
510 let base_gain = match target {
511 OptimizationTarget::Speed => 3.0,
512 OptimizationTarget::Memory => 1.5,
513 OptimizationTarget::Balanced => 2.0,
514 };
515
516 let thread_multiplier = (thread_count as f64).sqrt();
518
519 let shard_multiplier = if shard_size > 2000 {
521 1.2
522 } else if shard_size < 500 {
523 0.8
524 } else {
525 1.0
526 };
527
528 base_gain * thread_multiplier * shard_multiplier
529 }
530
531 fn estimate_memory_usage(
533 &self,
534 shard_size: usize,
535 thread_count: usize,
536 buffer_size: usize,
537 ) -> f64 {
538 let base_memory = 20.0; let shard_memory = (shard_size as f64 * 500.0 * thread_count as f64) / (1024.0 * 1024.0);
543
544 let buffer_memory = (buffer_size as f64 * thread_count as f64) / (1024.0 * 1024.0);
546
547 base_memory + shard_memory + buffer_memory
548 }
549
550 fn calculate_confidence(&self, target: &OptimizationTarget) -> f64 {
552 let mut confidence: f64 = 0.7; confidence += match self.system_resources.system_type {
556 SystemType::HighPerformanceServer => 0.2,
557 SystemType::DevelopmentWorkstation => 0.15,
558 SystemType::Desktop => 0.1,
559 SystemType::Laptop => 0.05,
560 SystemType::Embedded => -0.1,
561 SystemType::Unknown => -0.2,
562 };
563
564 if !self.performance_history.is_empty() {
566 confidence += 0.1;
567 }
568
569 confidence += match target {
571 OptimizationTarget::Balanced => 0.1,
572 OptimizationTarget::Speed => 0.05,
573 OptimizationTarget::Memory => 0.05,
574 };
575
576 confidence.clamp(0.0, 1.0)
577 }
578
579 pub fn validate_configuration(
581 &self,
582 _config: &FastExportConfigBuilder,
583 ) -> ConfigurationValidationResult {
584 let mut errors = Vec::new();
585 let mut warnings = Vec::new();
586 let mut suggestions = Vec::new();
587
588 let shard_size = 1000; if shard_size < self.validation_rules.min_shard_size {
591 errors.push(format!(
592 "shard size {} is less than minimum value {}",
593 shard_size, self.validation_rules.min_shard_size
594 ));
595 } else if shard_size > self.validation_rules.max_shard_size {
596 errors.push(format!(
597 "shard size {} is greater than maximum value {}",
598 shard_size, self.validation_rules.max_shard_size
599 ));
600 }
601
602 let thread_count = num_cpus::get(); if thread_count > self.system_resources.cpu_cores * 2 {
605 warnings.push(format!(
606 "thread count {thread_count} exceeds twice the number of CPU cores ({}), may cause context switch overhead",
607 self.system_resources.cpu_cores
608 ));
609 }
610
611 let estimated_memory = self.estimate_memory_usage(shard_size, thread_count, 256 * 1024);
613 if estimated_memory > self.system_resources.available_memory_mb as f64 * 0.8 {
614 errors.push(format!(
615 "estimated memory usage {:.1} MB exceeds 80% of available memory ({:.1} MB)",
616 estimated_memory,
617 self.system_resources.available_memory_mb as f64 * 0.8
618 ));
619 }
620
621 if shard_size < 500 && self.system_resources.cpu_cores >= 4 {
623 suggestions.push("consider increasing shard size for better parallelism".to_string());
624 }
625
626 if thread_count == 1 && self.system_resources.cpu_cores > 2 {
627 suggestions
628 .push("consider enabling multi-threading for better performance".to_string());
629 }
630
631 ConfigurationValidationResult {
632 is_valid: errors.is_empty(),
633 errors,
634 warnings,
635 suggestions,
636 estimated_performance_impact: self
637 .estimate_configuration_impact(shard_size, thread_count),
638 }
639 }
640
641 fn estimate_configuration_impact(
643 &self,
644 shard_size: usize,
645 thread_count: usize,
646 ) -> ConfigurationImpact {
647 let performance_score = match (shard_size, thread_count) {
648 (s, t) if s >= 2000 && t >= 4 => 9,
649 (s, t) if s >= 1000 && t >= 2 => 7,
650 (s, t) if s >= 500 && t >= 1 => 5,
651 _ => 3,
652 };
653
654 let memory_efficiency = if shard_size <= 1000 && thread_count <= 4 {
655 8
656 } else {
657 6
658 };
659 let stability_score = if thread_count <= self.system_resources.cpu_cores {
660 9
661 } else {
662 6
663 };
664
665 ConfigurationImpact {
666 performance_score,
667 memory_efficiency,
668 stability_score,
669 overall_score: (performance_score + memory_efficiency + stability_score) / 3,
670 }
671 }
672
673 pub fn diagnose_performance(&self) -> PerformanceDiagnosis {
675 let system_status = self.get_system_resource_status();
676 let bottlenecks = self.identify_bottlenecks(&system_status);
677 let optimization_suggestions = self.generate_optimization_suggestions(&bottlenecks);
678 let health_score = self.calculate_health_score(&system_status, &bottlenecks);
679
680 PerformanceDiagnosis {
681 diagnosis_time: std::time::SystemTime::now()
682 .duration_since(std::time::UNIX_EPOCH)
683 .unwrap_or_default()
684 .as_secs(),
685 system_status,
686 bottlenecks,
687 optimization_suggestions,
688 health_score,
689 }
690 }
691
692 fn get_system_resource_status(&self) -> SystemResourceStatus {
694 let cpu_usage = self.get_cpu_usage();
695 let memory_usage =
696 (self.system_resources.available_memory_mb as f64 / 8192.0 * 100.0).min(100.0);
697 let disk_usage = 50.0; let load_status = match self.system_resources.system_load {
700 load if load < 1.0 => LoadStatus::Low,
701 load if load < 2.0 => LoadStatus::Medium,
702 load if load < 4.0 => LoadStatus::High,
703 _ => LoadStatus::Overloaded,
704 };
705
706 SystemResourceStatus {
707 cpu_usage_percent: cpu_usage,
708 memory_usage_percent: memory_usage,
709 disk_usage_percent: disk_usage,
710 load_status,
711 }
712 }
713
714 fn get_cpu_usage(&self) -> f64 {
716 (self.system_resources.system_load / self.system_resources.cpu_cores as f64 * 100.0)
718 .min(100.0)
719 }
720
721 fn identify_bottlenecks(&self, status: &SystemResourceStatus) -> Vec<PerformanceBottleneck> {
723 let mut bottlenecks = Vec::new();
724
725 if status.cpu_usage_percent > 80.0 {
727 bottlenecks.push(PerformanceBottleneck {
728 bottleneck_type: BottleneckType::Cpu,
729 severity: if status.cpu_usage_percent > 95.0 {
730 9
731 } else {
732 7
733 },
734 description: format!("CPU usage is high: {:.1}%", status.cpu_usage_percent),
735 impact: "Export performance significantly degraded, response time increased"
736 .to_string(),
737 suggested_solutions: vec![
738 "reduce parallel thread count".to_string(),
739 "increase shard size to reduce thread switch overhead".to_string(),
740 "consider exporting when system load is low".to_string(),
741 ],
742 });
743 }
744
745 if status.memory_usage_percent > 85.0 {
747 bottlenecks.push(PerformanceBottleneck {
748 bottleneck_type: BottleneckType::Memory,
749 severity: if status.memory_usage_percent > 95.0 {
750 10
751 } else {
752 8
753 },
754 description: format!("Memory usage is high: {:.1}%", status.memory_usage_percent),
755 impact: "possible memory underutilization, system may slow down or crash"
756 .to_string(),
757 suggested_solutions: vec![
758 "reduce shard size".to_string(),
759 "reduce parallel thread count".to_string(),
760 "reduce buffer size".to_string(),
761 "enable streaming processing mode".to_string(),
762 ],
763 });
764 }
765
766 if self.system_resources.cpu_cores >= 8 && status.cpu_usage_percent < 30.0 {
768 bottlenecks.push(PerformanceBottleneck {
769 bottleneck_type: BottleneckType::Configuration,
770 severity: 5,
771 description: "CPU resource underutilized".to_string(),
772 impact: "Export performance suboptimal".to_string(),
773 suggested_solutions: vec![
774 "add more threads".to_string(),
775 "reduce shard size to increase parallelism".to_string(),
776 "enable speed optimization mode".to_string(),
777 ],
778 });
779 }
780
781 bottlenecks
782 }
783
784 fn generate_optimization_suggestions(
786 &self,
787 bottlenecks: &[PerformanceBottleneck],
788 ) -> Vec<OptimizationSuggestion> {
789 let mut suggestions = Vec::new();
790
791 for bottleneck in bottlenecks {
793 match bottleneck.bottleneck_type {
794 BottleneckType::Cpu => {
795 suggestions.push(OptimizationSuggestion {
796 suggestion_type: SuggestionType::ConfigurationTuning,
797 priority: bottleneck.severity,
798 title: "Optimize CPU usage".to_string(),
799 description: "Adjust parallel configuration to optimize CPU usage"
800 .to_string(),
801 expected_impact: "Increase export speed by 20-40%".to_string(),
802 implementation_difficulty: 3,
803 });
804 }
805 BottleneckType::Memory => {
806 suggestions.push(OptimizationSuggestion {
807 suggestion_type: SuggestionType::ConfigurationTuning,
808 priority: bottleneck.severity,
809 title: "Optimize memory usage".to_string(),
810 description: "Adjust shard size and buffer size to reduce memory usage"
811 .to_string(),
812 expected_impact: "Reduce memory usage by 30-50%".to_string(),
813 implementation_difficulty: 2,
814 });
815 }
816 BottleneckType::Configuration => {
817 suggestions.push(OptimizationSuggestion {
818 suggestion_type: SuggestionType::ConfigurationTuning,
819 priority: bottleneck.severity,
820 title: "Optimize configuration parameters".to_string(),
821 description: "Adjust configuration to fully utilize system resources"
822 .to_string(),
823 expected_impact: "Increase overall performance by 15-30%".to_string(),
824 implementation_difficulty: 1,
825 });
826 }
827 _ => {}
828 }
829 }
830
831 if self.system_resources.system_type == SystemType::HighPerformanceServer {
833 suggestions.push(OptimizationSuggestion {
834 suggestion_type: SuggestionType::ConfigurationTuning,
835 priority: 6,
836 title: "Enable high performance mode".to_string(),
837 description: "Enable maximum performance configuration on high performance servers"
838 .to_string(),
839 expected_impact: "Increase export speed by 50-80%".to_string(),
840 implementation_difficulty: 2,
841 });
842 }
843
844 suggestions
845 }
846
847 fn calculate_health_score(
849 &self,
850 status: &SystemResourceStatus,
851 bottlenecks: &[PerformanceBottleneck],
852 ) -> u8 {
853 let mut score = 100u8;
854
855 if status.cpu_usage_percent > 80.0 {
857 score = score.saturating_sub(20);
858 } else if status.cpu_usage_percent > 60.0 {
859 score = score.saturating_sub(10);
860 }
861
862 if status.memory_usage_percent > 85.0 {
863 score = score.saturating_sub(25);
864 } else if status.memory_usage_percent > 70.0 {
865 score = score.saturating_sub(15);
866 }
867
868 for bottleneck in bottlenecks {
870 score = score.saturating_sub(bottleneck.severity * 2);
871 }
872
873 score.max(10) }
875
876 pub fn add_performance_data(&mut self, result: PerformanceTestResult) {
878 self.performance_history.push(result);
879
880 if self.performance_history.len() > 100 {
882 self.performance_history.remove(0);
883 }
884 }
885
886 pub fn get_system_resources(&self) -> &SystemResources {
888 &self.system_resources
889 }
890
891 pub fn refresh_system_resources(&mut self) -> TrackingResult<()> {
893 self.system_resources = Self::detect_system_resources()?;
894 Ok(())
895 }
896
897 pub fn run_performance_test(&self, _config: &FastExportConfig) -> PerformanceTestResult {
899 let start = std::time::Instant::now();
901
902 std::thread::sleep(std::time::Duration::from_millis(10));
904
905 let duration = start.elapsed();
906
907 PerformanceTestResult {
908 duration_ms: duration.as_millis() as u64,
909 memory_usage_mb: 50.0, success: true,
911 }
912 }
913}
914
915impl Default for SystemOptimizer {
916 fn default() -> Self {
917 Self::new().unwrap_or_else(|_| Self {
918 system_resources: SystemResources {
919 cpu_cores: num_cpus::get(),
920 available_memory_mb: 4096,
921 system_load: 0.5,
922 disk_space_mb: 10240,
923 system_type: SystemType::Unknown,
924 },
925 performance_history: Vec::new(),
926 validation_rules: ConfigurationValidationRules::default(),
927 })
928 }
929}
930
931#[derive(Debug, Clone, Serialize, Deserialize)]
933pub struct ConfigurationValidationResult {
934 pub is_valid: bool,
936 pub errors: Vec<String>,
938 pub warnings: Vec<String>,
940 pub suggestions: Vec<String>,
942 pub estimated_performance_impact: ConfigurationImpact,
944}
945
946#[derive(Debug, Clone, Serialize, Deserialize)]
948pub struct ConfigurationImpact {
949 pub performance_score: u8,
951 pub memory_efficiency: u8,
953 pub stability_score: u8,
955 pub overall_score: u8,
957}
958
959#[cfg(test)]
960mod tests {
961 use super::*;
962
963 #[test]
964 fn test_system_resources_creation() {
965 let resources = SystemResources {
966 cpu_cores: 8,
967 available_memory_mb: 16384,
968 system_load: 0.5,
969 disk_space_mb: 1024000,
970 system_type: SystemType::DevelopmentWorkstation,
971 };
972
973 assert_eq!(resources.cpu_cores, 8);
974 assert_eq!(resources.available_memory_mb, 16384);
975 assert_eq!(resources.system_load, 0.5);
976 assert_eq!(resources.disk_space_mb, 1024000);
977 assert_eq!(resources.system_type, SystemType::DevelopmentWorkstation);
978 }
979
980 #[test]
981 fn test_system_type_variants() {
982 let types = vec![
983 SystemType::HighPerformanceServer,
984 SystemType::DevelopmentWorkstation,
985 SystemType::Desktop,
986 SystemType::Laptop,
987 SystemType::Embedded,
988 SystemType::Unknown,
989 ];
990
991 for system_type in types {
992 assert!(!format!("{system_type:?}").is_empty());
993 }
994 }
995
996 #[test]
997 fn test_configuration_recommendation() {
998 let recommendation = ConfigurationRecommendation {
999 recommended_shard_size: 1024,
1000 recommended_thread_count: 4,
1001 recommended_buffer_size: 8192,
1002 optimization_target: OptimizationTarget::Speed,
1003 expected_performance_gain: 0.25,
1004 expected_memory_usage_mb: 512.0,
1005 reasoning: vec![
1006 "High CPU core count detected".to_string(),
1007 "Sufficient memory available".to_string(),
1008 ],
1009 confidence: 0.85,
1010 };
1011
1012 assert_eq!(recommendation.recommended_shard_size, 1024);
1013 assert_eq!(recommendation.recommended_thread_count, 4);
1014 assert_eq!(recommendation.recommended_buffer_size, 8192);
1015 assert_eq!(recommendation.expected_performance_gain, 0.25);
1016 assert_eq!(recommendation.expected_memory_usage_mb, 512.0);
1017 assert_eq!(recommendation.reasoning.len(), 2);
1018 assert_eq!(recommendation.confidence, 0.85);
1019 }
1020
1021 #[test]
1022 fn test_performance_diagnosis() {
1023 let diagnosis = PerformanceDiagnosis {
1024 diagnosis_time: 1234567890,
1025 system_status: SystemResourceStatus {
1026 cpu_usage_percent: 45.0,
1027 memory_usage_percent: 60.0,
1028 disk_usage_percent: 30.0,
1029 load_status: LoadStatus::Medium,
1030 },
1031 bottlenecks: vec![PerformanceBottleneck {
1032 bottleneck_type: BottleneckType::Memory,
1033 severity: 6,
1034 description: "High memory usage detected".to_string(),
1035 impact: "May cause performance degradation".to_string(),
1036 suggested_solutions: vec![
1037 "Increase buffer sizes".to_string(),
1038 "Optimize memory allocation patterns".to_string(),
1039 ],
1040 }],
1041 optimization_suggestions: vec![OptimizationSuggestion {
1042 suggestion_type: SuggestionType::ConfigurationTuning,
1043 priority: 5,
1044 title: "Consider increasing thread count".to_string(),
1045 description: "Consider increasing thread count".to_string(),
1046 implementation_difficulty: 2,
1047 expected_impact: "Increase performance by 15%".to_string(),
1048 }],
1049 health_score: 75,
1050 };
1051
1052 assert_eq!(diagnosis.diagnosis_time, 1234567890);
1053 assert_eq!(diagnosis.system_status.cpu_usage_percent, 45.0);
1054 assert_eq!(diagnosis.system_status.memory_usage_percent, 60.0);
1055 assert_eq!(diagnosis.bottlenecks.len(), 1);
1056 assert_eq!(diagnosis.optimization_suggestions.len(), 1);
1057 assert_eq!(diagnosis.health_score, 75);
1058 }
1059
1060 #[test]
1061 fn test_system_resource_status() {
1062 let status = SystemResourceStatus {
1063 cpu_usage_percent: 80.0,
1064 memory_usage_percent: 90.0,
1065 disk_usage_percent: 95.0,
1066 load_status: LoadStatus::High,
1067 };
1068
1069 assert_eq!(status.cpu_usage_percent, 80.0);
1070 assert_eq!(status.memory_usage_percent, 90.0);
1071 assert_eq!(status.disk_usage_percent, 95.0);
1072 assert!(matches!(status.load_status, LoadStatus::High));
1073 }
1074
1075 #[test]
1076 fn test_load_status_variants() {
1077 let statuses = vec![
1078 LoadStatus::Low,
1079 LoadStatus::Medium,
1080 LoadStatus::High,
1081 LoadStatus::Overloaded,
1082 ];
1083
1084 for status in statuses {
1085 assert!(!format!("{:?}", status).is_empty());
1086 }
1087 }
1088
1089 #[test]
1090 fn test_performance_bottleneck() {
1091 let bottleneck = PerformanceBottleneck {
1092 bottleneck_type: BottleneckType::Cpu,
1093 severity: 8,
1094 description: "CPU utilization at 95%".to_string(),
1095 impact: "Significant performance impact".to_string(),
1096 suggested_solutions: vec![
1097 "Optimize algorithms".to_string(),
1098 "Reduce computational complexity".to_string(),
1099 "Consider hardware upgrade".to_string(),
1100 ],
1101 };
1102
1103 assert!(matches!(bottleneck.bottleneck_type, BottleneckType::Cpu));
1104 assert_eq!(bottleneck.severity, 8);
1105 assert!(bottleneck.description.contains("CPU"));
1106 assert_eq!(bottleneck.suggested_solutions.len(), 3);
1107 }
1108
1109 #[test]
1110 fn test_bottleneck_type_variants() {
1111 let types = vec![
1112 BottleneckType::Cpu,
1113 BottleneckType::Memory,
1114 BottleneckType::Io,
1115 BottleneckType::Network,
1116 BottleneckType::Configuration,
1117 ];
1118
1119 for bottleneck_type in types {
1120 assert!(!format!("{bottleneck_type:?}").is_empty());
1121 }
1122 }
1123
1124 #[test]
1125 fn test_performance_test_result() {
1126 let result = PerformanceTestResult {
1127 duration_ms: 1500,
1128 memory_usage_mb: 256.5,
1129 success: true,
1130 };
1131
1132 assert_eq!(result.duration_ms, 1500);
1133 assert_eq!(result.memory_usage_mb, 256.5);
1134 assert!(result.success);
1135 }
1136
1137 #[test]
1138 fn test_performance_test_result_failure() {
1139 let result = PerformanceTestResult {
1140 duration_ms: 0,
1141 memory_usage_mb: 0.0,
1142 success: false,
1143 };
1144
1145 assert_eq!(result.duration_ms, 0);
1146 assert_eq!(result.memory_usage_mb, 0.0);
1147 assert!(!result.success);
1148 }
1149
1150 #[test]
1151 fn test_system_optimizer_creation() {
1152 let optimizer = SystemOptimizer::new();
1153
1154 assert!(!format!("{optimizer:?}").is_empty());
1156 }
1157
1158 #[test]
1159 fn test_system_optimizer_detect_resources() {
1160 let _optimizer = SystemOptimizer::new().expect("Failed to create optimizer");
1161 let resources =
1162 SystemOptimizer::detect_system_resources().expect("Failed to detect resources");
1163
1164 assert!(resources.cpu_cores > 0);
1166 assert!(resources.available_memory_mb > 0);
1167 assert!(resources.system_load >= 0.0);
1168 assert!(resources.disk_space_mb > 0);
1169 }
1170
1171 #[test]
1172 fn test_system_optimizer_generate_recommendations() {
1173 let optimizer = SystemOptimizer::new().expect("Failed to create optimizer");
1174 let _resources = SystemResources {
1175 cpu_cores: 8,
1176 available_memory_mb: 16384,
1177 system_load: 0.3,
1178 disk_space_mb: 1024000,
1179 system_type: SystemType::DevelopmentWorkstation,
1180 };
1181
1182 let recommendation =
1183 optimizer.generate_configuration_recommendation(OptimizationTarget::Speed, Some(10000));
1184
1185 assert!(recommendation.recommended_shard_size > 0);
1186 assert!(recommendation.recommended_thread_count > 0);
1187 assert!(recommendation.recommended_buffer_size > 0);
1188 assert!(recommendation.expected_performance_gain >= 0.0);
1189 assert!(recommendation.confidence >= 0.0 && recommendation.confidence <= 1.0);
1190 assert!(!recommendation.reasoning.is_empty());
1191 }
1192
1193 #[test]
1194 fn test_system_optimizer_diagnose_performance() {
1195 let optimizer = SystemOptimizer::new().expect("Failed to create optimizer");
1196 let diagnosis = optimizer.diagnose_performance();
1197
1198 assert!(diagnosis.diagnosis_time > 0);
1199 assert!(diagnosis.system_status.cpu_usage_percent >= 0.0);
1200 assert!(diagnosis.system_status.memory_usage_percent >= 0.0);
1201 assert!(diagnosis.system_status.disk_usage_percent >= 0.0);
1202 assert!(diagnosis.health_score <= 100);
1203 }
1204
1205 #[test]
1206 fn test_system_optimizer_run_performance_test() {
1207 let optimizer = SystemOptimizer::new().expect("Failed to create optimizer");
1208 let config = FastExportConfigBuilder::new()
1209 .shard_size(1024)
1210 .max_threads(Some(2))
1211 .buffer_size(4096)
1212 .build();
1213
1214 let result = optimizer.run_performance_test(&config);
1215
1216 assert!(result.success);
1218 assert!(result.memory_usage_mb >= 0.0);
1219 }
1220
1221 #[test]
1222 fn test_system_optimizer_serialization() {
1223 let resources = SystemResources {
1224 cpu_cores: 4,
1225 available_memory_mb: 8192,
1226 system_load: 0.7,
1227 disk_space_mb: 512000,
1228 system_type: SystemType::Laptop,
1229 };
1230
1231 let serialized = serde_json::to_string(&resources).expect("Failed to serialize");
1233 let deserialized: SystemResources =
1234 serde_json::from_str(&serialized).expect("Failed to deserialize");
1235
1236 assert_eq!(deserialized.cpu_cores, 4);
1237 assert_eq!(deserialized.available_memory_mb, 8192);
1238 assert_eq!(deserialized.system_load, 0.7);
1239 assert_eq!(deserialized.system_type, SystemType::Laptop);
1240 }
1241
1242 #[test]
1243 fn test_configuration_recommendation_serialization() {
1244 let recommendation = ConfigurationRecommendation {
1245 recommended_shard_size: 2048,
1246 recommended_thread_count: 6,
1247 recommended_buffer_size: 16384,
1248 optimization_target: OptimizationTarget::Memory,
1249 expected_performance_gain: 0.20,
1250 expected_memory_usage_mb: 1024.0,
1251 reasoning: vec!["Test reasoning".to_string()],
1252 confidence: 0.90,
1253 };
1254
1255 let serialized = serde_json::to_string(&recommendation).expect("Failed to serialize");
1256 let deserialized: ConfigurationRecommendation =
1257 serde_json::from_str(&serialized).expect("Failed to deserialize");
1258
1259 assert_eq!(deserialized.recommended_shard_size, 2048);
1260 assert_eq!(deserialized.recommended_thread_count, 6);
1261 assert_eq!(deserialized.expected_performance_gain, 0.20);
1262 assert_eq!(deserialized.confidence, 0.90);
1263 }
1264
1265 #[test]
1266 fn test_performance_diagnosis_serialization() {
1267 let diagnosis = PerformanceDiagnosis {
1268 diagnosis_time: 9876543210,
1269 system_status: SystemResourceStatus {
1270 cpu_usage_percent: 55.5,
1271 memory_usage_percent: 70.2,
1272 disk_usage_percent: 40.8,
1273 load_status: LoadStatus::Medium,
1274 },
1275 bottlenecks: vec![],
1276 optimization_suggestions: vec![],
1277 health_score: 80,
1278 };
1279
1280 let serialized = serde_json::to_string(&diagnosis).expect("Failed to serialize");
1281 let deserialized: PerformanceDiagnosis =
1282 serde_json::from_str(&serialized).expect("Failed to deserialize");
1283
1284 assert_eq!(deserialized.diagnosis_time, 9876543210);
1285 assert_eq!(deserialized.system_status.cpu_usage_percent, 55.5);
1286 assert_eq!(deserialized.health_score, 80);
1287 }
1288
1289 #[test]
1290 fn test_optimization_target_variants() {
1291 let targets = vec![
1293 OptimizationTarget::Speed,
1294 OptimizationTarget::Memory,
1295 OptimizationTarget::Balanced,
1296 ];
1297
1298 for target in targets {
1299 assert!(!format!("{:?}", target).is_empty());
1300 }
1301 }
1302
1303 #[test]
1304 fn test_edge_case_zero_resources() {
1305 let _resources = SystemResources {
1306 cpu_cores: 0,
1307 available_memory_mb: 0,
1308 system_load: 0.0,
1309 disk_space_mb: 0,
1310 system_type: SystemType::Unknown,
1311 };
1312
1313 let optimizer = SystemOptimizer::new().expect("Failed to create optimizer");
1314 let recommendation = optimizer
1315 .generate_configuration_recommendation(OptimizationTarget::Balanced, Some(10000));
1316
1317 assert!(recommendation.recommended_shard_size > 0); assert!(recommendation.recommended_thread_count > 0);
1320 assert!(recommendation.confidence >= 0.0);
1321 }
1322
1323 #[test]
1324 fn test_high_load_scenario() {
1325 let resources = SystemResources {
1326 cpu_cores: 16,
1327 available_memory_mb: 65536,
1328 system_load: 0.95, disk_space_mb: 2048000,
1330 system_type: SystemType::HighPerformanceServer,
1331 };
1332
1333 let optimizer = SystemOptimizer::new().expect("Failed to create optimizer");
1334 let recommendation =
1335 optimizer.generate_configuration_recommendation(OptimizationTarget::Speed, Some(10000));
1336
1337 assert!(recommendation.recommended_thread_count <= resources.cpu_cores);
1339 assert!(recommendation.expected_performance_gain >= 0.0);
1340 assert!(!recommendation.reasoning.is_empty());
1341 }
1342
1343 #[test]
1344 fn test_optimization_score_creation() {
1345 let score = OptimizationScore {
1346 performance_score: 8,
1347 memory_efficiency: 7,
1348 stability_score: 9,
1349 overall_score: 8,
1350 };
1351
1352 assert_eq!(score.performance_score, 8);
1353 assert_eq!(score.memory_efficiency, 7);
1354 assert_eq!(score.stability_score, 9);
1355 assert_eq!(score.overall_score, 8);
1356 }
1357
1358 #[test]
1359 fn test_optimization_score_debug() {
1360 let score = OptimizationScore {
1361 performance_score: 5,
1362 memory_efficiency: 6,
1363 stability_score: 7,
1364 overall_score: 6,
1365 };
1366
1367 let debug_str = format!("{:?}", score);
1368 assert!(debug_str.contains("performance_score: 5"));
1369 assert!(debug_str.contains("memory_efficiency: 6"));
1370 assert!(debug_str.contains("stability_score: 7"));
1371 assert!(debug_str.contains("overall_score: 6"));
1372 }
1373}