volta/gpu/
system_monitor.rs1use std::sync::Mutex;
7use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
8use std::time::Instant;
9
10pub struct SystemMonitor {
32 start_time: Instant,
33 peak_memory_mb: AtomicUsize,
34 operation_count: AtomicU64,
35 sync_count: AtomicU64,
36 last_checkpoint_ops: AtomicU64,
37 last_checkpoint_time: Mutex<Instant>,
38}
39
40impl SystemMonitor {
41 #[must_use]
43 pub fn new() -> Self {
44 Self {
45 start_time: Instant::now(),
46 peak_memory_mb: AtomicUsize::new(0),
47 operation_count: AtomicU64::new(0),
48 sync_count: AtomicU64::new(0),
49 last_checkpoint_ops: AtomicU64::new(0),
50 last_checkpoint_time: Mutex::new(Instant::now()),
51 }
52 }
53
54 pub fn checkpoint(&self, label: &str) {
62 let current_memory_mb = crate::gpu::monitor::get_process_memory_mb();
63 let _peak = self
64 .peak_memory_mb
65 .fetch_max(current_memory_mb, Ordering::Relaxed);
66 let ops = self.operation_count.load(Ordering::Relaxed);
67 let syncs = self.sync_count.load(Ordering::Relaxed);
68 let elapsed = self.start_time.elapsed().as_secs_f64();
69 let pending = crate::gpu::gpu_pending_count();
70
71 let last_ops = self.last_checkpoint_ops.swap(ops, Ordering::Relaxed);
73 let ops_delta = ops - last_ops;
74
75 let mut last_time = self.last_checkpoint_time.lock().unwrap();
76 let time_delta = last_time.elapsed().as_secs_f64();
77 *last_time = Instant::now();
78
79 let ops_per_sec = if time_delta > 0.0 {
80 ops_delta as f64 / time_delta
81 } else {
82 0.0
83 };
84
85 println!(
86 "[{label}] Mem: {current_memory_mb}MB, Ops: {ops} (+{ops_delta}, {ops_per_sec:.0}/s), Syncs: {syncs}, Pending: {pending}, Time: {elapsed:.2}s"
87 );
88 }
89
90 pub fn record_operation(&self) {
95 self.operation_count.fetch_add(1, Ordering::Relaxed);
96 }
97
98 pub fn record_sync(&self) {
103 self.sync_count.fetch_add(1, Ordering::Relaxed);
104 }
105
106 pub fn stats(&self) -> MonitorStats {
111 let elapsed = self.start_time.elapsed().as_secs_f64();
112 let ops = self.operation_count.load(Ordering::Relaxed);
113
114 MonitorStats {
115 elapsed_secs: elapsed,
116 peak_memory_mb: self.peak_memory_mb.load(Ordering::Relaxed),
117 operation_count: ops,
118 sync_count: self.sync_count.load(Ordering::Relaxed),
119 ops_per_sec: if elapsed > 0.0 {
120 ops as f64 / elapsed
121 } else {
122 0.0
123 },
124 }
125 }
126
127 pub fn reset(&self) {
132 self.peak_memory_mb.store(0, Ordering::Relaxed);
133 self.operation_count.store(0, Ordering::Relaxed);
134 self.sync_count.store(0, Ordering::Relaxed);
135 self.last_checkpoint_ops.store(0, Ordering::Relaxed);
136 *self.last_checkpoint_time.lock().unwrap() = Instant::now();
137 }
138}
139
140impl Default for SystemMonitor {
141 fn default() -> Self {
142 Self::new()
143 }
144}
145
146#[derive(Debug, Clone)]
148pub struct MonitorStats {
149 pub elapsed_secs: f64,
151 pub peak_memory_mb: usize,
153 pub operation_count: u64,
155 pub sync_count: u64,
157 pub ops_per_sec: f64,
159}
160
161impl std::fmt::Display for MonitorStats {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 write!(
164 f,
165 "MonitorStats {{ elapsed: {:.2}s, peak_mem: {}MB, ops: {}, syncs: {}, throughput: {:.0} ops/s }}",
166 self.elapsed_secs,
167 self.peak_memory_mb,
168 self.operation_count,
169 self.sync_count,
170 self.ops_per_sec
171 )
172 }
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn test_monitor_creation() {
181 let monitor = SystemMonitor::new();
182 let stats = monitor.stats();
183 assert_eq!(stats.operation_count, 0);
184 assert_eq!(stats.sync_count, 0);
185 }
186
187 #[test]
188 fn test_record_operations() {
189 let monitor = SystemMonitor::new();
190
191 monitor.record_operation();
192 monitor.record_operation();
193 monitor.record_operation();
194
195 let stats = monitor.stats();
196 assert_eq!(stats.operation_count, 3);
197 }
198
199 #[test]
200 fn test_record_syncs() {
201 let monitor = SystemMonitor::new();
202
203 monitor.record_sync();
204 monitor.record_sync();
205
206 let stats = monitor.stats();
207 assert_eq!(stats.sync_count, 2);
208 }
209
210 #[test]
211 fn test_reset() {
212 let monitor = SystemMonitor::new();
213
214 monitor.record_operation();
215 monitor.record_sync();
216 monitor.reset();
217
218 let stats = monitor.stats();
219 assert_eq!(stats.operation_count, 0);
220 assert_eq!(stats.sync_count, 0);
221 }
222
223 #[test]
224 fn test_checkpoint_does_not_panic() {
225 let monitor = SystemMonitor::new();
226 monitor.checkpoint("test");
227 }
229
230 #[test]
231 fn test_stats_display() {
232 let monitor = SystemMonitor::new();
233 monitor.record_operation();
234 let stats = monitor.stats();
235 let display = format!("{}", stats);
236 assert!(display.contains("ops: 1"));
237 }
238}