pub mod core_tracker;
pub mod core_types;
pub mod export_options;
pub mod lockfree_tracker;
pub mod lockfree_types;
pub mod async_tracker;
pub mod async_types;
pub mod task_profile;
pub mod efficiency_scoring;
pub mod bottleneck_analysis;
pub mod hotspot_analysis;
pub mod resource_ranking;
pub mod unsafe_tracking;
pub mod unified_tracker;
pub mod global_tracking;
use crate::event_store::{MemoryEvent, MemoryEventType};
pub use core_tracker::{
collect_all_trackers_local, configure_tracking_strategy, get_registry_stats_local, get_tracker,
MemoryTracker,
};
pub use export_options::{ExportMode, ExportOptions};
pub use async_tracker::{
create_tracked, get_memory_snapshot, initialize, is_tracking_active, shutdown, spawn_tracked,
track_current_allocation, track_current_deallocation, AsyncTracker,
};
pub use async_types::{
AsyncAllocation, AsyncError, AsyncMemorySnapshot, AsyncResult, AsyncSnapshot, AsyncStats,
ExtendedTaskInfo, TaskId, TaskInfo, TrackedFuture,
};
pub use task_profile::{AggregatedTaskStats, TaskMemoryProfile, TaskProfileManager, TaskType};
pub use efficiency_scoring::{
ComponentScores, EfficiencyConfig, EfficiencyScorer, EfficiencyWeights,
};
pub use bottleneck_analysis::{
BottleneckAnalyzer, BottleneckConfig, BottleneckKind, BottleneckMetrics, PerformanceIssue,
TaskMetrics,
};
pub use hotspot_analysis::{
AllocationFrequencyPattern, CallStackHotspot, FrequencyAnalysis, HotspotAnalyzer,
HotspotConfig, HotspotStatistics, MemoryUsagePeak,
};
pub use resource_ranking::{
EfficiencyScores, RankingConfig, RankingStatistics, ResourceRanking, ResourceRankingAnalyzer,
TaskResourceMetrics,
};
pub use unsafe_tracking::{
AllocationInfo, AllocationOrigin, AllocationSource, MemoryPassport, OwnershipInfo,
PassportStamp, SafetyViolation, SecurityClearance, UnsafeTracker, UnsafeTrackingConfig,
UnsafeTrackingStats, ValidityStatus, ViolationSeverity,
};
pub use lockfree_tracker::{
finalize_thread_tracker, get_current_tracker, init_thread_tracker, is_tracking,
memory_snapshot, quick_trace, stop_tracing, trace_all, trace_thread, track_allocation_lockfree,
track_deallocation_lockfree, ThreadLocalTracker,
};
pub use lockfree_types::{
AllocationCategory, AnalysisSummary, Event, EventType, FrequencyData, FrequencyPattern,
InteractionType, LockfreeAnalysis, MemorySnapshot, MemoryStats, SamplingConfig, SystemMetrics,
ThreadInteraction, ThreadStats,
};
pub use unified_tracker::{
detect_environment, get_backend, initialize as initialize_unified, AsyncRuntimeType,
BackendConfig, DetectionConfig, DispatcherConfig, DispatcherMetrics, EnvironmentDetection,
EnvironmentDetector, MemoryAnalysisData, MemoryStatistics,
MemoryTracker as UnifiedMemoryTracker, RuntimeEnvironment, SessionMetadata, TrackerConfig,
TrackerStatistics, TrackerType, TrackingDispatcher, TrackingOperation, TrackingSession,
TrackingStrategy, UnifiedBackend,
};
pub use global_tracking::{
global_tracker, init_global_tracking, init_global_tracking_with_config, is_initialized,
GlobalTracker, GlobalTrackerConfig, GlobalTrackerStats,
};
pub trait CaptureBackend: Send + Sync {
fn capture_alloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent;
fn capture_dealloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent;
fn capture_realloc(
&self,
ptr: usize,
old_size: usize,
new_size: usize,
thread_id: u64,
) -> MemoryEvent;
fn capture_move(
&self,
_from_ptr: usize,
to_ptr: usize,
size: usize,
thread_id: u64,
) -> MemoryEvent;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CaptureBackendType {
Core,
Lockfree,
Async,
Unified,
}
impl CaptureBackendType {
pub fn create_backend(&self) -> Box<dyn CaptureBackend> {
match self {
CaptureBackendType::Core => Box::new(CoreBackend),
CaptureBackendType::Lockfree => Box::new(LockfreeBackend),
CaptureBackendType::Async => Box::new(AsyncBackend),
CaptureBackendType::Unified => Box::new(UnifiedCaptureBackend::new()),
}
}
}
#[derive(Debug)]
pub struct CoreBackend;
impl CaptureBackend for CoreBackend {
fn capture_alloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
MemoryEvent::allocate(ptr, size, thread_id)
}
fn capture_dealloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
MemoryEvent::deallocate(ptr, size, thread_id)
}
fn capture_realloc(
&self,
ptr: usize,
old_size: usize,
new_size: usize,
thread_id: u64,
) -> MemoryEvent {
MemoryEvent::reallocate(ptr, old_size, new_size, thread_id)
}
fn capture_move(
&self,
_from_ptr: usize,
to_ptr: usize,
size: usize,
thread_id: u64,
) -> MemoryEvent {
MemoryEvent {
timestamp: MemoryEvent::now(),
event_type: MemoryEventType::Move,
ptr: to_ptr,
size,
old_size: None,
thread_id,
var_name: None,
type_name: None,
call_stack_hash: None,
thread_name: None,
source_file: None,
source_line: None,
module_path: None,
clone_source_ptr: None,
clone_target_ptr: None,
stack_ptr: None,
task_id: None,
}
}
}
#[derive(Debug)]
pub struct LockfreeBackend;
impl CaptureBackend for LockfreeBackend {
fn capture_alloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
MemoryEvent::allocate(ptr, size, thread_id).with_call_stack_hash(self.hash_call_stack())
}
fn capture_dealloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
MemoryEvent::deallocate(ptr, size, thread_id).with_call_stack_hash(self.hash_call_stack())
}
fn capture_realloc(
&self,
ptr: usize,
old_size: usize,
new_size: usize,
thread_id: u64,
) -> MemoryEvent {
MemoryEvent::reallocate(ptr, old_size, new_size, thread_id)
.with_call_stack_hash(self.hash_call_stack())
}
fn capture_move(
&self,
_from_ptr: usize,
to_ptr: usize,
size: usize,
thread_id: u64,
) -> MemoryEvent {
MemoryEvent {
timestamp: MemoryEvent::now(),
event_type: MemoryEventType::Move,
ptr: to_ptr,
size,
old_size: None,
thread_id,
var_name: None,
type_name: None,
call_stack_hash: Some(self.hash_call_stack()),
thread_name: None,
source_file: None,
source_line: None,
module_path: None,
clone_source_ptr: None,
clone_target_ptr: None,
stack_ptr: None,
task_id: None,
}
}
}
impl LockfreeBackend {
#[inline]
fn hash_call_stack(&self) -> u64 {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
std::thread::current().id().hash(&mut hasher);
static COUNTER: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
let count = COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
count.hash(&mut hasher);
hasher.finish()
}
}
#[derive(Debug)]
pub struct AsyncBackend;
impl CaptureBackend for AsyncBackend {
fn capture_alloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
MemoryEvent::allocate(ptr, size, thread_id)
}
fn capture_dealloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
MemoryEvent::deallocate(ptr, size, thread_id)
}
fn capture_realloc(
&self,
ptr: usize,
old_size: usize,
new_size: usize,
thread_id: u64,
) -> MemoryEvent {
MemoryEvent::reallocate(ptr, old_size, new_size, thread_id)
}
fn capture_move(
&self,
_from_ptr: usize,
to_ptr: usize,
size: usize,
thread_id: u64,
) -> MemoryEvent {
MemoryEvent {
timestamp: MemoryEvent::now(),
event_type: MemoryEventType::Move,
ptr: to_ptr,
size,
old_size: None,
thread_id,
var_name: None,
type_name: None,
call_stack_hash: None,
thread_name: None,
source_file: None,
source_line: None,
module_path: None,
clone_source_ptr: None,
clone_target_ptr: None,
stack_ptr: None,
task_id: None,
}
}
}
pub struct UnifiedCaptureBackend {
inner: Box<dyn CaptureBackend>,
backend_type: CaptureBackendType,
}
impl UnifiedCaptureBackend {
fn detect_best_backend() -> (Box<dyn CaptureBackend>, CaptureBackendType) {
let thread_count = std::thread::available_parallelism()
.map(|p| p.get())
.unwrap_or(1);
if thread_count <= 1 {
(Box::new(CoreBackend), CaptureBackendType::Core)
} else {
(Box::new(LockfreeBackend), CaptureBackendType::Lockfree)
}
}
pub fn new() -> Self {
let (inner, backend_type) = Self::detect_best_backend();
Self {
inner,
backend_type,
}
}
pub fn backend_type(&self) -> CaptureBackendType {
self.backend_type
}
pub fn refresh_backend(&mut self) {
let (new_inner, new_type) = Self::detect_best_backend();
self.inner = new_inner;
self.backend_type = new_type;
}
}
impl Default for UnifiedCaptureBackend {
fn default() -> Self {
Self::new()
}
}
impl CaptureBackend for UnifiedCaptureBackend {
fn capture_alloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
self.inner.capture_alloc(ptr, size, thread_id)
}
fn capture_dealloc(&self, ptr: usize, size: usize, thread_id: u64) -> MemoryEvent {
self.inner.capture_dealloc(ptr, size, thread_id)
}
fn capture_realloc(
&self,
ptr: usize,
old_size: usize,
new_size: usize,
thread_id: u64,
) -> MemoryEvent {
self.inner
.capture_realloc(ptr, old_size, new_size, thread_id)
}
fn capture_move(
&self,
from_ptr: usize,
to_ptr: usize,
size: usize,
thread_id: u64,
) -> MemoryEvent {
self.inner.capture_move(from_ptr, to_ptr, size, thread_id)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_core_backend() {
let backend = CoreBackend;
let event = backend.capture_alloc(0x1000, 1024, 1);
assert_eq!(event.ptr, 0x1000);
assert_eq!(event.size, 1024);
assert_eq!(event.thread_id, 1);
assert!(event.is_allocation());
}
#[test]
fn test_lockfree_backend() {
let backend = LockfreeBackend;
let event = backend.capture_alloc(0x1000, 1024, 1);
assert_eq!(event.ptr, 0x1000);
assert_eq!(event.size, 1024);
assert!(event.call_stack_hash.is_some());
}
#[test]
fn test_async_backend() {
let backend = AsyncBackend;
let event = backend.capture_alloc(0x1000, 1024, 1);
assert_eq!(event.ptr, 0x1000);
assert_eq!(event.size, 1024);
}
#[test]
fn test_unified_backend() {
let backend = UnifiedCaptureBackend::default();
let event = backend.capture_alloc(0x1000, 1024, 1);
assert_eq!(event.ptr, 0x1000);
assert_eq!(event.size, 1024);
}
#[test]
fn test_backend_type_creation() {
let core_backend = CaptureBackendType::Core.create_backend();
let lockfree_backend = CaptureBackendType::Lockfree.create_backend();
let async_backend = CaptureBackendType::Async.create_backend();
let unified_backend = CaptureBackendType::Unified.create_backend();
let event1 = core_backend.capture_alloc(0x1000, 1024, 1);
let event2 = lockfree_backend.capture_alloc(0x2000, 2048, 2);
let event3 = async_backend.capture_alloc(0x3000, 3072, 3);
let event4 = unified_backend.capture_alloc(0x4000, 4096, 4);
assert_eq!(event1.ptr, 0x1000);
assert_eq!(event2.ptr, 0x2000);
assert_eq!(event3.ptr, 0x3000);
assert_eq!(event4.ptr, 0x4000);
}
}