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 mod mem_ctx;
63
64pub mod auto_export;
66pub mod guard;
68pub mod lifecycle;
70pub mod periodic_flusher;
72
73pub mod prelude {
75 pub use crate::auto_export::{AutoExportConfig, ExportFormatSet, MemScopeConfig, SignalPolicy};
76 pub use crate::guard::{start, start_with, MemScopeGuard};
77 pub use crate::lifecycle::ExportReason;
78 pub use crate::mem_ctx::MemCtx;
79 pub use crate::{track, track_clone, MemScopeResult};
80}
81
82pub use crate::auto_export::{AutoExportConfig, ExportFormatSet, MemScopeConfig, SignalPolicy};
84pub use crate::guard::{start, start_with, MemScopeGuard};
85pub use crate::lifecycle::{export_for_reason, snapshot_json, trigger_export_now, ExportReason};
86
87pub fn init_logging() -> MemScopeResult<()> {
118 use tracing_subscriber::{fmt, EnvFilter};
119
120 static INIT: std::sync::Once = std::sync::Once::new();
121
122 let result = Ok(());
123 INIT.call_once(|| {
124 let filter = EnvFilter::from_default_env()
125 .add_directive(tracing::Level::INFO.into())
126 .add_directive(
127 "memscope_rs=info"
128 .parse()
129 .unwrap_or(tracing::Level::INFO.into()),
130 );
131
132 fmt()
133 .with_env_filter(filter)
134 .with_target(true)
135 .with_thread_ids(true)
136 .with_file(true)
137 .with_line_number(true)
138 .with_thread_names(true)
139 .init();
140
141 tracing::info!("memscope-rs logging initialized");
142 });
143 result
144}
145
146pub use analysis::*;
147pub use capture::backends::bottleneck_analysis::{BottleneckKind, PerformanceIssue};
148pub use capture::backends::hotspot_analysis::{CallStackHotspot, MemoryUsagePeak};
149pub use capture::backends::{
150 configure_tracking_strategy, get_tracker as get_capture_tracker, AllocationCategory,
151 AnalysisSummary, AsyncAllocation, AsyncBackend, AsyncMemorySnapshot, AsyncSnapshot, AsyncStats,
152 AsyncTracker, CoreBackend, Event, EventType, FrequencyData, FrequencyPattern, InteractionType,
153 LockfreeAnalysis, LockfreeBackend, RuntimeEnvironment, SamplingConfig, SystemMetrics, TaskInfo,
154 TaskMemoryProfile, ThreadInteraction, ThreadLocalTracker, ThreadStats, TrackedFuture,
155 TrackingStrategy, UnifiedBackend,
156};
157pub use capture::backends::{
158 is_tracking, memory_snapshot, quick_trace, stop_tracing, trace_all, trace_thread,
159};
160pub use capture::types::{AllocationInfo, SmartPointerInfo, TrackingError, TrackingResult};
161pub use capture::{CaptureBackend, CaptureBackendType, CaptureEngine};
162pub use core::allocator::TrackingAllocator;
163pub use core::tracker::{get_tracker, MemoryTracker};
164pub use core::{ExportMode, ExportOptions};
165pub use core::{MemScopeError, MemScopeResult};
166
167pub use analyzer::{
169 AnalysisReport, Analyzer, ClassificationAnalysis, ClassificationSummary, CycleReport,
170 DetectionAnalysis, ExportEngine, GraphAnalysis, LeakReport, MetricsAnalysis, MetricsReport,
171 SafetyAnalysis, SafetySummary, TimelineAnalysis, TypeCategory, TypeClassification,
172};
173pub use view::{FilterBuilder, MemoryView, ViewStats};
174
175pub fn analyzer(tracker: &GlobalTracker) -> MemScopeResult<Analyzer> {
198 let events = tracker.tracker().events();
200
201 for event in &events {
203 if event.size > isize::MAX as usize {
204 return Err(MemScopeError::new(
205 crate::core::error::ErrorKind::ValidationError,
206 format!(
207 "Invalid allocation size: {} bytes (exceeds maximum)",
208 event.size
209 ),
210 ));
211 }
212 }
213
214 Ok(Analyzer::from_tracker(tracker))
215}
216#[cfg(feature = "derive")]
217pub use memscope_derive::Trackable;
218pub use snapshot::engine::SnapshotEngine;
219pub use snapshot::memory::{
220 BoundedHistory, BoundedHistoryConfig, BoundedHistoryStats, MemoryConfig, TimestampedEntry,
221};
222pub use snapshot::types::{ActiveAllocation, MemorySnapshot, MemoryStats, ThreadMemoryStats};
223#[cfg(feature = "tracking-allocator")]
226#[global_allocator]
227pub static GLOBAL: TrackingAllocator = TrackingAllocator::new();
228pub trait Trackable {
233 fn track_kind(&self) -> TrackKind;
239 fn get_type_name(&self) -> &'static str;
241 fn get_size_estimate(&self) -> usize;
243 fn get_ref_count(&self) -> Option<usize> {
245 None
246 }
247 fn get_data_ptr(&self) -> Option<usize>;
249 fn get_data_size(&self) -> Option<usize>;
251}
252
253impl<T> Trackable for Vec<T> {
254 fn track_kind(&self) -> TrackKind {
255 TrackKind::HeapOwner {
256 ptr: self.as_ptr() as usize,
257 size: self.capacity() * std::mem::size_of::<T>(),
258 }
259 }
260 fn get_type_name(&self) -> &'static str {
261 "Vec<T>"
262 }
263 fn get_size_estimate(&self) -> usize {
264 std::mem::size_of::<T>() * 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(std::mem::size_of::<T>() * self.len())
271 }
272}
273
274impl Trackable for String {
275 fn track_kind(&self) -> TrackKind {
276 TrackKind::HeapOwner {
277 ptr: self.as_ptr() as usize,
278 size: self.capacity(),
279 }
280 }
281 fn get_type_name(&self) -> &'static str {
282 "String"
283 }
284 fn get_size_estimate(&self) -> usize {
285 self.capacity()
286 }
287 fn get_data_ptr(&self) -> Option<usize> {
288 Some(self.as_ptr() as usize)
289 }
290 fn get_data_size(&self) -> Option<usize> {
291 Some(self.len())
292 }
293}
294
295impl<K, V> Trackable for std::collections::HashMap<K, V> {
296 fn track_kind(&self) -> TrackKind {
297 TrackKind::Container
298 }
299 fn get_type_name(&self) -> &'static str {
300 "HashMap<K, V>"
301 }
302 fn get_size_estimate(&self) -> usize {
303 std::mem::size_of::<(K, V)>() * self.capacity()
304 }
305 fn get_data_ptr(&self) -> Option<usize> {
306 None
307 }
308 fn get_data_size(&self) -> Option<usize> {
309 Some(std::mem::size_of::<(K, V)>() * self.len())
310 }
311}
312
313impl<K, V> Trackable for std::collections::BTreeMap<K, V> {
314 fn track_kind(&self) -> TrackKind {
315 TrackKind::Container
316 }
317 fn get_type_name(&self) -> &'static str {
318 "BTreeMap<K, V>"
319 }
320 fn get_size_estimate(&self) -> usize {
321 std::mem::size_of::<(K, V)>() * self.len()
322 }
323 fn get_data_ptr(&self) -> Option<usize> {
324 None
325 }
326 fn get_data_size(&self) -> Option<usize> {
327 Some(std::mem::size_of::<(K, V)>() * self.len())
328 }
329}
330
331impl<T> Trackable for std::collections::VecDeque<T> {
332 fn track_kind(&self) -> TrackKind {
333 TrackKind::Container
334 }
335 fn get_type_name(&self) -> &'static str {
336 "VecDeque<T>"
337 }
338 fn get_size_estimate(&self) -> usize {
339 std::mem::size_of::<T>() * self.capacity()
340 }
341 fn get_data_ptr(&self) -> Option<usize> {
342 None
343 }
344 fn get_data_size(&self) -> Option<usize> {
345 Some(std::mem::size_of::<T>() * self.len())
346 }
347}
348
349impl<T> Trackable for Box<T> {
350 fn track_kind(&self) -> TrackKind {
351 TrackKind::HeapOwner {
352 ptr: &**self as *const T as usize,
353 size: std::mem::size_of_val(&**self),
354 }
355 }
356 fn get_type_name(&self) -> &'static str {
357 "Box<T>"
358 }
359 fn get_size_estimate(&self) -> usize {
360 std::mem::size_of_val(&**self)
361 }
362 fn get_data_ptr(&self) -> Option<usize> {
363 Some(&**self as *const T as usize)
364 }
365 fn get_data_size(&self) -> Option<usize> {
366 Some(std::mem::size_of::<T>())
367 }
368}
369
370impl<T> Trackable for std::rc::Rc<T> {
371 fn track_kind(&self) -> TrackKind {
372 let stack_ptr = self as *const _ as usize;
374 let heap_ptr = &**self as *const T as usize;
375 TrackKind::StackOwner {
376 ptr: stack_ptr,
377 heap_ptr,
378 size: std::mem::size_of::<T>(),
379 }
380 }
381 fn get_type_name(&self) -> &'static str {
382 "Rc<T>"
383 }
384 fn get_size_estimate(&self) -> usize {
385 std::mem::size_of::<T>()
386 }
387 fn get_ref_count(&self) -> Option<usize> {
388 Some(std::rc::Rc::strong_count(self))
389 }
390 fn get_data_ptr(&self) -> Option<usize> {
391 Some(&**self as *const T as usize)
392 }
393 fn get_data_size(&self) -> Option<usize> {
394 Some(std::mem::size_of::<T>())
395 }
396}
397
398impl<T> Trackable for std::sync::Arc<T> {
399 fn track_kind(&self) -> TrackKind {
400 let stack_ptr = self as *const _ as usize;
402 let heap_ptr = &**self as *const T as usize;
403 TrackKind::StackOwner {
404 ptr: stack_ptr,
405 heap_ptr,
406 size: std::mem::size_of::<T>(),
407 }
408 }
409 fn get_type_name(&self) -> &'static str {
410 "Arc<T>"
411 }
412 fn get_size_estimate(&self) -> usize {
413 std::mem::size_of::<T>()
414 }
415 fn get_ref_count(&self) -> Option<usize> {
416 Some(std::sync::Arc::strong_count(self))
417 }
418 fn get_data_ptr(&self) -> Option<usize> {
419 Some(&**self as *const T as usize)
420 }
421 fn get_data_size(&self) -> Option<usize> {
422 Some(std::mem::size_of::<T>())
423 }
424}
425
426impl<T: Trackable> Trackable for std::cell::RefCell<T> {
427 fn track_kind(&self) -> TrackKind {
428 TrackKind::Container
429 }
430 fn get_type_name(&self) -> &'static str {
431 "RefCell<T>"
432 }
433 fn get_size_estimate(&self) -> usize {
434 std::mem::size_of::<T>()
435 }
436 fn get_data_ptr(&self) -> Option<usize> {
437 None
438 }
439 fn get_data_size(&self) -> Option<usize> {
440 Some(std::mem::size_of::<T>())
441 }
442}
443
444impl<T: Trackable> Trackable for std::sync::RwLock<T> {
445 fn track_kind(&self) -> TrackKind {
446 TrackKind::Container
447 }
448 fn get_type_name(&self) -> &'static str {
449 "RwLock<T>"
450 }
451 fn get_size_estimate(&self) -> usize {
452 std::mem::size_of::<T>()
453 }
454 fn get_data_ptr(&self) -> Option<usize> {
455 None
456 }
457 fn get_data_size(&self) -> Option<usize> {
458 Some(std::mem::size_of::<T>())
459 }
460}