Skip to main content

optirs_bench/
advanced_leak_detectors.rs

1// Advanced memory leak detection algorithms
2//
3// This module implements sophisticated memory leak detection algorithms including
4// reference counting analysis, cycle detection, real-time monitoring, and
5// pattern-based leak identification.
6
7use super::memory_leak_detector::{
8    AllocationEvent, AllocationType, GrowthPattern, GrowthTrend, LeakDetector, LeakSource,
9    MemoryGrowthAnalysis, MemoryLeakResult, MemoryUsageSnapshot,
10};
11use crate::error::{OptimError, Result};
12use scirs2_core::numeric::Float;
13use serde::{Deserialize, Serialize};
14use std::collections::{HashMap, HashSet, VecDeque};
15use std::fmt::Debug;
16use std::sync::{Arc, Mutex, RwLock};
17use std::thread;
18use std::time::{Duration, Instant};
19
20/// Reference counting leak detector
21///
22/// Detects memory leaks by analyzing reference count patterns and identifying
23/// potential circular references or unreleased references.
24#[derive(Debug)]
25#[allow(dead_code)]
26pub struct ReferenceCountingDetector {
27    /// Configuration for reference counting analysis
28    config: ReferenceCountingConfig,
29    /// Reference tracking state
30    reference_tracker: Arc<RwLock<ReferenceTracker>>,
31    /// Cycle detection engine
32    cycle_detector: CycleDetector,
33}
34
35/// Configuration for reference counting detection
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct ReferenceCountingConfig {
38    /// Minimum reference count threshold for suspicion
39    pub min_suspicious_refcount: usize,
40    /// Maximum reference count before flagging
41    pub max_normal_refcount: usize,
42    /// Cycle detection depth
43    pub cycle_detection_depth: usize,
44    /// Reference age threshold (seconds)
45    pub reference_age_threshold: u64,
46    /// Enable strong reference analysis
47    pub enable_strong_ref_analysis: bool,
48    /// Enable weak reference analysis
49    pub enable_weak_ref_analysis: bool,
50}
51
52impl Default for ReferenceCountingConfig {
53    fn default() -> Self {
54        Self {
55            min_suspicious_refcount: 5,
56            max_normal_refcount: 100,
57            cycle_detection_depth: 10,
58            reference_age_threshold: 300, // 5 minutes
59            enable_strong_ref_analysis: true,
60            enable_weak_ref_analysis: true,
61        }
62    }
63}
64
65/// Reference tracking state
66#[derive(Debug)]
67pub struct ReferenceTracker {
68    /// Active references by allocation ID
69    active_references: HashMap<usize, ReferenceInfo>,
70    /// Reference graph for cycle detection
71    reference_graph: HashMap<usize, HashSet<usize>>,
72    /// Reference history
73    reference_history: VecDeque<ReferenceEvent>,
74    /// Suspected leaks
75    suspectedleaks: Vec<SuspectedLeak>,
76}
77
78/// Information about a reference
79#[derive(Debug, Clone)]
80pub struct ReferenceInfo {
81    /// Allocation ID
82    pub allocation_id: usize,
83    /// Current reference count
84    pub reference_count: usize,
85    /// Creation timestamp
86    pub created_at: Instant,
87    /// Last accessed timestamp
88    pub last_accessed: Instant,
89    /// Reference type
90    pub reference_type: ReferenceType,
91    /// Source location
92    pub source_location: Option<String>,
93    /// References to other allocations
94    pub references_to: HashSet<usize>,
95    /// Referenced by other allocations
96    pub referenced_by: HashSet<usize>,
97}
98
99/// Types of references
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub enum ReferenceType {
102    /// Strong reference (prevents deallocation)
103    Strong,
104    /// Weak reference (doesn't prevent deallocation)
105    Weak,
106    /// Shared reference (shared ownership)
107    Shared,
108    /// Unique reference (exclusive ownership)
109    Unique,
110}
111
112/// Reference event for tracking
113#[derive(Debug, Clone)]
114pub struct ReferenceEvent {
115    /// Event timestamp
116    pub timestamp: Instant,
117    /// Allocation ID
118    pub allocation_id: usize,
119    /// Event type
120    pub event_type: ReferenceEventType,
121    /// Reference count after event
122    pub reference_count: usize,
123}
124
125/// Types of reference events
126#[derive(Debug, Clone)]
127pub enum ReferenceEventType {
128    /// Reference created
129    Created,
130    /// Reference incremented
131    Incremented,
132    /// Reference decremented
133    Decremented,
134    /// Reference destroyed
135    Destroyed,
136    /// Reference accessed
137    Accessed,
138}
139
140/// Suspected memory leak
141#[derive(Debug, Clone)]
142pub struct SuspectedLeak {
143    /// Allocation ID
144    pub allocation_id: usize,
145    /// Leak confidence (0.0 to 1.0)
146    pub confidence: f64,
147    /// Leak type
148    pub leak_type: LeakType,
149    /// Evidence for the leak
150    pub evidence: Vec<String>,
151    /// Detection timestamp
152    pub detected_at: Instant,
153}
154
155/// Types of memory leaks
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub enum LeakType {
158    /// Circular reference
159    CircularReference,
160    /// Dangling reference
161    DanglingReference,
162    /// Unreleased reference
163    UnreleasedReference,
164    /// Reference count overflow
165    ReferenceCountOverflow,
166    /// Stale reference
167    StaleReference,
168}
169
170impl ReferenceCountingDetector {
171    /// Create a new reference counting detector
172    pub fn new(config: ReferenceCountingConfig) -> Self {
173        Self {
174            config,
175            reference_tracker: Arc::new(RwLock::new(ReferenceTracker::new())),
176            cycle_detector: CycleDetector::new(),
177        }
178    }
179
180    /// Track a reference operation
181    pub fn track_reference_operation(
182        &self,
183        allocation_id: usize,
184        event_type: ReferenceEventType,
185        reference_count: usize,
186    ) -> Result<()> {
187        let mut tracker = self.reference_tracker.write().map_err(|_| {
188            OptimError::InvalidState("Failed to acquire reference tracker lock".to_string())
189        })?;
190
191        let now = Instant::now();
192
193        // Update reference info
194        let ref_info = tracker
195            .active_references
196            .entry(allocation_id)
197            .or_insert_with(|| ReferenceInfo {
198                allocation_id,
199                reference_count: 0,
200                created_at: now,
201                last_accessed: now,
202                reference_type: ReferenceType::Strong,
203                source_location: None,
204                references_to: HashSet::new(),
205                referenced_by: HashSet::new(),
206            });
207
208        ref_info.reference_count = reference_count;
209        ref_info.last_accessed = now;
210
211        // Record the event
212        let event = ReferenceEvent {
213            timestamp: now,
214            allocation_id,
215            event_type,
216            reference_count,
217        };
218
219        tracker.reference_history.push_back(event);
220
221        // Limit history size
222        while tracker.reference_history.len() > 10000 {
223            tracker.reference_history.pop_front();
224        }
225
226        // Analyze for potential leaks
227        self.analyze_reference_patterns(&mut tracker)?;
228
229        Ok(())
230    }
231
232    /// Analyze reference patterns for potential leaks
233    fn analyze_reference_patterns(&self, tracker: &mut ReferenceTracker) -> Result<()> {
234        let now = Instant::now();
235
236        // Check for suspicious reference counts
237        for (allocation_id, ref_info) in &tracker.active_references {
238            let mut evidence = Vec::new();
239            let mut confidence = 0.0;
240            let mut leak_type = LeakType::UnreleasedReference;
241
242            // Check reference count thresholds
243            if ref_info.reference_count > self.config.max_normal_refcount {
244                evidence.push(format!(
245                    "Reference count {} exceeds normal threshold {}",
246                    ref_info.reference_count, self.config.max_normal_refcount
247                ));
248                confidence += 0.3;
249                leak_type = LeakType::ReferenceCountOverflow;
250            }
251
252            // Check reference age
253            let age = now.duration_since(ref_info.created_at).as_secs();
254            if age > self.config.reference_age_threshold {
255                evidence.push(format!(
256                    "Reference age {} seconds exceeds threshold {}",
257                    age, self.config.reference_age_threshold
258                ));
259                confidence += 0.2;
260            }
261
262            // Check for stale references (not accessed recently)
263            let last_access_age = now.duration_since(ref_info.last_accessed).as_secs();
264            if last_access_age > self.config.reference_age_threshold / 2 {
265                evidence.push(format!(
266                    "Reference not accessed for {} seconds",
267                    last_access_age
268                ));
269                confidence += 0.15;
270                leak_type = LeakType::StaleReference;
271            }
272
273            // Check for circular references
274            if self.has_circular_reference(*allocation_id, &tracker.reference_graph) {
275                evidence.push("Circular reference detected".to_string());
276                confidence += 0.4;
277                leak_type = LeakType::CircularReference;
278            }
279
280            // Add suspected leak if confidence is high enough
281            if confidence > 0.5 && !evidence.is_empty() {
282                let suspected_leak = SuspectedLeak {
283                    allocation_id: *allocation_id,
284                    confidence,
285                    leak_type,
286                    evidence,
287                    detected_at: now,
288                };
289
290                tracker.suspectedleaks.push(suspected_leak);
291            }
292        }
293
294        // Clean up old suspected leaks
295        tracker.suspectedleaks.retain(|leak| {
296            now.duration_since(leak.detected_at).as_secs() < 3600 // Keep for 1 hour
297        });
298
299        Ok(())
300    }
301
302    /// Check for circular references using DFS
303    fn has_circular_reference(
304        &self,
305        allocation_id: usize,
306        reference_graph: &HashMap<usize, HashSet<usize>>,
307    ) -> bool {
308        let mut visited = HashSet::new();
309        let mut recursion_stack = HashSet::new();
310
311        Self::dfs_cycle_detection(
312            allocation_id,
313            reference_graph,
314            &mut visited,
315            &mut recursion_stack,
316        )
317    }
318
319    /// Depth-first search for cycle detection
320    fn dfs_cycle_detection(
321        node: usize,
322        graph: &HashMap<usize, HashSet<usize>>,
323        visited: &mut HashSet<usize>,
324        recursion_stack: &mut HashSet<usize>,
325    ) -> bool {
326        visited.insert(node);
327        recursion_stack.insert(node);
328
329        if let Some(neighbors) = graph.get(&node) {
330            for &neighbor in neighbors {
331                if !visited.contains(&neighbor) {
332                    if Self::dfs_cycle_detection(neighbor, graph, visited, recursion_stack) {
333                        return true;
334                    }
335                } else if recursion_stack.contains(&neighbor) {
336                    // Found a back edge (cycle)
337                    return true;
338                }
339            }
340        }
341
342        recursion_stack.remove(&node);
343        false
344    }
345}
346
347impl LeakDetector for ReferenceCountingDetector {
348    fn detect_leaks(
349        &self,
350        allocation_history: &VecDeque<AllocationEvent>,
351        usage_snapshots: &VecDeque<MemoryUsageSnapshot>,
352    ) -> Result<MemoryLeakResult> {
353        let tracker = self.reference_tracker.read().map_err(|_| {
354            OptimError::InvalidState("Failed to acquire reference tracker lock".to_string())
355        })?;
356
357        let mut leak_sources = Vec::new();
358        let mut total_leaked_bytes = 0;
359        let mut max_confidence = 0.0;
360
361        // Analyze suspected leaks
362        for suspected_leak in &tracker.suspectedleaks {
363            if let Some(ref_info) = tracker.active_references.get(&suspected_leak.allocation_id) {
364                // Estimate leak size from allocation _history
365                let leak_size = allocation_history
366                    .iter()
367                    .find(|event| event.allocation_id == suspected_leak.allocation_id)
368                    .map(|event| event.size)
369                    .unwrap_or(0);
370
371                let leak_source = LeakSource {
372                    source_type: AllocationType::OptimizerState, // Default type
373                    location: ref_info.source_location.clone(),
374                    leak_size,
375                    probability: suspected_leak.confidence,
376                    stack_trace: None,
377                };
378
379                leak_sources.push(leak_source);
380                total_leaked_bytes += leak_size;
381                max_confidence = max_confidence.max(suspected_leak.confidence);
382            }
383        }
384
385        // Perform memory growth analysis
386        let growth_analysis = self.analyze_memory_growth(usage_snapshots)?;
387
388        // Generate recommendations
389        let recommendations = self.generate_recommendations(&tracker.suspectedleaks);
390
391        // Create detailed analysis
392        let detailed_analysis = format!(
393            "Reference Counting Analysis:\n\
394             - Active References: {}\n\
395             - Suspected Leaks: {}\n\
396             - Circular References Detected: {}\n\
397             - Average Reference Count: {:.2}\n\
398             - Maximum Reference Count: {}",
399            tracker.active_references.len(),
400            tracker.suspectedleaks.len(),
401            tracker
402                .suspectedleaks
403                .iter()
404                .filter(|l| matches!(l.leak_type, LeakType::CircularReference))
405                .count(),
406            tracker
407                .active_references
408                .values()
409                .map(|r| r.reference_count)
410                .sum::<usize>() as f64
411                / tracker.active_references.len().max(1) as f64,
412            tracker
413                .active_references
414                .values()
415                .map(|r| r.reference_count)
416                .max()
417                .unwrap_or(0)
418        );
419
420        Ok(MemoryLeakResult {
421            leak_detected: !leak_sources.is_empty(),
422            severity: max_confidence,
423            confidence: max_confidence,
424            leaked_memory_bytes: total_leaked_bytes,
425            leak_sources,
426            growth_analysis,
427            recommendations,
428            detailed_analysis,
429        })
430    }
431
432    fn name(&self) -> &str {
433        "ReferenceCountingDetector"
434    }
435
436    fn config(&self) -> HashMap<String, String> {
437        let mut config = HashMap::new();
438        config.insert(
439            "min_suspicious_refcount".to_string(),
440            self.config.min_suspicious_refcount.to_string(),
441        );
442        config.insert(
443            "max_normal_refcount".to_string(),
444            self.config.max_normal_refcount.to_string(),
445        );
446        config.insert(
447            "cycle_detection_depth".to_string(),
448            self.config.cycle_detection_depth.to_string(),
449        );
450        config.insert(
451            "reference_age_threshold".to_string(),
452            self.config.reference_age_threshold.to_string(),
453        );
454        config
455    }
456}
457
458impl ReferenceCountingDetector {
459    /// Analyze memory growth patterns
460    fn analyze_memory_growth(
461        &self,
462        snapshots: &VecDeque<MemoryUsageSnapshot>,
463    ) -> Result<MemoryGrowthAnalysis> {
464        if snapshots.len() < 2 {
465            return Ok(MemoryGrowthAnalysis {
466                growth_trend: GrowthTrend::Stable,
467                growth_rate: 0.0,
468                projected_usage: Vec::new(),
469                pattern_type: GrowthPattern::Normal,
470            });
471        }
472
473        let memory_values: Vec<f64> = snapshots.iter().map(|s| s.total_memory as f64).collect();
474
475        // Calculate growth rate using linear regression
476        let n = memory_values.len() as f64;
477        let sum_x = (0..memory_values.len()).sum::<usize>() as f64;
478        let sum_y = memory_values.iter().sum::<f64>();
479        let sum_xy = memory_values
480            .iter()
481            .enumerate()
482            .map(|(i, &y)| i as f64 * y)
483            .sum::<f64>();
484        let sum_x2 = (0..memory_values.len())
485            .map(|i| (i * i) as f64)
486            .sum::<f64>();
487
488        let growth_rate = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x);
489
490        // Determine growth trend
491        let growth_trend = if growth_rate.abs() < 1000.0 {
492            GrowthTrend::Stable
493        } else if growth_rate > 0.0 {
494            if growth_rate > 100000.0 {
495                GrowthTrend::Exponential
496            } else {
497                GrowthTrend::Linear
498            }
499        } else {
500            GrowthTrend::Irregular
501        };
502
503        // Determine pattern type
504        let pattern_type = if growth_rate > 50000.0 {
505            GrowthPattern::Leak
506        } else if memory_values
507            .windows(2)
508            .any(|w| (w[1] - w[0]).abs() > 10000000.0)
509        {
510            GrowthPattern::Burst
511        } else {
512            GrowthPattern::Normal
513        };
514
515        // Project future memory usage
516        let last_timestamp = snapshots.back().expect("unwrap failed").timestamp;
517        let projected_usage = (1..=10)
518            .map(|i| {
519                let future_timestamp = last_timestamp + (i * 60); // 1 minute intervals
520                let future_memory =
521                    memory_values.last().expect("unwrap failed") + (growth_rate * i as f64);
522                (future_timestamp, future_memory.max(0.0) as usize)
523            })
524            .collect();
525
526        Ok(MemoryGrowthAnalysis {
527            growth_trend,
528            growth_rate,
529            projected_usage,
530            pattern_type,
531        })
532    }
533
534    /// Generate recommendations based on detected issues
535    fn generate_recommendations(&self, suspectedleaks: &[SuspectedLeak]) -> Vec<String> {
536        let mut recommendations = Vec::new();
537
538        let circular_ref_count = suspectedleaks
539            .iter()
540            .filter(|l| matches!(l.leak_type, LeakType::CircularReference))
541            .count();
542
543        let stale_ref_count = suspectedleaks
544            .iter()
545            .filter(|l| matches!(l.leak_type, LeakType::StaleReference))
546            .count();
547
548        let overflow_count = suspectedleaks
549            .iter()
550            .filter(|l| matches!(l.leak_type, LeakType::ReferenceCountOverflow))
551            .count();
552
553        if circular_ref_count > 0 {
554            recommendations.push(format!(
555                "Detected {} circular references. Consider using weak references to break cycles.",
556                circular_ref_count
557            ));
558        }
559
560        if stale_ref_count > 0 {
561            recommendations.push(format!(
562                "Detected {} stale references. Implement automatic cleanup for unused references.",
563                stale_ref_count
564            ));
565        }
566
567        if overflow_count > 0 {
568            recommendations.push(format!(
569                "Detected {} reference count overflows. Review reference sharing patterns.",
570                overflow_count
571            ));
572        }
573
574        if suspectedleaks.len() > 10 {
575            recommendations.push(
576                "High number of suspected _leaks detected. Consider implementing reference pooling."
577                    .to_string(),
578            );
579        }
580
581        if recommendations.is_empty() {
582            recommendations.push("Reference counting patterns appear healthy.".to_string());
583        }
584
585        recommendations
586    }
587}
588
589/// Cycle detector for identifying circular references
590#[derive(Debug)]
591#[allow(dead_code)]
592pub struct CycleDetector {
593    /// Maximum detection depth
594    max_depth: usize,
595}
596
597/// State for Tarjan's algorithm
598struct TarjanState {
599    index: usize,
600    stack: Vec<usize>,
601    indices: HashMap<usize, usize>,
602    lowlinks: HashMap<usize, usize>,
603    on_stack: HashSet<usize>,
604    strongly_connected_components: Vec<Vec<usize>>,
605}
606
607impl TarjanState {
608    fn new() -> Self {
609        Self {
610            index: 0,
611            stack: Vec::new(),
612            indices: HashMap::new(),
613            lowlinks: HashMap::new(),
614            on_stack: HashSet::new(),
615            strongly_connected_components: Vec::new(),
616        }
617    }
618}
619
620impl CycleDetector {
621    /// Create a new cycle detector
622    pub fn new() -> Self {
623        Self { max_depth: 20 }
624    }
625
626    /// Detect cycles in reference graph using Tarjan's algorithm
627    pub fn detect_cycles(&self, graph: &HashMap<usize, HashSet<usize>>) -> Vec<Vec<usize>> {
628        let mut state = TarjanState::new();
629
630        for &node in graph.keys() {
631            if !state.indices.contains_key(&node) {
632                Self::strongconnect(node, &mut state, graph);
633            }
634        }
635
636        // Filter to return only cycles (SCCs with more than one node or self-loops)
637        state
638            .strongly_connected_components
639            .into_iter()
640            .filter(|scc| {
641                scc.len() > 1
642                    || (scc.len() == 1
643                        && graph
644                            .get(&scc[0])
645                            .is_some_and(|neighbors| neighbors.contains(&scc[0])))
646            })
647            .collect()
648    }
649
650    /// Tarjan's strongly connected components algorithm
651    fn strongconnect(v: usize, state: &mut TarjanState, graph: &HashMap<usize, HashSet<usize>>) {
652        state.indices.insert(v, state.index);
653        state.lowlinks.insert(v, state.index);
654        state.index += 1;
655        state.stack.push(v);
656        state.on_stack.insert(v);
657
658        if let Some(neighbors) = graph.get(&v) {
659            for &w in neighbors {
660                if !state.indices.contains_key(&w) {
661                    Self::strongconnect(w, state, graph);
662                    let v_lowlink = *state.lowlinks.get(&v).expect("unwrap failed");
663                    let w_lowlink = *state.lowlinks.get(&w).expect("unwrap failed");
664                    state.lowlinks.insert(v, v_lowlink.min(w_lowlink));
665                } else if state.on_stack.contains(&w) {
666                    let v_lowlink = *state.lowlinks.get(&v).expect("unwrap failed");
667                    let w_index = *state.indices.get(&w).expect("unwrap failed");
668                    state.lowlinks.insert(v, v_lowlink.min(w_index));
669                }
670            }
671        }
672
673        if state.lowlinks.get(&v) == state.indices.get(&v) {
674            let mut component = Vec::new();
675            loop {
676                let w = state.stack.pop().expect("unwrap failed");
677                state.on_stack.remove(&w);
678                component.push(w);
679                if w == v {
680                    break;
681                }
682            }
683            state.strongly_connected_components.push(component);
684        }
685    }
686}
687
688impl Default for ReferenceTracker {
689    fn default() -> Self {
690        Self::new()
691    }
692}
693
694impl ReferenceTracker {
695    /// Create a new reference tracker
696    pub fn new() -> Self {
697        Self {
698            active_references: HashMap::new(),
699            reference_graph: HashMap::new(),
700            reference_history: VecDeque::new(),
701            suspectedleaks: Vec::new(),
702        }
703    }
704}
705
706impl Default for CycleDetector {
707    fn default() -> Self {
708        Self::new()
709    }
710}
711
712/// Real-time memory monitor
713///
714/// Provides continuous monitoring of memory usage patterns and leak detection
715/// in real-time with configurable sampling rates and alert thresholds.
716#[allow(dead_code)]
717pub struct RealTimeMemoryMonitor {
718    /// Monitor configuration
719    config: RealTimeMonitorConfig,
720    /// Current monitoring state
721    state: Arc<Mutex<MonitorState>>,
722    /// Alert system
723    alert_system: AlertSystem,
724    /// Is monitoring active
725    is_active: Arc<Mutex<bool>>,
726}
727
728/// Real-time monitor configuration
729#[derive(Debug, Clone)]
730pub struct RealTimeMonitorConfig {
731    /// Sampling interval in milliseconds
732    pub sampling_interval_ms: u64,
733    /// Memory threshold for alerts (bytes)
734    pub memory_threshold_bytes: usize,
735    /// Growth rate threshold (bytes/second)
736    pub growth_rate_threshold: f64,
737    /// Window size for trend analysis
738    pub trend_window_size: usize,
739    /// Enable automatic garbage collection hints
740    pub enable_gc_hints: bool,
741}
742
743impl Default for RealTimeMonitorConfig {
744    fn default() -> Self {
745        Self {
746            sampling_interval_ms: 1000,                // 1 second
747            memory_threshold_bytes: 100 * 1024 * 1024, // 100MB
748            growth_rate_threshold: 1024.0 * 1024.0,    // 1MB/s
749            trend_window_size: 60,                     // 1 minute of samples
750            enable_gc_hints: true,
751        }
752    }
753}
754
755/// Monitor state
756#[derive(Debug)]
757pub struct MonitorState {
758    /// Recent memory samples
759    memory_samples: VecDeque<MemorySample>,
760    /// Current memory usage
761    current_memory_usage: usize,
762    /// Peak memory usage
763    peak_memory_usage: usize,
764    /// Memory growth rate
765    current_growth_rate: f64,
766    /// Alert history
767    alert_history: VecDeque<MemoryAlert>,
768}
769
770/// Memory sample for monitoring
771#[derive(Debug, Clone)]
772pub struct MemorySample {
773    /// Sample timestamp
774    pub timestamp: Instant,
775    /// Memory usage in bytes
776    pub memory_usage: usize,
777    /// Allocation rate
778    pub allocation_rate: f64,
779    /// Deallocation rate
780    pub deallocation_rate: f64,
781}
782
783/// Memory alert
784#[derive(Debug, Clone)]
785pub struct MemoryAlert {
786    /// Alert timestamp
787    pub timestamp: Instant,
788    /// Alert type
789    pub alert_type: AlertType,
790    /// Alert message
791    pub message: String,
792    /// Severity level
793    pub severity: AlertSeverity,
794}
795
796/// Types of memory alerts
797#[derive(Debug, Clone)]
798pub enum AlertType {
799    /// Memory threshold exceeded
800    MemoryThreshold,
801    /// Growth rate exceeded
802    GrowthRate,
803    /// Potential leak detected
804    PotentialLeak,
805    /// Memory fragmentation
806    Fragmentation,
807    /// System memory pressure
808    SystemPressure,
809}
810
811/// Alert severity levels
812#[derive(Debug, Clone)]
813pub enum AlertSeverity {
814    Low,
815    Medium,
816    High,
817    Critical,
818}
819
820/// Type alias for alert callbacks
821type AlertCallback = Box<dyn Fn(&MemoryAlert) + Send + Sync>;
822
823/// Alert system for memory monitoring
824pub struct AlertSystem {
825    /// Alert callbacks
826    alert_callbacks: Vec<AlertCallback>,
827}
828
829impl RealTimeMemoryMonitor {
830    /// Create a new real-time memory monitor
831    pub fn new(config: RealTimeMonitorConfig) -> Self {
832        Self {
833            config,
834            state: Arc::new(Mutex::new(MonitorState::new())),
835            alert_system: AlertSystem::new(),
836            is_active: Arc::new(Mutex::new(false)),
837        }
838    }
839
840    /// Start monitoring
841    pub fn start_monitoring(&self) -> Result<()> {
842        let mut is_active = self
843            .is_active
844            .lock()
845            .map_err(|_| OptimError::InvalidState("Failed to acquire monitor lock".to_string()))?;
846
847        if *is_active {
848            return Ok(()); // Already monitoring
849        }
850
851        *is_active = true;
852
853        let state = Arc::clone(&self.state);
854        let config = self.config.clone();
855        let is_active_flag = Arc::clone(&self.is_active);
856
857        thread::spawn(move || {
858            let mut _last_sample_time = Instant::now();
859
860            loop {
861                // Check if monitoring should continue
862                {
863                    let active = is_active_flag.lock().expect("lock poisoned");
864                    if !*active {
865                        break;
866                    }
867                }
868
869                // Sleep for sampling interval
870                thread::sleep(Duration::from_millis(config.sampling_interval_ms));
871
872                // Take memory sample
873                let now = Instant::now();
874                let sample = Self::take_memory_sample(now);
875
876                // Update state
877                {
878                    let mut monitor_state = state.lock().expect("lock poisoned");
879                    monitor_state.add_sample(sample);
880                    monitor_state.update_metrics(&config);
881                }
882
883                _last_sample_time = now;
884            }
885        });
886
887        Ok(())
888    }
889
890    /// Stop monitoring
891    pub fn stop_monitoring(&self) -> Result<()> {
892        let mut is_active = self
893            .is_active
894            .lock()
895            .map_err(|_| OptimError::InvalidState("Failed to acquire monitor lock".to_string()))?;
896
897        *is_active = false;
898        Ok(())
899    }
900
901    /// Take a memory sample
902    fn take_memory_sample(timestamp: Instant) -> MemorySample {
903        // In a real implementation, this would use system APIs to get actual memory usage
904        // For now, we'll simulate memory sampling
905        MemorySample {
906            timestamp,
907            memory_usage: Self::get_current_memory_usage(),
908            allocation_rate: 0.0,   // Would be calculated from real data
909            deallocation_rate: 0.0, // Would be calculated from real data
910        }
911    }
912
913    /// Get current memory usage (simulated)
914    fn get_current_memory_usage() -> usize {
915        // In a real implementation, this would use:
916        // - On Linux: /proc/self/status or mallinfo
917        // - On macOS: task_info or malloc_zone_statistics
918        // - On Windows: GetProcessMemoryInfo
919
920        // For now, return a simulated value
921        64 * 1024 * 1024 // 64MB
922    }
923
924    /// Get current monitoring statistics
925    pub fn get_statistics(&self) -> Result<MonitoringStatistics> {
926        let state = self.state.lock().map_err(|_| {
927            OptimError::InvalidState("Failed to acquire monitor state lock".to_string())
928        })?;
929
930        Ok(MonitoringStatistics {
931            current_memory_usage: state.current_memory_usage,
932            peak_memory_usage: state.peak_memory_usage,
933            current_growth_rate: state.current_growth_rate,
934            sample_count: state.memory_samples.len(),
935            recent_alerts: state.alert_history.iter().cloned().collect(),
936        })
937    }
938}
939
940/// Monitoring statistics
941#[derive(Debug, Clone)]
942pub struct MonitoringStatistics {
943    /// Current memory usage
944    pub current_memory_usage: usize,
945    /// Peak memory usage
946    pub peak_memory_usage: usize,
947    /// Current growth rate
948    pub current_growth_rate: f64,
949    /// Number of samples collected
950    pub sample_count: usize,
951    /// Recent alerts
952    pub recent_alerts: Vec<MemoryAlert>,
953}
954
955impl MonitorState {
956    /// Create new monitor state
957    pub fn new() -> Self {
958        Self {
959            memory_samples: VecDeque::new(),
960            current_memory_usage: 0,
961            peak_memory_usage: 0,
962            current_growth_rate: 0.0,
963            alert_history: VecDeque::new(),
964        }
965    }
966
967    /// Add a memory sample
968    pub fn add_sample(&mut self, sample: MemorySample) {
969        self.current_memory_usage = sample.memory_usage;
970        self.peak_memory_usage = self.peak_memory_usage.max(sample.memory_usage);
971
972        self.memory_samples.push_back(sample);
973
974        // Limit sample history
975        while self.memory_samples.len() > 3600 {
976            // 1 hour at 1s intervals
977            self.memory_samples.pop_front();
978        }
979    }
980
981    /// Update monitoring metrics
982    pub fn update_metrics(&mut self, config: &RealTimeMonitorConfig) {
983        // Calculate growth rate
984        if self.memory_samples.len() >= 2 {
985            let window_size = config.trend_window_size.min(self.memory_samples.len());
986            let recent_samples: Vec<_> =
987                self.memory_samples.iter().rev().take(window_size).collect();
988
989            if recent_samples.len() >= 2 {
990                let first = recent_samples.last().expect("unwrap failed");
991                let last = recent_samples.first().expect("unwrap failed");
992                let time_diff = last.timestamp.duration_since(first.timestamp).as_secs_f64();
993
994                if time_diff > 0.0 {
995                    let memory_diff = last.memory_usage as f64 - first.memory_usage as f64;
996                    self.current_growth_rate = memory_diff / time_diff;
997                }
998            }
999        }
1000
1001        // Check for alerts
1002        self.check_for_alerts(config);
1003    }
1004
1005    /// Check for alert conditions
1006    fn check_for_alerts(&mut self, config: &RealTimeMonitorConfig) {
1007        let now = Instant::now();
1008
1009        // Memory threshold alert
1010        if self.current_memory_usage > config.memory_threshold_bytes {
1011            let alert = MemoryAlert {
1012                timestamp: now,
1013                alert_type: AlertType::MemoryThreshold,
1014                message: format!(
1015                    "Memory usage {} exceeds threshold {}",
1016                    self.current_memory_usage, config.memory_threshold_bytes
1017                ),
1018                severity: AlertSeverity::High,
1019            };
1020            self.alert_history.push_back(alert);
1021        }
1022
1023        // Growth rate alert
1024        if self.current_growth_rate > config.growth_rate_threshold {
1025            let alert = MemoryAlert {
1026                timestamp: now,
1027                alert_type: AlertType::GrowthRate,
1028                message: format!(
1029                    "Memory growth rate {:.2} bytes/s exceeds threshold {:.2}",
1030                    self.current_growth_rate, config.growth_rate_threshold
1031                ),
1032                severity: AlertSeverity::Medium,
1033            };
1034            self.alert_history.push_back(alert);
1035        }
1036
1037        // Limit alert history
1038        while self.alert_history.len() > 1000 {
1039            self.alert_history.pop_front();
1040        }
1041    }
1042}
1043
1044impl AlertSystem {
1045    /// Create new alert system
1046    pub fn new() -> Self {
1047        Self {
1048            alert_callbacks: Vec::new(),
1049        }
1050    }
1051
1052    /// Add alert callback
1053    pub fn add_callback<F>(&mut self, callback: F)
1054    where
1055        F: Fn(&MemoryAlert) + Send + Sync + 'static,
1056    {
1057        self.alert_callbacks.push(Box::new(callback));
1058    }
1059
1060    /// Trigger alert
1061    pub fn trigger_alert(&self, alert: &MemoryAlert) {
1062        for callback in &self.alert_callbacks {
1063            callback(alert);
1064        }
1065    }
1066}
1067
1068impl Default for MonitorState {
1069    fn default() -> Self {
1070        Self::new()
1071    }
1072}
1073
1074impl Default for AlertSystem {
1075    fn default() -> Self {
1076        Self::new()
1077    }
1078}