refactor(track-memory-allocations): centralize metric declarations for heap and arena#24587
Merged
Conversation
Boshen
force-pushed
the
refactor-alloc-metrics
branch
from
July 16, 2026 12:27
3860b66 to
65998dd
Compare
Member
Author
Merge activity
|
…r heap and arena (#24587) Follow-up to #24565. Restructures the task so that adding a new heap or arena metric is a small, local change instead of edits scattered across measurement, diffing, rendering, and committed-value lookup: - `HeapTracker` groups the global-allocator atomics into one static `HEAP` with `read()`/`reset()`; its doc comment describes how to add a heap counter. - `Counters { heap: HeapCounters, arena: ArenaCounters }` replaces the flat `AllocatorStats`, with `record()` / `diff_since()` (the arena-chunk exclusion logic from #22621 is unchanged, just relocated). - `StageStats::metrics()` is now the single declaration of what a snapshot contains: an ordered list of `Metric`s, each a label plus a `MetricKind`. - `MetricKind` encodes the per-metric snapshot policy: `Count` (platform-exact), `ExactBytes` (exact, human-readable comment), `ApproxBytes` (tolerates cross-architecture layout noise by keeping the committed value within `APPROX_BYTES_TOLERANCE`, renamed from `ARENA_SIZE_TOLERANCE` since it is no longer specific to arena size). - `write_snapshot` / `render_file_stats` are fully metric-driven; nothing downstream needs touching when a metric is added. Adding e.g. a `sys deallocs` count is now: one `AtomicCounter` in `HeapTracker`, one field in `HeapCounters`, one `Metric::count(...)` entry. A new byte gauge (heap peak, arena capacity) is one gauge read plus one `Metric::approx_bytes(...)` entry. Behavior is unchanged: the committed snapshots are byte-identical when regenerated with the refactored code. 🤖 Implemented with [Claude Code](https://claude.com/claude-code).
graphite-app
Bot
force-pushed
the
refactor-alloc-metrics
branch
from
July 16, 2026 12:39
65998dd to
ba16a00
Compare
graphite-app Bot
pushed a commit
that referenced
this pull request
Jul 17, 2026
… peak growth (#24619) Adds three heap-side metrics to the allocation snapshots, using the metric machinery from #24587: - `sys deallocs` (exact count) — system deallocations per stage; read against `sys allocs` it shows whether a stage churns or retains heap. - `sys alloc bytes` — cumulative bytes requested from the system allocator per stage (allocation sizes plus reallocation growth). - `sys peak growth` — high-water mark of live heap during a stage relative to the live bytes at stage start, via live-bytes accounting in the `GlobalAlloc` wrapper. Captures transient heap a stage needs even when it frees it before finishing. Arena chunk operations are excluded from all `sys` metrics at the source: `oxc_allocator` marks each chunk allocation/deallocation immediately before calling the system allocator (task-only `track_allocations` feature, compiled out everywhere else), and the task's tracking allocator consumes the marker and skips the call. This replaces the previous global chunk counter + per-stage subtraction: a subtraction can correct counts but not a high-water mark, and chunk sizes are quantized and platform-dependent (whether an arena needs one more chunk depends on byte totals that vary across architectures with type layout — the #22621 mechanism). The first CI run demonstrated this concretely: kitchen-sink's minifier peak differed deterministically by 720 kB between aarch64 and x86_64 because the mangler's temporary arena crossed a chunk-growth boundary only on x86_64; and antd's formatter "peak" was 762 MB of main-arena chunk-doubling history rather than formatter behavior (now 13.8 MB of actual heap use). Cross-platform tolerances: the cumulative byte metrics still drift with the number of heap hashbrown tables allocated (their control-group width is architecture-dependent), so they use a relative tolerance (1%, 4 kB floor) via the committed-value comparison from #24565; `arena size` keeps its tight 1024-byte tolerance. Sample values for checker.ts (2.9 MB source): parser needs only 2.4 kB of transient heap (fully arena-based), semantic peaks at 3.9 MB, the minifier is the pipeline's largest heap consumer at 10.2 MB, and the formatter requests 5.9 MB total while peaking at 3 MB (heavy alloc/free churn). 🤖 Implemented with [Claude Code](https://claude.com/claude-code).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #24565. Restructures the task so that adding a new heap or arena metric is a small, local change instead of edits scattered across measurement, diffing, rendering, and committed-value lookup:
HeapTrackergroups the global-allocator atomics into one staticHEAPwithread()/reset(); its doc comment describes how to add a heap counter.Counters { heap: HeapCounters, arena: ArenaCounters }replaces the flatAllocatorStats, withrecord()/diff_since()(the arena-chunk exclusion logic from fix(track-memory-allocations): reserve transform scoping capacity #22621 is unchanged, just relocated).StageStats::metrics()is now the single declaration of what a snapshot contains: an ordered list ofMetrics, each a label plus aMetricKind.MetricKindencodes the per-metric snapshot policy:Count(platform-exact),ExactBytes(exact, human-readable comment),ApproxBytes(tolerates cross-architecture layout noise by keeping the committed value withinAPPROX_BYTES_TOLERANCE, renamed fromARENA_SIZE_TOLERANCEsince it is no longer specific to arena size).write_snapshot/render_file_statsare fully metric-driven; nothing downstream needs touching when a metric is added.Adding e.g. a
sys deallocscount is now: oneAtomicCounterinHeapTracker, one field inHeapCounters, oneMetric::count(...)entry. A new byte gauge (heap peak, arena capacity) is one gauge read plus oneMetric::approx_bytes(...)entry.Behavior is unchanged: the committed snapshots are byte-identical when regenerated with the refactored code.
🤖 Implemented with Claude Code.