1use crate::event_store::MemoryEvent;
6use serde::{Deserialize, Serialize};
7use std::collections::{BTreeMap, HashMap};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
11pub struct TimelineIndex {
12 pub by_ptr: HashMap<usize, Vec<usize>>,
14 pub by_thread: HashMap<u64, Vec<usize>>,
16 pub by_scope: HashMap<String, Vec<usize>>,
18 pub by_task: HashMap<u64, Vec<usize>>,
20 pub by_time: BTreeMap<u64, Vec<usize>>,
22}
23
24impl TimelineIndex {
25 pub fn new() -> Self {
27 Self {
28 by_ptr: HashMap::new(),
29 by_thread: HashMap::new(),
30 by_scope: HashMap::new(),
31 by_task: HashMap::new(),
32 by_time: BTreeMap::new(),
33 }
34 }
35
36 pub fn index_event(&mut self, event_index: usize, event: &MemoryEvent) {
42 self.by_ptr.entry(event.ptr).or_default().push(event_index);
44
45 self.by_thread
47 .entry(event.thread_id)
48 .or_default()
49 .push(event_index);
50
51 self.by_time
53 .entry(event.timestamp)
54 .or_default()
55 .push(event_index);
56
57 if let Some(ref var_name) = event.var_name {
59 self.by_scope
60 .entry(var_name.clone())
61 .or_default()
62 .push(event_index);
63 }
64 }
65
66 pub fn index_events(&mut self, events: &[MemoryEvent]) {
71 for (i, event) in events.iter().enumerate() {
72 self.index_event(i, event);
73 }
74 }
75
76 pub fn get_by_ptr(&self, ptr: usize) -> Option<&Vec<usize>> {
78 self.by_ptr.get(&ptr)
79 }
80
81 pub fn get_by_thread(&self, thread_id: u64) -> Option<&Vec<usize>> {
83 self.by_thread.get(&thread_id)
84 }
85
86 pub fn get_by_scope(&self, scope: &str) -> Option<&Vec<usize>> {
88 self.by_scope.get(scope)
89 }
90
91 pub fn get_by_time_range(&self, start: u64, end: u64) -> Vec<usize> {
93 let mut result = Vec::new();
94 for (_timestamp, indices) in self.by_time.range(start..=end) {
95 result.extend(indices);
96 }
97 result
98 }
99
100 pub fn clear(&mut self) {
102 self.by_ptr.clear();
103 self.by_thread.clear();
104 self.by_scope.clear();
105 self.by_task.clear();
106 self.by_time.clear();
107 }
108}
109
110impl Default for TimelineIndex {
111 fn default() -> Self {
112 Self::new()
113 }
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use crate::event_store::MemoryEventType;
120
121 #[test]
122 fn test_timeline_index_creation() {
123 let index = TimelineIndex::new();
124 assert!(index.by_ptr.is_empty());
125 assert!(index.by_thread.is_empty());
126 }
127
128 #[test]
129 fn test_index_event() {
130 let mut index = TimelineIndex::new();
131 let event = MemoryEvent {
132 timestamp: 1000,
133 event_type: MemoryEventType::Allocate,
134 ptr: 0x1000,
135 size: 1024,
136 old_size: None,
137 thread_id: 1,
138 var_name: Some("test_var".to_string()),
139 type_name: Some("i32".to_string()),
140 call_stack_hash: None,
141 thread_name: None,
142 source_file: None,
143 source_line: None,
144 module_path: None,
145 clone_source_ptr: None,
146 clone_target_ptr: None,
147 stack_ptr: None,
148 task_id: None,
149 };
150
151 index.index_event(0, &event);
152
153 assert!(index.get_by_ptr(0x1000).is_some());
154 assert!(index.get_by_thread(1).is_some());
155 assert!(index.get_by_scope("test_var").is_some());
156 }
157
158 #[test]
159 fn test_index_multiple_events() {
160 let mut index = TimelineIndex::new();
161 let events = vec![
162 MemoryEvent::allocate(0x1000, 1024, 1),
163 MemoryEvent::allocate(0x2000, 2048, 1),
164 MemoryEvent::deallocate(0x1000, 1024, 1),
165 ];
166
167 index.index_events(&events);
168
169 assert_eq!(index.get_by_ptr(0x1000).unwrap().len(), 2);
170 assert_eq!(index.get_by_ptr(0x2000).unwrap().len(), 1);
171 }
172
173 #[test]
174 fn test_get_by_time_range() {
175 let mut index = TimelineIndex::new();
176 let events = vec![
177 MemoryEvent::allocate(0x1000, 1024, 1),
178 MemoryEvent::allocate(0x2000, 2048, 1),
179 MemoryEvent::deallocate(0x1000, 1024, 1),
180 ];
181
182 index.index_events(&events);
183
184 let range_events = index.get_by_time_range(0, u64::MAX);
185 assert_eq!(range_events.len(), 3);
186 }
187
188 #[test]
189 fn test_timeline_index_default() {
190 let index = TimelineIndex::default();
191 assert!(index.by_ptr.is_empty());
192 assert!(index.by_thread.is_empty());
193 assert!(index.by_scope.is_empty());
194 assert!(index.by_task.is_empty());
195 assert!(index.by_time.is_empty());
196 }
197
198 #[test]
199 fn test_timeline_index_clear() {
200 let mut index = TimelineIndex::new();
201 let event = MemoryEvent::allocate(0x1000, 1024, 1);
202 index.index_event(0, &event);
203
204 assert!(!index.by_ptr.is_empty());
205
206 index.clear();
207
208 assert!(index.by_ptr.is_empty());
209 assert!(index.by_thread.is_empty());
210 assert!(index.by_scope.is_empty());
211 assert!(index.by_task.is_empty());
212 assert!(index.by_time.is_empty());
213 }
214
215 #[test]
216 fn test_get_by_ptr_not_found() {
217 let index = TimelineIndex::new();
218 assert!(index.get_by_ptr(0xDEADBEEF).is_none());
219 }
220
221 #[test]
222 fn test_get_by_thread_not_found() {
223 let index = TimelineIndex::new();
224 assert!(index.get_by_thread(999).is_none());
225 }
226
227 #[test]
228 fn test_get_by_scope_not_found() {
229 let index = TimelineIndex::new();
230 assert!(index.get_by_scope("nonexistent").is_none());
231 }
232
233 #[test]
234 fn test_index_event_without_var_name() {
235 let mut index = TimelineIndex::new();
236 let mut event = MemoryEvent::allocate(0x1000, 1024, 1);
237 event.var_name = None;
238
239 index.index_event(0, &event);
240
241 assert!(index.get_by_ptr(0x1000).is_some());
242 assert!(index.by_scope.is_empty());
243 }
244
245 #[test]
246 fn test_get_by_time_range_empty() {
247 let index = TimelineIndex::new();
248 let range_events = index.get_by_time_range(0, 1000);
249 assert!(range_events.is_empty());
250 }
251
252 #[test]
253 fn test_get_by_time_range_partial() {
254 let mut index = TimelineIndex::new();
255 let mut event1 = MemoryEvent::allocate(0x1000, 1024, 1);
256 event1.timestamp = 100;
257 let mut event2 = MemoryEvent::allocate(0x2000, 2048, 1);
258 event2.timestamp = 200;
259 let mut event3 = MemoryEvent::allocate(0x3000, 4096, 1);
260 event3.timestamp = 300;
261
262 index.index_event(0, &event1);
263 index.index_event(1, &event2);
264 index.index_event(2, &event3);
265
266 let range_events = index.get_by_time_range(150, 250);
267 assert_eq!(range_events.len(), 1);
268 }
269
270 #[test]
271 fn test_timeline_index_clone() {
272 let mut index = TimelineIndex::new();
273 let event = MemoryEvent::allocate(0x1000, 1024, 1);
274 index.index_event(0, &event);
275
276 let cloned = index.clone();
277 assert!(cloned.get_by_ptr(0x1000).is_some());
278 }
279
280 #[test]
281 fn test_timeline_index_debug() {
282 let index = TimelineIndex::new();
283 let debug_str = format!("{:?}", index);
284 assert!(debug_str.contains("TimelineIndex"));
285 }
286
287 #[test]
288 fn test_index_multiple_threads() {
289 let mut index = TimelineIndex::new();
290 let event1 = MemoryEvent::allocate(0x1000, 1024, 1);
291 let event2 = MemoryEvent::allocate(0x2000, 2048, 2);
292 let event3 = MemoryEvent::allocate(0x3000, 4096, 1);
293
294 index.index_events(&[event1, event2, event3]);
295
296 assert_eq!(index.get_by_thread(1).unwrap().len(), 2);
297 assert_eq!(index.get_by_thread(2).unwrap().len(), 1);
298 }
299
300 #[test]
301 fn test_index_same_ptr_multiple_times() {
302 let mut index = TimelineIndex::new();
303 let event1 = MemoryEvent::allocate(0x1000, 1024, 1);
304 let event2 = MemoryEvent::deallocate(0x1000, 1024, 1);
305
306 index.index_events(&[event1, event2]);
307
308 let ptr_events = index.get_by_ptr(0x1000).unwrap();
309 assert_eq!(ptr_events.len(), 2);
310 assert_eq!(ptr_events[0], 0);
311 assert_eq!(ptr_events[1], 1);
312 }
313}