Render a ranked table of crates with inline bars and code/data split. crate_sizes: dict of crate -> {"code": N, "rodata": N, "data": N, "total": N} section_sizes: authoritative section totals from the map header.
(title, crate_sizes, section_sizes, top_n)
| 505 | |
| 506 | |
| 507 | def render_crate_table(title, crate_sizes, section_sizes, top_n): |
| 508 | """Render a ranked table of crates with inline bars and code/data split. |
| 509 | |
| 510 | crate_sizes: dict of crate -> {"code": N, "rodata": N, "data": N, "total": N} |
| 511 | section_sizes: authoritative section totals from the map header. |
| 512 | """ |
| 513 | header(title) |
| 514 | if not crate_sizes: |
| 515 | iprint(f"{DIM}(no data){RESET}") |
| 516 | return |
| 517 | |
| 518 | total = section_sizes.get("CODE", 0) + section_sizes.get(".rodata", 0) + \ |
| 519 | section_sizes.get(".data", 0) + section_sizes.get(".bss", 0) |
| 520 | sorted_crates = sorted(crate_sizes.items(), key=lambda x: x[1]["total"], reverse=True) |
| 521 | max_size = sorted_crates[0][1]["total"] if sorted_crates else 1 |
| 522 | name_w = max(len(c) for c, _ in sorted_crates[:top_n]) |
| 523 | name_w = max(name_w, 10) |
| 524 | |
| 525 | # Row layout (no leading indent): |
| 526 | # "{i:>3}. {name:<name_w} {total:>10} {code:>10} {data:>10} {bar:20} {pct:5.1f}%" |
| 527 | # = 5 + name_w + 2+10 + 2+10 + 2+10 + 2+20 + 2+6 = name_w + 71 |
| 528 | row_w = name_w + 71 |
| 529 | iprint(f" {'':>{name_w}} {'total':>10} {'code':>10} {'data':>10} {'':20} {'%':>6}") |
| 530 | iprint(f"{DIM}{'─' * row_w}{RESET}") |
| 531 | |
| 532 | for i, (name, sizes) in enumerate(sorted_crates[:top_n], 1): |
| 533 | pct = 100 * sizes["total"] / total if total else 0 |
| 534 | frac = sizes["total"] / max_size if max_size else 0 |
| 535 | data_sz = sizes["rodata"] + sizes["data"] |
| 536 | |
| 537 | # Stacked bar: code portion in cyan, data portion in magenta |
| 538 | bar_w = 20 |
| 539 | if sizes["total"] > 0: |
| 540 | code_frac_of_bar = sizes["code"] / sizes["total"] |
| 541 | else: |
| 542 | code_frac_of_bar = 0 |
| 543 | full = int(frac * bar_w) |
| 544 | code_part = int(code_frac_of_bar * full) |
| 545 | data_part = full - code_part |
| 546 | empty = bar_w - full |
| 547 | stacked = (f"{CYAN}{BAR_FULL * code_part}{RESET}" |
| 548 | f"{MAGENTA}{BAR_FULL * data_part}{RESET}" |
| 549 | f"{' ' * empty}") |
| 550 | |
| 551 | iprint( |
| 552 | f"{DIM}{i:>3}.{RESET} {name:<{name_w}} " |
| 553 | f"{format_bytes(sizes['total']):>10} " |
| 554 | f"{CYAN}{format_bytes(sizes['code']):>10}{RESET} " |
| 555 | f"{MAGENTA}{format_bytes(data_sz):>10}{RESET} " |
| 556 | f"{stacked} " |
| 557 | f"{DIM}{pct:5.1f}%{RESET}" |
| 558 | ) |
| 559 | |
| 560 | |
| 561 | def shorten_symbol(crate, symbol): |