How do I read an EK9 flame graph?

← Profiling · Ref: Q629

The -t6p flag generates an interactive HTML flame graph. 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.

INTERACTIVE FEATURES

- Click a frame to zoom into that subtree.
- Hover to see exact call count, self-time, and total time.
- Search to highlight all frames matching a function name.
- Reset to return to the full view.

ACTIONABLE STRATEGY

1. Look for the widest red frames. These are your bottlenecks.
2. Check call count. 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. Click to zoom and 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)

Correct:

transformed <- transformItem(item)
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, interactive with zoom/search/hover, integrated with coverage and quality dashboard on same page.

Keywords: profile, read, blue, flame-graph, dashboard, flame, interpret, total-time, graph, width, self-time, performance, red, zoom