| 439 | |
| 440 | @classmethod |
| 441 | def from_snapshot( |
| 442 | cls, |
| 443 | allocations: Iterator[AllocationRecord], |
| 444 | *, |
| 445 | biggest_allocs: int = 200, |
| 446 | native_traces: bool, |
| 447 | ) -> "TreeReporter": |
| 448 | data = Frame(location=ROOT_NODE, value=0, import_system=False, interesting=True) |
| 449 | sorted_records = sorted(allocations, key=lambda alloc: alloc.size, reverse=True) |
| 450 | for record in sorted_records[:biggest_allocs]: |
| 451 | size = record.size |
| 452 | data.value += size |
| 453 | data.n_allocations += record.n_allocations |
| 454 | |
| 455 | current_frame = data |
| 456 | stack = ( |
| 457 | tuple(record.hybrid_stack_trace()) |
| 458 | if native_traces |
| 459 | else record.stack_trace() |
| 460 | ) |
| 461 | for index, stack_frame in enumerate(reversed(stack)): |
| 462 | if is_cpython_internal(stack_frame): |
| 463 | continue |
| 464 | is_import_system = is_frame_from_import_system(stack_frame) |
| 465 | is_interesting = not is_import_system and is_frame_interesting( |
| 466 | stack_frame |
| 467 | ) |
| 468 | if stack_frame not in current_frame.children: |
| 469 | node = Frame( |
| 470 | value=0, |
| 471 | location=stack_frame, |
| 472 | import_system=is_import_system, |
| 473 | interesting=is_interesting, |
| 474 | ) |
| 475 | current_frame.children[stack_frame] = node |
| 476 | |
| 477 | current_frame = current_frame.children[stack_frame] |
| 478 | current_frame.value += size |
| 479 | current_frame.n_allocations += record.n_allocations |
| 480 | current_frame.thread_id = format_thread_name(record) |
| 481 | |
| 482 | if index > MAX_STACKS: |
| 483 | break |
| 484 | |
| 485 | elided_locations = ElidedLocations() |
| 486 | elided_locations.cutoff = biggest_allocs |
| 487 | |
| 488 | for record in sorted_records[biggest_allocs:]: |
| 489 | data.value += record.size |
| 490 | data.n_allocations += record.n_allocations |
| 491 | elided_locations.n_locations += 1 |
| 492 | elided_locations.n_bytes += record.size |
| 493 | elided_locations.n_allocations += record.n_allocations |
| 494 | |
| 495 | return cls(data, elided_locations) |
| 496 | |
| 497 | def get_app(self) -> TreeApp: |
| 498 | return TreeApp(self.data, self.elided_locations) |