Flame Graph

Width is time, depth is stack. Frames stay in call order rather than being sorted by cost — reordering them destroys the shape a flame graph exists to show.

src/components/ui/flame-graph.tsx

About

From the component's own source, where it was written.

A flame graph of a profile.

Width is time, depth is stack. That is the whole grammar, and it is why the frames are not sorted by cost: their order is the call order, and reordering them would destroy the shape people read a flame graph for.

Clicking a frame zooms to it and the ancestors stay as a breadcrumb. A deep profile is unreadable at full width, and losing your place while zooming is what makes most flame graph implementations frustrating.

Self time is separated from total. A frame 400ms wide that spends 3ms of it in itself is not the problem; its child is. Total time alone cannot tell you which.

Frames narrower than a pixel are dropped rather than drawn as slivers — thousands of sub-pixel rectangles cost real render time and show nothing.

Install

npx astralyx-ui add flame-graph

Usage

import { FlameGraph } from '@/components/ui/flame-graph'

<FlameGraph root={profile} unit="ms" />

Composer

Change the props and the source below follows.

Props
tsx
<FlameGraph root={profile} unit="ms" />

Examples

A CPU profile

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

FlameGraph

Extends Omit<ComponentProps<'div'>, 'children'>.

PropTypeDefaultDescription
rootFlameFramerequired{ name, value, children? } where value is total time including children.
rowHeightnumber20—
unitstring'ms'—
selfLabelReactNode'self'—
totalLabelReactNode'total'—
resetLabelReactNode'Reset zoom'—

Functions

FunctionSignatureDescription
layoutFlame(root: FlameFrame, zoomPath: FlameFrame[]) => Laid[]Flattens the tree into positioned rows within [0,1] of the zoom root.

Types

FlameFrame

A flame graph of a profile.

FieldTypeDescription
namestring—
valuenumberTotal time in this frame, including children.
children?FlameFrame[]—

Behaviour

TopicDetailDescription
zoomclick a frameAncestors stay as a breadcrumb. Losing your place while zooming is what makes most flame graph implementations frustrating.
self timeshown on hoverA frame 400ms wide spending 3ms in itself is not the problem — its child is. Total alone cannot tell you which.
sub-pixel framesdroppedThousands of sliver rectangles cost real render time and show nothing.