Flame Graph

Hierarchical profiler frames sized by value, icicle layout.

Overview

The FlameGraph control visualizes a call tree as stacked frames. It uses an icicle layout (root at the top): each FlameNode is a horizontal bar whose width is proportional to its value relative to the root, and children are laid out proportionally in the row beneath their parent. Widths use eighth-blocks for sub-cell precision and labels are overlaid in a contrasting color. Set the tree via the Root content property.

<FlameGraph Title="CPU profile">
    <FlameNode Name="main" Value="100">
        <FlameNode Name="parseRequest" Value="25">
            <FlameNode Name="decodeJson" Value="18" />
        </FlameNode>
        <FlameNode Name="handleQuery" Value="60">
            <FlameNode Name="sqlExec" Value="40">
                <FlameNode Name="ioWait" Value="30" />
            </FlameNode>
            <FlameNode Name="mapRows" Value="15" />
        </FlameNode>
        <FlameNode Name="writeResponse" Value="15" />
    </FlameNode>
</FlameGraph>

Properties

PropertyTypeDescription
RootFlameNodeRoot frame of the graph (content property).
SelectedNodeobjectThe selected frame. Navigate with the arrow keys or click. Two-way bindable.
TitlestringOptional heading drawn along the top edge.

FlameNode fields: Name, Value, Color, and nested Children. When Value is zero it is derived from the sum of the children.

Data Binding

A flame graph has a single tree, so bind the Root property to a FlameNode on your ViewModel. Reassigning Root (via SetProperty) pushes the new tree and re-renders. Data classes and ViewModels must be public or internal so the AOT source generator can bind them.

public sealed class ProfileViewModel : ViewModelBase
{
    public FlameNode Profile
    {
        get;
        set => SetProperty(ref field, value);
    } = Build();

    // Reloading the profile swaps the whole tree and re-renders.
    public void Reload() => Profile = Build();

    private static FlameNode Build() => new()
    {
        Name = "main", Value = 100,
        Children =
        {
            new FlameNode { Name = "handleQuery", Value = 60,
                Children = { new FlameNode { Name = "sqlExec", Value = 40 } } },
            new FlameNode { Name = "writeResponse", Value = 15 },
        }
    };
}
<FlameGraph Root="{Binding Profile}" />

Interactivity

The graph is focusable and walkable. Give it focus (Tab, or click) and use the arrow keys to move through the call tree — ↓ into the first child, ↑ to the parent, ←/→ across siblings — or click any frame. The selected frame is highlighted (brighter while focused) and SelectedNode updates two-way, ready to drive a details pane.

<FlameGraph Root="{Binding Profile}"
            SelectedNode="{Binding Selected, Mode=TwoWay}" />

Key Concepts