Introduction
A table of method names and sample counts can be hard to scan when you have hundreds of methods. Flamegraphs transform profiling data into a visual stack chart where performance bottlenecks jump out immediately.
Key Concepts
- Flamegraph: A visualization of sampled stack traces where the x-axis represents the proportion of samples and the y-axis represents call depth.
- Plateau: A wide bar at the top of the stack, indicating a method that consumes significant CPU time directly (high self time).
- Speedscope / Firefox Profiler: Browser-based tools that render interactive flamegraphs from JSON profiling data.
Real World Context
When triaging a slow endpoint, engineers share flamegraph screenshots in pull requests and incident channels. A single image tells the story faster than pages of profiler text output.
Deep Dive
Flamegraphs encode three things visually:
- Width of a bar is proportional to how many samples included that method. Wider bars mean more time.
- Vertical position shows the call hierarchy. The bottom is the entry point (e.g.,
main), and the top holds leaf methods doing actual work. - Color is typically random or grouped by module. It carries no performance meaning.
A simplified ASCII flamegraph looks like this, where slow_method is the hotspot:
+--slow_method--+
+--------process---------+
+------------handle_request-----------+
+------------------main------------------------+
To generate a flamegraph from StackProf, pass raw: true when profiling:
rubyrequire 'stackprof' StackProf.run(mode: :cpu, raw: true, out: 'profile.dump') do your_code end
Then convert the dump to an interactive HTML flamegraph:
bashstackprof profile.dump --d3-flamegraph > flame.html
Vernier is a modern alternative that outputs JSON compatible with Firefox Profiler and Speedscope:
rubyrequire 'vernier' Vernier.profile(out: 'profile.json') do your_code end # Open profile.json at https://profiler.firefox.com or https://speedscope.app
Vernier captures thread activity and GC pauses automatically, giving richer context than StackProf alone.
Common Pitfalls
- Confusing width with call count — A wide bar means more samples, not necessarily more calls. A method called once but running for 500ms will be wider than a method called 10,000 times but finishing in 1ms total.
- Ignoring the top of the stack — Beginners focus on the wide bars at the bottom (entry points). The actionable hotspots are the wide bars at the top, where the CPU actually spends time.
Best Practices
- Compare before and after — Generate flamegraphs before and after your optimization. The visual diff makes it obvious whether you shrunk the right hotspot.
- Use Vernier for GC visibility — Vernier annotates GC pauses directly in the flamegraph, so you can see whether garbage collection is a significant contributor.
Summary
- Flamegraphs turn profiler data into a visual chart where wide bars at the top indicate hotspots.
- Use
stackprof --d3-flamegraphor Vernier with Speedscope/Firefox Profiler for interactive exploration. - Always compare flamegraphs before and after optimization to verify your changes had the intended effect.
Code Examples
require 'vernier'
# Profile a block and write output for Firefox Profiler
Vernier.profile(out: 'profile.json') do
users = User.where(active: true).includes(:posts)
users.each { |u| u.posts.map(&:title) }
end
# Open the resulting file:
# 1. Go to https://profiler.firefox.com
# 2. Drag and drop profile.json
# 3. Look for wide bars at the top of the flamegraph