Share a flame graph

A flame graph is one of the few artifacts where the interaction is the finding. The picture tells you something is wide. Clicking into it — zooming a frame, hitting Ctrl-F to highlight every malloc in the stack — is how you work out why.

Which is why sending one is so consistently disappointing. flamegraph.pl writes a self-contained SVG with the whole interaction layer in an embedded <script> block, and almost every place you'd naturally drop it removes that script:

  • GitHub sanitizes SVG on render and strips <script>. Zoom and search die; the image survives.
  • Slack shows a flattened preview. Everything below the fold is gone.
  • Confluence and Notion treat it as an image attachment.
  • Email is a coin flip between an inline flat render and an attachment the reader has to save and open by hand.

So the profile gets screenshotted, and the person reading it has to trust your crop.

Publish the SVG

Whichever tool produced it, the output is one file:

# perf, the original path
perf record -F 99 -g -- ./myserver
perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg

# Rust
cargo flamegraph --bin myserver          # → flamegraph.svg

# Python
py-spy record -o flame.svg --pid 12345

Drag that SVG into the app, or send it to the API:

curl -fsS -X POST "https://commareports.com/api/v1/reports" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile svg flame.svg \
        --arg t "CPU profile — checkout path" '{title: $t, html: $svg}')"

Report content renders with scripts enabled inside a sandboxed iframe (allow-scripts, no allow-same-origin), which is exactly the capability GitHub's sanitizer removes. Click-to-zoom, the reset-zoom link, the search box and the frame tooltips all behave at the URL.

Publish the differential too

The single most useful flame graph is usually the second one. If you have a before and an after:

stackcollapse-perf.pl < before.perf > before.folded
stackcollapse-perf.pl < after.perf  > after.folded
difffolded.pl before.folded after.folded | flamegraph.pl > diff.svg

PATCH both onto the same report id and you get a revision history rather than two orphaned files named flame.svg and flame(2).svg:

curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile svg diff.svg \
        --arg t "CPU profile — after batching" '{title: $t, html: $svg}')"

One URL per service, a revision per investigation. "Is this the same regression as March?" becomes a diff instead of a Slack search.

What review adds

Profiles are read by people who did not run them, which is where they usually stall:

  • Anchored threads on the wide frame, so the diagnosis lives with the evidence — see commenting on HTML.
  • Revisions, so the before/after pair is one artifact.
  • Access per report — private, team, domain-gated, or named reviewers. Stack traces leak internal module and path names, so this is worth setting deliberately. See the sharing model.

Limits

  • Entry HTML/SVG: 5 MB. A deep profile with hundreds of thousands of unique stacks can approach this — sample at a lower frequency (-F 49) or narrow the recording window rather than trimming the graph.
  • 60 requests/minute per token.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Publish a flame graph →

Related