(&self, top: usize)
| 489 | } |
| 490 | |
| 491 | pub fn modules_report(&self, top: usize) -> MemoryModuleReport { |
| 492 | let Some(_guard) = ReentryGuard::enter() else { |
| 493 | return MemoryModuleReport { |
| 494 | generated_at_ms: now_ms(), |
| 495 | top: normalize_top(top), |
| 496 | total_live_bytes_estimate: 0, |
| 497 | process_rss_bytes: 0, |
| 498 | entries: Vec::new(), |
| 499 | }; |
| 500 | }; |
| 501 | let top = normalize_top(top); |
| 502 | let (process_rss_bytes, _) = read_process_memory(); |
| 503 | let (total_live_bytes, rows) = self.collect_stack_rows(); |
| 504 | |
| 505 | let mut agg: HashMap<String, ModuleAggregate> = HashMap::new(); |
| 506 | for (stack, stats) in rows { |
| 507 | let function = self.resolve_function_for_stack(&stack); |
| 508 | let module = module_name_from_function(&function); |
| 509 | let entry = agg |
| 510 | .entry(module.clone()) |
| 511 | .or_insert_with(|| ModuleAggregate { |
| 512 | module, |
| 513 | live_bytes: 0, |
| 514 | alloc_bytes_total: 0, |
| 515 | function_names: HashSet::new(), |
| 516 | stack_count: 0, |
| 517 | alloc_count: 0, |
| 518 | free_count: 0, |
| 519 | }); |
| 520 | entry.live_bytes = entry.live_bytes.saturating_add(stats.live_bytes); |
| 521 | entry.alloc_bytes_total = entry |
| 522 | .alloc_bytes_total |
| 523 | .saturating_add(stats.alloc_bytes_total); |
| 524 | entry.function_names.insert(function); |
| 525 | entry.stack_count = entry.stack_count.saturating_add(1); |
| 526 | entry.alloc_count = entry.alloc_count.saturating_add(stats.alloc_count); |
| 527 | entry.free_count = entry.free_count.saturating_add(stats.free_count); |
| 528 | } |
| 529 | |
| 530 | let mut values = agg.into_values().collect::<Vec<_>>(); |
| 531 | values.sort_by(|left, right| right.live_bytes.cmp(&left.live_bytes)); |
| 532 | |
| 533 | let entries = values |
| 534 | .into_iter() |
| 535 | .take(top) |
| 536 | .map(|item| MemoryModuleEntry { |
| 537 | module: item.module, |
| 538 | live_bytes_estimate: item.live_bytes, |
| 539 | alloc_bytes_total_estimate: item.alloc_bytes_total, |
| 540 | function_count: item.function_names.len(), |
| 541 | stack_count: item.stack_count, |
| 542 | alloc_count: item.alloc_count, |
| 543 | free_count: item.free_count, |
| 544 | live_ratio_heap: ratio(item.live_bytes, total_live_bytes), |
| 545 | live_ratio_rss: ratio(item.live_bytes, process_rss_bytes), |
| 546 | }) |
| 547 | .collect(); |
| 548 |
no test coverage detected