1pub mod core_tracker;
10pub mod core_types;
11pub mod export_options;
12
13pub mod lockfree_tracker;
15pub mod lockfree_types;
16
17pub mod async_tracker;
19pub mod async_types;
20
21pub mod profile_replay;
23pub mod task_profile;
24
25pub mod efficiency_scoring;
27
28pub mod bottleneck_analysis;
30
31pub mod hotspot_analysis;
33
34pub mod resource_ranking;
36
37pub mod unsafe_tracking;
39
40pub mod unified_tracker;
42
43pub mod global_tracking;
45
46use crate::event_store::{MemoryEvent, MemoryEventType};
47
48pub use core_tracker::{
50 collect_all_trackers_local, configure_tracking_strategy, get_registry_stats_local, get_tracker,
51 MemoryTracker,
52};
53
54pub use export_options::{ExportMode, ExportOptions};
56
57pub use async_tracker::{
59 create_tracked, get_memory_snapshot, initialize, is_tracking_active, shutdown, spawn_tracked,
60 track_current_allocation, track_current_deallocation, AsyncTracker,
61};
62pub use async_types::{
63 AsyncAllocation, AsyncError, AsyncMemorySnapshot, AsyncResult, AsyncSnapshot, AsyncStats,
64 ExtendedTaskInfo, TaskId, TaskInfo, TrackedFuture,
65};
66
67pub use profile_replay::{
69 finalize_metrics, rebuild_async_profiles_from_events, rebuild_with_live_tracker,
70 RebuiltProfiles,
71};
72pub use task_profile::{AggregatedTaskStats, TaskMemoryProfile, TaskProfileManager, TaskType};
73
74pub use efficiency_scoring::{
76 ComponentScores, EfficiencyConfig, EfficiencyScorer, EfficiencyWeights,
77};
78
79pub use bottleneck_analysis::{
81 BottleneckAnalyzer, BottleneckConfig, BottleneckKind, BottleneckMetrics, PerformanceIssue,
82 TaskMetrics,
83};
84
85pub use hotspot_analysis::{
87 AllocationFrequencyPattern, CallStackHotspot, FrequencyAnalysis, HotspotAnalyzer,
88 HotspotConfig, HotspotStatistics, MemoryUsagePeak,
89};
90
91pub use resource_ranking::{
93 EfficiencyScores, RankingConfig, RankingStatistics, ResourceRanking, ResourceRankingAnalyzer,
94 TaskResourceMetrics,
95};
96
97pub use unsafe_tracking::{
99 AllocationInfo, AllocationOrigin, AllocationSource, MemoryPassport, OwnershipInfo,
100 PassportStamp, SafetyViolation, SecurityClearance, UnsafeTracker, UnsafeTrackingConfig,
101 UnsafeTrackingStats, ValidityStatus, ViolationSeverity,
102};
103
104pub use lockfree_tracker::{
106 finalize_thread_tracker, get_current_tracker, init_thread_tracker, is_tracking,
107 memory_snapshot, quick_trace, stop_tracing, trace_all, trace_thread, track_allocation_lockfree,
108 track_deallocation_lockfree, ThreadLocalTracker,
109};
110pub use lockfree_types::{
111 AllocationCategory, AnalysisSummary, Event, EventType, FrequencyData, FrequencyPattern,
112 InteractionType, LockfreeAnalysis, MemorySnapshot, MemoryStats, SamplingConfig, SystemMetrics,
113 ThreadInteraction, ThreadStats,
114};
115
116pub use unified_tracker::{
118 detect_environment, get_backend, initialize as initialize_unified, AsyncRuntimeType,
119 BackendConfig, DetectionConfig, DispatcherConfig, DispatcherMetrics, EnvironmentDetection,
120 EnvironmentDetector, MemoryAnalysisData, MemoryStatistics,
121 MemoryTracker as UnifiedMemoryTracker, RuntimeEnvironment, SessionMetadata, TrackerConfig,
122 TrackerStatistics, TrackerType, TrackingDispatcher, TrackingOperation, TrackingSession,
123 TrackingStrategy, UnifiedBackend,
124};
125
126pub use global_tracking::{
128 global_tracker, init_global_tracking, init_global_tracking_with_config, is_initialized,
129 GlobalTracker, GlobalTrackerConfig, GlobalTrackerStats,
130};
131
132pub trait CaptureBackend: Send + Sync {
137 fn capture_alloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent;
139
140 fn capture_dealloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent;
142
143 fn capture_realloc(
145 &self,
146 ptr: usize,
147 old_size: usize,
148 new_size: usize,
149 thread_id: u64,
150 ) -> MemoryEvent;
151
152 fn capture_move(
154 &self,
155 _from_ptr: usize,
156 to_ptr: usize,
157 size: usize,
158 thread_id: u64,
159 ) -> MemoryEvent;
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq)]
164pub enum CaptureBackendType {
165 Core,
167 Lockfree,
169 Async,
171 Unified,
173}
174
175impl CaptureBackendType {
176 pub fn create_backend(&self) -> Box<dyn CaptureBackend> {
178 match self {
179 CaptureBackendType::Core => Box::new(CoreBackend),
180 CaptureBackendType::Lockfree => Box::new(LockfreeBackend),
181 CaptureBackendType::Async => Box::new(AsyncBackend),
182 CaptureBackendType::Unified => Box::new(UnifiedCaptureBackend::new()),
183 }
184 }
185}
186
187#[derive(Debug)]
191pub struct CoreBackend;
192
193impl CaptureBackend for CoreBackend {
194 fn capture_alloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
195 MemoryEvent::allocate(ptr, size, thread_id)
196 }
197
198 fn capture_dealloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
199 MemoryEvent::deallocate(ptr, size, thread_id)
200 }
201
202 fn capture_realloc(
203 &self,
204 ptr: usize,
205 old_size: usize,
206 new_size: usize,
207 thread_id: u64,
208 ) -> MemoryEvent {
209 MemoryEvent::reallocate(ptr, old_size, new_size, thread_id)
210 }
211
212 fn capture_move(
213 &self,
214 _from_ptr: usize,
215 to_ptr: usize,
216 size: usize,
217 thread_id: u64,
218 ) -> MemoryEvent {
219 MemoryEvent {
220 timestamp: MemoryEvent::now(),
221 event_type: MemoryEventType::Move,
222 ptr: to_ptr,
223 size,
224 old_size: None,
225 new_ptr: None,
226 binding_serial: None,
227 degraded_release: false,
228 charge_outcome: None,
229 thread_id,
230 var_name: None,
231 type_name: None,
232 call_stack_hash: None,
233 thread_name: None,
234 source_file: None,
235 source_line: None,
236 module_path: None,
237 clone_source_ptr: None,
238 clone_target_ptr: None,
239 stack_ptr: None,
240 task_id: None,
241 }
242 }
243}
244
245#[derive(Debug)]
250pub struct LockfreeBackend;
251
252impl CaptureBackend for LockfreeBackend {
253 fn capture_alloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
254 MemoryEvent::allocate(ptr, size, thread_id).with_call_stack_hash(self.hash_call_stack())
255 }
256
257 fn capture_dealloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
258 MemoryEvent::deallocate(ptr, size, thread_id).with_call_stack_hash(self.hash_call_stack())
259 }
260
261 fn capture_realloc(
262 &self,
263 ptr: usize,
264 old_size: usize,
265 new_size: usize,
266 thread_id: u64,
267 ) -> MemoryEvent {
268 MemoryEvent::reallocate(ptr, old_size, new_size, thread_id)
269 .with_call_stack_hash(self.hash_call_stack())
270 }
271
272 fn capture_move(
273 &self,
274 _from_ptr: usize,
275 to_ptr: usize,
276 size: usize,
277 thread_id: u64,
278 ) -> MemoryEvent {
279 MemoryEvent {
280 timestamp: MemoryEvent::now(),
281 event_type: MemoryEventType::Move,
282 ptr: to_ptr,
283 size,
284 old_size: None,
285 new_ptr: None,
286 binding_serial: None,
287 degraded_release: false,
288 charge_outcome: None,
289 thread_id,
290 var_name: None,
291 type_name: None,
292 call_stack_hash: Some(self.hash_call_stack()),
293 thread_name: None,
294 source_file: None,
295 source_line: None,
296 module_path: None,
297 clone_source_ptr: None,
298 clone_target_ptr: None,
299 stack_ptr: None,
300 task_id: None,
301 }
302 }
303}
304
305impl LockfreeBackend {
306 #[inline]
312 fn hash_call_stack(&self) -> u64 {
313 use std::collections::hash_map::DefaultHasher;
314 use std::hash::{Hash, Hasher};
315
316 let mut hasher = DefaultHasher::new();
317
318 std::thread::current().id().hash(&mut hasher);
320
321 static COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
324 let count = COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
325 count.hash(&mut hasher);
326
327 hasher.finish()
328 }
329}
330
331#[derive(Debug)]
335pub struct AsyncBackend;
336
337impl CaptureBackend for AsyncBackend {
338 fn capture_alloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
339 MemoryEvent::allocate(ptr, size, thread_id)
340 }
341
342 fn capture_dealloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
343 MemoryEvent::deallocate(ptr, size, thread_id)
344 }
345
346 fn capture_realloc(
347 &self,
348 ptr: usize,
349 old_size: usize,
350 new_size: usize,
351 thread_id: u64,
352 ) -> MemoryEvent {
353 MemoryEvent::reallocate(ptr, old_size, new_size, thread_id)
354 }
355
356 fn capture_move(
357 &self,
358 _from_ptr: usize,
359 to_ptr: usize,
360 size: usize,
361 thread_id: u64,
362 ) -> MemoryEvent {
363 MemoryEvent {
364 timestamp: MemoryEvent::now(),
365 event_type: MemoryEventType::Move,
366 ptr: to_ptr,
367 size,
368 old_size: None,
369 new_ptr: None,
370 binding_serial: None,
371 degraded_release: false,
372 charge_outcome: None,
373 thread_id,
374 var_name: None,
375 type_name: None,
376 call_stack_hash: None,
377 thread_name: None,
378 source_file: None,
379 source_line: None,
380 module_path: None,
381 clone_source_ptr: None,
382 clone_target_ptr: None,
383 stack_ptr: None,
384 task_id: None,
385 }
386 }
387}
388
389pub struct UnifiedCaptureBackend {
394 inner: Box<dyn CaptureBackend>,
396 backend_type: CaptureBackendType,
398}
399
400impl UnifiedCaptureBackend {
401 fn detect_best_backend() -> (Box<dyn CaptureBackend>, CaptureBackendType) {
411 let thread_count = std::thread::available_parallelism()
412 .map(|p| p.get())
413 .unwrap_or(1);
414
415 if thread_count <= 1 {
416 (Box::new(CoreBackend), CaptureBackendType::Core)
417 } else {
418 (Box::new(LockfreeBackend), CaptureBackendType::Lockfree)
419 }
420 }
421
422 pub fn new() -> Self {
424 let (inner, backend_type) = Self::detect_best_backend();
425 Self {
426 inner,
427 backend_type,
428 }
429 }
430
431 pub fn backend_type(&self) -> CaptureBackendType {
433 self.backend_type
434 }
435
436 pub fn refresh_backend(&mut self) {
445 let (new_inner, new_type) = Self::detect_best_backend();
446 self.inner = new_inner;
447 self.backend_type = new_type;
448 }
449}
450
451impl Default for UnifiedCaptureBackend {
452 fn default() -> Self {
453 Self::new()
454 }
455}
456
457impl CaptureBackend for UnifiedCaptureBackend {
458 fn capture_alloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
459 self.inner.capture_alloc(ptr, size, thread_id)
460 }
461
462 fn capture_dealloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
463 self.inner.capture_dealloc(ptr, size, thread_id)
464 }
465
466 fn capture_realloc(
467 &self,
468 ptr: usize,
469 old_size: usize,
470 new_size: usize,
471 thread_id: u64,
472 ) -> MemoryEvent {
473 self.inner
474 .capture_realloc(ptr, old_size, new_size, thread_id)
475 }
476
477 fn capture_move(
478 &self,
479 from_ptr: usize,
480 to_ptr: usize,
481 size: usize,
482 thread_id: u64,
483 ) -> MemoryEvent {
484 self.inner.capture_move(from_ptr, to_ptr, size, thread_id)
485 }
486}
487
488#[cfg(test)]
489mod tests {
490 use super::*;
491
492 #[test]
493 fn test_core_backend() {
494 let backend = CoreBackend;
495 let event = backend.capture_alloc(0x1000, 1024, 1);
496 assert_eq!(event.ptr, 0x1000);
497 assert_eq!(event.size, 1024);
498 assert_eq!(event.thread_id, 1);
499 assert!(event.is_allocation());
500 }
501
502 #[test]
503 fn test_lockfree_backend() {
504 let backend = LockfreeBackend;
505 let event = backend.capture_alloc(0x1000, 1024, 1);
506 assert_eq!(event.ptr, 0x1000);
507 assert_eq!(event.size, 1024);
508 assert!(event.call_stack_hash.is_some());
509 }
510
511 #[test]
512 fn test_async_backend() {
513 let backend = AsyncBackend;
514 let event = backend.capture_alloc(0x1000, 1024, 1);
515 assert_eq!(event.ptr, 0x1000);
516 assert_eq!(event.size, 1024);
517 }
518
519 #[test]
520 fn test_unified_backend() {
521 let backend = UnifiedCaptureBackend::default();
522 let event = backend.capture_alloc(0x1000, 1024, 1);
523 assert_eq!(event.ptr, 0x1000);
524 assert_eq!(event.size, 1024);
525 }
526
527 #[test]
528 fn test_backend_type_creation() {
529 let core_backend = CaptureBackendType::Core.create_backend();
530 let lockfree_backend = CaptureBackendType::Lockfree.create_backend();
531 let async_backend = CaptureBackendType::Async.create_backend();
532 let unified_backend = CaptureBackendType::Unified.create_backend();
533
534 let event1 = core_backend.capture_alloc(0x1000, 1024, 1);
536 let event2 = lockfree_backend.capture_alloc(0x2000, 2048, 2);
537 let event3 = async_backend.capture_alloc(0x3000, 3072, 3);
538 let event4 = unified_backend.capture_alloc(0x4000, 4096, 4);
539
540 assert_eq!(event1.ptr, 0x1000);
541 assert_eq!(event2.ptr, 0x2000);
542 assert_eq!(event3.ptr, 0x3000);
543 assert_eq!(event4.ptr, 0x4000);
544 }
545}