1use crate::core::optimized_locks::OptimizedMutex;
4use crate::core::sharded_locks::ShardedRwLock;
5use crate::core::types::*;
6use std::collections::HashMap;
7use std::sync::atomic::{AtomicU64, Ordering};
8use std::sync::{Arc, OnceLock};
9use std::time::{Duration, SystemTime, UNIX_EPOCH};
10
11static GLOBAL_SCOPE_TRACKER: OnceLock<Arc<ScopeTracker>> = OnceLock::new();
13
14pub fn get_global_scope_tracker() -> Arc<ScopeTracker> {
16 GLOBAL_SCOPE_TRACKER
17 .get_or_init(|| Arc::new(ScopeTracker::new()))
18 .clone()
19}
20
21pub type ScopeId = u64;
23
24pub struct ScopeTracker {
26 pub active_scopes: ShardedRwLock<ScopeId, ScopeInfo>,
28 pub completed_scopes: OptimizedMutex<Vec<ScopeInfo>>,
30 pub scope_hierarchy: OptimizedMutex<ScopeHierarchy>,
32 next_scope_id: AtomicU64,
34 pub scope_stack: ShardedRwLock<String, Vec<ScopeId>>,
36}
37
38impl ScopeTracker {
39 pub fn new() -> Self {
41 Self {
42 active_scopes: ShardedRwLock::new(),
43 completed_scopes: OptimizedMutex::new(Vec::new()),
44 scope_hierarchy: OptimizedMutex::new(ScopeHierarchy {
45 root_scopes: Vec::new(),
46 scope_tree: HashMap::new(),
47 max_depth: 0,
48 total_scopes: 0,
49 relationships: HashMap::new(),
50 depth_map: HashMap::new(),
51 }),
52 next_scope_id: AtomicU64::new(1),
53 scope_stack: ShardedRwLock::new(),
54 }
55 }
56
57 pub fn enter_scope(&self, name: String) -> TrackingResult<ScopeId> {
59 let scope_id = self.allocate_scope_id();
60 let thread_id = format!("{:?}", std::thread::current().id());
61 let timestamp = current_timestamp();
62
63 let (parent_scope, depth) = {
65 if let Some(thread_stack) = self.scope_stack.get(&thread_id) {
66 if let Some(&parent_id) = thread_stack.last() {
67 if let Some(parent) = self.active_scopes.get(&parent_id) {
68 (Some(parent.name.clone()), parent.depth + 1)
69 } else {
70 (None, 0)
71 }
72 } else {
73 (None, 0)
74 }
75 } else {
76 (None, 0)
77 }
78 };
79
80 let scope_info = ScopeInfo {
82 name: name.clone(),
83 parent: parent_scope.clone(),
84 children: Vec::new(),
85 depth,
86 variables: Vec::new(),
87 total_memory: 0,
88 peak_memory: 0,
89 allocation_count: 0,
90 lifetime_start: Some(timestamp as u64),
91 lifetime_end: None,
92 is_active: true,
93 start_time: timestamp as u64,
94 end_time: None,
95 memory_usage: 0,
96 child_scopes: Vec::new(),
97 parent_scope: parent_scope.clone(),
98 };
99
100 self.active_scopes.insert(scope_id, scope_info);
102
103 self.scope_stack.with_shard_write(&thread_id, |shard| {
105 shard.entry(thread_id.clone()).or_default().push(scope_id);
106 });
107
108 if let Some(mut hierarchy) = self.scope_hierarchy.try_lock() {
110 hierarchy.depth_map.insert(name.clone(), depth);
111
112 if let Some(parent) = parent_scope.clone() {
113 hierarchy
114 .relationships
115 .entry(parent)
116 .or_default()
117 .push(name.clone());
118 } else {
119 hierarchy.root_scopes.push(name);
120 }
121 }
122
123 Ok(scope_id)
124 }
125
126 pub fn exit_scope(&self, scope_id: ScopeId) -> TrackingResult<()> {
128 let thread_id = format!("{:?}", std::thread::current().id());
129 let timestamp = current_timestamp();
130
131 let mut scope_info = self.active_scopes.remove(&scope_id).ok_or_else(|| {
133 TrackingError::InvalidPointer(format!("Invalid scope ID: {scope_id}"))
134 })?;
135
136 scope_info.end_time = Some(timestamp as u64);
138 scope_info.lifetime_end = Some(timestamp as u64);
139
140 self.scope_stack.with_shard_write(&thread_id, |shard| {
142 if let Some(thread_stack) = shard.get_mut(&thread_id) {
143 if let Some(pos) = thread_stack.iter().position(|&id| id == scope_id) {
144 thread_stack.remove(pos);
145 }
146 }
147 });
148
149 let mut retries = 0;
151 const MAX_RETRIES: u32 = 10;
152 const RETRY_DELAY: Duration = Duration::from_millis(10);
153
154 while retries < MAX_RETRIES {
155 if let Some(mut completed_scopes) = self.completed_scopes.try_lock() {
156 completed_scopes.push(scope_info);
157 break;
158 }
159
160 retries += 1;
162 if retries < MAX_RETRIES {
163 std::thread::sleep(RETRY_DELAY);
164 } else {
165 eprintln!(
168 "Failed to add scope {scope_id} to completed_scopes after {MAX_RETRIES} retries",
169 );
170 }
171 }
172
173 Ok(())
174 }
175
176 pub fn associate_variable(
178 &self,
179 variable_name: String,
180 memory_size: usize,
181 ) -> TrackingResult<()> {
182 let thread_id = format!("{:?}", std::thread::current().id());
183
184 let current_scope_id = self
186 .scope_stack
187 .get(&thread_id)
188 .and_then(|stack| stack.last().copied());
189
190 if let Some(scope_id) = current_scope_id {
191 self.active_scopes.with_shard_write(&scope_id, |shard| {
192 if let Some(scope) = shard.get_mut(&scope_id) {
193 scope.variables.push(variable_name);
194 scope.memory_usage += memory_size;
195 scope.peak_memory = scope.peak_memory.max(scope.memory_usage);
196 scope.allocation_count += 1;
197 }
198 });
199 }
200
201 Ok(())
202 }
203
204 pub fn get_scope_analysis(&self) -> TrackingResult<ScopeAnalysis> {
206 let mut all_scopes = Vec::new();
207
208 for i in 0..16 {
210 self.active_scopes.with_shard_read(&i, |shard| {
212 all_scopes.extend(shard.values().cloned());
213 });
214 }
215
216 if let Some(completed_scopes) = self.completed_scopes.try_lock() {
218 all_scopes.extend(completed_scopes.iter().cloned());
219 }
220
221 let hierarchy = if let Some(hierarchy) = self.scope_hierarchy.try_lock() {
222 hierarchy.clone()
223 } else {
224 ScopeHierarchy {
226 root_scopes: Vec::new(),
227 scope_tree: HashMap::new(),
228 max_depth: 0,
229 total_scopes: 0,
230 relationships: HashMap::new(),
231 depth_map: HashMap::new(),
232 }
233 };
234
235 Ok(ScopeAnalysis {
236 total_scopes: all_scopes.len(),
237 active_scopes: all_scopes.iter().filter(|s| s.is_active).count(),
238 max_depth: hierarchy.max_depth,
239 average_lifetime: 1000.0, memory_efficiency: 0.8, scopes: all_scopes,
242 scope_hierarchy: hierarchy,
243 cross_scope_references: Vec::new(), })
245 }
246
247 pub fn get_scope_lifecycle_metrics(&self) -> TrackingResult<Vec<ScopeLifecycleMetrics>> {
249 let metrics = if let Some(completed_scopes) = self.completed_scopes.try_lock() {
250 completed_scopes
251 .iter()
252 .map(|scope| {
253 let lifetime =
254 scope.end_time.unwrap_or(current_timestamp() as u64) - scope.start_time;
255 let efficiency_score = if scope.peak_memory > 0 {
256 scope.memory_usage as f64 / scope.peak_memory as f64
257 } else {
258 1.0
259 };
260
261 ScopeLifecycleMetrics {
262 scope_name: scope.name.clone(),
263 variable_count: scope.variables.len(),
264 average_lifetime_ms: lifetime as f64,
265 total_memory_usage: scope.memory_usage,
266 peak_memory_usage: scope.peak_memory,
267 allocation_frequency: 1.0, deallocation_efficiency: efficiency_score,
269 completed_allocations: scope.allocation_count,
270 memory_growth_events: 0,
271 peak_concurrent_variables: scope.variables.len(),
272 memory_efficiency_ratio: if scope.peak_memory > 0 {
273 scope.memory_usage as f64 / scope.peak_memory as f64
274 } else {
275 1.0
276 },
277 ownership_transfer_events: 0,
278 fragmentation_score: 0.0,
279 instant_allocations: 0,
280 short_term_allocations: 0,
281 medium_term_allocations: 0,
282 long_term_allocations: 0,
283 suspected_leaks: 0,
284 risk_distribution: crate::core::types::RiskDistribution::default(),
285 scope_metrics: Vec::new(),
286 type_lifecycle_patterns: Vec::new(),
287 }
288 })
289 .collect()
290 } else {
291 Vec::new()
292 };
293
294 Ok(metrics)
295 }
296
297 pub fn get_all_scopes(&self) -> Vec<ScopeInfo> {
299 let mut all_scopes = Vec::new();
300
301 for i in 0..16 {
303 self.active_scopes.with_shard_read(&i, |shard| {
305 all_scopes.extend(shard.values().cloned());
306 });
307 }
308
309 if let Some(completed_scopes) = self.completed_scopes.try_lock() {
311 all_scopes.extend(completed_scopes.iter().cloned());
312 }
313
314 all_scopes
315 }
316
317 fn allocate_scope_id(&self) -> ScopeId {
319 self.next_scope_id.fetch_add(1, Ordering::Relaxed)
320 }
321}
322
323impl Default for ScopeTracker {
324 fn default() -> Self {
325 Self::new()
326 }
327}
328
329pub struct ScopeGuard {
331 scope_id: ScopeId,
332 tracker: Arc<ScopeTracker>,
333}
334
335impl ScopeGuard {
336 pub fn enter(name: &str) -> TrackingResult<Self> {
338 let tracker = get_global_scope_tracker();
339 let scope_id = tracker.enter_scope(name.to_string())?;
340
341 Ok(Self { scope_id, tracker })
342 }
343
344 pub fn scope_id(&self) -> ScopeId {
346 self.scope_id
347 }
348}
349
350impl Drop for ScopeGuard {
351 fn drop(&mut self) {
352 let _ = self.tracker.exit_scope(self.scope_id);
353 }
354}
355fn current_timestamp() -> u128 {
356 SystemTime::now()
357 .duration_since(UNIX_EPOCH)
358 .map(|d| d.as_millis())
359 .unwrap_or(0)
360}
361
362#[macro_export]
364macro_rules! track_scope {
365 ($scope_name:expr) => {
366 let _scope_guard = $crate::scope_tracker::ScopeGuard::enter($scope_name)?;
367 };
368 ($scope_name:expr, $block:block) => {{
369 let _scope_guard = $crate::scope_tracker::ScopeGuard::enter($scope_name)?;
370 $block
371 }};
372}
373
374#[macro_export]
376macro_rules! track_var_with_scope {
377 ($var:ident) => {{
378 let result = $crate::_track_var_impl(&$var, stringify!($var));
380
381 if result.is_ok() {
383 if let Some(size) = $crate::Trackable::get_heap_ptr(&$var) {
384 let scope_tracker = $crate::scope_tracker::get_global_scope_tracker();
385 let _ = scope_tracker
386 .associate_variable(stringify!($var).to_string(), std::mem::size_of_val(&$var));
387 }
388 }
389
390 result
391 }};
392}
393
394#[cfg(test)]
395mod tests {
396 use super::*;
397 use std::{thread, time::Duration};
398
399 #[test]
400 fn test_scope_tracker_creation() {
401 let tracker = ScopeTracker::new();
402 assert_eq!(tracker.next_scope_id.load(Ordering::SeqCst), 1);
403 }
404
405 #[test]
406 fn test_enter_and_exit_scope() {
407 let tracker = ScopeTracker::new();
408 let scope_id = tracker.enter_scope("test_scope".to_string()).unwrap();
409
410 assert!(tracker.active_scopes.get(&scope_id).is_some());
412
413 tracker.exit_scope(scope_id).unwrap();
415
416 assert!(tracker.active_scopes.get(&scope_id).is_none());
418 }
419
420 #[test]
421 fn test_scope_hierarchy() {
422 let tracker = ScopeTracker::new();
423
424 let parent_id = tracker.enter_scope("parent".to_string()).unwrap();
426
427 let thread_id = format!("{:?}", std::thread::current().id());
429
430 assert!(tracker.active_scopes.get(&parent_id).is_some());
432
433 let scope_stack = tracker.scope_stack.get(&thread_id).unwrap();
435 assert_eq!(scope_stack.last(), Some(&parent_id));
436
437 let child_id = tracker.enter_scope("child".to_string()).unwrap();
439
440 assert!(tracker.active_scopes.get(&child_id).is_some());
442
443 let scope_stack = tracker.scope_stack.get(&thread_id).unwrap();
445 assert_eq!(scope_stack.last(), Some(&child_id));
446
447 assert!(scope_stack.contains(&parent_id));
449
450 tracker.exit_scope(child_id).unwrap();
452
453 let scope_stack = tracker.scope_stack.get(&thread_id).unwrap();
455 assert_eq!(scope_stack.last(), Some(&parent_id));
456
457 tracker.exit_scope(parent_id).unwrap();
459
460 let scope_stack = tracker.scope_stack.get(&thread_id);
462 assert!(scope_stack.is_none() || scope_stack.unwrap().is_empty());
463 }
464
465 #[test]
466 fn test_variable_association() {
467 let tracker = ScopeTracker::new();
468 let scope_id = tracker.enter_scope("test_scope".to_string()).unwrap();
469
470 tracker
472 .associate_variable("test_var".to_string(), 1024)
473 .unwrap();
474
475 let scope = tracker.active_scopes.get(&scope_id).unwrap();
477 assert_eq!(scope.variables.len(), 1);
478 assert_eq!(scope.variables[0], "test_var");
479 assert_eq!(scope.memory_usage, 1024);
480
481 tracker.exit_scope(scope_id).unwrap();
482 }
483
484 #[test]
485 fn test_scope_guard() {
486 let tracker = Arc::new(ScopeTracker::new());
488
489 let _ = GLOBAL_SCOPE_TRACKER.set(Arc::clone(&tracker));
491
492 let scope_id;
493 let start_time;
494
495 {
497 let _guard = ScopeGuard::enter("guarded_scope").unwrap();
498 scope_id = _guard.scope_id();
499
500 assert!(tracker.active_scopes.get(&scope_id).is_some());
502
503 let scope = tracker.active_scopes.get(&scope_id).unwrap();
505 assert!(scope.is_active);
506 assert!(scope.end_time.is_none());
507
508 start_time = scope.start_time;
510
511 tracker
513 .associate_variable("guard_var".to_string(), 512)
514 .unwrap();
515
516 let scope = tracker.active_scopes.get(&scope_id).unwrap();
518 assert_eq!(scope.variables.len(), 1);
519 assert_eq!(scope.variables[0], "guard_var");
520 assert!(scope.memory_usage >= 512);
521 } assert!(tracker.active_scopes.get(&scope_id).is_none());
525
526 let completed_scopes = tracker.completed_scopes.lock();
528 assert!(!completed_scopes.is_empty());
529
530 let completed_scope = completed_scopes.last().expect("No completed scopes found");
532
533 assert_eq!(completed_scope.name, "guarded_scope");
535 assert!(completed_scope.end_time.is_some(), "End time should be set");
536
537 assert!(
539 completed_scope.end_time.unwrap() >= start_time,
540 "End time should be after start time"
541 );
542
543 assert!(
544 completed_scope.memory_usage >= 512,
545 "Memory usage should be at least 512 bytes"
546 );
547
548 }
551
552 #[test]
553 fn test_concurrent_scope_operations() {
554 let tracker = Arc::new(ScopeTracker::new());
556 let num_threads = 5;
557
558 let created_scopes = Arc::new(std::sync::Mutex::new(Vec::new()));
560 let completed_scopes_copy = Arc::new(std::sync::Mutex::new(Vec::new()));
561
562 let start_barrier = Arc::new(std::sync::Barrier::new(num_threads));
564
565 let handles = (0..num_threads)
567 .map(|i| {
568 let tracker = Arc::clone(&tracker);
569 let start_barrier = start_barrier.clone();
570 let created_scopes = Arc::clone(&created_scopes);
571 let completed_scopes_copy = Arc::clone(&completed_scopes_copy);
572
573 thread::spawn(move || {
574 start_barrier.wait();
576
577 let scope_name = format!("thread_{i}");
579 let scope_id = tracker.enter_scope(scope_name.clone()).unwrap();
580
581 assert!(tracker.active_scopes.get(&scope_id).is_some());
583
584 created_scopes.lock().unwrap().push(scope_name.clone());
586
587 thread::sleep(Duration::from_millis(10));
589
590 let var_name = format!("var_{i}");
592 tracker.associate_variable(var_name, 256).unwrap();
593
594 let scope = tracker.active_scopes.get(&scope_id).unwrap();
596 assert_eq!(scope.variables.len(), 1);
597
598 tracker.exit_scope(scope_id).unwrap();
600
601 completed_scopes_copy.lock().unwrap().push(scope_name);
603
604 scope_id
606 })
607 })
608 .collect::<Vec<_>>();
609
610 let _: Vec<_> = handles.into_iter().map(|h| h.join().unwrap()).collect();
612
613 let created = created_scopes.lock().unwrap();
615 let completed = completed_scopes_copy.lock().unwrap();
616
617 assert_eq!(created.len(), num_threads);
619 assert_eq!(completed.len(), num_threads);
620
621 let tracker_scopes = tracker.completed_scopes.lock();
623
624 assert!(
628 !tracker_scopes.is_empty(),
629 "No scopes were completed in the tracker"
630 );
631
632 println!(
634 "Completed {} out of {} scopes in the tracker",
635 tracker_scopes.len(),
636 num_threads
637 );
638
639 let mut tracker_scope_names: Vec<String> =
641 tracker_scopes.iter().map(|s| s.name.clone()).collect();
642
643 let mut expected_names = created.clone();
645 expected_names.sort();
646 tracker_scope_names.sort();
647
648 assert_eq!(
650 expected_names, tracker_scope_names,
651 "Expected scopes in tracker: {expected_names:?}, but found: {tracker_scope_names:?}",
652 );
653
654 for scope in tracker_scopes.iter() {
656 assert!(
657 scope.end_time.is_some(),
658 "Scope {} has no end time",
659 scope.name
660 );
661 assert!(
662 scope.end_time.unwrap() >= scope.start_time,
663 "Scope {} has end time before start time",
664 scope.name
665 );
666
667 assert!(
669 completed.contains(&scope.name),
670 "Scope {} not found in completed list",
671 scope.name
672 );
673 }
674 }
675}