scirs2_core/memory/metrics/
event.rs1use std::collections::HashMap;
7use std::fmt;
8use std::thread::ThreadId;
9use std::time::Instant;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum MemoryEventType {
14 Allocation,
16 Deallocation,
18 Resize,
20 Access,
22 Transfer,
24}
25
26impl fmt::Display for MemoryEventType {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 match self {
29 MemoryEventType::Allocation => write!(f, "Allocation"),
30 MemoryEventType::Deallocation => write!(f, "Deallocation"),
31 MemoryEventType::Resize => write!(f, "Resize"),
32 MemoryEventType::Access => write!(f, "Access"),
33 MemoryEventType::Transfer => write!(f, "Transfer"),
34 }
35 }
36}
37
38#[derive(Debug, Clone)]
40pub struct MemoryEvent {
41 pub event_type: MemoryEventType,
43 pub component: String,
45 pub context: Option<String>,
47 pub size: usize,
49 pub address: usize,
51 pub thread_id: ThreadId,
53 pub timestamp: Instant,
55 pub call_stack: Option<Vec<String>>,
57 pub metadata: HashMap<String, String>,
59}
60
61impl MemoryEvent {
62 pub fn new(
64 event_type: MemoryEventType,
65 component: impl Into<String>,
66 size: usize,
67 address: usize,
68 ) -> Self {
69 Self {
70 event_type,
71 component: component.into(),
72 context: None,
73 size,
74 address,
75 thread_id: std::thread::current().id(),
76 timestamp: Instant::now(),
77 call_stack: None,
78 metadata: HashMap::new(),
79 }
80 }
81
82 pub fn with_context(mut self, context: impl Into<String>) -> Self {
84 self.context = Some(context.into());
85 self
86 }
87
88 pub fn with_call_stack(mut self) -> Self {
90 if cfg!(feature = "memory_call_stack") {
91 self.call_stack = Some(capture_call_stack(3)); }
93 self
94 }
95
96 pub fn with_metadata(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
98 self.metadata.insert(key.into(), value.into());
99 self
100 }
101}
102
103fn capture_call_stack(skipframes: usize) -> Vec<String> {
105 vec![format!("frame_{}", skipframes)]
107}
108
109#[cfg(feature = "memory_call_stack")]
111#[allow(dead_code)]
112fn capture_stack_frames(maxframes: usize) -> Vec<String> {
113 vec!["<callstack not available>".to_string()]
116}
117
118#[cfg(not(feature = "memory_call_stack"))]
119#[allow(dead_code)]
120fn capture_stack_frames(maxframes: usize) -> Vec<String> {
121 Vec::new()
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_memory_event_creation() {
130 let event = MemoryEvent::new(
131 MemoryEventType::Allocation,
132 "TestComponent",
133 1024,
134 0xdeadbeef,
135 );
136
137 assert_eq!(event.event_type, MemoryEventType::Allocation);
138 assert_eq!(event.component, "TestComponent");
139 assert_eq!(event.size, 1024);
140 assert_eq!(event.address, 0xdeadbeef);
141 assert_eq!(event.context, None);
142 assert!(event.call_stack.is_none());
143 assert!(event.metadata.is_empty());
144 }
145
146 #[test]
147 fn test_memory_event_with_context() {
148 let event = MemoryEvent::new(
149 MemoryEventType::Allocation,
150 "TestComponent",
151 1024,
152 0xdeadbeef,
153 )
154 .with_context("TestContext");
155
156 assert_eq!(event.context, Some("TestContext".to_string()));
157 }
158
159 #[test]
160 fn test_memory_event_with_metadata() {
161 let event = MemoryEvent::new(
162 MemoryEventType::Allocation,
163 "TestComponent",
164 1024,
165 0xdeadbeef,
166 )
167 .with_metadata("key1", "value1")
168 .with_metadata("key2", "value2");
169
170 assert_eq!(event.metadata.len(), 2);
171 assert_eq!(event.metadata.get("key1"), Some(&"value1".to_string()));
172 assert_eq!(event.metadata.get("key2"), Some(&"value2".to_string()));
173 }
174}