system_analysis/
utils.rs

1//! Utility functions and helpers for system analysis.
2
3use crate::error::Result;
4use crate::resources::{ResourceType, ResourceAmount, CapabilityLevel};
5use crate::types::{SystemProfile, WorkloadRequirements};
6use serde::{Deserialize, Serialize};
7use std::time::{Duration, Instant};
8
9/// Benchmark runner for performance testing
10pub struct BenchmarkRunner {
11    timeout: Duration,
12    #[allow(dead_code)]
13    iterations: u32,
14}
15
16impl BenchmarkRunner {
17    /// Create a new benchmark runner
18    pub fn new(timeout: Duration, iterations: u32) -> Self {
19        Self { timeout, iterations }
20    }
21
22    /// Run CPU benchmark
23    pub fn run_cpu_benchmark(&self) -> Result<BenchmarkResult> {
24        let start = Instant::now();
25        let mut operations = 0u64;
26
27        while start.elapsed() < self.timeout {
28            // Simple CPU-intensive operation
29            for _ in 0..10000 {
30                operations += 1;
31                let _ = (operations as f64).sqrt();
32            }
33        }
34
35        Ok(BenchmarkResult {
36            benchmark_type: BenchmarkType::CPU,
37            duration: start.elapsed(),
38            operations,
39            score: self.calculate_cpu_score(operations, start.elapsed()),
40        })
41    }
42
43    /// Run memory benchmark
44    pub fn run_memory_benchmark(&self) -> Result<BenchmarkResult> {
45        let start = Instant::now();
46        let mut operations = 0u64;
47        let mut data = vec![0u8; 1024 * 1024]; // 1MB buffer
48
49        while start.elapsed() < self.timeout {
50            // Memory-intensive operations
51            for chunk in data.chunks_mut(1024) {
52                chunk.fill(operations as u8);
53                operations += 1;
54            }
55        }
56
57        Ok(BenchmarkResult {
58            benchmark_type: BenchmarkType::Memory,
59            duration: start.elapsed(),
60            operations,
61            score: self.calculate_memory_score(operations, start.elapsed()),
62        })
63    }
64
65    /// Calculate CPU score from benchmark results
66    fn calculate_cpu_score(&self, operations: u64, duration: Duration) -> f64 {
67        let ops_per_sec = operations as f64 / duration.as_secs_f64();
68        // Normalize to 0-10 scale (this would be calibrated against known hardware)
69        (ops_per_sec / 100_000.0).min(10.0)
70    }
71
72    /// Calculate memory score from benchmark results
73    fn calculate_memory_score(&self, operations: u64, duration: Duration) -> f64 {
74        let ops_per_sec = operations as f64 / duration.as_secs_f64();
75        // Normalize to 0-10 scale
76        (ops_per_sec / 50_000.0).min(10.0)
77    }
78}
79
80/// Benchmark result
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct BenchmarkResult {
83    pub benchmark_type: BenchmarkType,
84    pub duration: Duration,
85    pub operations: u64,
86    pub score: f64,
87}
88
89/// Types of benchmarks
90#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
91pub enum BenchmarkType {
92    CPU,
93    Memory,
94    Storage,
95    Network,
96    GPU,
97}
98
99/// System fingerprinting utilities
100pub struct SystemFingerprinter;
101
102impl SystemFingerprinter {
103    /// Generate a unique fingerprint for the system
104    pub fn generate_fingerprint() -> String {
105        use std::collections::hash_map::DefaultHasher;
106        use std::hash::{Hash, Hasher};
107
108        let mut hasher = DefaultHasher::new();
109        
110        // Include system-specific information
111        std::env::consts::OS.hash(&mut hasher);
112        std::env::consts::ARCH.hash(&mut hasher);
113        
114        // Include hostname if available
115        if let Ok(hostname) = std::env::var("COMPUTERNAME") {
116            hostname.hash(&mut hasher);
117        } else if let Ok(hostname) = std::env::var("HOSTNAME") {
118            hostname.hash(&mut hasher);
119        }
120
121        format!("{:x}", hasher.finish())
122    }
123
124    /// Check if system configuration has changed
125    pub fn has_system_changed(last_fingerprint: &str) -> bool {
126        let current_fingerprint = Self::generate_fingerprint();
127        current_fingerprint != last_fingerprint
128    }
129}
130
131/// Performance optimization suggestions
132pub struct PerformanceOptimizer;
133
134impl PerformanceOptimizer {
135    /// Suggest optimizations for a specific workload
136    pub fn suggest_optimizations(
137        system_profile: &SystemProfile,
138        _workload_requirements: &WorkloadRequirements,
139    ) -> Vec<OptimizationSuggestion> {
140        let mut suggestions = Vec::new();
141
142        // CPU optimizations
143        if system_profile.cpu_score() < 7.0 {
144            suggestions.push(OptimizationSuggestion {
145                resource_type: ResourceType::CPU,
146                suggestion: "Consider enabling CPU performance mode".to_string(),
147                expected_improvement: "5-15% performance increase".to_string(),
148                difficulty: OptimizationDifficulty::Easy,
149            });
150        }
151
152        // Memory optimizations
153        if system_profile.memory_score() < 6.0 {
154            suggestions.push(OptimizationSuggestion {
155                resource_type: ResourceType::Memory,
156                suggestion: "Close unnecessary applications to free memory".to_string(),
157                expected_improvement: "10-20% memory availability increase".to_string(),
158                difficulty: OptimizationDifficulty::Easy,
159            });
160        }
161
162        // Storage optimizations
163        if system_profile.storage_score() < 5.0 {
164            suggestions.push(OptimizationSuggestion {
165                resource_type: ResourceType::Storage,
166                suggestion: "Enable storage optimization and defragmentation".to_string(),
167                expected_improvement: "10-30% I/O performance increase".to_string(),
168                difficulty: OptimizationDifficulty::Medium,
169            });
170        }
171
172        // GPU optimizations
173        if system_profile.gpu_score() < 4.0 {
174            suggestions.push(OptimizationSuggestion {
175                resource_type: ResourceType::GPU,
176                suggestion: "Update GPU drivers and enable GPU scheduling".to_string(),
177                expected_improvement: "5-25% graphics performance increase".to_string(),
178                difficulty: OptimizationDifficulty::Medium,
179            });
180        }
181
182        suggestions
183    }
184}
185
186/// Optimization suggestion
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct OptimizationSuggestion {
189    pub resource_type: ResourceType,
190    pub suggestion: String,
191    pub expected_improvement: String,
192    pub difficulty: OptimizationDifficulty,
193}
194
195/// Difficulty levels for optimizations
196#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
197pub enum OptimizationDifficulty {
198    Easy,
199    Medium,
200    Hard,
201    Expert,
202}
203
204/// Resource comparison utilities
205pub struct ResourceComparator;
206
207impl ResourceComparator {
208    /// Compare two systems and highlight differences
209    pub fn compare_systems(
210        system_a: &SystemProfile,
211        system_b: &SystemProfile,
212    ) -> SystemComparison {
213        let cpu_diff = system_b.cpu_score() - system_a.cpu_score();
214        let gpu_diff = system_b.gpu_score() - system_a.gpu_score();
215        let memory_diff = system_b.memory_score() - system_a.memory_score();
216        let storage_diff = system_b.storage_score() - system_a.storage_score();
217        let network_diff = system_b.network_score() - system_a.network_score();
218
219        let overall_diff = system_b.overall_score() - system_a.overall_score();
220
221        SystemComparison {
222            cpu_difference: cpu_diff,
223            gpu_difference: gpu_diff,
224            memory_difference: memory_diff,
225            storage_difference: storage_diff,
226            network_difference: network_diff,
227            overall_difference: overall_diff,
228            winner: if overall_diff > 0.0 {
229                ComparisonResult::SystemB
230            } else if overall_diff < 0.0 {
231                ComparisonResult::SystemA
232            } else {
233                ComparisonResult::Tie
234            },
235        }
236    }
237
238    /// Compare resource amounts
239    pub fn compare_resource_amounts(
240        amount_a: &ResourceAmount,
241        amount_b: &ResourceAmount,
242    ) -> Option<f64> {
243        match (amount_a, amount_b) {
244            (ResourceAmount::Score(a), ResourceAmount::Score(b)) => Some(b - a),
245            (ResourceAmount::Gigabytes(a), ResourceAmount::Gigabytes(b)) => Some(b - a),
246            (ResourceAmount::Megahertz(a), ResourceAmount::Megahertz(b)) => Some(b - a),
247            (ResourceAmount::Units(a), ResourceAmount::Units(b)) => Some(*b as f64 - *a as f64),
248            (ResourceAmount::Percentage(a), ResourceAmount::Percentage(b)) => Some(b - a),
249            (ResourceAmount::Level(a), ResourceAmount::Level(b)) => {
250                let a_score: f64 = (*a).into();
251                let b_score: f64 = (*b).into();
252                Some(b_score - a_score)
253            }
254            _ => None, // Different types, cannot compare directly
255        }
256    }
257}
258
259/// System comparison result
260#[derive(Debug, Clone, Serialize, Deserialize)]
261pub struct SystemComparison {
262    pub cpu_difference: f64,
263    pub gpu_difference: f64,
264    pub memory_difference: f64,
265    pub storage_difference: f64,
266    pub network_difference: f64,
267    pub overall_difference: f64,
268    pub winner: ComparisonResult,
269}
270
271/// Comparison result
272#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
273pub enum ComparisonResult {
274    SystemA,
275    SystemB,
276    Tie,
277}
278
279/// Configuration validation utilities
280pub struct ConfigValidator;
281
282impl ConfigValidator {
283    /// Validate workload requirements for consistency
284    pub fn validate_workload_requirements(
285        workload_requirements: &WorkloadRequirements,
286    ) -> Result<Vec<ValidationIssue>> {
287        let mut issues = Vec::new();
288
289        // Check for conflicting requirements
290        let mut resource_types = std::collections::HashSet::new();
291        for req in &workload_requirements.resource_requirements {
292            if resource_types.contains(&req.resource_type) {
293                issues.push(ValidationIssue {
294                    severity: ValidationSeverity::Warning,
295                    message: format!("Duplicate resource requirement for {:?}", req.resource_type),
296                    suggestion: "Merge duplicate requirements".to_string(),
297                });
298            }
299            resource_types.insert(req.resource_type);
300        }
301
302        // Check for unrealistic requirements
303        for req in &workload_requirements.resource_requirements {
304            match &req.minimum {
305                ResourceAmount::Gigabytes(gb) if *gb > 1000.0 => {
306                    issues.push(ValidationIssue {
307                        severity: ValidationSeverity::Warning,
308                        message: format!("Very high {} requirement: {:.1}GB", req.resource_type, gb),
309                        suggestion: "Verify this requirement is realistic".to_string(),
310                    });
311                }
312                ResourceAmount::Score(score) if *score > 10.0 => {
313                    issues.push(ValidationIssue {
314                        severity: ValidationSeverity::Error,
315                        message: format!("Invalid score for {}: {:.1} (max 10.0)", req.resource_type, score),
316                        suggestion: "Adjust score to be within 0-10 range".to_string(),
317                    });
318                }
319                _ => {}
320            }
321        }
322
323        // Validate workload-specific requirements
324        if let Some(workload) = &workload_requirements.workload {
325            if let Err(e) = workload.validate() {
326                issues.push(ValidationIssue {
327                    severity: ValidationSeverity::Error,
328                    message: format!("Workload validation failed: {}", e),
329                    suggestion: "Fix workload configuration".to_string(),
330                });
331            }
332        }
333
334        Ok(issues)
335    }
336
337    /// Validate system profile for consistency
338    pub fn validate_system_profile(system_profile: &SystemProfile) -> Result<Vec<ValidationIssue>> {
339        let mut issues = Vec::new();
340
341        // Check for unrealistic scores
342        let scores = [
343            ("CPU", system_profile.cpu_score()),
344            ("GPU", system_profile.gpu_score()),
345            ("Memory", system_profile.memory_score()),
346            ("Storage", system_profile.storage_score()),
347            ("Network", system_profile.network_score()),
348        ];
349
350        for (name, score) in scores {
351            if score < 0.0 || score > 10.0 {
352                issues.push(ValidationIssue {
353                    severity: ValidationSeverity::Error,
354                    message: format!("Invalid {} score: {:.1} (should be 0-10)", name, score),
355                    suggestion: "Recalibrate scoring algorithm".to_string(),
356                });
357            }
358        }
359
360        // Check for inconsistencies in system info
361        let memory_gb = system_profile.system_info.memory_info.total_ram as f64 / 1024.0;
362        if memory_gb > 1000.0 {
363            issues.push(ValidationIssue {
364                severity: ValidationSeverity::Warning,
365                message: format!("Very high memory amount detected: {:.1}GB", memory_gb),
366                suggestion: "Verify memory detection is accurate".to_string(),
367            });
368        }
369
370        Ok(issues)
371    }
372}
373
374/// Validation issue
375#[derive(Debug, Clone, Serialize, Deserialize)]
376pub struct ValidationIssue {
377    pub severity: ValidationSeverity,
378    pub message: String,
379    pub suggestion: String,
380}
381
382/// Validation severity levels
383#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
384pub enum ValidationSeverity {
385    Info,
386    Warning,
387    Error,
388}
389
390/// Hardware detection utilities
391pub struct HardwareDetector;
392
393impl HardwareDetector {
394    /// Detect hardware changes since last analysis
395    pub fn detect_hardware_changes(
396        last_system_info: &crate::types::SystemInfo,
397        current_system_info: &crate::types::SystemInfo,
398    ) -> Vec<HardwareChange> {
399        let mut changes = Vec::new();
400
401        // Check CPU changes
402        if last_system_info.cpu_info.brand != current_system_info.cpu_info.brand {
403            changes.push(HardwareChange {
404                component: HardwareComponent::CPU,
405                change_type: HardwareChangeType::Replaced,
406                details: format!("CPU changed from '{}' to '{}'", 
407                    last_system_info.cpu_info.brand, 
408                    current_system_info.cpu_info.brand),
409            });
410        }
411
412        // Check memory changes
413        if last_system_info.memory_info.total_ram != current_system_info.memory_info.total_ram {
414            changes.push(HardwareChange {
415                component: HardwareComponent::Memory,
416                change_type: if current_system_info.memory_info.total_ram > last_system_info.memory_info.total_ram {
417                    HardwareChangeType::Upgraded
418                } else {
419                    HardwareChangeType::Downgraded
420                },
421                details: format!("Memory changed from {}MB to {}MB", 
422                    last_system_info.memory_info.total_ram, 
423                    current_system_info.memory_info.total_ram),
424            });
425        }
426
427        // Check GPU changes
428        if last_system_info.gpu_info.len() != current_system_info.gpu_info.len() {
429            changes.push(HardwareChange {
430                component: HardwareComponent::GPU,
431                change_type: if current_system_info.gpu_info.len() > last_system_info.gpu_info.len() {
432                    HardwareChangeType::Added
433                } else {
434                    HardwareChangeType::Removed
435                },
436                details: format!("GPU count changed from {} to {}", 
437                    last_system_info.gpu_info.len(), 
438                    current_system_info.gpu_info.len()),
439            });
440        }
441
442        // Check storage changes
443        if last_system_info.storage_info.len() != current_system_info.storage_info.len() {
444            changes.push(HardwareChange {
445                component: HardwareComponent::Storage,
446                change_type: if current_system_info.storage_info.len() > last_system_info.storage_info.len() {
447                    HardwareChangeType::Added
448                } else {
449                    HardwareChangeType::Removed
450                },
451                details: format!("Storage device count changed from {} to {}", 
452                    last_system_info.storage_info.len(), 
453                    current_system_info.storage_info.len()),
454            });
455        }
456
457        changes
458    }
459}
460
461/// Hardware change information
462#[derive(Debug, Clone, Serialize, Deserialize)]
463pub struct HardwareChange {
464    pub component: HardwareComponent,
465    pub change_type: HardwareChangeType,
466    pub details: String,
467}
468
469/// Hardware components
470#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
471pub enum HardwareComponent {
472    CPU,
473    GPU,
474    Memory,
475    Storage,
476    Network,
477}
478
479/// Types of hardware changes
480#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
481pub enum HardwareChangeType {
482    Added,
483    Removed,
484    Replaced,
485    Upgraded,
486    Downgraded,
487}
488
489/// Performance trend analysis
490pub struct TrendAnalyzer;
491
492impl TrendAnalyzer {
493    /// Analyze performance trends over time
494    pub fn analyze_trends(
495        historical_profiles: &[SystemProfile],
496    ) -> PerformanceTrends {
497        if historical_profiles.is_empty() {
498            return PerformanceTrends::default();
499        }
500
501        let mut cpu_scores = Vec::new();
502        let mut gpu_scores = Vec::new();
503        let mut memory_scores = Vec::new();
504        let mut storage_scores = Vec::new();
505        let mut network_scores = Vec::new();
506
507        for profile in historical_profiles {
508            cpu_scores.push(profile.cpu_score());
509            gpu_scores.push(profile.gpu_score());
510            memory_scores.push(profile.memory_score());
511            storage_scores.push(profile.storage_score());
512            network_scores.push(profile.network_score());
513        }
514
515        PerformanceTrends {
516            cpu_trend: Self::calculate_trend(&cpu_scores),
517            gpu_trend: Self::calculate_trend(&gpu_scores),
518            memory_trend: Self::calculate_trend(&memory_scores),
519            storage_trend: Self::calculate_trend(&storage_scores),
520            network_trend: Self::calculate_trend(&network_scores),
521            overall_trend: Self::calculate_trend(&historical_profiles.iter()
522                .map(|p| p.overall_score())
523                .collect::<Vec<_>>()),
524        }
525    }
526
527    /// Calculate trend for a series of values
528    fn calculate_trend(values: &[f64]) -> TrendDirection {
529        if values.len() < 2 {
530            return TrendDirection::Stable;
531        }
532
533        let first_half = &values[..values.len() / 2];
534        let second_half = &values[values.len() / 2..];
535
536        let first_avg = first_half.iter().sum::<f64>() / first_half.len() as f64;
537        let second_avg = second_half.iter().sum::<f64>() / second_half.len() as f64;
538
539        let diff = second_avg - first_avg;
540
541        if diff > 0.5 {
542            TrendDirection::Improving
543        } else if diff < -0.5 {
544            TrendDirection::Declining
545        } else {
546            TrendDirection::Stable
547        }
548    }
549}
550
551/// Performance trends over time
552#[derive(Debug, Clone, Serialize, Deserialize)]
553pub struct PerformanceTrends {
554    pub cpu_trend: TrendDirection,
555    pub gpu_trend: TrendDirection,
556    pub memory_trend: TrendDirection,
557    pub storage_trend: TrendDirection,
558    pub network_trend: TrendDirection,
559    pub overall_trend: TrendDirection,
560}
561
562impl Default for PerformanceTrends {
563    fn default() -> Self {
564        Self {
565            cpu_trend: TrendDirection::Stable,
566            gpu_trend: TrendDirection::Stable,
567            memory_trend: TrendDirection::Stable,
568            storage_trend: TrendDirection::Stable,
569            network_trend: TrendDirection::Stable,
570            overall_trend: TrendDirection::Stable,
571        }
572    }
573}
574
575/// Trend direction
576#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
577pub enum TrendDirection {
578    Improving,
579    Stable,
580    Declining,
581}
582
583/// Utility functions for common operations
584pub mod common {
585    use super::*;
586
587    /// Convert capability level to human-readable string
588    pub fn capability_level_to_string(level: CapabilityLevel) -> &'static str {
589        match level {
590            CapabilityLevel::VeryLow => "Very Low",
591            CapabilityLevel::Low => "Low",
592            CapabilityLevel::Medium => "Medium",
593            CapabilityLevel::High => "High",
594            CapabilityLevel::VeryHigh => "Very High",
595            CapabilityLevel::Exceptional => "Exceptional",
596        }
597    }
598
599    /// Format resource amount for display
600    pub fn format_resource_amount(amount: &ResourceAmount) -> String {
601        match amount {
602            ResourceAmount::Level(level) => capability_level_to_string(*level).to_string(),
603            ResourceAmount::Gigabytes(gb) => format!("{:.1} GB", gb),
604            ResourceAmount::Megahertz(mhz) => format!("{:.0} MHz", mhz),
605            ResourceAmount::Score(score) => format!("{:.1}/10", score),
606            ResourceAmount::Units(units) => format!("{} units", units),
607            ResourceAmount::Percentage(pct) => format!("{:.1}%", pct),
608            ResourceAmount::Custom { value, unit } => format!("{:.1} {}", value, unit),
609        }
610    }
611
612    /// Calculate percentage difference between two values
613    pub fn percentage_difference(old_value: f64, new_value: f64) -> f64 {
614        if old_value == 0.0 {
615            if new_value == 0.0 { 0.0 } else { 100.0 }
616        } else {
617            ((new_value - old_value) / old_value) * 100.0
618        }
619    }
620
621    /// Round to specified decimal places
622    pub fn round_to_decimal(value: f64, decimal_places: u32) -> f64 {
623        let factor = 10.0_f64.powi(decimal_places as i32);
624        (value * factor).round() / factor
625    }
626}