Reads CPU flame-graph output from py-spy (Python), async-profiler (JVM), Go pprof, or Node.js `perf_hooks` / clinic.js: identifies the hot path (top sample-time frames), classifies the bottleneck (CPU-bound vs lock contention vs allocator pressure), and proposes the next investigation step. Use when a perf regression is bisected to a commit but the hot path inside it is unclear; for tail-latency percentiles use latency-percentile-analyzer, for GC pauses specifically use jvm-gc-tuning, and for a slow SQL hot path use db-query-plan-analyzer.
80
100%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Deep reference for flame-graph-analyzer SKILL.md. Consult for the full
per-runtime capture wiring, the category-to-fix remediation catalog, and
worked interpretation cases beyond the single inline example.
Each runtime produces flame-graph data from its own profiler. Export folded
stacks (.txt, one line per unique stack + sample count) wherever the profiler
supports it - that is the machine-readable form the analyzer reads.
py-spy record -o flame.svg -d 30 --pid <pid>
# or run-and-record
py-spy record -o flame.svg -d 30 -- python app.py
# raw folded stacks for analysis
py-spy record -f raw -o folded.txt -d 30 --pid <pid>java -agentpath:/path/to/libasyncProfiler.so=start,event=cpu,duration=30s,file=flame.html ...
# JFR output
java -agentpath:.../libasyncProfiler.so=start,event=cpu,file=profile.jfr ...Output: HTML flame graph or JFR (Java Flight Recorder) format.
Go's built-in pprof:
# in-process: import _ "net/http/pprof"; http.ListenAndServe(":6060", nil)
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/profile?seconds=30Open the served URL, then VIEW -> Flame Graph.
npx clinic flame -- node app.js
# writes flame.html when the process exitsperf record piped through Brendan Gregg's stackcollapse-perf.pl and
flamegraph.pl produces folded stacks and the SVG (bg).
All major profilers can emit folded stacks: one line per unique stack with its sample count.
main;handleRequest;serializeJson;Buffer.from 4521
main;handleRequest;dbQuery;parseRows 1832
main;handleRequest;authCheck;jwtVerify 904flamegraph.pl consumes this format directly. Folded stacks are the canonical
machine-readable input for this skill's analysis.
Once a hot leaf is classified, map the category to a typical fix:
| Category | Typical fix |
|---|---|
| CPU-bound hot algo | Cache the result; switch to a faster algorithm; move it out of the hot path. |
| Allocator pressure | Reuse buffers / pools; switch to streaming serialization; escape-analysis fixes for the JVM. |
| Lock contention | Reduce critical-section scope; move to lock-free data structures; per-shard locking. |
| Reflection overhead | Replace dynamic dispatch with cached call-sites or codegen. |
| Logging overhead | Lazy log-message construction; level-check before format. |
| Rank | Share | Stack (leaf) | Category |
|-----:|------:|------------------|----------|
| 1 | 32% | `gc.collect` | Allocator pressure |
| 2 | 18% | `dict.update` | (callsite) |
| 3 | 14% | `parse_response` | CPU-bound hot algo |GC at 32% of samples means allocator pressure dominates. The fix is not making
any one function faster - it is reducing the rate of allocations from
dict.update and parse_response (object pooling, streaming parsing).
| Rank | Share | Stack (leaf) | Category |
|-----:|------:|-----------------------|----------|
| 1 | 41% | `pthread_mutex_lock` | Lock contention |
| 2 | 12% | `cache.get` | (callsite) |41% of samples in lock acquisition. The fix is not "make cache.get faster" -
it is "reduce the contention" (per-shard locks, lock-free structures, or a
lock-free cache such as Caffeine for the JVM).
| Rank | Share | Stack (leaf) | Category |
|-----:|------:|-----------------------------|----------|
| 1 | 28% | `Method.invoke` / `getattr` | Reflection overhead |A common surprise - an ORM's reflective field access dominates the profile of
an otherwise simple endpoint. The fix is the ORM-equivalent of "compile the
mapping": cached method handles in the JVM, __slots__ in Python, generated
SQL in Go.