# フレームグラフ ## 定義 フレームグラフ(flame graph)は、CPUプロファイル(サンプリングツールによって取得した計測値のサブセット)を可視化する手法で、Brendan Greggが考案した。横幅はサンプリングされたCPU時間に比例し、縦方向はコールスタックのコードパスの深さを示す。1枚のスナップショットで対象のおおよその姿を描き出すため、CPUの問題そのものだけでなく、CPUに残された痕跡から他のタイプの問題も発見できる。たとえばロック競合はスピンパスに費やされたCPU時間として、メモリ問題は過度にCPUを消費するメモリアロケーション関数(malloc())とそこまでのコードパスとして、ネットワークの設定ミスは遅いコードパスで使われるCPU時間として、それぞれフレームグラフ上に現れる。(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 1 イントロダクション]] §1.7.2) フレームグラフはCPUプロファイリング以外にも適用でき、off-CPU時間のフレームグラフはブロックされているスレッドのスタックトレースとブロック時間を可視化する。CPUフレームグラフの横幅がon-CPU時間に比例するのに対し、off-CPU時間のフレームグラフの横幅はoff-CPU(ブロック)時間に比例する。両者を別々に描いて組み合わせれば、コードパスのon-CPU時間とoff-CPU時間を完全に捉えられる。両者を1枚にまとめた「ホット/コールドフレームグラフ」も作れるが、off-CPUスレッド数がon-CPUスレッド数より2桁多くなりやすいため大半が待ち時間の表示に埋め尽くされ、あまり効果的ではないとされる。(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 5 アプリケーション]] §5.4.1.2, §5.4.2.1) ### 生成パイプラインと特徴(6章) CPUフレームグラフの生成は、Linux 2.6〜4.8では`perf record`でスタックをサンプリングし`perf.data`に書き込み、`perf script`で複数行スタックとして読み出し、`stackcollapse-perf.pl`で1行にまとめて`flamegraph.pl`に渡す。Linux 4.9以降はBPFベースの`profile.py`がカーネルメモリでスタック数を直接計算し、中間ファイルを介さずに1行スタックを生成できるためストレージI/Oのオーバーヘッドを避けられる。Linux 5.8以降は`perf script report flamegraph`でperf単体でもフレームグラフを直接出力できる(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]] §6.5.4.1, §6.6.13.3)。 フレームグラフの特徴は、個々のボックスがスタック内の関数(スタックフレーム)を表し、y軸がスタックの深さ(最上段がon-CPUの関数)、x軸がサンプル数(左右の順序はアルファベット順で時系列ではない)、ボックス幅がon-CPUだったかその呼び出し元だった時間の合計を表すことである。色は色相(コードタイプ: 赤=ネイティブユーザーレベル、オレンジ=ネイティブカーネルレベル、黄=C++、緑=インタープリタ関数、水色=インライン関数)・彩度(関数名のハッシュで隣接する塔を見分ける)・背景色(グラフ種別を示す。CPUフレームグラフは黄色、off-CPU/I/Oフレームグラフは青、メモリフレームグラフは緑)の3要素で構成される。SVG出力はJavaScriptによる対話的操作(クリックでズーム、Ctrl-Fでサーチ)に対応し、サーチではマッチしたスタックの全体比率も表示される(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]] §6.7.3.1〜§6.7.3.3)。 解釈の実践的な手順として、著者は(1)上から下(葉から根)に見て大きな「高原」(同じ関数が多くのサンプルでon-CPUになっている箇所)を探す、(2)下から上に見てコードの階層構造(呼び出し元)を理解する、(3)よりていねいに上から下を見て分散した共通のCPU消費パターン(ロック競合等)を探す、という3ステップを挙げる。3番目のステップでは、マージの順序を逆にして葉から根に向かうアイシクルチャートにすると見つけやすくなる(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]] §6.5.4.2)。 FlameScopeは秒未満オフセットヒートマップとフレームグラフを結合したNetflix製のオープンソースツールで、ヒートマップ上で時間範囲(秒未満も可)を選択するとその範囲だけのフレームグラフを表示する。30秒のプロファイル中の100m秒の摂動は全体フレームグラフの幅の0.3%にしかならず埋もれてしまうが、FlameScopeのヒートマップでは高さの1/10の縦棒として視覚化され、選択して原因コードパスを特定できる(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]] §6.7.4)。 ### perf(1)自体によるフレームグラフ生成(13章) perf(1) のフレームグラフサポートは Linux 5.8 で追加され、`perf script report flamegraph` により中間ツールを介さず perf 単体で SVG を直接生成できる(6章が説明する生成パイプラインの到達点にあたる)。広く使われているフレームグラフ作成ツールは著者自身のもの(flamegraph.pl)と d3-flame-graph の2つで、いずれも `perf script` の出力を可視化する。フレームグラフはスタックトレースを可視化する手法全般であり、CPU プロファイリング以外にも、perf(1) で収集したあらゆるスタックトレース(例: コンテキストスイッチイベント時のスタックトレースでスレッドが CPU を手放した理由を知る、ブロック I/O 発生時のスタックトレースでどのコードパスがディスク I/O を発行したか知る)に適用できる。(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 13 perf]] §13.11.1) ## 横断的知見 - **「Linux 5.8 で perf(1) 単体生成に対応した」という到達点は、6章と13章で相互補完的に確認できる**: 6章はフレームグラフ生成パイプラインの歴史(Linux 2.6〜4.8のperf経由 → 4.9以降のBPF直接計算 → 5.8以降のperf単体生成)を包括的に図解するが、「広く使われるツールは著者自身のものとd3-flame-graphの2つ」という道具立ての整理は13章が明示的に述べている。両者を合わせると、フレームグラフの生成手段は「データ収集元(perf/BPF)」と「SVG化ツール(flamegraph.pl/d3-flame-graph)」の2軸で独立に選択できることが分かる。(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]] §6.5.4.1, [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 13 perf]] §13.11.1) - **フレームグラフの適用対象は「CPU プロファイリングの副産物」から「perf(1) が収集するあらゆるスタックトレースの汎用可視化手法」へ一般化されている**: 5章は on-CPU/off-CPU の2種類のフレームグラフを個別の用途として説明するが、13章はこれをさらに一般化し、コンテキストスイッチイベントやブロック I/O イベントなど「perf(1) で収集したあらゆるスタックトレース」を可視化できるとする。特定リソース向けのフレームグラフ(5章)は、この汎用フレームワーク(13章)の具体例として位置づけ直せる。(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 5 アプリケーション]], [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 13 perf]] §13.11.1) - CPUフレームグラフの解釈手順(幅の広い「高原」と「塔」に注目する)は1章の導入的な説明(§1.7.2)と5章のMySQLの実例(§5.4.1.1)で一致しており、加えて5章は関数名の断片(ext4/blk/TCP/utex/alloc)から他リソースの手がかりを読み取る実践的な語彙を追加している。CPUフレームグラフ単体では、ブロックされon-CPUに戻ってこないoff-CPU時間そのものは見えないため、on-CPU/off-CPUの2種類のフレームグラフを組み合わせて初めてコードパスの時間消費を完全に捉えられる、という補完関係が明確になった。(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 1 イントロダクション]], [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 5 アプリケーション]]) - 1章・5章が読み方の実例を積み重ねるのに対し、6章は生成パイプライン(perf/BPFの内部処理)・色の設計原理(色相/彩度/背景色の役割分担)・解釈の3ステップ手順という「方法論としてのフレームグラフ」を体系化している。3つの章は「実例で読み方を学ぶ」層と「原理を理解する」層が補完し合う構成になっており、6章の3ステップ解釈法(高原を探す→階層構造を理解する→分散した共通パターンを探す)は1章・5章の個別実例に共通する暗黙の読み方を明文化したものと言える。(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 1 イントロダクション]], [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 5 アプリケーション]], [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]] §6.5.4.2) - BPFベースの生成パイプライン(profile.py→1行スタック→flamegraph.pl)は、5章のoff-CPUフレームグラフ生成(offcputime等のBCC/BPFツール)と同じ「中間ファイルを介さずカーネルメモリでサマリーを作る」設計思想を共有しており、ストレージI/Oオーバーヘッドの回避というBPF移行の動機が、on-CPU・off-CPUの両フレームグラフで一貫している。(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 5 アプリケーション]], [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]] §6.5.4.1) - **『詳解 システム・パフォーマンス 第2版』が体系化する解釈手順(高原を探す→階層構造を理解する→分散パターンを探す)は、Honeycombの実務事例で「頻繁に呼ばれ中程度の実行時間を持つ関数」「根に近く自身の時間が長い関数」という優先順位づけの言葉で言い換えられている**: 『詳解 システム・パフォーマンス 第2版』6章がフレームグラフの読み方を一般的な3ステップとして提示するのに対し、`Observability Engineering`第2版第20章は同じ読み方を「最適化対象の選び方」という実務判断の言葉で表現し直す。Honeycombの2つの実例(regexp.Compileバグ、Retrieverのjsonpbエンコード)はいずれも「頻繁に呼ばれる」に該当し、著者らはこれを最も費用対効果の高い最適化対象だと位置づける。異なる書籍が独立に同じ読み方の指針へ収束していることが分かる。(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]] §6.5.4.2, [[@2026__OReilly__Observability Engineering 2E - Chapter 20 Performance Engineering with Observability]]) - **フレームグラフが「発見」ではなく「検証」の道具として使われる場面がHoneycombの事例に加わる**: 『詳解 システム・パフォーマンス 第2版』の実例は主にオンデマンドの障害調査(6章・16章)や実験(12章)でのフレームグラフ生成を扱うが、`Observability Engineering`第2版第20章のHoneycomb事例は、トレーシングで「どのリクエストが遅いか」という仮説を立てたのちにフレームグラフで「なぜ遅いか」を内側関数レベルまで検証するという2段階の使い方を明示する。フレームグラフ単体の解釈手法(高原・塔を探す)は両ソースで共通するが、フレームグラフを取得するに至った動線(場当たり的な障害調査 対 トレーシングによる絞り込みの後段)が異なる点は、フレームグラフというツール自体の解釈と、それを他のオブザーバビリティシグナルとどう組み合わせて起動するかという運用設計が独立した論点であることを示す。(Source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]], [[@2026__OReilly__Observability Engineering 2E - Chapter 20 Performance Engineering with Observability]]) ## 未解決の問い - [[継続的プロファイリング]]製品(Polar Signals、Pyroscope等)はフレームグラフの表現をどのように発展させているか(差分フレームグラフ、時系列での変化の可視化など)。 - BPF([[BPF]])・DTrace([[DTrace]])のようなトレーシング基盤から取得したスタックサンプルを、フレームグラフ生成パイプラインへどう統合しているか、実装レベルでの比較はあるか。 - ホット/コールドフレームグラフ(on-CPU/off-CPU統合)が「効果的ではない」とされる問題を、表示側の工夫(重み付け・フィルタリング)で緩和した実装例はあるか。 - FlameScopeの秒未満オフセットヒートマップ+フレームグラフという組み合わせは、CPU以外のリソース(ディスクI/O・ネットワーク)のプロファイルにも同様に適用され有効性を持つか。 - 13章が示すコンテキストスイッチ/ブロックI/O向けフレームグラフの実例(具体的なコマンド列やスタック解釈)は他章にどの程度詳しく記載されているか。汎用性の主張を具体的な生成手順まで裏付けられるか。 ## 関連 - source: [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 1 イントロダクション]] / [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 5 アプリケーション]] / [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]] / [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 13 perf]] / [[@2026__OReilly__Observability Engineering 2E - Chapter 20 Performance Engineering with Observability]] - entity: [[Brendan Gregg]] / [[perf]] / [[Honeycomb.io]] / [[Retriever]] - concept: [[継続的プロファイリング]] / [[BPF]] / [[DTrace]] / [[スレッド状態分析]] / [[パフォーマンスエンジニアリング]] ## 出典 - [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 1 イントロダクション]](§1.7.2、図1-6 CPUフレームグラフの例) - [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 5 アプリケーション]](§5.4.1.1〜§5.4.1.2 CPUフレームグラフ、§5.4.2.1〜§5.4.2.2 off-CPU時間のフレームグラフ) - [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 6 CPU]](§6.5.4.1 生成パイプライン・§6.5.4.2 解釈方法・§6.6.13.3 perfによる生成・§6.7.3 特徴/色/対話操作・§6.7.4 FlameScope) - [[@2023__OReillyJapan__詳解 システム・パフォーマンス 第2版 - Chapter 13 perf]](§13.11.1 perf(1)単体でのフレームグラフ生成・Linux 5.8対応・作成ツールの整理) - [[@2026__OReilly__Observability Engineering 2E - Chapter 20 Performance Engineering with Observability]]("The Case for Performance Engineering"、"Blending Performance Engineering and Observability"、Honeycombの3実例)