How do I read an EK9 flame graph?
← Profiling · Ref: Q629
The -t6p flag generates an HTML report whose flame graph is a static SVG. Understanding how to read it is the key skill for performance work.
GENERATING A FLAME GRAPH
ek9 -t6p myproject.ek9
Output: .ek9/coverage/index.html (open in browser).
READING THE GRAPH
Each horizontal bar represents a function. The bars are stacked vertically to show the call chain: the bottom bar is the entry point, and each bar above it is a function called by the one below.
WIDTH = TIME
The width of each bar represents total time spent in that function (including its callees). A wide bar means that call path consumed a large fraction of execution time.
COLOUR MEANING
- Red frames: high self-time. These functions are doing the actual work. They are your primary optimisation targets.
- Blue frames: orchestrators. High total time but low self-time. They spend time calling other functions, not doing work themselves.
- Narrow frames: fast or rarely called. Usually not worth optimising.
HOVER TOOLTIPS
The flame graph is a static SVG: it does not zoom, search or reset. Hover over a frame to see its total time and self time. Call counts are not in the tooltip - read them from the hot function table on the same page.
ACTIONABLE STRATEGY
1. Look for the widest red frames. These are your bottlenecks.
2. Check call count in the hot function table. A fast function called millions of times can dominate.
3. Compare self-time vs total time. If total is high but self is low, the bottleneck is deeper in the call chain.
4. Follow the stack upwards to find the deepest hot function.
See Q627 for profiling programs. See Q630 for identifying hot methods. See Q321 for the quality report dashboard. See Q322 for profiling overview.
Example
defines module qa.profilingdeep.flamegraph defines function <?- A call chain that produces a clear flame graph: orchestrate calls processItems which calls transformItem. In the flame graph, orchestrate is at the bottom (wide), processItems in the middle, and transformItem at the top. -?> transformItem() as pure -> item as Integer <- result as Integer: item * item + 1 processItems() -> items as List of Integer <- total as Integer: 0 for item in items transformed <- transformItem(item) total: total + transformed orchestrate() -> size as Integer <- result as Integer: 0 items <- List() of Integer for i in 1 ... size items += i result: processItems(items) defines program FlameGraphDemo() stdout <- Stdout() batchSize <- 50 result <- orchestrate(batchSize) stdout.println(`Result: ${result}`)
Common mistakes
E50001 — Removing the variable declaration means later references to the variable become unresolved, triggering E50001. See ek9 -h E50001 for details.
Incorrect:
transformItem(item)
total: total + transformed
Correct:
transformed <- transformItem(item) total: total + transformed
Other ways to ask this
- What do the colours in the flame graph mean?
- How do I interpret the EK9 profiling dashboard?
- What is a flame graph and how do I use it?
Coming from another language?
Java: async-profiler generates flame graphs (SVG), JFR with JMC for interactive analysis. Python: py-spy generates flame graphs (SVG/HTML). Rust: flamegraph crate wraps perf into SVG output. Go: go tool pprof generates flame graphs. JavaScript: Chrome DevTools flame chart. EK9: built-in HTML flame graph from -t6p, static SVG with hover tooltips, integrated with coverage and quality dashboard on same page.
Keywords: performance, red, zoom, profile, read, blue, flame-graph, dashboard, flame, interpret, total-time, graph, width, self-time