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