1use crate::snapshot::MemorySnapshot;
4use serde::{Deserialize, Serialize};
5use std::collections::HashSet;
6
7#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9pub struct ViewStats {
10 pub allocation_count: usize,
12 pub event_count: usize,
14 pub total_bytes: usize,
16 pub peak_bytes: usize,
18 pub thread_count: usize,
20 pub type_count: usize,
22 pub deallocation_count: usize,
24 pub reallocation_count: usize,
26}
27
28impl ViewStats {
29 pub fn from_snapshot(snapshot: &MemorySnapshot) -> Self {
31 let types: HashSet<&str> = snapshot
32 .active_allocations
33 .values()
34 .filter_map(|a| a.type_name.as_deref())
35 .collect();
36
37 Self {
38 allocation_count: snapshot.stats.active_allocations,
39 event_count: 0, total_bytes: snapshot.stats.current_memory,
41 peak_bytes: snapshot.stats.peak_memory,
42 thread_count: snapshot.thread_stats.len(),
43 type_count: types.len(),
44 deallocation_count: snapshot.stats.total_deallocations,
45 reallocation_count: snapshot.stats.total_reallocations,
46 }
47 }
48
49 pub fn from_view(view: &super::MemoryView) -> Self {
51 let mut stats = Self::from_snapshot(view.snapshot());
52 stats.event_count = view.events().len();
53 stats
54 }
55
56 pub fn is_empty(&self) -> bool {
58 self.allocation_count == 0
59 }
60
61 pub fn avg_allocation_size(&self) -> usize {
63 self.total_bytes
64 .checked_div(self.allocation_count)
65 .unwrap_or(0)
66 }
67
68 pub fn memory_efficiency(&self) -> f64 {
70 if self.peak_bytes == 0 {
71 1.0
72 } else {
73 self.total_bytes as f64 / self.peak_bytes as f64
74 }
75 }
76}
77
78impl std::fmt::Display for ViewStats {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 write!(
81 f,
82 "ViewStats {{ allocations: {}, events: {}, bytes: {}, peak: {}, threads: {}, types: {} }}",
83 self.allocation_count,
84 self.event_count,
85 self.total_bytes,
86 self.peak_bytes,
87 self.thread_count,
88 self.type_count
89 )
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use crate::event_store::MemoryEvent;
97
98 #[test]
99 fn test_empty_stats() {
100 let view = super::super::MemoryView::from_events(vec![]);
101 let stats = ViewStats::from_view(&view);
102 assert!(stats.is_empty());
103 assert_eq!(stats.allocation_count, 0);
104 }
105
106 #[test]
107 fn test_stats_with_allocations() {
108 let events = vec![
109 MemoryEvent::allocate(0x1000, 64, 1),
110 MemoryEvent::allocate(0x2000, 128, 2),
111 ];
112 let view = super::super::MemoryView::from_events(events);
113 let stats = ViewStats::from_view(&view);
114 assert_eq!(stats.allocation_count, 2);
115 assert_eq!(stats.total_bytes, 192);
116 assert_eq!(stats.thread_count, 2);
117 }
118
119 #[test]
120 fn test_view_stats_default() {
121 let stats = ViewStats::default();
122 assert!(stats.is_empty());
123 assert_eq!(stats.allocation_count, 0);
124 assert_eq!(stats.event_count, 0);
125 assert_eq!(stats.total_bytes, 0);
126 assert_eq!(stats.peak_bytes, 0);
127 assert_eq!(stats.thread_count, 0);
128 assert_eq!(stats.type_count, 0);
129 }
130
131 #[test]
132 fn test_view_stats_clone() {
133 let stats = ViewStats {
134 allocation_count: 10,
135 event_count: 20,
136 total_bytes: 1024,
137 peak_bytes: 2048,
138 thread_count: 4,
139 type_count: 5,
140 deallocation_count: 2,
141 reallocation_count: 1,
142 };
143
144 let cloned = stats.clone();
145 assert_eq!(cloned.allocation_count, 10);
146 assert_eq!(cloned.event_count, 20);
147 assert_eq!(cloned.total_bytes, 1024);
148 }
149
150 #[test]
151 fn test_view_stats_debug() {
152 let stats = ViewStats {
153 allocation_count: 5,
154 event_count: 10,
155 total_bytes: 512,
156 peak_bytes: 1024,
157 thread_count: 2,
158 type_count: 3,
159 deallocation_count: 1,
160 reallocation_count: 0,
161 };
162
163 let debug_str = format!("{:?}", stats);
164 assert!(debug_str.contains("ViewStats"));
165 assert!(debug_str.contains("allocation_count"));
166 }
167
168 #[test]
169 fn test_view_stats_display() {
170 let stats = ViewStats {
171 allocation_count: 5,
172 event_count: 10,
173 total_bytes: 512,
174 peak_bytes: 1024,
175 thread_count: 2,
176 type_count: 3,
177 deallocation_count: 1,
178 reallocation_count: 0,
179 };
180
181 let display_str = format!("{}", stats);
182 assert!(display_str.contains("allocations: 5"));
183 assert!(display_str.contains("events: 10"));
184 assert!(display_str.contains("bytes: 512"));
185 }
186
187 #[test]
188 fn test_avg_allocation_size_zero() {
189 let stats = ViewStats::default();
190 assert_eq!(stats.avg_allocation_size(), 0);
191 }
192
193 #[test]
194 fn test_avg_allocation_size_nonzero() {
195 let stats = ViewStats {
196 allocation_count: 4,
197 total_bytes: 100,
198 ..Default::default()
199 };
200 assert_eq!(stats.avg_allocation_size(), 25);
201 }
202
203 #[test]
204 fn test_memory_efficiency_zero_peak() {
205 let stats = ViewStats {
206 peak_bytes: 0,
207 total_bytes: 100,
208 ..Default::default()
209 };
210 assert_eq!(stats.memory_efficiency(), 1.0);
211 }
212
213 #[test]
214 fn test_memory_efficiency_half() {
215 let stats = ViewStats {
216 peak_bytes: 100,
217 total_bytes: 50,
218 ..Default::default()
219 };
220 assert!((stats.memory_efficiency() - 0.5).abs() < 0.001);
221 }
222
223 #[test]
224 fn test_memory_efficiency_full() {
225 let stats = ViewStats {
226 peak_bytes: 100,
227 total_bytes: 100,
228 ..Default::default()
229 };
230 assert!((stats.memory_efficiency() - 1.0).abs() < 0.001);
231 }
232
233 #[test]
234 fn test_view_stats_serialization() {
235 let stats = ViewStats {
236 allocation_count: 10,
237 event_count: 20,
238 total_bytes: 1024,
239 peak_bytes: 2048,
240 thread_count: 4,
241 type_count: 5,
242 deallocation_count: 2,
243 reallocation_count: 1,
244 };
245
246 let json = serde_json::to_string(&stats);
247 assert!(json.is_ok());
248
249 let deserialized: Result<ViewStats, _> = serde_json::from_str(&json.unwrap());
250 assert!(deserialized.is_ok());
251 }
252
253 #[test]
254 fn test_from_snapshot() {
255 let events = vec![
256 MemoryEvent::allocate(0x1000, 64, 1),
257 MemoryEvent::allocate(0x2000, 128, 2),
258 ];
259 let view = super::super::MemoryView::from_events(events);
260 let stats = ViewStats::from_snapshot(view.snapshot());
261
262 assert_eq!(stats.allocation_count, 2);
263 assert_eq!(stats.total_bytes, 192);
264 assert_eq!(stats.event_count, 0); }
266
267 #[test]
268 fn test_from_view_event_count() {
269 let events = vec![
270 MemoryEvent::allocate(0x1000, 64, 1),
271 MemoryEvent::allocate(0x2000, 128, 2),
272 MemoryEvent::deallocate(0x1000, 64, 1),
273 ];
274 let view = super::super::MemoryView::from_events(events);
275 let stats = ViewStats::from_view(&view);
276
277 assert_eq!(stats.event_count, 3);
278 }
279}