Skip to main content

memscope_rs/event_store/
event.rs

1//! Core memory event types for the event store
2//!
3//! This module defines the unified memory event type used across
4//! all engines in the memscope architecture.
5
6use serde::{Deserialize, Serialize};
7use std::fmt;
8
9/// Type of memory event
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
11pub enum MemoryEventType {
12    /// Memory allocation event
13    Allocate,
14    /// Memory deallocation event
15    Deallocate,
16    /// Memory reallocation event
17    Reallocate,
18    /// Memory move event
19    Move,
20    /// Memory borrow event
21    Borrow,
22    /// Memory return event
23    Return,
24    /// Metadata event for Container/Value types (no heap allocation)
25    Metadata,
26    /// Clone event
27    Clone,
28}
29
30impl fmt::Display for MemoryEventType {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        match self {
33            MemoryEventType::Allocate => write!(f, "Allocate"),
34            MemoryEventType::Deallocate => write!(f, "Deallocate"),
35            MemoryEventType::Reallocate => write!(f, "Reallocate"),
36            MemoryEventType::Move => write!(f, "Move"),
37            MemoryEventType::Borrow => write!(f, "Borrow"),
38            MemoryEventType::Return => write!(f, "Return"),
39            MemoryEventType::Metadata => write!(f, "Metadata"),
40            MemoryEventType::Clone => write!(f, "Clone"),
41        }
42    }
43}
44
45/// Unified memory event type
46///
47/// This structure captures all essential information about memory operations
48/// across all tracking backends (core, lockfree, async, unified).
49#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct MemoryEvent {
51    /// Event timestamp (nanoseconds since epoch)
52    pub timestamp: u64,
53    /// Event type
54    pub event_type: MemoryEventType,
55    /// Memory pointer address
56    pub ptr: usize,
57    /// Allocation size in bytes
58    pub size: usize,
59    /// Previous allocation size (for Reallocate events)
60    pub old_size: Option<usize>,
61    /// Thread identifier
62    pub thread_id: u64,
63    /// Optional variable name
64    pub var_name: Option<String>,
65    /// Optional type name
66    pub type_name: Option<String>,
67    /// Optional call stack hash
68    pub call_stack_hash: Option<u64>,
69    /// Optional thread name
70    pub thread_name: Option<String>,
71    /// Optional source file path
72    pub source_file: Option<String>,
73    /// Optional source line number
74    pub source_line: Option<u32>,
75    /// Optional module path
76    pub module_path: Option<String>,
77    /// Clone source pointer (for Clone events)
78    pub clone_source_ptr: Option<usize>,
79    /// Clone target pointer (for Clone events)
80    pub clone_target_ptr: Option<usize>,
81    /// Stack pointer (for StackOwner types like Arc/Rc)
82    pub stack_ptr: Option<usize>,
83    /// Task ID (for task-aware memory tracking)
84    pub task_id: Option<u64>,
85}
86
87impl MemoryEvent {
88    /// Create a new allocation event
89    pub fn allocate(ptr: usize, size: usize, thread_id: u64) -> Self {
90        // Record allocation in task registry
91        crate::task_registry::global_registry().record_allocation(size);
92
93        Self {
94            timestamp: Self::now(),
95            event_type: MemoryEventType::Allocate,
96            ptr,
97            size,
98            old_size: None,
99            thread_id,
100            var_name: None,
101            type_name: None,
102            call_stack_hash: None,
103            thread_name: None,
104            source_file: None,
105            source_line: None,
106            module_path: None,
107            clone_source_ptr: None,
108            clone_target_ptr: None,
109            stack_ptr: None,
110            task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
111        }
112    }
113
114    /// Create a new deallocation event
115    pub fn deallocate(ptr: usize, size: usize, thread_id: u64) -> Self {
116        Self {
117            timestamp: Self::now(),
118            event_type: MemoryEventType::Deallocate,
119            ptr,
120            size,
121            old_size: None,
122            thread_id,
123            var_name: None,
124            type_name: None,
125            call_stack_hash: None,
126            thread_name: None,
127            source_file: None,
128            source_line: None,
129            module_path: None,
130            clone_source_ptr: None,
131            clone_target_ptr: None,
132            stack_ptr: None,
133            task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
134        }
135    }
136
137    /// Create a new reallocation event
138    pub fn reallocate(ptr: usize, old_size: usize, new_size: usize, thread_id: u64) -> Self {
139        Self {
140            timestamp: Self::now(),
141            event_type: MemoryEventType::Reallocate,
142            ptr,
143            size: new_size,
144            old_size: Some(old_size),
145            thread_id,
146            var_name: None,
147            type_name: None,
148            call_stack_hash: None,
149            thread_name: None,
150            source_file: None,
151            source_line: None,
152            module_path: None,
153            clone_source_ptr: None,
154            clone_target_ptr: None,
155            stack_ptr: None,
156            task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
157        }
158    }
159
160    /// Create a new metadata event for Container/Value types (no heap allocation)
161    pub fn metadata(var_name: String, type_name: String, thread_id: u64, size: usize) -> Self {
162        Self {
163            timestamp: Self::now(),
164            event_type: MemoryEventType::Metadata,
165            ptr: 0, // No heap pointer
166            size,
167            old_size: None,
168            thread_id,
169            var_name: Some(var_name),
170            type_name: Some(type_name),
171            call_stack_hash: None,
172            thread_name: None,
173            source_file: None,
174            source_line: None,
175            module_path: None,
176            clone_source_ptr: None,
177            clone_target_ptr: None,
178            stack_ptr: None,
179            task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
180        }
181    }
182
183    /// Create a new clone event
184    pub fn clone_event(
185        source_ptr: usize,
186        target_ptr: usize,
187        size: usize,
188        thread_id: u64,
189        var_name: Option<String>,
190        type_name: Option<String>,
191    ) -> Self {
192        Self {
193            timestamp: Self::now(),
194            event_type: MemoryEventType::Clone,
195            ptr: target_ptr,
196            size,
197            old_size: None,
198            thread_id,
199            var_name,
200            type_name,
201            call_stack_hash: None,
202            thread_name: None,
203            source_file: None,
204            source_line: None,
205            module_path: None,
206            clone_source_ptr: Some(source_ptr),
207            clone_target_ptr: Some(target_ptr),
208            stack_ptr: None,
209            task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
210        }
211    }
212
213    /// Create a new borrow event
214    pub fn borrow(ptr: usize, size: usize, thread_id: u64, is_mutable: bool) -> Self {
215        Self {
216            timestamp: Self::now(),
217            event_type: MemoryEventType::Borrow,
218            ptr,
219            size,
220            old_size: None,
221            thread_id,
222            var_name: None,
223            type_name: Some(if is_mutable {
224                "mutable borrow".to_string()
225            } else {
226                "immutable borrow".to_string()
227            }),
228            call_stack_hash: None,
229            thread_name: None,
230            source_file: None,
231            source_line: None,
232            module_path: None,
233            clone_source_ptr: None,
234            clone_target_ptr: None,
235            stack_ptr: None,
236            task_id: crate::task_registry::TaskIdRegistry::current_task_id(),
237        }
238    }
239
240    /// Get current timestamp in nanoseconds
241    /// Returns 0 if system time is before Unix epoch (should not happen in practice)
242    pub fn now() -> u64 {
243        use std::time::{SystemTime, UNIX_EPOCH};
244        SystemTime::now()
245            .duration_since(UNIX_EPOCH)
246            .map(|d| d.as_nanos() as u64)
247            .unwrap_or_default()
248    }
249
250    /// Set variable name
251    pub fn with_var_name(mut self, name: String) -> Self {
252        self.var_name = Some(name);
253        self
254    }
255
256    /// Set type name
257    pub fn with_type_name(mut self, name: String) -> Self {
258        self.type_name = Some(name);
259        self
260    }
261
262    /// Set source file path
263    pub fn with_source_file(mut self, file: String) -> Self {
264        self.source_file = Some(file);
265        self
266    }
267
268    /// Set source line number
269    pub fn with_source_line(mut self, line: u32) -> Self {
270        self.source_line = Some(line);
271        self
272    }
273
274    /// Set call stack hash
275    pub fn with_call_stack_hash(mut self, hash: u64) -> Self {
276        self.call_stack_hash = Some(hash);
277        self
278    }
279
280    /// Set thread name
281    pub fn with_thread_name(mut self, name: String) -> Self {
282        self.thread_name = Some(name);
283        self
284    }
285
286    /// Check if this is an allocation event
287    pub fn is_allocation(&self) -> bool {
288        matches!(
289            self.event_type,
290            MemoryEventType::Allocate | MemoryEventType::Reallocate | MemoryEventType::Metadata
291        )
292    }
293
294    /// Check if this is a deallocation event
295    pub fn is_deallocation(&self) -> bool {
296        matches!(self.event_type, MemoryEventType::Deallocate)
297    }
298
299    /// Check if this is a move event
300    pub fn is_move(&self) -> bool {
301        matches!(self.event_type, MemoryEventType::Move)
302    }
303
304    /// Check if this is a borrow event
305    pub fn is_borrow(&self) -> bool {
306        matches!(self.event_type, MemoryEventType::Borrow)
307    }
308
309    /// Check if this is a return event
310    pub fn is_return(&self) -> bool {
311        matches!(self.event_type, MemoryEventType::Return)
312    }
313}