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