scirs2_core/memory/metrics/
collector.rs1use std::collections::{HashMap, VecDeque};
6use std::sync::{Mutex, RwLock};
7use std::time::{Duration, Instant};
8
9use crate::memory::metrics::event::{MemoryEvent, MemoryEventType};
10use rand::rngs::StdRng;
11use rand::{Rng, SeedableRng};
12#[cfg(feature = "memory_metrics")]
13#[cfg(feature = "serialization")]
14use serde::{Deserialize, Serialize};
15
16struct Random {
18 rng: StdRng,
19}
20
21impl Default for Random {
22 fn default() -> Self {
23 Self {
24 rng: StdRng::seed_from_u64(0), }
26 }
27}
28
29impl Random {
30 fn gen_range(&mut self, range: std::ops::Range<f64>) -> f64 {
31 self.rng.random_range(range)
32 }
33
34 fn random_range(&mut self, range: std::ops::Range<f64>) -> f64 {
35 self.rng.random_range(range)
36 }
37}
38
39#[derive(Debug, Clone)]
41pub struct MemoryMetricsConfig {
42 pub enabled: bool,
44 pub capture_call_stacks: bool,
46 pub max_events: usize,
48 pub real_time_aggregation: bool,
50 pub samplingrate: f64,
52}
53
54impl Default for MemoryMetricsConfig {
55 fn default() -> Self {
56 Self {
57 enabled: true,
58 capture_call_stacks: cfg!(feature = "memory_call_stack"),
59 max_events: 10000,
60 real_time_aggregation: true,
61 samplingrate: 1.0,
62 }
63 }
64}
65
66#[derive(Debug, Clone)]
68pub struct AllocationStats {
69 pub count: usize,
71 pub total_bytes: usize,
73 pub average_size: f64,
75 pub peak_usage: usize,
77}
78
79#[derive(Debug, Clone)]
81#[cfg_attr(feature = "memory_metrics", derive(Serialize, Deserialize))]
82pub struct ComponentMemoryStats {
83 pub current_usage: usize,
85 pub peak_usage: usize,
87 pub allocation_count: usize,
89 pub total_allocated: usize,
91 pub avg_allocation_size: f64,
93}
94
95#[derive(Debug, Clone)]
97#[cfg_attr(
98 feature = "memory_metrics",
99 derive(serde::Serialize, serde::Deserialize)
100)]
101pub struct MemoryReport {
102 pub total_current_usage: usize,
104 pub total_peak_usage: usize,
106 pub total_allocation_count: usize,
108 pub total_allocated_bytes: usize,
110 pub component_stats: HashMap<String, ComponentMemoryStats>,
112 pub duration: Duration,
114}
115
116pub struct MemoryMetricsCollector {
118 config: MemoryMetricsConfig,
120 events: RwLock<VecDeque<MemoryEvent>>,
122 current_usage: RwLock<HashMap<String, usize>>,
124 peak_usage: RwLock<HashMap<String, usize>>,
126 allocation_count: RwLock<HashMap<String, usize>>,
128 total_allocated: RwLock<HashMap<String, usize>>,
130 avg_allocation_size: RwLock<HashMap<String, f64>>,
132 start_time: Instant,
134 rng: Mutex<Random>,
136}
137
138impl MemoryMetricsCollector {
139 pub fn new(config: MemoryMetricsConfig) -> Self {
141 Self {
142 config,
143 events: RwLock::new(VecDeque::with_capacity(1000)),
144 current_usage: RwLock::new(HashMap::new()),
145 peak_usage: RwLock::new(HashMap::new()),
146 allocation_count: RwLock::new(HashMap::new()),
147 total_allocated: RwLock::new(HashMap::new()),
148 avg_allocation_size: RwLock::new(HashMap::new()),
149 start_time: Instant::now(),
150 rng: Mutex::new(Random::default()),
151 }
152 }
153
154 pub fn record_event(&self, event: MemoryEvent) {
156 if !self.config.enabled {
157 return;
158 }
159
160 if self.config.samplingrate < 1.0 {
162 let mut rng = self.rng.lock().expect("Operation failed");
163 if rng.random_range(0.0..1.0) > self.config.samplingrate {
164 return;
165 }
166 }
167
168 if self.config.real_time_aggregation {
170 self.update_metrics(&event);
171 }
172
173 if self.config.max_events > 0 {
175 let mut events = self.events.write().expect("Operation failed");
176 events.push_back(event);
177
178 while events.len() > self.config.max_events {
180 events.pop_front();
181 }
182 }
183 }
184
185 fn update_metrics(&self, event: &MemoryEvent) {
187 match event.event_type {
188 MemoryEventType::Allocation => {
189 let mut current_usage = self.current_usage.write().expect("Operation failed");
191 let component_usage = current_usage.entry(event.component.clone()).or_insert(0);
192 *component_usage += event.size;
193
194 let mut peak_usage = self.peak_usage.write().expect("Operation failed");
196 let peak = peak_usage.entry(event.component.clone()).or_insert(0);
197 *peak = (*peak).max(*component_usage);
198
199 let mut allocation_count = self.allocation_count.write().expect("Operation failed");
201 let count = allocation_count.entry(event.component.clone()).or_insert(0);
202 *count += 1;
203
204 let mut total_allocated = self.total_allocated.write().expect("Operation failed");
206 let total = total_allocated.entry(event.component.clone()).or_insert(0);
207 *total += event.size;
208
209 let mut avg_allocation_size =
211 self.avg_allocation_size.write().expect("Operation failed");
212 let avg = avg_allocation_size
213 .entry(event.component.clone())
214 .or_insert(0.0);
215 *avg = (*avg * (*count as f64 - 1.0) + event.size as f64) / *count as f64;
216 }
217 MemoryEventType::Deallocation => {
218 let mut current_usage = self.current_usage.write().expect("Operation failed");
220 let component_usage = current_usage.entry(event.component.clone()).or_insert(0);
221 *component_usage = component_usage.saturating_sub(event.size);
222 }
223 MemoryEventType::Resize => {
224 if let Some(old_size) = event
226 .metadata
227 .get("old_size")
228 .and_then(|s| s.parse::<usize>().ok())
229 {
230 let size_diff = event.size as isize - old_size as isize;
231
232 let mut current_usage = self.current_usage.write().expect("Operation failed");
233 let component_usage = current_usage.entry(event.component.clone()).or_insert(0);
234
235 if size_diff > 0 {
236 *component_usage += size_diff as usize;
237 } else {
238 *component_usage = component_usage.saturating_sub((-size_diff) as usize);
239 }
240
241 let mut peak_usage = self.peak_usage.write().expect("Operation failed");
243 let peak = peak_usage.entry(event.component.clone()).or_insert(0);
244 *peak = (*peak).max(*component_usage);
245 }
246 }
247 MemoryEventType::Access | MemoryEventType::Transfer => {
248 }
250 }
251 }
252
253 pub fn get_current_usage(&self, component: &str) -> usize {
255 let current_usage = self.current_usage.read().expect("Operation failed");
256 *current_usage.get(component).unwrap_or(&0)
257 }
258
259 pub fn get_peak_usage(&self, component: &str) -> usize {
261 let peak_usage = self.peak_usage.read().expect("Operation failed");
262 *peak_usage.get(component).unwrap_or(&0)
263 }
264
265 pub fn get_total_current_usage(&self) -> usize {
267 let current_usage = self.current_usage.read().expect("Operation failed");
268 current_usage.values().sum()
269 }
270
271 pub fn get_total_peak_usage(&self) -> usize {
273 let peak_usage = self.peak_usage.read().expect("Operation failed");
274
275 let component_sum: usize = peak_usage.values().sum();
277
278 component_sum
281 }
282
283 pub fn get_allocation_stats(&self, component: &str) -> Option<AllocationStats> {
285 let allocation_count = self.allocation_count.read().expect("Operation failed");
286 let count = *allocation_count.get(component)?;
287
288 let total_allocated = self.total_allocated.read().expect("Operation failed");
289 let total = *total_allocated.get(component)?;
290
291 let avg_allocation_size = self.avg_allocation_size.read().expect("Operation failed");
292 let avg = *avg_allocation_size.get(component)?;
293
294 let peak_usage = self.peak_usage.read().expect("Operation failed");
295 let peak = *peak_usage.get(component)?;
296
297 Some(AllocationStats {
298 count,
299 total_bytes: total,
300 average_size: avg,
301 peak_usage: peak,
302 })
303 }
304
305 pub fn generate_report(&self) -> MemoryReport {
307 let current_usage = self.current_usage.read().expect("Operation failed");
308 let peak_usage = self.peak_usage.read().expect("Operation failed");
309 let allocation_count = self.allocation_count.read().expect("Operation failed");
310 let total_allocated = self.total_allocated.read().expect("Operation failed");
311 let avg_allocation_size = self.avg_allocation_size.read().expect("Operation failed");
312
313 let mut component_stats = HashMap::new();
314
315 let mut components = std::collections::HashSet::new();
317 components.extend(current_usage.keys().cloned());
318 components.extend(peak_usage.keys().cloned());
319 components.extend(allocation_count.keys().cloned());
320
321 for component in components {
323 let stats = ComponentMemoryStats {
324 current_usage: *current_usage.get(&component).unwrap_or(&0),
325 peak_usage: *peak_usage.get(&component).unwrap_or(&0),
326 allocation_count: *allocation_count.get(&component).unwrap_or(&0),
327 total_allocated: *total_allocated.get(&component).unwrap_or(&0),
328 avg_allocation_size: *avg_allocation_size.get(&component).unwrap_or(&0.0),
329 };
330
331 component_stats.insert(component, stats);
332 }
333
334 MemoryReport {
335 total_current_usage: current_usage.values().sum(),
336 total_peak_usage: self.get_total_peak_usage(),
337 total_allocation_count: allocation_count.values().sum(),
338 total_allocated_bytes: total_allocated.values().sum(),
339 component_stats,
340 duration: self.start_time.elapsed(),
341 }
342 }
343
344 pub fn reset(&self) {
346 let mut events = self.events.write().expect("Operation failed");
347 events.clear();
348
349 let mut current_usage = self.current_usage.write().expect("Operation failed");
350 current_usage.clear();
351
352 let mut peak_usage = self.peak_usage.write().expect("Operation failed");
353 peak_usage.clear();
354
355 let mut allocation_count = self.allocation_count.write().expect("Operation failed");
356 allocation_count.clear();
357
358 let mut total_allocated = self.total_allocated.write().expect("Operation failed");
359 total_allocated.clear();
360
361 let mut avg_allocation_size = self.avg_allocation_size.write().expect("Operation failed");
362 avg_allocation_size.clear();
363 }
364
365 pub fn get_events(&self) -> Vec<MemoryEvent> {
367 let events = self.events.read().expect("Operation failed");
368 events.iter().cloned().collect()
369 }
370
371 pub fn to_json(&self) -> serde_json::Value {
373 let report = self.generate_report();
375
376 let mut json_obj = serde_json::Map::new();
377
378 json_obj.insert(
379 "total_allocation_count".to_string(),
380 serde_json::Value::Number(report.total_allocation_count.into()),
381 );
382 json_obj.insert(
383 "total_peak_usage".to_string(),
384 serde_json::Value::Number(report.total_peak_usage.into()),
385 );
386 json_obj.insert(
387 "total_current_usage".to_string(),
388 serde_json::Value::Number(report.total_current_usage.into()),
389 );
390 json_obj.insert(
391 "total_allocated_bytes".to_string(),
392 serde_json::Value::Number(report.total_allocated_bytes.into()),
393 );
394
395 let component_stats: serde_json::Value = report
397 .component_stats
398 .iter()
399 .map(|(k, v)| {
400 (
401 k.clone(),
402 serde_json::json!({
403 "current_usage": v.current_usage,
404 "peak_usage": v.peak_usage,
405 "allocation_count": v.allocation_count,
406 "total_allocated": v.total_allocated,
407 "avg_allocation_size": v.avg_allocation_size
408 }),
409 )
410 })
411 .collect::<serde_json::Map<String, serde_json::Value>>()
412 .into();
413
414 json_obj.insert("component_stats".to_string(), component_stats);
415 json_obj.insert(
416 "duration_secs".to_string(),
417 serde_json::Value::Number(report.duration.as_secs().into()),
418 );
419
420 serde_json::Value::Object(json_obj)
421 }
422}
423
424#[cfg(test)]
425mod tests {
426 use super::*;
427 use crate::memory::metrics::event::MemoryEventType;
428
429 #[test]
430 fn test_memory_metrics_collector() {
431 let config = MemoryMetricsConfig {
432 enabled: true,
433 capture_call_stacks: false,
434 max_events: 100,
435 real_time_aggregation: true,
436 samplingrate: 1.0,
437 };
438
439 let collector = MemoryMetricsCollector::new(config);
440
441 collector.record_event(MemoryEvent::new(
443 MemoryEventType::Allocation,
444 "Component1",
445 1024,
446 0x1000,
447 ));
448
449 collector.record_event(MemoryEvent::new(
450 MemoryEventType::Allocation,
451 "Component1",
452 2048,
453 0x2000,
454 ));
455
456 collector.record_event(MemoryEvent::new(
457 MemoryEventType::Allocation,
458 "Component2",
459 4096,
460 0x3000,
461 ));
462
463 assert_eq!(collector.get_current_usage("Component1"), 3072);
465 assert_eq!(collector.get_current_usage("Component2"), 4096);
466 assert_eq!(collector.get_total_current_usage(), 7168);
467
468 collector.record_event(MemoryEvent::new(
470 MemoryEventType::Deallocation,
471 "Component1",
472 1024,
473 0x1000,
474 ));
475
476 assert_eq!(collector.get_current_usage("Component1"), 2048);
478 assert_eq!(collector.get_total_current_usage(), 6144);
479
480 let comp1_stats = collector
482 .get_allocation_stats("Component1")
483 .expect("Operation failed");
484 assert_eq!(comp1_stats.count, 2);
485 assert_eq!(comp1_stats.total_bytes, 3072);
486 assert_eq!(comp1_stats.peak_usage, 3072);
487
488 let report = collector.generate_report();
490 assert_eq!(report.total_current_usage, 6144);
491 assert_eq!(report.total_allocation_count, 3);
492
493 let comp1_report = report
495 .component_stats
496 .get("Component1")
497 .expect("Operation failed");
498 assert_eq!(comp1_report.current_usage, 2048);
499 assert_eq!(comp1_report.allocation_count, 2);
500 }
501}