use crate::core::types::TrackKind;
pub mod analysis;
pub mod analysis_engine;
pub mod core;
pub mod capture;
pub mod event_store;
pub mod facade;
pub mod metadata;
pub mod query;
pub mod render_engine;
pub mod snapshot;
pub mod memory {
pub use crate::snapshot::memory::*;
}
pub mod task_registry;
pub mod timeline;
pub mod tracker;
pub use capture::backends::global_tracking::{
global_tracker, init_global_tracking, init_global_tracking_with_config, is_initialized,
GlobalTracker, GlobalTrackerConfig, GlobalTrackerStats, TrackerConfig,
};
pub mod analyzer;
pub mod error;
pub mod tracking;
pub mod utils;
pub mod variable_registry;
pub mod view;
pub fn init_logging() -> MemScopeResult<()> {
use tracing_subscriber::{fmt, EnvFilter};
static INIT: std::sync::Once = std::sync::Once::new();
let mut result = Ok(());
INIT.call_once(|| {
let filter = match "memscope_rs=info".parse::<tracing::Level>() {
Ok(level) => EnvFilter::from_default_env()
.add_directive(tracing::Level::INFO.into())
.add_directive(level.into()),
Err(_) => {
result = Err(MemScopeError::config(
"logging",
"Failed to parse default log level directive",
));
return;
}
};
fmt()
.with_env_filter(filter)
.with_target(true)
.with_thread_ids(true)
.with_file(true)
.with_line_number(true)
.with_thread_names(true)
.init();
tracing::info!("memscope-rs logging initialized");
});
result
}
pub use analysis::*;
pub use capture::backends::bottleneck_analysis::{BottleneckKind, PerformanceIssue};
pub use capture::backends::hotspot_analysis::{CallStackHotspot, MemoryUsagePeak};
pub use capture::backends::{
configure_tracking_strategy, get_tracker as get_capture_tracker, AllocationCategory,
AnalysisSummary, AsyncAllocation, AsyncBackend, AsyncMemorySnapshot, AsyncSnapshot, AsyncStats,
AsyncTracker, CoreBackend, Event, EventType, FrequencyData, FrequencyPattern, InteractionType,
LockfreeAnalysis, LockfreeBackend, RuntimeEnvironment, SamplingConfig, SystemMetrics, TaskInfo,
TaskMemoryProfile, ThreadInteraction, ThreadLocalTracker, ThreadStats, TrackedFuture,
TrackingStrategy, UnifiedBackend,
};
pub use capture::backends::{
is_tracking, memory_snapshot, quick_trace, stop_tracing, trace_all, trace_thread,
};
pub use capture::types::{AllocationInfo, SmartPointerInfo, TrackingError, TrackingResult};
pub use capture::{CaptureBackend, CaptureBackendType, CaptureEngine};
pub use core::allocator::TrackingAllocator;
pub use core::tracker::{get_tracker, MemoryTracker};
pub use core::{ExportMode, ExportOptions};
pub use core::{MemScopeError, MemScopeResult};
pub use analyzer::{
AnalysisReport, Analyzer, ClassificationAnalysis, ClassificationSummary, CycleReport,
DetectionAnalysis, ExportEngine, GraphAnalysis, LeakReport, MetricsAnalysis, MetricsReport,
SafetyAnalysis, SafetySummary, TimelineAnalysis, TypeCategory, TypeClassification,
};
pub use view::{FilterBuilder, MemoryView, ViewStats};
pub fn analyzer(tracker: &GlobalTracker) -> MemScopeResult<Analyzer> {
let events = tracker.tracker().events();
for event in &events {
if event.size > isize::MAX as usize {
return Err(MemScopeError::new(
crate::core::error::ErrorKind::ValidationError,
format!(
"Invalid allocation size: {} bytes (exceeds maximum)",
event.size
),
));
}
}
Ok(Analyzer::from_tracker(tracker))
}
#[cfg(feature = "derive")]
pub use memscope_derive::Trackable;
pub use snapshot::engine::SnapshotEngine;
pub use snapshot::memory::{
BoundedHistory, BoundedHistoryConfig, BoundedHistoryStats, MemoryConfig, TimestampedEntry,
};
pub use snapshot::types::{ActiveAllocation, MemorySnapshot, MemoryStats, ThreadMemoryStats};
#[cfg(feature = "tracking-allocator")]
#[global_allocator]
pub static GLOBAL: TrackingAllocator = TrackingAllocator::new();
pub trait Trackable {
fn track_kind(&self) -> TrackKind;
fn get_type_name(&self) -> &'static str;
fn get_size_estimate(&self) -> usize;
fn get_ref_count(&self) -> Option<usize> {
None
}
fn get_data_ptr(&self) -> Option<usize>;
fn get_data_size(&self) -> Option<usize>;
}
impl<T> Trackable for Vec<T> {
fn track_kind(&self) -> TrackKind {
TrackKind::HeapOwner {
ptr: self.as_ptr() as usize,
size: self.capacity() * std::mem::size_of::<T>(),
}
}
fn get_type_name(&self) -> &'static str {
"Vec<T>"
}
fn get_size_estimate(&self) -> usize {
std::mem::size_of::<T>() * self.capacity()
}
fn get_data_ptr(&self) -> Option<usize> {
Some(self.as_ptr() as usize)
}
fn get_data_size(&self) -> Option<usize> {
Some(std::mem::size_of::<T>() * self.len())
}
}
impl Trackable for String {
fn track_kind(&self) -> TrackKind {
TrackKind::HeapOwner {
ptr: self.as_ptr() as usize,
size: self.capacity(),
}
}
fn get_type_name(&self) -> &'static str {
"String"
}
fn get_size_estimate(&self) -> usize {
self.capacity()
}
fn get_data_ptr(&self) -> Option<usize> {
Some(self.as_ptr() as usize)
}
fn get_data_size(&self) -> Option<usize> {
Some(self.len())
}
}
impl<K, V> Trackable for std::collections::HashMap<K, V> {
fn track_kind(&self) -> TrackKind {
TrackKind::Container
}
fn get_type_name(&self) -> &'static str {
"HashMap<K, V>"
}
fn get_size_estimate(&self) -> usize {
std::mem::size_of::<(K, V)>() * self.capacity()
}
fn get_data_ptr(&self) -> Option<usize> {
None
}
fn get_data_size(&self) -> Option<usize> {
Some(std::mem::size_of::<(K, V)>() * self.len())
}
}
impl<K, V> Trackable for std::collections::BTreeMap<K, V> {
fn track_kind(&self) -> TrackKind {
TrackKind::Container
}
fn get_type_name(&self) -> &'static str {
"BTreeMap<K, V>"
}
fn get_size_estimate(&self) -> usize {
std::mem::size_of::<(K, V)>() * self.len()
}
fn get_data_ptr(&self) -> Option<usize> {
None
}
fn get_data_size(&self) -> Option<usize> {
Some(std::mem::size_of::<(K, V)>() * self.len())
}
}
impl<T> Trackable for std::collections::VecDeque<T> {
fn track_kind(&self) -> TrackKind {
TrackKind::Container
}
fn get_type_name(&self) -> &'static str {
"VecDeque<T>"
}
fn get_size_estimate(&self) -> usize {
std::mem::size_of::<T>() * self.capacity()
}
fn get_data_ptr(&self) -> Option<usize> {
None
}
fn get_data_size(&self) -> Option<usize> {
Some(std::mem::size_of::<T>() * self.len())
}
}
impl<T> Trackable for Box<T> {
fn track_kind(&self) -> TrackKind {
TrackKind::HeapOwner {
ptr: &**self as *const T as usize,
size: std::mem::size_of_val(&**self),
}
}
fn get_type_name(&self) -> &'static str {
"Box<T>"
}
fn get_size_estimate(&self) -> usize {
std::mem::size_of_val(&**self)
}
fn get_data_ptr(&self) -> Option<usize> {
Some(&**self as *const T as usize)
}
fn get_data_size(&self) -> Option<usize> {
Some(std::mem::size_of::<T>())
}
}
impl<T> Trackable for std::rc::Rc<T> {
fn track_kind(&self) -> TrackKind {
let stack_ptr = self as *const _ as usize;
let heap_ptr = &**self as *const T as usize;
TrackKind::StackOwner {
ptr: stack_ptr,
heap_ptr,
size: std::mem::size_of::<T>(),
}
}
fn get_type_name(&self) -> &'static str {
"Rc<T>"
}
fn get_size_estimate(&self) -> usize {
std::mem::size_of::<T>()
}
fn get_ref_count(&self) -> Option<usize> {
Some(std::rc::Rc::strong_count(self))
}
fn get_data_ptr(&self) -> Option<usize> {
Some(&**self as *const T as usize)
}
fn get_data_size(&self) -> Option<usize> {
Some(std::mem::size_of::<T>())
}
}
impl<T> Trackable for std::sync::Arc<T> {
fn track_kind(&self) -> TrackKind {
let stack_ptr = self as *const _ as usize;
let heap_ptr = &**self as *const T as usize;
TrackKind::StackOwner {
ptr: stack_ptr,
heap_ptr,
size: std::mem::size_of::<T>(),
}
}
fn get_type_name(&self) -> &'static str {
"Arc<T>"
}
fn get_size_estimate(&self) -> usize {
std::mem::size_of::<T>()
}
fn get_ref_count(&self) -> Option<usize> {
Some(std::sync::Arc::strong_count(self))
}
fn get_data_ptr(&self) -> Option<usize> {
Some(&**self as *const T as usize)
}
fn get_data_size(&self) -> Option<usize> {
Some(std::mem::size_of::<T>())
}
}
impl<T: Trackable> Trackable for std::cell::RefCell<T> {
fn track_kind(&self) -> TrackKind {
TrackKind::Container
}
fn get_type_name(&self) -> &'static str {
"RefCell<T>"
}
fn get_size_estimate(&self) -> usize {
std::mem::size_of::<T>()
}
fn get_data_ptr(&self) -> Option<usize> {
None
}
fn get_data_size(&self) -> Option<usize> {
Some(std::mem::size_of::<T>())
}
}
impl<T: Trackable> Trackable for std::sync::RwLock<T> {
fn track_kind(&self) -> TrackKind {
TrackKind::Container
}
fn get_type_name(&self) -> &'static str {
"RwLock<T>"
}
fn get_size_estimate(&self) -> usize {
std::mem::size_of::<T>()
}
fn get_data_ptr(&self) -> Option<usize> {
None
}
fn get_data_size(&self) -> Option<usize> {
Some(std::mem::size_of::<T>())
}
}