1use std::sync::Arc;
7use std::sync::atomic::{AtomicU64, Ordering};
8use std::time::{Duration, Instant};
9
10#[derive(Debug, Default)]
12pub struct MemoryTracker {
13 pub total_allocated: AtomicU64,
15 pub peak_usage: AtomicU64,
17 pub allocation_count: AtomicU64,
19}
20
21impl MemoryTracker {
22 pub fn new() -> Arc<Self> {
24 Arc::new(Self::default())
25 }
26
27 pub fn record_allocation(&self, size: u64) {
29 self.total_allocated.fetch_add(size, Ordering::Relaxed);
30 self.allocation_count.fetch_add(1, Ordering::Relaxed);
31
32 let current = self.total_allocated.load(Ordering::Relaxed);
33 let mut peak = self.peak_usage.load(Ordering::Relaxed);
34 while current > peak {
35 match self.peak_usage.compare_exchange_weak(
36 peak,
37 current,
38 Ordering::Relaxed,
39 Ordering::Relaxed,
40 ) {
41 Ok(_) => break,
42 Err(actual) => peak = actual,
43 }
44 }
45 }
46
47 pub fn record_deallocation(&self, size: u64) {
49 self.total_allocated.fetch_sub(size, Ordering::Relaxed);
50 }
51
52 pub fn get_stats(&self) -> MemoryStats {
54 MemoryStats {
55 current_usage: self.total_allocated.load(Ordering::Relaxed),
56 peak_usage: self.peak_usage.load(Ordering::Relaxed),
57 allocation_count: self.allocation_count.load(Ordering::Relaxed),
58 }
59 }
60
61 pub fn reset(&self) {
63 self.total_allocated.store(0, Ordering::Relaxed);
64 self.peak_usage.store(0, Ordering::Relaxed);
65 self.allocation_count.store(0, Ordering::Relaxed);
66 }
67}
68
69#[derive(Debug, Clone)]
71pub struct MemoryStats {
72 pub current_usage: u64,
74 pub peak_usage: u64,
76 pub allocation_count: u64,
78}
79
80#[derive(Debug)]
82pub struct ThroughputMeter {
83 start_time: Instant,
84 bytes_transferred: Arc<AtomicU64>,
85}
86
87impl Default for ThroughputMeter {
88 fn default() -> Self {
89 Self::new()
90 }
91}
92
93impl ThroughputMeter {
94 pub fn new() -> Self {
96 Self {
97 start_time: Instant::now(),
98 bytes_transferred: Arc::new(AtomicU64::new(0)),
99 }
100 }
101
102 pub fn record_bytes(&self, bytes: u64) {
104 self.bytes_transferred.fetch_add(bytes, Ordering::Relaxed);
105 }
106
107 pub fn current_throughput(&self) -> f64 {
109 let bytes = self.bytes_transferred.load(Ordering::Relaxed);
110 let elapsed = self.start_time.elapsed().as_secs_f64();
111 if elapsed > 0.0 {
112 bytes as f64 / elapsed
113 } else {
114 0.0
115 }
116 }
117
118 pub fn total_bytes(&self) -> u64 {
120 self.bytes_transferred.load(Ordering::Relaxed)
121 }
122
123 pub fn elapsed(&self) -> Duration {
125 self.start_time.elapsed()
126 }
127
128 pub fn reset(&self) {
130 self.bytes_transferred.store(0, Ordering::Relaxed);
131 }
132}
133
134#[derive(Debug)]
136pub struct Timer {
137 start_time: Option<Instant>,
138 total_duration: Arc<AtomicU64>,
139}
140
141impl Default for Timer {
142 fn default() -> Self {
143 Self::new()
144 }
145}
146
147impl Timer {
148 pub fn new() -> Self {
150 Self {
151 start_time: None,
152 total_duration: Arc::new(AtomicU64::new(0)),
153 }
154 }
155
156 pub fn start(&mut self) {
158 self.start_time = Some(Instant::now());
159 }
160
161 pub fn stop(&mut self) -> Duration {
163 if let Some(start) = self.start_time {
164 let elapsed = start.elapsed();
165 self.total_duration
166 .fetch_add(elapsed.as_nanos() as u64, Ordering::Relaxed);
167 self.start_time = None;
168 elapsed
169 } else {
170 Duration::ZERO
171 }
172 }
173
174 pub fn total_duration(&self) -> Duration {
176 Duration::from_nanos(self.total_duration.load(Ordering::Relaxed))
177 }
178
179 pub fn is_running(&self) -> bool {
181 self.start_time.is_some()
182 }
183
184 pub fn reset(&self) {
186 self.total_duration.store(0, Ordering::Relaxed);
187 }
188}
189
190#[derive(Debug)]
192pub struct Profiler {
193 memory_tracker: Arc<MemoryTracker>,
194 throughput_meter: Arc<ThroughputMeter>,
195 timer: Arc<Timer>,
196}
197
198impl Default for Profiler {
199 fn default() -> Self {
200 Self::new()
201 }
202}
203
204impl Profiler {
205 pub fn new() -> Self {
207 Self {
208 memory_tracker: MemoryTracker::new(),
209 throughput_meter: Arc::new(ThroughputMeter::new()),
210 timer: Arc::new(Timer::new()),
211 }
212 }
213
214 pub fn memory_tracker(&self) -> &Arc<MemoryTracker> {
216 &self.memory_tracker
217 }
218
219 pub fn throughput_meter(&self) -> &Arc<ThroughputMeter> {
221 &self.throughput_meter
222 }
223
224 pub fn timer(&self) -> &Arc<Timer> {
226 &self.timer
227 }
228
229 pub fn get_report(&self) -> PerformanceReport {
231 PerformanceReport {
232 memory_stats: self.memory_tracker.get_stats(),
233 throughput_bps: self.throughput_meter.current_throughput(),
234 total_bytes: self.throughput_meter.total_bytes(),
235 elapsed_time: self.throughput_meter.elapsed(),
236 total_duration: self.timer.total_duration(),
237 }
238 }
239
240 pub fn reset(&self) {
242 self.memory_tracker.reset();
243 self.throughput_meter.reset();
244 self.timer.reset();
245 }
246}
247
248#[derive(Debug, Clone)]
250pub struct PerformanceReport {
251 pub memory_stats: MemoryStats,
253 pub throughput_bps: f64,
255 pub total_bytes: u64,
257 pub elapsed_time: Duration,
259 pub total_duration: Duration,
261}
262
263impl PerformanceReport {
264 pub fn throughput_mbps(&self) -> f64 {
266 self.throughput_bps / (1024.0 * 1024.0)
267 }
268
269 pub fn memory_usage_mb(&self) -> f64 {
271 self.memory_stats.current_usage as f64 / (1024.0 * 1024.0)
272 }
273
274 pub fn peak_memory_mb(&self) -> f64 {
276 self.memory_stats.peak_usage as f64 / (1024.0 * 1024.0)
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283 use std::thread;
284 use std::time::Duration;
285
286 #[test]
287 fn test_memory_tracker() {
288 let tracker = MemoryTracker::new();
289
290 tracker.record_allocation(1024);
291 tracker.record_allocation(2048);
292
293 let stats = tracker.get_stats();
294 assert_eq!(stats.current_usage, 3072);
295 assert_eq!(stats.allocation_count, 2);
296 assert_eq!(stats.peak_usage, 3072);
297
298 tracker.record_deallocation(1024);
299 let stats = tracker.get_stats();
300 assert_eq!(stats.current_usage, 2048);
301 assert_eq!(stats.peak_usage, 3072);
302 }
303
304 #[test]
305 fn test_throughput_meter() {
306 let meter = ThroughputMeter::new();
307
308 meter.record_bytes(1024);
309 thread::sleep(Duration::from_millis(10));
310 meter.record_bytes(1024);
311
312 assert_eq!(meter.total_bytes(), 2048);
313 assert!(meter.current_throughput() > 0.0);
314 assert!(meter.elapsed() > Duration::ZERO);
315 }
316
317 #[test]
318 fn test_timer() {
319 let mut timer = Timer::new();
320
321 assert!(!timer.is_running());
322 assert_eq!(timer.total_duration(), Duration::ZERO);
323
324 timer.start();
325 assert!(timer.is_running());
326
327 thread::sleep(Duration::from_millis(10));
328 let elapsed = timer.stop();
329
330 assert!(!timer.is_running());
331 assert!(elapsed > Duration::ZERO);
332 assert_eq!(timer.total_duration(), elapsed);
333 }
334
335 #[test]
336 fn test_profiler() {
337 let profiler = Profiler::new();
338
339 profiler.memory_tracker().record_allocation(1024);
340 profiler.throughput_meter().record_bytes(2048);
341
342 let report = profiler.get_report();
343 assert_eq!(report.memory_stats.current_usage, 1024);
344 assert_eq!(report.total_bytes, 2048);
345 assert!(report.elapsed_time >= Duration::ZERO);
346 }
347
348 #[test]
349 fn test_performance_report_formatting() {
350 let report = PerformanceReport {
351 memory_stats: MemoryStats {
352 current_usage: 1024 * 1024,
353 peak_usage: 2 * 1024 * 1024,
354 allocation_count: 10,
355 },
356 throughput_bps: (10 * 1024 * 1024) as f64,
357 total_bytes: 5 * 1024 * 1024,
358 elapsed_time: Duration::from_secs(1),
359 total_duration: Duration::from_millis(500),
360 };
361
362 assert_eq!(report.throughput_mbps(), 10.0);
363 assert_eq!(report.memory_usage_mb(), 1.0);
364 assert_eq!(report.peak_memory_mb(), 2.0);
365 }
366}