import json
import re
import sys
from collections import defaultdict
ALLOCATOR_FRAME = re.compile(
r"dhat::|alloc::alloc|alloc::raw_vec|__rust_|core::alloc|<alloc::|std::alloc|hashbrown::raw|"
r"alloc::vec::|alloc::string::|alloc::boxed::|alloc::collections::|indexmap::|serde_json::|"
r"core::ptr::|core::iter::|core::ops::|"
r"\(dhat-|\(alloc/|\(core/|\(std/|\(src/(?:raw_vec|vec|string|alloc|collections|boxed|slice|str)/|"
r"\([A-Za-z_]+-\d+\.\d+"
)
CRATE_PATH = re.compile(
r"\((?:.*/)?(?:src/)?"
r"(?:xml/|disassemble\.rs|reassemble\.rs|format\.rs|meta\.rs|cli\.rs|xml_cmd\.rs|ignore_file\.rs|error\.rs)"
)
DEPENDENCY_PATH = re.compile(r"\([A-Za-z_]+-\d+\.\d+")
def frame_name(raw: str) -> str:
name = raw.split(": ", 1)[-1]
return re.sub(r":\d+\)$", ")", name)
def is_crate_frame(name: str) -> bool:
if name.startswith("config_disassembler::"):
return True
if DEPENDENCY_PATH.search(name):
return False
return bool(CRATE_PATH.search(name))
def main() -> None:
path = sys.argv[1]
top_n = int(sys.argv[2]) if len(sys.argv) > 2 else 15
data = json.load(open(path))
frames = data["ftbl"]
total_at_peak = sum(pp["gb"] for pp in data["pps"])
by_site = defaultdict(lambda: {"bytes": 0, "blocks": 0, "inner": defaultdict(int)})
for pp in data["pps"]:
if pp["gb"] == 0:
continue
names = [frame_name(frames[i]) for i in pp["fs"]]
site = next((n for n in names if is_crate_frame(n)), None)
if site is None:
site = next((n for n in names if not ALLOCATOR_FRAME.search(n)), names[-1] if names else "?")
idx = names.index(site)
inner = names[idx - 1] if idx > 0 else "(direct)"
entry = by_site[site]
entry["bytes"] += pp["gb"]
entry["blocks"] += pp["gbk"]
entry["inner"][inner] += pp["gb"]
mb = lambda b: b / (1024 * 1024)
print(f"heap at global peak: {mb(total_at_peak):.1f} MB across {len(by_site)} call sites\n")
print("| MB at peak | share | blocks | crate call site | largest inner allocation |")
print("|---:|---:|---:|---|---|")
ranked = sorted(by_site.items(), key=lambda kv: kv[1]["bytes"], reverse=True)[:top_n]
for site, entry in ranked:
inner, _ = max(entry["inner"].items(), key=lambda kv: kv[1])
share = entry["bytes"] / total_at_peak * 100 if total_at_peak else 0
print(
f"| {mb(entry['bytes']):.2f} | {share:.1f}% | {entry['blocks']} | "
f"`{site[:110]}` | `{inner[:90]}` |"
)
if __name__ == "__main__":
main()