Repository navigation
feat(operator): AnalyzeDump reports what holds the heap (gcheapstat, dumpheap -stat) - #7100
Merged
Merged
Conversation
…dumpheap -stat) The governed dump read ran only thread/lock commands, so an out-of-memory dump (#7082, 14.6 GB) could name every thread and still not say what filled the heap. The fixed command set gains `gcheapstat` (generation sizes per GC heap) and `dumpheap -stat` (one row per TYPE, never an object). - In the pod, `dumpheap -stat` keeps the TAIL of an over-cap table: SOS lists types smallest first and ends with the Total line, so a head cut would keep exactly the rows that do not matter. The full byte count is still reported. - The condensation turns the table into the N largest types (40, shrinking with the other caps to fit the lane's budget, never omitted), each with bytes, objects and share of the heap total; the cut is stated, the Free row kept, a walk stopped by its bound says it did not finish instead of reading as an empty heap. It lands as a `dumpheap` section (rendered by the existing Plugins page unchanged) and as a structured `heap` field. Refs #7082 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
SOS fragmentation output can corrupt or displace heap statistics, and capped heap sections report inaccurate completeness metadata.
No open issues 🎉
What changed in this PR
Extends the operator’s governed AnalyzeDump read with heap statistics to help investigate memory pressure such as #7082.
Changes:
- Adds
gcheapstatanddumpheap -statto the bounded command set. - Condenses heap output into largest-type statistics, totals and percentage shares.
- Adds regression fixtures and documents the expanded analysis.
| File | Description |
|---|---|
src/MeshWeaver.Documentation/Data/Architecture/OperatingFromThePortal.md |
Updates the supported analysis commands. |
src/MeshWeaver.Documentation/Data/Architecture/DebuggingNativeCrashes.md |
Explains heap reporting and its limits. |
deploy/aks/operator/test/stubs/dump-analyze/dotnet |
Generates heap command output for tests. |
deploy/aks/operator/test/run-tests.sh |
Adds heap parsing, output-cap and timeout assertions. |
deploy/aks/operator/test/fixtures/dump-analyze/pod.txt |
Adds representative heap statistics. |
deploy/aks/operator/bin/hosting-dump-analyze |
Parses and summarizes heap statistics. |
deploy/aks/operator/bin/_dump_analyze_pod.sh |
Runs heap commands and retains capped tail output. |
Review effort: Balanced
Contributor
Test Results 29 files ±0 29 suites ±0 1h 8m 45s ⏱️ -16s Results for commit a965a66. ± Comparison against base commit b85e51b. This pull request removes 44 and adds 18 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
…tal line CI ran the suite inside the operator image (Azure Linux 3), which ships no awk: the 20,000-type fixture generator printed `awk: command not found`, the log held no rows, and the heap read zero types (FAIL heap cap / heap cut stated). The generator is pure bash now, and the fixture's row count is asserted before it is used, so a failed generator names itself. Also, from the review overview: - SOS can print a "Fragmented blocks" table after the Total line. It names object addresses and could displace the statistics in the kept tail, and its rows can match a type row. The pod keeps the output only through the Total line, and the condensation reads type rows only before it. - `rowsCut` is now read off the table header being gone (the pod cut the head), not off a byte count that also covers non-table lines, and the dumpheap section is marked truncated when rows or types were cut. Refs #7082 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.
Refs #7082
Why
The governed
AnalyzeDumpread (deploy/aks/operator/bin/hosting-dump-analyze) runs a fixed set of thread and lock commands. For the out-of-memory dump in #7082 (14.6 GB, result atOps/Dumps/i7082-analyzedump-hwx6z-podon the control instance), it named every thread but could not say what filled the heap, because it ran no heap statistics.What
gcheapstatgives generation sizes per GC heap. It is kept as printed, under the normal text cap.dumpheap -statprints one row per type (count, total bytes, name) and never prints an object. A plaindumpheapobject listing,dumpobjand!envstay excluded.dumpheap -statkeeps the TAIL of the output. SOS lists types smallest first and prints theTotal … objects, … bytesline last. Cutting from the head, as every other section does, would keep only the rows that do not matter. The cut starts at a whole line, and theendsentinel still reports the full byte count.Freerow is kept, because free space means fragmentation, not retention. A heap walk stopped by its time bound prints no total, so the table says the walk did not finish rather than reporting an empty heap.dumpheapentry insections, which the existing PluginsDumpAnalysis.Markdownpage renders as is (no Plugins change needed), and also as a structuredheapfield. The Plugins reader ignores fields it does not know.Doc/Architecture/DebuggingNativeCrashes→ "Reading a production dump", and theAnalyzeDumprow inOperatingFromThePortal.Proof
deploy/aks/operator/test/run-tests.sh: 1074 passed, 0 failed locally on macOS. New assertions pin:Freerow;gcheapstattext;postgres:16, Debian) against the stubdotnet-dump, which now prints a ~174 KBdumpheap -statagainst a 100 KB cap. All eight sections ran in order. The tail withGenerated.Type003000and theTotalline was kept, the cut started at a whole line, and the full byte count was reported.section head(how every other section is cut), the same assertions FAIL. The kept text isLoading core dump…,Statistics:and the smallest types, ending in a partial line, and theTotalline is lost.shellcheck -S warningpasses on the operator scripts, as CI runs it.Bounds
The per-command bound (300 s) and the Job deadline (1800 s) are unchanged.
dumpasyncalready walks the heap once and finished on the 14.6 GB dump;dumpheap -statis one more walk of the same kind. If every command ran to its bound, the total would exceed the Job deadline. In that case the Job fails by name and nothing partial is reported, which is unchanged behaviour. This is stated in the script header.After merge
The operator picks this up with its image. The #7082 dump is then re-read by filing a new
AnalyzeDumpagainst the same dump (dumpFile: memex-portal-deployment-8556887fd9-hwx6z.1792742631/coredump.1.1792742595). Nothing was run against the cluster for this PR.🤖 Generated with Claude Code