qudag_protocol/
instrumentation.rs

1use std::sync::atomic::{AtomicUsize, Ordering};
2use std::time::Instant;
3
4/// Tracks memory usage patterns and churn metrics
5pub struct MemoryTracker {
6    peak_usage: AtomicUsize,
7    allocation_count: AtomicUsize,
8    deallocation_count: AtomicUsize,
9    start_time: Instant,
10}
11
12impl Default for MemoryTracker {
13    fn default() -> Self {
14        Self::new()
15    }
16}
17
18impl MemoryTracker {
19    pub fn new() -> Self {
20        Self {
21            peak_usage: AtomicUsize::new(0),
22            allocation_count: AtomicUsize::new(0),
23            deallocation_count: AtomicUsize::new(0),
24            start_time: Instant::now(),
25        }
26    }
27
28    pub fn track_allocation(&self, _size: usize) {
29        self.allocation_count.fetch_add(1, Ordering::SeqCst);
30        let current = super::allocator::get_memory_usage();
31        let mut peak = self.peak_usage.load(Ordering::SeqCst);
32        while current > peak {
33            match self.peak_usage.compare_exchange(
34                peak,
35                current,
36                Ordering::SeqCst,
37                Ordering::SeqCst,
38            ) {
39                Ok(_) => break,
40                Err(x) => peak = x,
41            }
42        }
43    }
44
45    pub fn track_deallocation(&self, _size: usize) {
46        self.deallocation_count.fetch_add(1, Ordering::SeqCst);
47    }
48
49    pub fn get_metrics(&self) -> MemoryMetrics {
50        MemoryMetrics {
51            current_usage: super::allocator::get_memory_usage(),
52            peak_usage: self.peak_usage.load(Ordering::SeqCst),
53            allocation_count: self.allocation_count.load(Ordering::SeqCst),
54            deallocation_count: self.deallocation_count.load(Ordering::SeqCst),
55            total_allocated: super::allocator::get_total_allocated(),
56            total_deallocated: super::allocator::get_total_deallocated(),
57            uptime_seconds: self.start_time.elapsed().as_secs(),
58        }
59    }
60}
61
62/// Memory usage metrics
63#[derive(Debug, Clone, Copy)]
64pub struct MemoryMetrics {
65    pub current_usage: usize,
66    pub peak_usage: usize,
67    pub allocation_count: usize,
68    pub deallocation_count: usize,
69    pub total_allocated: usize,
70    pub total_deallocated: usize,
71    pub uptime_seconds: u64,
72}
73
74impl MemoryMetrics {
75    pub fn allocation_rate(&self) -> f64 {
76        self.allocation_count as f64 / self.uptime_seconds as f64
77    }
78
79    pub fn deallocation_rate(&self) -> f64 {
80        self.deallocation_count as f64 / self.uptime_seconds as f64
81    }
82
83    pub fn churn_rate(&self) -> f64 {
84        (self.total_allocated + self.total_deallocated) as f64 / self.uptime_seconds as f64
85    }
86}
87
88#[cfg(test)]
89mod tests {
90    use super::*;
91    use std::thread;
92    use std::time::Duration;
93
94    #[test]
95    fn test_memory_tracking() {
96        let tracker = MemoryTracker::new();
97
98        // Track some allocations
99        tracker.track_allocation(1024);
100        tracker.track_allocation(2048);
101
102        // Track some deallocations
103        tracker.track_deallocation(1024);
104
105        // Sleep to get non-zero uptime
106        thread::sleep(Duration::from_secs(1));
107
108        let metrics = tracker.get_metrics();
109
110        assert_eq!(metrics.allocation_count, 2);
111        assert_eq!(metrics.deallocation_count, 1);
112        assert!(metrics.uptime_seconds >= 1);
113        assert!(metrics.allocation_rate() > 0.0);
114        assert!(metrics.deallocation_rate() > 0.0);
115        assert!(metrics.churn_rate() > 0.0);
116    }
117}