Skip to main content

memscope_rs/analyzer/
classify.rs

1//! Classification analysis module.
2
3use crate::view::MemoryView;
4use std::collections::HashMap;
5
6/// Classification analysis module.
7///
8/// Provides type classification and categorization.
9pub struct ClassificationAnalysis {
10    view: MemoryView,
11}
12
13impl ClassificationAnalysis {
14    /// Create from view.
15    pub fn from_view(view: &MemoryView) -> Self {
16        Self { view: view.clone() }
17    }
18
19    /// Classify allocations by type.
20    pub fn by_type(&self) -> HashMap<String, TypeClassification> {
21        let mut types: HashMap<String, TypeClassification> = HashMap::new();
22
23        for alloc in self.view.allocations() {
24            let type_name = alloc
25                .type_name
26                .clone()
27                .unwrap_or_else(|| "unknown".to_string());
28
29            let entry = types.entry(type_name).or_default();
30            entry.count += 1;
31            entry.total_bytes += alloc.size;
32            entry.category = classify_type(&alloc.type_name.clone().unwrap_or_default());
33        }
34
35        types
36    }
37
38    /// Get classification summary.
39    pub fn summary(&self) -> ClassificationSummary {
40        let types = self.by_type();
41        let mut categories: HashMap<TypeCategory, usize> = HashMap::new();
42
43        for classification in types.values() {
44            *categories.entry(classification.category).or_default() += classification.count;
45        }
46
47        ClassificationSummary {
48            total_types: types.len(),
49            categories,
50        }
51    }
52}
53
54/// Classification for a specific type.
55#[derive(Debug, Clone, Default)]
56pub struct TypeClassification {
57    /// Number of allocations
58    pub count: usize,
59    /// Total bytes
60    pub total_bytes: usize,
61    /// Type category
62    pub category: TypeCategory,
63}
64
65/// Type category.
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
67pub enum TypeCategory {
68    /// Unknown type
69    #[default]
70    Unknown,
71    /// Collection type (Vec, HashMap, etc.)
72    Collection,
73    /// String type
74    String,
75    /// Smart pointer (Arc, Rc, Box)
76    SmartPointer,
77    /// Primitive type
78    Primitive,
79    /// Custom type
80    Custom,
81}
82
83/// Classification summary.
84#[derive(Debug, Clone)]
85pub struct ClassificationSummary {
86    /// Total unique types
87    pub total_types: usize,
88    /// Count by category
89    pub categories: HashMap<TypeCategory, usize>,
90}
91
92/// Classify a type name into a category.
93fn classify_type(type_name: &str) -> TypeCategory {
94    if type_name.contains("Vec<")
95        || type_name.contains("HashMap<")
96        || type_name.contains("HashSet<")
97        || type_name.contains("BTreeMap<")
98        || type_name.contains("BTreeSet<")
99        || type_name.contains("LinkedList<")
100        || type_name.contains("VecDeque<")
101    {
102        TypeCategory::Collection
103    } else if type_name.contains("String") || type_name.contains("str") {
104        TypeCategory::String
105    } else if type_name.contains("Arc<")
106        || type_name.contains("Rc<")
107        || type_name.contains("Box<")
108        || type_name.contains("Weak<")
109    {
110        TypeCategory::SmartPointer
111    } else if type_name.contains("i32")
112        || type_name.contains("u32")
113        || type_name.contains("i64")
114        || type_name.contains("u64")
115        || type_name.contains("f32")
116        || type_name.contains("f64")
117        || type_name.contains("bool")
118        || type_name.contains("char")
119    {
120        TypeCategory::Primitive
121    } else if !type_name.is_empty() && type_name != "unknown" {
122        TypeCategory::Custom
123    } else {
124        TypeCategory::Unknown
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use crate::event_store::MemoryEvent;
132
133    #[test]
134    fn test_classification() {
135        let events = vec![
136            MemoryEvent::allocate(0x1000, 64, 1).with_type_name("Vec<i32>".to_string()),
137            MemoryEvent::allocate(0x2000, 32, 1).with_type_name("String".to_string()),
138        ];
139        let view = MemoryView::from_events(events);
140        let analysis = ClassificationAnalysis::from_view(&view);
141        let types = analysis.by_type();
142        assert_eq!(types.len(), 2);
143    }
144
145    #[test]
146    fn test_type_category() {
147        assert_eq!(classify_type("Vec<i32>"), TypeCategory::Collection);
148        assert_eq!(classify_type("String"), TypeCategory::String);
149        assert_eq!(classify_type("Arc<Mutex<T>>"), TypeCategory::SmartPointer);
150    }
151}