Skip to content

Releases: stephenberry/heapscope

heapscope 0.3.0

Choose a tag to compare

@stephenberry stephenberry released this 07 Oct 20:59
[dependencies]
heapscope = "0.3"

Changed

  • Text summaries name functions, not return addresses. Every summary, including the one a failing assertion prints, renders each frame as its function name, the way folded output does since 0.2.0, instead of repeating an address and an absolute image path. The profile files keep every address, and write_text_summary_with takes Symbolized for the old rendering. (#15)
  • The ranking leaves out sites that allocated nothing. After Profiler::reset, a program point that only held memory from before the reset is no longer listed among the top sites; the summary says how many were left out. (#15)
  • Failure profiles go under target/. With HEAPSCOPE_ASSERT_PROFILE unset, a failing assertion writes its profile to target/heapscope/ (target/<triple>/heapscope/ with --target, following CARGO_TARGET_DIR) rather than into the package's source tree. (#17)

Added

  • HeapStats::allocations_since(&mark) returns the count assert_alloc_count!(since: mark) checks, or a MarkError saying why the mark cannot be compared. (#15)
  • RegionBreakdown::totals carries the run's counters from the same instant as the rows, so the rows plus outside_regions add up to it exactly. (#15)
  • CHANGELOG.md. (#15)

Fixed

  • Writing folded stacks while profiling no longer records the writer's own allocations. (#15)
  • Summaries say "1 block", "1 event" and "1 program point". (#18)

heapscope 0.2.0

Choose a tag to compare

@stephenberry stephenberry released this 06 Oct 22:57
[dependencies]
heapscope = "0.2"

Changed

  • Folded output names functions, not return addresses. Each frame is its demangled function name, so a flame graph merges a function however many call sites reached it. The 0.1.0 addressed rendering is still available through write_folded_with, and heapscope-symbolize -f folded writes the new form too. (#7)
  • Frames are named at the call site. heapscope-symbolize and in-process lookup now resolve the call instruction rather than the return address, so a frame no longer takes the name of whatever the compiler placed after the call, which across inlining is often another function. Recorded addresses are unchanged.

Added

  • Profiler::reset restarts a running profile's counts while keeping what is live, to leave a warm-up out. Every output except folded stacks records that a reset happened. (#9)
  • RegionBreakdown::get() reads per-region totals without taking a full snapshot, and a new (no region) row covers what no region did, so the rows sum to the run's totals. (#8)
  • assert_alloc_count! gains a ceiling form (<= n) and a since: mark form. (#5)

Fixed

  • The live-block table no longer stops recording new blocks after long churn of distinct addresses at its size limit. (#11)

heapscope 0.1.0

Choose a tag to compare

@stephenberry stephenberry released this 14 Aug 02:26

First release. A heap profiler that tracks every allocation, attributes it to the call site that made it, and writes a profile you can open in a bundled single-file viewer or in Valgrind's DHAT viewer.

[dependencies]
heapscope = "0.1"

What it does

  • No dependencies outside the standard library. [dependencies] is empty and enforced by a test, so what reaches your build is this crate and std.
  • About 97 ns per allocation, against dhat-rs's 8,300 on the same workload — a factor of roughly 85. Sampling trades exactness for most of the remaining cost, and the profile says which one it is.
  • Four outputs from one reading, so a summary and a file can never disagree about the same run: DHAT v2, a native JSON superset, a self-contained HTML page, and folded stacks for any flame graph tool.
  • Numbers a test can read, so "this parser allocates at most 64 KiB" runs on every commit instead of being measured once and written in a comment.
  • Thread and phase attribution, which DHAT v2 has no field for.
  • Offline symbolization via the bundled heapscope-symbolize, which matters most on Linux, where the loader names almost nothing at record time.

Platforms

macOS aarch64, Linux x86_64, Linux aarch64, and Windows x86_64. All four run the test suite in CI on every push, Windows natively. AddressSanitizer and ThreadSanitizer run it as well, each behind a positive control that fails the job if the sanitizer cannot see a planted defect through this crate's #[global_allocator], and Miri runs it under the race detector.

musl / Alpine is not supported and never will be.

Requirements

heapscope::Alloc must be the program's #[global_allocator], and x86_64 targets need -C force-frame-pointers=yes. A run missing either refuses to start and says which, rather than producing an empty or much slower profile. MSRV is 1.96.

Status

Pre-1.0, and the version number is the promise: the public API may still change. What is still unproven is written down rather than left out — the cost of RtlCaptureStackBackTrace on Windows is unmeasured, no Windows browser has opened the bundled page, and Module::bias on Windows is a relative virtual address rather than the address the file records, so llvm-symbolizer needs --relative-address there and addr2line cannot be used at all.

Documentation · Design record