Skip to main content

memscope_rs/analysis_engine/
engine.rs

1//! Analysis Engine - Memory analysis logic
2//!
3//! This module provides the AnalysisEngine which coordinates multiple
4//! analyzers to detect memory issues.
5
6use crate::analysis_engine::analyzer::{AnalysisResult, Analyzer};
7use crate::snapshot::{MemorySnapshot, SharedSnapshotEngine};
8
9/// Analysis Engine - Coordinates memory analysis
10///
11/// The AnalysisEngine manages multiple analyzers and runs them on
12/// memory snapshots to detect issues like leaks, fragmentation, and
13/// safety violations.
14///
15/// Key properties:
16/// - Pluggable: Supports adding custom analyzers
17/// - Concurrent: Can run analyzers in parallel
18/// - Comprehensive: Covers multiple analysis dimensions
19pub struct AnalysisEngine {
20    /// Reference to the snapshot engine
21    snapshot_engine: SharedSnapshotEngine,
22    /// Registered analyzers
23    analyzers: Vec<Box<dyn Analyzer>>,
24}
25
26impl AnalysisEngine {
27    /// Create a new AnalysisEngine
28    pub fn new(snapshot_engine: SharedSnapshotEngine) -> Self {
29        Self {
30            snapshot_engine,
31            analyzers: Vec::new(),
32        }
33    }
34
35    /// Register an analyzer
36    ///
37    /// # Arguments
38    /// * `analyzer` - The analyzer to register
39    pub fn register_analyzer(&mut self, analyzer: Box<dyn Analyzer>) {
40        self.analyzers.push(analyzer);
41    }
42
43    /// Run all registered analyzers on the current snapshot
44    ///
45    /// # Returns
46    /// A vector of analysis results from all analyzers
47    pub fn analyze(&self) -> Vec<AnalysisResult> {
48        let snapshot = self.snapshot_engine.build_snapshot();
49        self.analyze_snapshot(&snapshot)
50    }
51
52    /// Run all registered analyzers on a specific snapshot
53    ///
54    /// # Arguments
55    /// * `snapshot` - The snapshot to analyze
56    ///
57    /// # Returns
58    /// A vector of analysis results from all analyzers
59    pub fn analyze_snapshot(&self, snapshot: &MemorySnapshot) -> Vec<AnalysisResult> {
60        self.analyzers
61            .iter()
62            .map(|analyzer| analyzer.analyze(snapshot))
63            .collect()
64    }
65
66    /// Get the number of registered analyzers
67    pub fn analyzer_count(&self) -> usize {
68        self.analyzers.len()
69    }
70
71    /// Check if any analyzers are registered
72    pub fn has_analyzers(&self) -> bool {
73        !self.analyzers.is_empty()
74    }
75}
76
77#[cfg(test)]
78mod tests {
79    use super::*;
80    use crate::analysis_engine::analyzer::{AnalysisResult, Analyzer, Severity};
81    use crate::event_store::EventStore;
82    use crate::snapshot::SnapshotEngine;
83
84    use std::sync::Arc;
85
86    struct TestAnalyzer {
87        name: String,
88    }
89
90    impl Analyzer for TestAnalyzer {
91        fn name(&self) -> &str {
92            &self.name
93        }
94
95        fn analyze(&self, snapshot: &MemorySnapshot) -> AnalysisResult {
96            AnalysisResult {
97                analyzer_name: self.name.clone(),
98                issue_count: snapshot.active_count(),
99                severity: Severity::Warning,
100                description: format!("Analysis by {}", self.name),
101                findings: vec![],
102            }
103        }
104    }
105
106    #[test]
107    fn test_analysis_engine_creation() {
108        let event_store = Arc::new(EventStore::new());
109        let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
110        let engine = AnalysisEngine::new(snapshot_engine);
111
112        assert_eq!(engine.analyzer_count(), 0);
113        assert!(!engine.has_analyzers());
114    }
115
116    #[test]
117    fn test_register_analyzer() {
118        let event_store = Arc::new(EventStore::new());
119        let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
120        let mut engine = AnalysisEngine::new(snapshot_engine);
121
122        engine.register_analyzer(Box::new(TestAnalyzer {
123            name: "test".to_string(),
124        }));
125
126        assert_eq!(engine.analyzer_count(), 1);
127        assert!(engine.has_analyzers());
128    }
129
130    #[test]
131    fn test_analyze() {
132        let event_store = Arc::new(EventStore::new());
133        let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
134        let mut engine = AnalysisEngine::new(snapshot_engine);
135
136        engine.register_analyzer(Box::new(TestAnalyzer {
137            name: "test".to_string(),
138        }));
139
140        let results = engine.analyze();
141        assert_eq!(results.len(), 1);
142        assert_eq!(results[0].analyzer_name, "test");
143    }
144
145    #[test]
146    fn test_multiple_analyzers() {
147        let event_store = Arc::new(EventStore::new());
148        let snapshot_engine = Arc::new(SnapshotEngine::new(event_store));
149        let mut engine = AnalysisEngine::new(snapshot_engine);
150
151        engine.register_analyzer(Box::new(TestAnalyzer {
152            name: "analyzer1".to_string(),
153        }));
154        engine.register_analyzer(Box::new(TestAnalyzer {
155            name: "analyzer2".to_string(),
156        }));
157
158        assert_eq!(engine.analyzer_count(), 2);
159
160        let results = engine.analyze();
161        assert_eq!(results.len(), 2);
162    }
163}