Skip to main content

scirs2_core/memory/metrics/
analytics.rs

1//! Advanced memory analytics for pattern detection and optimization recommendations
2//!
3//! This module provides sophisticated analysis of memory usage patterns to detect
4//! potential issues, memory leaks, and optimization opportunities.
5
6use std::collections::{HashMap, VecDeque};
7use std::time::{Duration, Instant};
8
9use crate::memory::metrics::{MemoryEvent, MemoryEventType};
10
11#[cfg(feature = "memory_metrics")]
12#[cfg(feature = "serialization")]
13use serde::{Deserialize, Serialize};
14
15/// Memory leak detection configuration
16#[derive(Debug, Clone)]
17pub struct LeakDetectionConfig {
18    /// Window size for leak detection analysis
19    pub analysis_windowsize: usize,
20    /// Minimum threshold for considering a component as potentially leaking (bytes)
21    pub leak_threshold_bytes: usize,
22    /// Minimum time threshold for leak detection (seconds)
23    pub leak_threshold_duration: Duration,
24    /// Growth rate threshold for leak detection (bytes/second)
25    pub growth_rate_threshold: f64,
26    /// Minimum number of data points for reliable analysis
27    pub min_data_points: usize,
28}
29
30impl Default for LeakDetectionConfig {
31    fn default() -> Self {
32        Self {
33            analysis_windowsize: 100,
34            leak_threshold_bytes: 1024 * 1024, // 1 MB
35            leak_threshold_duration: Duration::from_secs(30),
36            growth_rate_threshold: 1024.0, // 1 KB/sec
37            min_data_points: 10,
38        }
39    }
40}
41
42/// Memory pattern analysis results
43#[derive(Debug, Clone)]
44#[cfg_attr(feature = "memory_metrics", derive(Serialize, Deserialize))]
45pub struct MemoryPatternAnalysis {
46    /// Component being analyzed
47    pub component: String,
48    /// Detected allocation patterns
49    pub patterns: Vec<AllocationPattern>,
50    /// Memory efficiency metrics
51    pub efficiency: MemoryEfficiencyMetrics,
52    /// Potential issues found
53    pub potential_issues: Vec<MemoryIssue>,
54    /// Optimization recommendations
55    pub recommendations: Vec<OptimizationRecommendation>,
56}
57
58/// Detected allocation patterns
59#[derive(Debug, Clone)]
60#[cfg_attr(feature = "memory_metrics", derive(Serialize, Deserialize))]
61pub enum AllocationPattern {
62    /// Steady growth in memory usage
63    SteadyGrowth {
64        /// Growth rate in bytes per second
65        rate: f64,
66        /// Confidence level (0.0 to 1.0)
67        confidence: f64,
68    },
69    /// Periodic allocation/deallocation cycles
70    PeriodicCycle {
71        /// Cycle duration
72        cycle_duration: Duration,
73        /// Peak size during cycle
74        peak_size: usize,
75        /// Confidence level
76        confidence: f64,
77    },
78    /// Burst allocations followed by steady usage
79    BurstAllocation {
80        /// Burst size in bytes
81        burst_size: usize,
82        /// Burst duration
83        burst_duration: Duration,
84        /// Confidence level
85        confidence: f64,
86    },
87    /// Memory usage plateau
88    Plateau {
89        /// Plateau size in bytes
90        size: usize,
91        /// Duration of plateau
92        duration: Duration,
93        /// Confidence level
94        confidence: f64,
95    },
96}
97
98/// Memory efficiency metrics
99#[derive(Debug, Clone)]
100#[cfg_attr(feature = "memory_metrics", derive(Serialize, Deserialize))]
101pub struct MemoryEfficiencyMetrics {
102    /// Memory reuse ratio (total allocated / peak usage)
103    pub reuse_ratio: f64,
104    /// Allocation frequency (allocations per second)
105    pub allocation_frequency: f64,
106    /// Average allocation lifetime
107    pub avg_allocation_lifetime: Duration,
108    /// Memory fragmentation estimate (0.0 to 1.0)
109    pub fragmentation_estimate: f64,
110    /// Buffer pool efficiency (if applicable)
111    pub buffer_pool_efficiency: Option<f64>,
112}
113
114/// Potential memory issues
115#[derive(Debug, Clone)]
116#[cfg_attr(feature = "memory_metrics", derive(Serialize, Deserialize))]
117pub enum MemoryIssue {
118    /// Potential memory leak detected
119    MemoryLeak {
120        /// Growth rate in bytes per second
121        growth_rate: f64,
122        /// Duration of observed growth
123        duration: Duration,
124        /// Severity level (0.0 to 1.0)
125        severity: f64,
126    },
127    /// High allocation frequency
128    HighAllocationFrequency {
129        /// Allocations per second
130        frequency: f64,
131        /// Potential performance impact
132        impact: String,
133    },
134    /// Large peak memory usage
135    HighPeakUsage {
136        /// Peak size in bytes
137        peak_size: usize,
138        /// Percentage of total system memory (if available)
139        system_percentage: Option<f64>,
140    },
141    /// Memory fragmentation
142    MemoryFragmentation {
143        /// Estimated fragmentation ratio
144        fragmentation_ratio: f64,
145        /// Potential waste in bytes
146        potential_waste: usize,
147    },
148    /// Inefficient buffer pool usage
149    IneffientBufferPool {
150        /// Pool efficiency ratio
151        efficiency: f64,
152        /// Number of pool misses
153        pool_misses: usize,
154    },
155}
156
157/// Optimization recommendations
158#[derive(Debug, Clone)]
159#[cfg_attr(feature = "memory_metrics", derive(Serialize, Deserialize))]
160pub enum OptimizationRecommendation {
161    /// Use buffer pooling
162    UseBufferPooling {
163        /// Expected memory savings
164        expected_savings: usize,
165        /// Suggested pool sizes
166        suggested_poolsizes: Vec<usize>,
167    },
168    /// Batch allocations
169    BatchAllocations {
170        /// Current allocation frequency
171        current_frequency: f64,
172        /// Suggested batch size
173        suggested_batch_size: usize,
174    },
175    /// Pre-allocate memory
176    PreAllocateMemory {
177        /// Suggested pre-allocation size
178        suggested_size: usize,
179        /// Expected performance improvement
180        performance_gain: String,
181    },
182    /// Use memory-efficient data structures
183    UseMemoryEfficientStructures {
184        /// Current structure type
185        current_type: String,
186        /// Suggested alternative
187        suggested_alternative: String,
188        /// Expected memory reduction
189        memory_reduction: usize,
190    },
191    /// Implement memory compaction
192    ImplementCompaction {
193        /// Estimated fragmentation reduction
194        fragmentation_reduction: f64,
195        /// Suggested compaction frequency
196        suggested_frequency: Duration,
197    },
198}
199
200/// Memory leak detection result
201#[derive(Debug, Clone)]
202#[cfg_attr(feature = "memory_metrics", derive(Serialize, Deserialize))]
203pub struct LeakDetectionResult {
204    /// Component being analyzed
205    pub component: String,
206    /// Whether a leak was detected
207    pub leak_detected: bool,
208    /// Growth rate (bytes per second)
209    pub growth_rate: f64,
210    /// Confidence level (0.0 to 1.0)
211    pub confidence: f64,
212    /// Duration of analysis
213    pub analysis_duration: Duration,
214    /// Current memory usage
215    pub current_usage: usize,
216    /// Projected usage after 1 hour
217    pub projected_usage_1h: usize,
218    /// Projected usage after 24 hours
219    pub projected_usage_24h: usize,
220}
221
222/// Advanced memory analytics engine
223pub struct MemoryAnalytics {
224    /// Configuration for leak detection
225    leak_config: LeakDetectionConfig,
226    /// Historical memory usage data per component
227    usage_history: HashMap<String, VecDeque<(Instant, usize)>>,
228    /// Allocation event history per component
229    allocation_history: HashMap<String, VecDeque<(Instant, usize, MemoryEventType)>>,
230}
231
232impl MemoryAnalytics {
233    /// Create a new memory analytics engine
234    pub fn new(leakconfig: LeakDetectionConfig) -> Self {
235        Self {
236            leak_config: leakconfig,
237            usage_history: HashMap::new(),
238            allocation_history: HashMap::new(),
239        }
240    }
241
242    /// Update analytics with a new memory event
243    pub fn record_event(&mut self, event: MemoryEvent) {
244        let component = event.component.clone();
245        let timestamp = event.timestamp;
246
247        // Update allocation history
248        let alloc_history = self
249            .allocation_history
250            .entry(component.clone())
251            .or_default();
252        alloc_history.push_back((timestamp, event.size, event.event_type));
253
254        // Limit history size
255        while alloc_history.len() > self.leak_config.analysis_windowsize {
256            alloc_history.pop_front();
257        }
258
259        // Calculate current usage for this component
260        let current_usage = self.calculate_current_usage(&component);
261
262        // Update usage history
263        let usage_history = self.usage_history.entry(component).or_default();
264        usage_history.push_back((timestamp, current_usage));
265
266        // Limit history size
267        while usage_history.len() > self.leak_config.analysis_windowsize {
268            usage_history.pop_front();
269        }
270    }
271
272    /// Calculate current memory usage for a component
273    fn calculate_current_usage(&self, component: &str) -> usize {
274        if let Some(history) = self.allocation_history.get(component) {
275            let mut usage = 0usize;
276            for (_timestamp, size, event_type) in history {
277                match event_type {
278                    MemoryEventType::Allocation => usage += size,
279                    MemoryEventType::Deallocation => usage = usage.saturating_sub(*size),
280                    MemoryEventType::Resize => {
281                        // For resize events, we need additional metadata
282                        // For now, treat as allocation
283                        usage += size;
284                    }
285                    MemoryEventType::Access | MemoryEventType::Transfer => {
286                        // These events don't affect memory usage calculations
287                    }
288                }
289            }
290            usage
291        } else {
292            0
293        }
294    }
295
296    /// Perform leak detection for a specific component
297    pub fn detect_memory_leak(&self, component: &str) -> Option<LeakDetectionResult> {
298        let usage_history = self.usage_history.get(component)?;
299
300        if usage_history.len() < self.leak_config.min_data_points {
301            return None;
302        }
303
304        // Calculate linear regression to detect growth trend
305        let (growth_rate, confidence) = self.calculate_growth_rate(usage_history);
306
307        let analysis_duration = usage_history
308            .back()?
309            .0
310            .duration_since(usage_history.front()?.0);
311
312        if analysis_duration < self.leak_config.leak_threshold_duration {
313            return None;
314        }
315
316        let current_usage = usage_history.back()?.1;
317        let leak_detected = growth_rate > self.leak_config.growth_rate_threshold
318            && confidence > 0.7
319            && current_usage > self.leak_config.leak_threshold_bytes;
320
321        Some(LeakDetectionResult {
322            component: component.to_string(),
323            leak_detected,
324            growth_rate,
325            confidence,
326            analysis_duration,
327            current_usage,
328            projected_usage_1h: current_usage + (growth_rate * 3600.0) as usize,
329            projected_usage_24h: current_usage + (growth_rate * 86400.0) as usize,
330        })
331    }
332
333    /// Calculate growth rate using linear regression
334    fn calculate_growth_rate(&self, history: &VecDeque<(Instant, usize)>) -> (f64, f64) {
335        if history.len() < 2 {
336            return (0.0, 0.0);
337        }
338
339        let start_time = history.front().expect("Operation failed").0;
340        let points: Vec<(f64, f64)> = history
341            .iter()
342            .map(|(timestamp, usage)| {
343                let x = timestamp.duration_since(start_time).as_secs_f64();
344                let y = *usage as f64;
345                (x, y)
346            })
347            .collect();
348
349        self.linear_regression(&points)
350    }
351
352    /// Perform linear regression to find slope (growth rate) and R-squared (confidence)
353    fn linear_regression(&self, points: &[(f64, f64)]) -> (f64, f64) {
354        let n = points.len() as f64;
355        if n < 2.0 {
356            return (0.0, 0.0);
357        }
358
359        let sum_x: f64 = points.iter().map(|(x, _)| x).sum();
360        let sum_y: f64 = points.iter().map(|(_, y)| y).sum();
361        let sum_xy: f64 = points.iter().map(|(x, y)| x * y).sum();
362        let sum_x2: f64 = points.iter().map(|(x, _)| x * x).sum();
363        let sum_y2: f64 = points.iter().map(|(_, y)| y * y).sum();
364
365        let mean_x = sum_x / n;
366        let mean_y = sum_y / n;
367
368        let numerator = sum_xy - n * mean_x * mean_y;
369        let denominator = sum_x2 - n * mean_x * mean_x;
370
371        if denominator.abs() < f64::EPSILON {
372            return (0.0, 0.0);
373        }
374
375        let slope = numerator / denominator;
376
377        // Calculate R-squared
378        let ss_tot = sum_y2 - n * mean_y * mean_y;
379        let ss_res: f64 = points
380            .iter()
381            .map(|(x, y)| {
382                let predicted = slope * (x - mean_x) + mean_y;
383                (y - predicted).powi(2)
384            })
385            .sum();
386
387        let r_squared = if ss_tot.abs() < f64::EPSILON {
388            0.0
389        } else {
390            1.0 - (ss_res / ss_tot).max(0.0)
391        };
392
393        (slope, r_squared)
394    }
395
396    /// Perform comprehensive pattern analysis for a component
397    pub fn analyze_patterns(&self, component: &str) -> Option<MemoryPatternAnalysis> {
398        let usage_history = self.usage_history.get(component)?;
399        let allocation_history = self.allocation_history.get(component)?;
400
401        if usage_history.len() < self.leak_config.min_data_points {
402            return None;
403        }
404
405        let patterns = self.detect_allocation_patterns(usage_history, allocation_history);
406        let efficiency = self.calculate_efficiency_metrics(component, allocation_history);
407        let potential_issues = self.identify_potential_issues(component);
408        let recommendations = self.generate_recommendations(&efficiency, &potential_issues);
409
410        Some(MemoryPatternAnalysis {
411            component: component.to_string(),
412            patterns,
413            efficiency,
414            potential_issues,
415            recommendations,
416        })
417    }
418
419    /// Detect allocation patterns in the usage history
420    fn detect_allocation_patterns(
421        &self,
422        usage_history: &VecDeque<(Instant, usize)>,
423        allocation_history: &VecDeque<(Instant, usize, MemoryEventType)>,
424    ) -> Vec<AllocationPattern> {
425        let mut patterns = Vec::new();
426
427        // Detect steady growth
428        let (growth_rate, confidence) = self.calculate_growth_rate(usage_history);
429        if growth_rate > 100.0 && confidence > 0.8 {
430            patterns.push(AllocationPattern::SteadyGrowth {
431                rate: growth_rate,
432                confidence,
433            });
434        }
435
436        // Detect periodic cycles
437        if let Some(cycle) = self.detect_periodic_cycles(usage_history) {
438            patterns.push(cycle);
439        }
440
441        // Detect burst allocations
442        if let Some(burst) = self.detect_burst_allocations(allocation_history) {
443            patterns.push(burst);
444        }
445
446        // Detect plateaus
447        if let Some(plateau) = self.detect_plateaus(usage_history) {
448            patterns.push(plateau);
449        }
450
451        patterns
452    }
453
454    /// Detect periodic allocation cycles
455    fn detect_periodic_cycles(
456        &self,
457        usage_history: &VecDeque<(Instant, usize)>,
458    ) -> Option<AllocationPattern> {
459        // This is a simplified cycle detection algorithm
460        // In a real implementation, you might use FFT or autocorrelation
461
462        if usage_history.len() < 10 {
463            return None;
464        }
465
466        // Look for repeating patterns in memory usage
467        let values: Vec<usize> = usage_history.iter().map(|(_, usage)| *usage).collect();
468
469        // Simple pattern detection: look for similar values at regular intervals
470        for cycle_len in 3..values.len() / 3 {
471            let mut correlation = 0.0;
472            let mut count = 0;
473
474            for i in cycle_len..values.len() {
475                let diff = (values[i] as f64 - values[i - cycle_len] as f64).abs();
476                let avg = (values[i] + values[i - cycle_len]) as f64 / 2.0;
477                if avg > 0.0 {
478                    correlation += 1.0 - (diff / avg).min(1.0);
479                    count += 1;
480                }
481            }
482
483            if count > 0 {
484                correlation /= count as f64;
485                if correlation > 0.8 {
486                    let cycle_duration = Duration::from_secs((cycle_len * 5) as u64); // Approximate
487                    let peak_size = values.iter().max().copied().unwrap_or(0);
488
489                    return Some(AllocationPattern::PeriodicCycle {
490                        cycle_duration,
491                        peak_size,
492                        confidence: correlation,
493                    });
494                }
495            }
496        }
497
498        None
499    }
500
501    /// Detect burst allocation patterns
502    fn detect_burst_allocations(
503        &self,
504        allocation_history: &VecDeque<(Instant, usize, MemoryEventType)>,
505    ) -> Option<AllocationPattern> {
506        if allocation_history.len() < 5 {
507            return None;
508        }
509
510        // Look for periods of high allocation activity
511        let mut burst_size = 0usize;
512        let mut burst_start: Option<Instant> = None;
513        let mut current_burst_size = 0usize;
514
515        for (timestamp, size, event_type) in allocation_history {
516            match event_type {
517                MemoryEventType::Allocation => {
518                    if burst_start.is_none() {
519                        burst_start = Some(*timestamp);
520                        current_burst_size = *size;
521                    } else {
522                        current_burst_size += size;
523                    }
524                }
525                MemoryEventType::Deallocation => {
526                    if let Some(start) = burst_start {
527                        let duration = timestamp.duration_since(start);
528                        if duration > Duration::from_millis(100) && current_burst_size > burst_size
529                        {
530                            burst_size = current_burst_size;
531                        }
532                        burst_start = None;
533                        current_burst_size = 0;
534                    }
535                }
536                _ => {}
537            }
538        }
539
540        if burst_size > 1024 * 1024 {
541            // 1 MB threshold
542            Some(AllocationPattern::BurstAllocation {
543                burst_size,
544                burst_duration: Duration::from_millis(500), // Approximate
545                confidence: 0.9,
546            })
547        } else {
548            None
549        }
550    }
551
552    /// Detect memory usage plateaus
553    fn detect_plateaus(
554        &self,
555        usage_history: &VecDeque<(Instant, usize)>,
556    ) -> Option<AllocationPattern> {
557        if usage_history.len() < 10 {
558            return None;
559        }
560
561        let values: Vec<usize> = usage_history.iter().map(|(_, usage)| *usage).collect();
562
563        // Look for periods of stable memory usage
564        let mut plateau_start = 0;
565        let mut max_plateau_len = 0;
566        let mut plateau_value = 0;
567
568        for i in 1..values.len() {
569            let diff_ratio = if values[i.saturating_sub(1)] > 0 {
570                (values[i] as f64 - values[i.saturating_sub(1)] as f64).abs()
571                    / values[i.saturating_sub(1)] as f64
572            } else {
573                0.0
574            };
575
576            if diff_ratio < 0.05 {
577                // Less than 5% change
578                if plateau_start == 0 {
579                    plateau_start = i.saturating_sub(1);
580                }
581            } else {
582                if plateau_start > 0 {
583                    let plateau_len = i - plateau_start;
584                    if plateau_len > max_plateau_len {
585                        max_plateau_len = plateau_len;
586                        plateau_value = values[plateau_start];
587                    }
588                }
589                plateau_start = 0;
590            }
591        }
592
593        // Check final plateau
594        if plateau_start > 0 {
595            let plateau_len = values.len() - plateau_start;
596            if plateau_len > max_plateau_len {
597                max_plateau_len = plateau_len;
598                plateau_value = values[plateau_start];
599            }
600        }
601
602        if max_plateau_len >= 5 && plateau_value > 0 {
603            Some(AllocationPattern::Plateau {
604                size: plateau_value,
605                duration: Duration::from_secs((max_plateau_len * 5) as u64), // Approximate
606                confidence: 0.8,
607            })
608        } else {
609            None
610        }
611    }
612
613    /// Calculate efficiency metrics for a component
614    fn calculate_efficiency_metrics(
615        &self,
616        component: &str,
617        allocation_history: &VecDeque<(Instant, usize, MemoryEventType)>,
618    ) -> MemoryEfficiencyMetrics {
619        if allocation_history.is_empty() {
620            return MemoryEfficiencyMetrics {
621                reuse_ratio: 0.0,
622                allocation_frequency: 0.0,
623                avg_allocation_lifetime: Duration::from_secs(0),
624                fragmentation_estimate: 0.0,
625                buffer_pool_efficiency: None,
626            };
627        }
628
629        // Calculate basic metrics
630        let total_allocated = allocation_history
631            .iter()
632            .filter_map(|(_, size, event_type)| {
633                if matches!(event_type, MemoryEventType::Allocation) {
634                    Some(*size)
635                } else {
636                    None
637                }
638            })
639            .sum::<usize>();
640
641        let current_usage = self.calculate_current_usage(component);
642        let reuse_ratio = if current_usage > 0 {
643            total_allocated as f64 / current_usage as f64
644        } else {
645            0.0
646        };
647
648        let allocation_count = allocation_history
649            .iter()
650            .filter(|(_, _, event_type)| matches!(event_type, MemoryEventType::Allocation))
651            .count();
652
653        let duration = if let (Some(first), Some(last)) =
654            (allocation_history.front(), allocation_history.back())
655        {
656            last.0.duration_since(first.0)
657        } else {
658            Duration::from_secs(1)
659        };
660
661        let allocation_frequency = allocation_count as f64 / duration.as_secs_f64();
662
663        // Estimate average allocation lifetime
664        let avg_allocation_lifetime = if allocation_count > 0 {
665            duration / allocation_count as u32
666        } else {
667            Duration::from_secs(0)
668        };
669
670        // Estimate fragmentation (simplified heuristic)
671        let fragmentation_estimate = self.estimate_fragmentation(allocation_history);
672
673        MemoryEfficiencyMetrics {
674            reuse_ratio,
675            allocation_frequency,
676            avg_allocation_lifetime,
677            fragmentation_estimate,
678            buffer_pool_efficiency: None, // Would require buffer pool instrumentation
679        }
680    }
681
682    /// Estimate memory fragmentation
683    fn estimate_fragmentation(
684        &self,
685        allocation_history: &VecDeque<(Instant, usize, MemoryEventType)>,
686    ) -> f64 {
687        // This is a simplified fragmentation estimate
688        // In reality, you'd need more detailed memory layout information
689
690        let allocation_sizes: Vec<usize> = allocation_history
691            .iter()
692            .filter_map(|(_, size, event_type)| {
693                if matches!(event_type, MemoryEventType::Allocation) {
694                    Some(*size)
695                } else {
696                    None
697                }
698            })
699            .collect();
700
701        if allocation_sizes.is_empty() {
702            return 0.0;
703        }
704
705        // Calculate coefficient of variation as a proxy for fragmentation
706        let mean = allocation_sizes.iter().sum::<usize>() as f64 / allocation_sizes.len() as f64;
707        let variance = allocation_sizes
708            .iter()
709            .map(|&size| {
710                let diff = size as f64 - mean;
711                diff * diff
712            })
713            .sum::<f64>()
714            / allocation_sizes.len() as f64;
715
716        let std_dev = variance.sqrt();
717
718        if mean > 0.0 {
719            (std_dev / mean).min(1.0)
720        } else {
721            0.0
722        }
723    }
724
725    /// Identify potential memory issues
726    fn identify_potential_issues(&self, component: &str) -> Vec<MemoryIssue> {
727        let mut issues = Vec::new();
728
729        // Check for memory leaks
730        if let Some(leak_result) = self.detect_memory_leak(component) {
731            if leak_result.leak_detected {
732                issues.push(MemoryIssue::MemoryLeak {
733                    growth_rate: leak_result.growth_rate,
734                    duration: leak_result.analysis_duration,
735                    severity: leak_result.confidence,
736                });
737            }
738        }
739
740        // Check for high allocation frequency
741        if let Some(allocation_history) = self.allocation_history.get(component) {
742            let efficiency = self.calculate_efficiency_metrics(component, allocation_history);
743
744            if efficiency.allocation_frequency > 100.0 {
745                // More than 100 allocations per second
746                issues.push(MemoryIssue::HighAllocationFrequency {
747                    frequency: efficiency.allocation_frequency,
748                    impact: "High allocation frequency can cause performance degradation"
749                        .to_string(),
750                });
751            }
752
753            if efficiency.fragmentation_estimate > 0.7 {
754                let current_usage = self.calculate_current_usage(component);
755                let potential_waste =
756                    (current_usage as f64 * efficiency.fragmentation_estimate) as usize;
757
758                issues.push(MemoryIssue::MemoryFragmentation {
759                    fragmentation_ratio: efficiency.fragmentation_estimate,
760                    potential_waste,
761                });
762            }
763        }
764
765        // Check for high peak usage
766        if let Some(usage_history) = self.usage_history.get(component) {
767            if let Some(peak_usage) = usage_history.iter().map(|(_, usage)| *usage).max() {
768                if peak_usage > 100 * 1024 * 1024 {
769                    // 100 MB threshold
770                    issues.push(MemoryIssue::HighPeakUsage {
771                        peak_size: peak_usage,
772                        system_percentage: None, // Would require system memory detection
773                    });
774                }
775            }
776        }
777
778        issues
779    }
780
781    /// Generate optimization recommendations
782    fn generate_recommendations(
783        &self,
784        efficiency: &MemoryEfficiencyMetrics,
785        issues: &[MemoryIssue],
786    ) -> Vec<OptimizationRecommendation> {
787        let mut recommendations = Vec::new();
788
789        // Recommend buffer pooling for high allocation frequency
790        if efficiency.allocation_frequency > 50.0 {
791            recommendations.push(OptimizationRecommendation::UseBufferPooling {
792                expected_savings: (efficiency.allocation_frequency * 1024.0) as usize, // Rough estimate
793                suggested_poolsizes: vec![1024, 4096, 16384, 65536],
794            });
795        }
796
797        // Recommend batching for frequent small allocations
798        if efficiency.allocation_frequency > 20.0
799            && efficiency.avg_allocation_lifetime.as_secs() < 10
800        {
801            recommendations.push(OptimizationRecommendation::BatchAllocations {
802                current_frequency: efficiency.allocation_frequency,
803                suggested_batch_size: (efficiency.allocation_frequency * 2.0) as usize,
804            });
805        }
806
807        // Recommend pre-allocation for predictable patterns
808        if efficiency.reuse_ratio > 2.0 {
809            recommendations.push(OptimizationRecommendation::PreAllocateMemory {
810                suggested_size: (efficiency.allocation_frequency * 1024.0) as usize,
811                performance_gain: "Reduced allocation overhead".to_string(),
812            });
813        }
814
815        // Recommend compaction for high fragmentation
816        if efficiency.fragmentation_estimate > 0.5 {
817            recommendations.push(OptimizationRecommendation::ImplementCompaction {
818                fragmentation_reduction: efficiency.fragmentation_estimate * 0.7, // Estimated reduction
819                suggested_frequency: Duration::from_secs(300),                    // 5 minutes
820            });
821        }
822
823        // Specific recommendations based on detected issues
824        for issue in issues {
825            if let MemoryIssue::HighPeakUsage { peak_size, .. } = issue {
826                recommendations.push(OptimizationRecommendation::UseMemoryEfficientStructures {
827                    current_type: "Unknown".to_string(),
828                    suggested_alternative: "Streaming or memory-mapped structures".to_string(),
829                    memory_reduction: peak_size / 2, // Rough estimate
830                });
831            }
832        }
833
834        recommendations
835    }
836
837    /// Get leak detection results for all components
838    pub fn get_leak_detection_results(&self) -> Vec<LeakDetectionResult> {
839        self.usage_history
840            .keys()
841            .filter_map(|component| self.detect_memory_leak(component))
842            .collect()
843    }
844
845    /// Get pattern analysis for all components
846    pub fn get_pattern_analysis_results(&self) -> Vec<MemoryPatternAnalysis> {
847        self.usage_history
848            .keys()
849            .filter_map(|component| self.analyze_patterns(component))
850            .collect()
851    }
852
853    /// Clear all analytics data
854    pub fn clear(&mut self) {
855        self.usage_history.clear();
856        self.allocation_history.clear();
857    }
858}
859
860impl Default for MemoryAnalytics {
861    fn default() -> Self {
862        Self::new(LeakDetectionConfig::default())
863    }
864}
865
866#[cfg(test)]
867mod tests {
868    use super::*;
869
870    #[test]
871    fn test_memory_analytics_creation() {
872        let analytics = MemoryAnalytics::new(LeakDetectionConfig::default());
873        assert!(analytics.usage_history.is_empty());
874        assert!(analytics.allocation_history.is_empty());
875    }
876
877    #[test]
878    fn test_leak_detection_insufficient_data() {
879        let analytics = MemoryAnalytics::new(LeakDetectionConfig::default());
880        let result = analytics.detect_memory_leak("test_component");
881        assert!(result.is_none());
882    }
883
884    #[test]
885    fn test_linear_regression() {
886        let analytics = MemoryAnalytics::new(LeakDetectionConfig::default());
887
888        // Test with perfect linear growth
889        let points = vec![(0.0, 0.0), (1.0, 100.0), (2.0, 200.0), (3.0, 300.0)];
890
891        let (slope, r_squared) = analytics.linear_regression(&points);
892        assert!((slope - 100.0).abs() < 1.0);
893        assert!(r_squared > 0.99);
894    }
895
896    #[test]
897    fn test_pattern_analysis_with_insufficient_data() {
898        let analytics = MemoryAnalytics::new(LeakDetectionConfig::default());
899        let result = analytics.analyze_patterns("test_component");
900        assert!(result.is_none());
901    }
902}