Skip to content

feat: extend gcprofile with --by=class and --fold (allocation hotspot views)#156

Merged
rlaope merged 1 commit intomasterfrom
feat/argus-alloc
Apr 18, 2026
Merged

feat: extend gcprofile with --by=class and --fold (allocation hotspot views)#156
rlaope merged 1 commit intomasterfrom
feat/argus-alloc

Conversation

@rlaope
Copy link
Copy Markdown
Owner

@rlaope rlaope commented Apr 18, 2026

Closes #152.

Summary

Extends argus gcprofile with two new views instead of introducing a redundant argus alloc command. During implementation it became clear that gcprofile already does 80% of what the original alloc proposal described β€” same JFR event types (jdk.ObjectAllocationInNewTLAB / OutsideTLAB), same --duration / --top, same top-N table, same JSON. A second command would just split the mental model.

What gcprofile was actually missing (vs async-profiler -e alloc / JDK Mission Control):

  1. A class-grouped view β€” today it only shows stack-frame sites.
  2. Flamegraph-compatible output β€” today there is no way to visualize call chains.

This PR closes both gaps with two surgical flags.

Changes

  • --by=site|class (default site β€” unchanged)
    • site β€” current stack-frame aggregation.
    • class β€” aggregates by the allocated object's type (event.getClass(\"objectClass\")). Answers "which classes are burning bytes".
  • --fold=FILE β€” writes folded stacks in Brendan Gregg's flamegraph.pl format (root-first, leaf-last, merged by total bytes). Render with flamegraph.pl --colors=mem FILE > alloc.svg.
  • New public API in AllocationProfiler:
    • analyzeByClass(Path) β†’ AllocationByClass
    • analyzeFoldedStacks(Path) β†’ Map<String, Long>
  • Help text and bash completion updated.

Non-goals in this PR

  • Not a new command. argus gcprofile remains the single entry point for allocation profiling.
  • No inline SVG rendering β€” --fold=FILE produces folded text; SVG is one flamegraph.pl call away. A bundled renderer can be added in a follow-up if needed.
  • No live streaming β€” bounded --duration, same as today.

Backwards compatibility

argus gcprofile <pid> (no extra flags) emits the exact same output as before. No existing caller is affected.

Developer experience

# Unchanged β€” default stack-frame view
argus gcprofile 12345 --duration=30s

# New β€” allocated types
argus gcprofile 12345 --duration=30s --by=class
#   1. byte[]                       1.8 GB  42.1%
#   2. java.util.HashMap\$Node       620 MB  14.4%

# New β€” folded stacks for flamegraph.pl
argus gcprofile 12345 --duration=30s --fold=alloc.folded
flamegraph.pl --colors=mem alloc.folded > alloc.svg

References

  • async-profiler -e alloc mode
  • JFR: jdk.ObjectAllocationInNewTLAB, jdk.ObjectAllocationOutsideTLAB
  • Brendan Gregg, "Folded stacks" format (flamegraph.pl)

Test plan

  • ./gradlew :argus-cli:compileJava β€” BUILD SUCCESSFUL
  • ./gradlew :argus-cli:test β€” full suite passes
  • New unit tests cover: byClass sort/rate/coalesce/empty; folded stacks reordering/merging/sorting/skip-empty
  • Existing argus gcprofile behavior unchanged (default --by=site path still the first branch)

Adds two new views to the existing 'argus gcprofile' command instead of
introducing a redundant 'argus alloc' that would duplicate 80% of its
behavior. Covers the gaps versus async-profiler -e alloc / JDK MC:

  - --by=site (default, unchanged) vs --by=class to aggregate JFR
    allocation events by the *allocated type* instead of stack frame.
    Answers "which classes are burning bytes" directly.
  - --fold=FILE writes folded stacks in Brendan Gregg's flamegraph.pl
    format (root-first, leaf-last, merged by total bytes). Renders to
    SVG with flamegraph.pl --colors=mem FILE > alloc.svg.

AllocationProfiler gains:
  - analyzeByClass(Path) β†’ AllocationByClass (new AllocatedType record)
  - analyzeFoldedStacks(Path) β†’ Map<String, Long> of folded -> bytes
  - readAllocationSize helper shared across both paths

Help and bash completion reflect the new flags. Existing output for
'argus gcprofile <pid>' with no extra flags is unchanged β€” no breaking
changes for current users.

Unit tests mirror both aggregation paths in test-local helpers
(JFR files can't be built from unit tests) and cover: sort order,
rate calculation, class-coalescing, empty input, stack reordering,
stack merging, and zero/empty-stack skipping.

Closes #152.

Signed-off-by: rlaope <piyrw9754@gmail.com>
@rlaope rlaope merged commit 294b91b into master Apr 18, 2026
7 checks passed
@rlaope rlaope deleted the feat/argus-alloc branch April 18, 2026 01:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: extend gcprofile with --by=class and --flame (allocation hotspot views)

1 participant