Skip to main content

memscope_rs/
lib.rs

1//! Memory tracking and visualization tools for Rust applications.
2//!
3//! This crate provides tools for tracking memory allocations and visualizing
4//! memory usage in Rust applications. It includes a custom global allocator
5//! that tracks all heap allocations and deallocations, and provides utilities
6//! for exporting memory usage data in various formats.
7
8// Import TrackKind for three-layer object model
9use crate::core::types::TrackKind;
10
11/// Advanced memory analysis functionality
12pub mod analysis;
13/// Analysis Engine - Memory analysis logic
14pub mod analysis_engine;
15/// Core memory tracking functionality
16pub mod core;
17
18pub mod capture;
19/// Event Store Engine - Centralized event storage
20pub mod event_store;
21/// Facade API - Unified user interface
22pub mod facade;
23/// Metadata Engine - Centralized metadata management
24pub mod metadata;
25/// Query Engine - Unified query interface
26pub mod query;
27/// Render Engine - Output rendering
28pub mod render_engine;
29/// Snapshot Engine - Snapshot construction and aggregation
30pub mod snapshot;
31/// Memory management utilities
32pub mod memory {
33    pub use crate::snapshot::memory::*;
34}
35/// Timeline Engine - Time-based memory analysis
36pub mod timeline;
37/// Unified Tracker API - Simple, unified interface for memory tracking
38pub mod tracker;
39
40// Export simplified global tracking API
41pub use capture::backends::global_tracking::{
42    global_tracker, init_global_tracking, init_global_tracking_with_config, is_initialized,
43    GlobalTracker, GlobalTrackerConfig, GlobalTrackerStats, TrackerConfig,
44};
45
46/// Analyzer Module - Unified analysis entry point
47pub mod analyzer;
48/// Unified error handling and recovery system
49pub mod error;
50/// Memory allocation tracking statistics and monitoring
51pub mod tracking;
52/// Utility functions
53pub mod utils;
54/// Variable registry for lightweight HashMap-based variable tracking
55pub mod variable_registry;
56/// View Module - Unified read-only access to memory data
57pub mod view;
58
59/// Initialize logging system for memscope-rs.
60///
61/// This function sets up the tracing subscriber with appropriate filtering
62/// and formatting for memory tracking operations.
63///
64/// # Example
65///
66/// ```ignore
67/// use memscope_rs::init_logging;
68///
69/// init_logging();
70/// // Now logging is configured and ready to use
71/// ```
72///
73/// # Environment Variables
74///
75/// The logging level can be controlled via the `RUST_LOG` environment variable:
76///
77/// - `RUST_LOG=memscope_rs=error` - Only errors
78/// - `RUST_LOG=memscope_rs=warn` - Warnings and errors
79/// - `RUST_LOG=memscope_rs=info` - Info, warnings, and errors (default)
80/// - `RUST_LOG=memscope_rs=debug` - Debug, info, warnings, and errors
81///
82/// # Note
83///
84/// This function can be called multiple times safely; subsequent calls will be ignored.
85pub fn init_logging() {
86    use tracing_subscriber::{fmt, EnvFilter};
87
88    // Only initialize once
89    static INIT: std::sync::Once = std::sync::Once::new();
90
91    INIT.call_once(|| {
92        // Initialize tracing subscriber with environment variable support
93        // Default log level: INFO
94        // Can be overridden with RUST_LOG environment variable
95        let filter =
96            EnvFilter::from_default_env().add_directive("memscope_rs=info".parse().unwrap());
97
98        fmt()
99            .with_env_filter(filter)
100            .with_target(true)
101            .with_thread_ids(true)
102            .with_file(true)
103            .with_line_number(true)
104            .with_thread_names(true)
105            .init();
106
107        tracing::info!("memscope-rs logging initialized");
108    });
109}
110
111pub use analysis::*;
112pub use capture::backends::bottleneck_analysis::{BottleneckKind, PerformanceIssue};
113pub use capture::backends::hotspot_analysis::{CallStackHotspot, MemoryUsagePeak};
114pub use capture::backends::{
115    configure_tracking_strategy, get_tracker as get_capture_tracker, AllocationCategory,
116    AnalysisSummary, AsyncAllocation, AsyncBackend, AsyncMemorySnapshot, AsyncSnapshot, AsyncStats,
117    AsyncTracker, CoreBackend, Event, EventType, FrequencyData, FrequencyPattern, InteractionType,
118    LockfreeAnalysis, LockfreeBackend, RuntimeEnvironment, SamplingConfig, SystemMetrics, TaskInfo,
119    TaskMemoryProfile, ThreadInteraction, ThreadLocalTracker, ThreadStats, TrackedFuture,
120    TrackingStrategy, UnifiedBackend,
121};
122pub use capture::backends::{
123    is_tracking, memory_snapshot, quick_trace, stop_tracing, trace_all, trace_thread,
124};
125pub use capture::types::{AllocationInfo, SmartPointerInfo, TrackingError, TrackingResult};
126pub use capture::{CaptureBackend, CaptureBackendType, CaptureEngine};
127pub use core::allocator::TrackingAllocator;
128pub use core::tracker::{get_tracker, MemoryTracker};
129pub use core::{ExportMode, ExportOptions};
130pub use core::{MemScopeError, MemScopeResult};
131
132// Re-export unified analyzer interface
133pub use analyzer::{
134    AnalysisReport, Analyzer, ClassificationAnalysis, ClassificationSummary, CycleReport,
135    DetectionAnalysis, ExportEngine, GraphAnalysis, LeakReport, MetricsAnalysis, MetricsReport,
136    SafetyAnalysis, SafetySummary, TimelineAnalysis, TypeCategory, TypeClassification,
137};
138pub use view::{FilterBuilder, MemoryView, ViewStats};
139
140/// Create analyzer from GlobalTracker (recommended entry point).
141///
142/// Returns an error if the tracker is not initialized or contains invalid data.
143///
144/// # Errors
145///
146/// Returns `MemScopeError` if:
147/// - The tracker has not been initialized
148/// - The tracker contains corrupted event data
149///
150/// # Example
151///
152/// ```ignore
153/// use memscope_rs::{init_global_tracking, global_tracker, analyzer};
154///
155/// init_global_tracking().unwrap();
156/// let tracker = global_tracker().unwrap();
157///
158/// let mut az = analyzer(&tracker).expect("Failed to create analyzer");
159/// let report = az.analyze();
160/// println!("{}", report.summary());
161/// ```
162pub fn analyzer(tracker: &GlobalTracker) -> MemScopeResult<Analyzer> {
163    // Validate tracker has valid data
164    let events = tracker.tracker().events();
165
166    // Basic validation: check for obviously corrupted data
167    for event in &events {
168        if event.size > isize::MAX as usize {
169            return Err(MemScopeError::new(
170                crate::core::error::ErrorKind::ValidationError,
171                format!(
172                    "Invalid allocation size: {} bytes (exceeds maximum)",
173                    event.size
174                ),
175            ));
176        }
177    }
178
179    Ok(Analyzer::from_tracker(tracker))
180}
181#[cfg(feature = "derive")]
182pub use memscope_derive::Trackable;
183pub use snapshot::engine::SnapshotEngine;
184pub use snapshot::memory::{
185    BoundedHistory, BoundedHistoryConfig, BoundedHistoryStats, MemoryConfig, TimestampedEntry,
186};
187pub use snapshot::types::{ActiveAllocation, MemorySnapshot, MemoryStats, ThreadMemoryStats};
188/// Global tracking allocator instance - only enabled with tracking-allocator feature
189/// for single-threaded or low-concurrency applications.
190#[cfg(feature = "tracking-allocator")]
191#[global_allocator]
192pub static GLOBAL: TrackingAllocator = TrackingAllocator::new();
193/// Trait for types that can be tracked by the memory tracker.
194///
195/// This trait defines the interface for tracking memory allocations and their
196/// semantic roles in the three-layer object model (HeapOwner, Container, Value).
197pub trait Trackable {
198    /// Get the memory role classification for this value.
199    ///
200    /// Returns `TrackKind::HeapOwner` for types that own heap memory,
201    /// `TrackKind::Container` for types that organize data internally,
202    /// and `TrackKind::Value` for types without heap allocation.
203    fn track_kind(&self) -> TrackKind;
204    /// Get the type name for this value.
205    fn get_type_name(&self) -> &'static str;
206    /// Get estimated size of the allocation.
207    fn get_size_estimate(&self) -> usize;
208    /// Get reference count for smart pointers (Arc/Rc).
209    fn get_ref_count(&self) -> Option<usize> {
210        None
211    }
212    /// Get data pointer for smart pointers.
213    fn get_data_ptr(&self) -> Option<usize>;
214    /// Get the size of the pointed-to data.
215    fn get_data_size(&self) -> Option<usize>;
216}
217
218impl<T> Trackable for Vec<T> {
219    fn track_kind(&self) -> TrackKind {
220        TrackKind::HeapOwner {
221            ptr: self.as_ptr() as usize,
222            size: self.capacity() * std::mem::size_of::<T>(),
223        }
224    }
225    fn get_type_name(&self) -> &'static str {
226        "Vec<T>"
227    }
228    fn get_size_estimate(&self) -> usize {
229        std::mem::size_of::<T>() * self.capacity()
230    }
231    fn get_data_ptr(&self) -> Option<usize> {
232        Some(self.as_ptr() as usize)
233    }
234    fn get_data_size(&self) -> Option<usize> {
235        Some(std::mem::size_of::<T>() * self.len())
236    }
237}
238
239impl Trackable for String {
240    fn track_kind(&self) -> TrackKind {
241        TrackKind::HeapOwner {
242            ptr: self.as_ptr() as usize,
243            size: self.capacity(),
244        }
245    }
246    fn get_type_name(&self) -> &'static str {
247        "String"
248    }
249    fn get_size_estimate(&self) -> usize {
250        self.capacity()
251    }
252    fn get_data_ptr(&self) -> Option<usize> {
253        Some(self.as_ptr() as usize)
254    }
255    fn get_data_size(&self) -> Option<usize> {
256        Some(self.len())
257    }
258}
259
260impl<K, V> Trackable for std::collections::HashMap<K, V> {
261    fn track_kind(&self) -> TrackKind {
262        TrackKind::Container
263    }
264    fn get_type_name(&self) -> &'static str {
265        "HashMap<K, V>"
266    }
267    fn get_size_estimate(&self) -> usize {
268        std::mem::size_of::<(K, V)>() * self.capacity()
269    }
270    fn get_data_ptr(&self) -> Option<usize> {
271        None
272    }
273    fn get_data_size(&self) -> Option<usize> {
274        Some(std::mem::size_of::<(K, V)>() * self.len())
275    }
276}
277
278impl<K, V> Trackable for std::collections::BTreeMap<K, V> {
279    fn track_kind(&self) -> TrackKind {
280        TrackKind::Container
281    }
282    fn get_type_name(&self) -> &'static str {
283        "BTreeMap<K, V>"
284    }
285    fn get_size_estimate(&self) -> usize {
286        std::mem::size_of::<(K, V)>() * self.len()
287    }
288    fn get_data_ptr(&self) -> Option<usize> {
289        None
290    }
291    fn get_data_size(&self) -> Option<usize> {
292        Some(std::mem::size_of::<(K, V)>() * self.len())
293    }
294}
295
296impl<T> Trackable for std::collections::VecDeque<T> {
297    fn track_kind(&self) -> TrackKind {
298        TrackKind::Container
299    }
300    fn get_type_name(&self) -> &'static str {
301        "VecDeque<T>"
302    }
303    fn get_size_estimate(&self) -> usize {
304        std::mem::size_of::<T>() * self.capacity()
305    }
306    fn get_data_ptr(&self) -> Option<usize> {
307        None
308    }
309    fn get_data_size(&self) -> Option<usize> {
310        Some(std::mem::size_of::<T>() * self.len())
311    }
312}
313
314impl<T> Trackable for Box<T> {
315    fn track_kind(&self) -> TrackKind {
316        TrackKind::HeapOwner {
317            ptr: &**self as *const T as usize,
318            size: std::mem::size_of_val(&**self),
319        }
320    }
321    fn get_type_name(&self) -> &'static str {
322        "Box<T>"
323    }
324    fn get_size_estimate(&self) -> usize {
325        std::mem::size_of_val(&**self)
326    }
327    fn get_data_ptr(&self) -> Option<usize> {
328        Some(&**self as *const T as usize)
329    }
330    fn get_data_size(&self) -> Option<usize> {
331        Some(std::mem::size_of::<T>())
332    }
333}
334
335impl<T> Trackable for std::rc::Rc<T> {
336    fn track_kind(&self) -> TrackKind {
337        TrackKind::HeapOwner {
338            ptr: &**self as *const T as usize,
339            size: std::mem::size_of::<T>(),
340        }
341    }
342    fn get_type_name(&self) -> &'static str {
343        "Rc<T>"
344    }
345    fn get_size_estimate(&self) -> usize {
346        std::mem::size_of::<T>()
347    }
348    fn get_ref_count(&self) -> Option<usize> {
349        Some(std::rc::Rc::strong_count(self))
350    }
351    fn get_data_ptr(&self) -> Option<usize> {
352        Some(&**self as *const T as usize)
353    }
354    fn get_data_size(&self) -> Option<usize> {
355        Some(std::mem::size_of::<T>())
356    }
357}
358
359impl<T> Trackable for std::sync::Arc<T> {
360    fn track_kind(&self) -> TrackKind {
361        TrackKind::HeapOwner {
362            ptr: &**self as *const T as usize,
363            size: std::mem::size_of::<T>(),
364        }
365    }
366    fn get_type_name(&self) -> &'static str {
367        "Arc<T>"
368    }
369    fn get_size_estimate(&self) -> usize {
370        std::mem::size_of::<T>()
371    }
372    fn get_ref_count(&self) -> Option<usize> {
373        Some(std::sync::Arc::strong_count(self))
374    }
375    fn get_data_ptr(&self) -> Option<usize> {
376        Some(&**self as *const T as usize)
377    }
378    fn get_data_size(&self) -> Option<usize> {
379        Some(std::mem::size_of::<T>())
380    }
381}
382
383impl<T: Trackable> Trackable for std::cell::RefCell<T> {
384    fn track_kind(&self) -> TrackKind {
385        TrackKind::Container
386    }
387    fn get_type_name(&self) -> &'static str {
388        "RefCell<T>"
389    }
390    fn get_size_estimate(&self) -> usize {
391        std::mem::size_of::<T>()
392    }
393    fn get_data_ptr(&self) -> Option<usize> {
394        None
395    }
396    fn get_data_size(&self) -> Option<usize> {
397        Some(std::mem::size_of::<T>())
398    }
399}
400
401impl<T: Trackable> Trackable for std::sync::RwLock<T> {
402    fn track_kind(&self) -> TrackKind {
403        TrackKind::Container
404    }
405    fn get_type_name(&self) -> &'static str {
406        "RwLock<T>"
407    }
408    fn get_size_estimate(&self) -> usize {
409        std::mem::size_of::<T>()
410    }
411    fn get_data_ptr(&self) -> Option<usize> {
412        None
413    }
414    fn get_data_size(&self) -> Option<usize> {
415        Some(std::mem::size_of::<T>())
416    }
417}