1use crate::core::types::TrackKind;
10
11pub mod analysis;
13pub mod analysis_engine;
15pub mod core;
17
18pub mod capture;
19pub mod event_store;
21pub mod facade;
23pub mod metadata;
25pub mod query;
27pub mod render_engine;
29pub mod snapshot;
31pub mod memory {
33 pub use crate::snapshot::memory::*;
34}
35pub mod task_registry;
37pub mod timeline;
39pub mod tracker;
41
42pub use capture::backends::global_tracking::{
44 global_tracker, init_global_tracking, init_global_tracking_with_config, is_initialized,
45 GlobalTracker, GlobalTrackerConfig, GlobalTrackerStats, TrackerConfig,
46};
47
48pub mod analyzer;
50pub mod error;
52pub mod tracking;
54pub mod utils;
56pub mod variable_registry;
58pub mod view;
60
61pub fn init_logging() -> MemScopeResult<()> {
92 use tracing_subscriber::{fmt, EnvFilter};
93
94 static INIT: std::sync::Once = std::sync::Once::new();
95
96 let mut result = Ok(());
97 INIT.call_once(|| {
98 let filter = match "memscope_rs=info".parse::<tracing::Level>() {
99 Ok(level) => EnvFilter::from_default_env()
100 .add_directive(tracing::Level::INFO.into())
101 .add_directive(level.into()),
102 Err(_) => {
103 result = Err(MemScopeError::config(
104 "logging",
105 "Failed to parse default log level directive",
106 ));
107 return;
108 }
109 };
110
111 fmt()
112 .with_env_filter(filter)
113 .with_target(true)
114 .with_thread_ids(true)
115 .with_file(true)
116 .with_line_number(true)
117 .with_thread_names(true)
118 .init();
119
120 tracing::info!("memscope-rs logging initialized");
121 });
122 result
123}
124
125pub use analysis::*;
126pub use capture::backends::bottleneck_analysis::{BottleneckKind, PerformanceIssue};
127pub use capture::backends::hotspot_analysis::{CallStackHotspot, MemoryUsagePeak};
128pub use capture::backends::{
129 configure_tracking_strategy, get_tracker as get_capture_tracker, AllocationCategory,
130 AnalysisSummary, AsyncAllocation, AsyncBackend, AsyncMemorySnapshot, AsyncSnapshot, AsyncStats,
131 AsyncTracker, CoreBackend, Event, EventType, FrequencyData, FrequencyPattern, InteractionType,
132 LockfreeAnalysis, LockfreeBackend, RuntimeEnvironment, SamplingConfig, SystemMetrics, TaskInfo,
133 TaskMemoryProfile, ThreadInteraction, ThreadLocalTracker, ThreadStats, TrackedFuture,
134 TrackingStrategy, UnifiedBackend,
135};
136pub use capture::backends::{
137 is_tracking, memory_snapshot, quick_trace, stop_tracing, trace_all, trace_thread,
138};
139pub use capture::types::{AllocationInfo, SmartPointerInfo, TrackingError, TrackingResult};
140pub use capture::{CaptureBackend, CaptureBackendType, CaptureEngine};
141pub use core::allocator::TrackingAllocator;
142pub use core::tracker::{get_tracker, MemoryTracker};
143pub use core::{ExportMode, ExportOptions};
144pub use core::{MemScopeError, MemScopeResult};
145
146pub use analyzer::{
148 AnalysisReport, Analyzer, ClassificationAnalysis, ClassificationSummary, CycleReport,
149 DetectionAnalysis, ExportEngine, GraphAnalysis, LeakReport, MetricsAnalysis, MetricsReport,
150 SafetyAnalysis, SafetySummary, TimelineAnalysis, TypeCategory, TypeClassification,
151};
152pub use view::{FilterBuilder, MemoryView, ViewStats};
153
154pub fn analyzer(tracker: &GlobalTracker) -> MemScopeResult<Analyzer> {
177 let events = tracker.tracker().events();
179
180 for event in &events {
182 if event.size > isize::MAX as usize {
183 return Err(MemScopeError::new(
184 crate::core::error::ErrorKind::ValidationError,
185 format!(
186 "Invalid allocation size: {} bytes (exceeds maximum)",
187 event.size
188 ),
189 ));
190 }
191 }
192
193 Ok(Analyzer::from_tracker(tracker))
194}
195#[cfg(feature = "derive")]
196pub use memscope_derive::Trackable;
197pub use snapshot::engine::SnapshotEngine;
198pub use snapshot::memory::{
199 BoundedHistory, BoundedHistoryConfig, BoundedHistoryStats, MemoryConfig, TimestampedEntry,
200};
201pub use snapshot::types::{ActiveAllocation, MemorySnapshot, MemoryStats, ThreadMemoryStats};
202#[cfg(feature = "tracking-allocator")]
205#[global_allocator]
206pub static GLOBAL: TrackingAllocator = TrackingAllocator::new();
207pub trait Trackable {
212 fn track_kind(&self) -> TrackKind;
218 fn get_type_name(&self) -> &'static str;
220 fn get_size_estimate(&self) -> usize;
222 fn get_ref_count(&self) -> Option<usize> {
224 None
225 }
226 fn get_data_ptr(&self) -> Option<usize>;
228 fn get_data_size(&self) -> Option<usize>;
230}
231
232impl<T> Trackable for Vec<T> {
233 fn track_kind(&self) -> TrackKind {
234 TrackKind::HeapOwner {
235 ptr: self.as_ptr() as usize,
236 size: self.capacity() * std::mem::size_of::<T>(),
237 }
238 }
239 fn get_type_name(&self) -> &'static str {
240 "Vec<T>"
241 }
242 fn get_size_estimate(&self) -> usize {
243 std::mem::size_of::<T>() * self.capacity()
244 }
245 fn get_data_ptr(&self) -> Option<usize> {
246 Some(self.as_ptr() as usize)
247 }
248 fn get_data_size(&self) -> Option<usize> {
249 Some(std::mem::size_of::<T>() * self.len())
250 }
251}
252
253impl Trackable for String {
254 fn track_kind(&self) -> TrackKind {
255 TrackKind::HeapOwner {
256 ptr: self.as_ptr() as usize,
257 size: self.capacity(),
258 }
259 }
260 fn get_type_name(&self) -> &'static str {
261 "String"
262 }
263 fn get_size_estimate(&self) -> usize {
264 self.capacity()
265 }
266 fn get_data_ptr(&self) -> Option<usize> {
267 Some(self.as_ptr() as usize)
268 }
269 fn get_data_size(&self) -> Option<usize> {
270 Some(self.len())
271 }
272}
273
274impl<K, V> Trackable for std::collections::HashMap<K, V> {
275 fn track_kind(&self) -> TrackKind {
276 TrackKind::Container
277 }
278 fn get_type_name(&self) -> &'static str {
279 "HashMap<K, V>"
280 }
281 fn get_size_estimate(&self) -> usize {
282 std::mem::size_of::<(K, V)>() * self.capacity()
283 }
284 fn get_data_ptr(&self) -> Option<usize> {
285 None
286 }
287 fn get_data_size(&self) -> Option<usize> {
288 Some(std::mem::size_of::<(K, V)>() * self.len())
289 }
290}
291
292impl<K, V> Trackable for std::collections::BTreeMap<K, V> {
293 fn track_kind(&self) -> TrackKind {
294 TrackKind::Container
295 }
296 fn get_type_name(&self) -> &'static str {
297 "BTreeMap<K, V>"
298 }
299 fn get_size_estimate(&self) -> usize {
300 std::mem::size_of::<(K, V)>() * self.len()
301 }
302 fn get_data_ptr(&self) -> Option<usize> {
303 None
304 }
305 fn get_data_size(&self) -> Option<usize> {
306 Some(std::mem::size_of::<(K, V)>() * self.len())
307 }
308}
309
310impl<T> Trackable for std::collections::VecDeque<T> {
311 fn track_kind(&self) -> TrackKind {
312 TrackKind::Container
313 }
314 fn get_type_name(&self) -> &'static str {
315 "VecDeque<T>"
316 }
317 fn get_size_estimate(&self) -> usize {
318 std::mem::size_of::<T>() * self.capacity()
319 }
320 fn get_data_ptr(&self) -> Option<usize> {
321 None
322 }
323 fn get_data_size(&self) -> Option<usize> {
324 Some(std::mem::size_of::<T>() * self.len())
325 }
326}
327
328impl<T> Trackable for Box<T> {
329 fn track_kind(&self) -> TrackKind {
330 TrackKind::HeapOwner {
331 ptr: &**self as *const T as usize,
332 size: std::mem::size_of_val(&**self),
333 }
334 }
335 fn get_type_name(&self) -> &'static str {
336 "Box<T>"
337 }
338 fn get_size_estimate(&self) -> usize {
339 std::mem::size_of_val(&**self)
340 }
341 fn get_data_ptr(&self) -> Option<usize> {
342 Some(&**self as *const T as usize)
343 }
344 fn get_data_size(&self) -> Option<usize> {
345 Some(std::mem::size_of::<T>())
346 }
347}
348
349impl<T> Trackable for std::rc::Rc<T> {
350 fn track_kind(&self) -> TrackKind {
351 let stack_ptr = self as *const _ as usize;
353 let heap_ptr = &**self as *const T as usize;
354 TrackKind::StackOwner {
355 ptr: stack_ptr,
356 heap_ptr,
357 size: std::mem::size_of::<T>(),
358 }
359 }
360 fn get_type_name(&self) -> &'static str {
361 "Rc<T>"
362 }
363 fn get_size_estimate(&self) -> usize {
364 std::mem::size_of::<T>()
365 }
366 fn get_ref_count(&self) -> Option<usize> {
367 Some(std::rc::Rc::strong_count(self))
368 }
369 fn get_data_ptr(&self) -> Option<usize> {
370 Some(&**self as *const T as usize)
371 }
372 fn get_data_size(&self) -> Option<usize> {
373 Some(std::mem::size_of::<T>())
374 }
375}
376
377impl<T> Trackable for std::sync::Arc<T> {
378 fn track_kind(&self) -> TrackKind {
379 let stack_ptr = self as *const _ as usize;
381 let heap_ptr = &**self as *const T as usize;
382 TrackKind::StackOwner {
383 ptr: stack_ptr,
384 heap_ptr,
385 size: std::mem::size_of::<T>(),
386 }
387 }
388 fn get_type_name(&self) -> &'static str {
389 "Arc<T>"
390 }
391 fn get_size_estimate(&self) -> usize {
392 std::mem::size_of::<T>()
393 }
394 fn get_ref_count(&self) -> Option<usize> {
395 Some(std::sync::Arc::strong_count(self))
396 }
397 fn get_data_ptr(&self) -> Option<usize> {
398 Some(&**self as *const T as usize)
399 }
400 fn get_data_size(&self) -> Option<usize> {
401 Some(std::mem::size_of::<T>())
402 }
403}
404
405impl<T: Trackable> Trackable for std::cell::RefCell<T> {
406 fn track_kind(&self) -> TrackKind {
407 TrackKind::Container
408 }
409 fn get_type_name(&self) -> &'static str {
410 "RefCell<T>"
411 }
412 fn get_size_estimate(&self) -> usize {
413 std::mem::size_of::<T>()
414 }
415 fn get_data_ptr(&self) -> Option<usize> {
416 None
417 }
418 fn get_data_size(&self) -> Option<usize> {
419 Some(std::mem::size_of::<T>())
420 }
421}
422
423impl<T: Trackable> Trackable for std::sync::RwLock<T> {
424 fn track_kind(&self) -> TrackKind {
425 TrackKind::Container
426 }
427 fn get_type_name(&self) -> &'static str {
428 "RwLock<T>"
429 }
430 fn get_size_estimate(&self) -> usize {
431 std::mem::size_of::<T>()
432 }
433 fn get_data_ptr(&self) -> Option<usize> {
434 None
435 }
436 fn get_data_size(&self) -> Option<usize> {
437 Some(std::mem::size_of::<T>())
438 }
439}