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 timeline;
37pub mod tracker;
39
40pub 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
46pub mod analyzer;
48pub mod error;
50pub mod tracking;
52pub mod utils;
54pub mod variable_registry;
56pub mod view;
58
59pub fn init_logging() {
86 use tracing_subscriber::{fmt, EnvFilter};
87
88 static INIT: std::sync::Once = std::sync::Once::new();
90
91 INIT.call_once(|| {
92 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
132pub 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
140pub fn analyzer(tracker: &GlobalTracker) -> MemScopeResult<Analyzer> {
163 let events = tracker.tracker().events();
165
166 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#[cfg(feature = "tracking-allocator")]
191#[global_allocator]
192pub static GLOBAL: TrackingAllocator = TrackingAllocator::new();
193pub trait Trackable {
198 fn track_kind(&self) -> TrackKind;
204 fn get_type_name(&self) -> &'static str;
206 fn get_size_estimate(&self) -> usize;
208 fn get_ref_count(&self) -> Option<usize> {
210 None
211 }
212 fn get_data_ptr(&self) -> Option<usize>;
214 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}