scirs2_core/profiling/
memory.rs

1//! Memory allocation tracking functionality for profiling
2
3use crate::profiling::profiler::Profiler;
4
5/// Memory allocation tracker
6pub struct MemoryTracker {
7    /// Name of the operation being tracked
8    name: String,
9    /// Start memory usage
10    start_memory: usize,
11    /// Whether the tracker is currently running
12    running: bool,
13    /// Whether to automatically report when dropped
14    auto_report: bool,
15}
16
17impl MemoryTracker {
18    /// Start a new memory tracker with the given name
19    pub fn start(name: &str) -> Self {
20        let current_memory = Self::current_memory_usage();
21        let tracker = Self {
22            name: name.to_string(),
23            start_memory: current_memory,
24            running: true,
25            auto_report: true,
26        };
27        if let Ok(mut profiler) = Profiler::global().lock() {
28            profiler.register_memory_tracker_start(&tracker);
29        }
30        tracker
31    }
32
33    /// Stop the tracker and record the memory usage
34    pub fn stop(&self) {
35        if !self.running {
36            return;
37        }
38
39        let current_memory = Self::current_memory_usage();
40        let memory_delta = current_memory.saturating_sub(self.start_memory);
41        if let Ok(mut profiler) = Profiler::global().lock() {
42            profiler.register_memory_tracker_stop(&self.name, memory_delta);
43        }
44    }
45
46    /// Track memory usage for a function call and return its result
47    pub fn track_function<F, R>(name: &str, f: F) -> R
48    where
49        F: FnOnce() -> R,
50    {
51        let tracker = Self::start(name);
52        let result = f();
53        tracker.stop();
54        result
55    }
56
57    /// Get the current memory delta without stopping the tracker
58    pub fn memory_delta(&self) -> isize {
59        let current_memory = Self::current_memory_usage();
60        current_memory as isize - self.start_memory as isize
61    }
62
63    /// Disable auto-reporting when dropped
64    pub fn without_auto_report(mut self) -> Self {
65        self.auto_report = false;
66        self
67    }
68
69    /// Get the name of the tracker
70    pub fn name(&self) -> &str {
71        &self.name
72    }
73
74    /// Get the start memory usage
75    pub fn start_memory(&self) -> usize {
76        self.start_memory
77    }
78
79    /// Check if the tracker is running
80    pub fn is_running(&self) -> bool {
81        self.running
82    }
83
84    /// Get the current memory usage (platform-dependent implementation)
85    fn current_memory_usage() -> usize {
86        // This is a simplified implementation that doesn't actually track real memory
87        // A real implementation would use platform-specific APIs to get memory usage
88        #[cfg(target_os = "linux")]
89        {
90            // On Linux, we would read /proc/self/statm
91            0
92        }
93
94        #[cfg(target_os = "macos")]
95        {
96            // On macOS, we would use task_info
97            0
98        }
99
100        #[cfg(target_os = "windows")]
101        {
102            // On Windows, we would use GetProcessMemoryInfo
103            0
104        }
105
106        #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
107        {
108            // Fallback for other platforms
109            0
110        }
111    }
112}
113
114impl Drop for MemoryTracker {
115    fn drop(&mut self) {
116        if self.running && self.auto_report {
117            let current_memory = Self::current_memory_usage();
118            let memory_delta = current_memory.saturating_sub(self.start_memory);
119            if let Ok(mut profiler) = Profiler::global().lock() {
120                profiler.register_memory_tracker_stop(&self.name, memory_delta);
121            }
122        }
123    }
124}
125
126/// Access a memory tracker from the profiling module to avoid name conflicts
127#[allow(dead_code)]
128pub fn profiling_memory_tracker() -> &'static MemoryTracker {
129    // Create a dummy memory tracker for static access
130    static MEMORY_TRACKER: once_cell::sync::Lazy<MemoryTracker> =
131        once_cell::sync::Lazy::new(|| MemoryTracker {
132            name: "global".to_string(),
133            start_memory: 0,
134            running: false,
135            auto_report: false,
136        });
137    &MEMORY_TRACKER
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143
144    #[test]
145    fn test_memory_tracker_basic() {
146        let tracker = MemoryTracker::start("test_memory");
147        tracker.stop();
148        // Memory tracking is a placeholder, so we just test that it doesn't panic
149    }
150}