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/// Task Registry - Unified task tracking and relationship management
36pub mod task_registry;
37/// Timeline Engine - Time-based memory analysis
38pub mod timeline;
39/// Unified Tracker API - Simple, unified interface for memory tracking
40pub mod tracker;
41
42// Export simplified global tracking API
43pub 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
48/// Analyzer Module - Unified analysis entry point
49pub mod analyzer;
50/// Unified error handling and recovery system
51pub mod error;
52/// Memory allocation tracking statistics and monitoring
53pub mod tracking;
54/// Utility functions
55pub mod utils;
56/// Variable registry for lightweight HashMap-based variable tracking
57pub mod variable_registry;
58/// View Module - Unified read-only access to memory data
59pub mod view;
60
61/// Initialize logging system for memscope-rs.
62///
63/// This function sets up the tracing subscriber with appropriate filtering
64/// and formatting for memory tracking operations.
65///
66/// # Example
67///
68/// ```ignore
69/// use memscope_rs::init_logging;
70///
71/// init_logging();
72/// // Now logging is configured and ready to use
73/// ```
74///
75/// # Environment Variables
76///
77/// The logging level can be controlled via the `RUST_LOG` environment variable:
78///
79/// - `RUST_LOG=memscope_rs=error` - Only errors
80/// - `RUST_LOG=memscope_rs=warn` - Warnings and errors
81/// - `RUST_LOG=memscope_rs=info` - Info, warnings, and errors (default)
82/// - `RUST_LOG=memscope_rs=debug` - Debug, info, warnings, and errors
83///
84/// # Errors
85///
86/// Returns an error if the log filter directive cannot be parsed.
87///
88/// # Note
89///
90/// This function can be called multiple times safely; subsequent calls will be ignored.
91pub 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
146// Re-export unified analyzer interface
147pub 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
154/// Create analyzer from GlobalTracker (recommended entry point).
155///
156/// Returns an error if the tracker is not initialized or contains invalid data.
157///
158/// # Errors
159///
160/// Returns `MemScopeError` if:
161/// - The tracker has not been initialized
162/// - The tracker contains corrupted event data
163///
164/// # Example
165///
166/// ```ignore
167/// use memscope_rs::{init_global_tracking, global_tracker, analyzer};
168///
169/// init_global_tracking().unwrap();
170/// let tracker = global_tracker().unwrap();
171///
172/// let mut az = analyzer(&tracker).expect("Failed to create analyzer");
173/// let report = az.analyze();
174/// println!("{}", report.summary());
175/// ```
176pub fn analyzer(tracker: &GlobalTracker) -> MemScopeResult<Analyzer> {
177    // Validate tracker has valid data
178    let events = tracker.tracker().events();
179
180    // Basic validation: check for obviously corrupted data
181    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/// Global tracking allocator instance - only enabled with tracking-allocator feature
203/// for single-threaded or low-concurrency applications.
204#[cfg(feature = "tracking-allocator")]
205#[global_allocator]
206pub static GLOBAL: TrackingAllocator = TrackingAllocator::new();
207/// Trait for types that can be tracked by the memory tracker.
208///
209/// This trait defines the interface for tracking memory allocations and their
210/// semantic roles in the three-layer object model (HeapOwner, Container, Value).
211pub trait Trackable {
212    /// Get the memory role classification for this value.
213    ///
214    /// Returns `TrackKind::HeapOwner` for types that own heap memory,
215    /// `TrackKind::Container` for types that organize data internally,
216    /// and `TrackKind::Value` for types without heap allocation.
217    fn track_kind(&self) -> TrackKind;
218    /// Get the type name for this value.
219    fn get_type_name(&self) -> &'static str;
220    /// Get estimated size of the allocation.
221    fn get_size_estimate(&self) -> usize;
222    /// Get reference count for smart pointers (Arc/Rc).
223    fn get_ref_count(&self) -> Option<usize> {
224        None
225    }
226    /// Get data pointer for smart pointers.
227    fn get_data_ptr(&self) -> Option<usize>;
228    /// Get the size of the pointed-to data.
229    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        // Rc is a StackOwner: it's allocated on stack (8 bytes pointer) but points to heap
352        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        // Arc is a StackOwner: it's allocated on stack (8 bytes pointer) but points to heap
380        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}