💻
概念 #システムパフォーマンス #Brendan Gregg #Linux #SRE #読書ノート #CPU #perf #フレームグラフ 📚 詳解 システム・パフォーマンス

詳解 システム・パフォーマンス - 第6章:CPU分析

CPU使用率・スケジューラ・CPI・フレームグラフ・キャッシュミス分析の完全ガイド。perfコマンドを使った実践的なCPUボトルネック調査手順。

CPU の性能指標

指標意味確認コマンド
使用率(%)CPUがビジー状態の割合mpstat, top
runキュー長実行待ちプロセス数(> コア数で飽和)vmstat r列
CPICycles Per Instruction(低いほど効率的)perf stat
コンテキストスイッチCPU切り替え回数(多すぎると問題)vmstat cs列
キャッシュミス率L1/L2/LLC ミスの割合perf stat -d

CPU 分析のフロー

1. 全体の CPU 使用率を確認
   vmstat 1 / mpstat -P ALL 1

2. プロセス別に絞り込む
   pidstat 1 / top

3. プロファイリングで「どの関数が重いか」を特定
   perf record -F 99 -g -p <PID> sleep 30
   perf report

4. フレームグラフで視覚化
   perf script | stackcollapse-perf.pl | flamegraph.pl > flame.svg

5. CPU ハードウェアカウンタで効率を評価
   perf stat -d -p <PID>

基本コマンド

全体の CPU 状況

# 仮想メモリ統計(CPU の大まかな状況)
vmstat 1 5
# us: ユーザーCPU / sy: システムCPU
# id: アイドル / wa: I/O待ちアイドル
# r: runキュー(コア数超えたら飽和)

# コア別の CPU 使用率(どのコアが偏っているか)
mpstat -P ALL 1 5
# %usr + %sys: 実質的な使用率
# %iowait: ディスクI/O待ちで CPU がアイドル → ディスクボトルネック
# %soft: ソフト割り込み(NIC処理が多いと高くなる)

# プロセス別の CPU 使用率(犯人特定)
pidstat 1 5
# %CPU 列を時系列で追う

perf によるプロファイリング

# システム全体の CPU サンプリング(99Hz、30秒)
sudo perf record -F 99 -a -g sleep 30

# 特定プロセスのプロファイリング
perf record -F 99 -g -p <PID> sleep 30

# 結果の確認
perf report
# → キー操作:Enter で展開、a でソースアノテーション

# CPU 使用率の高い関数 TOP 10(テキスト出力)
perf report --stdio --sort=symbol | head -30

フレームグラフ(Flame Graph)

CPU プロファイルを視覚的に表現する最強のツール。幅の広い箱 = CPU消費が多い関数

生成手順

# 1. FlameGraph ツールをクローン
git clone https://github.com/brendangregg/FlameGraph

# 2. perf でスタックを収集(60秒)
sudo perf record -F 99 -a -g -- sleep 60

# 3. スクリプト展開
perf script > out.perf

# 4. スタック折り畳み
./FlameGraph/stackcollapse-perf.pl out.perf > out.folded

# 5. SVG 生成
./FlameGraph/flamegraph.pl out.folded > flame.svg
open flame.svg  # ブラウザで開く

# 2〜5を一行で
perf script | ./FlameGraph/stackcollapse-perf.pl | \
  ./FlameGraph/flamegraph.pl --colors=hot --title="CPU Profile" > flame.svg

フレームグラフの読み方

[main]                                    ← エントリーポイント(下)
  [http_handler]
    [db_query]  [json_serialize]
      [pg_exec]    [marshal]  [strconv]
        [socket_write]
  • 下から上に呼び出し関係(下が呼び出し元)
  • 幅が広いほど CPU を多く使っている
  • **一番上(葉)**が実際に CPU 時間を消費している関数
  • 細長い塔:深い再帰や深いコールチェーン
  • 広くて浅い:特定の関数が直接 CPU を使い切っている

CPU ハードウェアカウンタ

CPU 内部の実行効率を測定する。チューニング効果の評価に使う。

# 主要カウンタの一括取得
perf stat -d -p <PID> sleep 10

# 出力例:
#  10,000,000,000  cycles                   # 実行クロック数
#   5,000,000,000  instructions             # 命令数
#            0.50  insn per cycle           # IPC(1以下は非効率)
#     100,000,000  cache-references
#      50,000,000  cache-misses             # 50%ミス率は非常に高い
#     500,000,000  branches
#       5,000,000  branch-misses            # 1%の分岐予測ミス

# 特定カウンタの指定
perf stat -e cycles,instructions,cache-references,cache-misses,\
L1-dcache-loads,L1-dcache-load-misses,LLC-loads,LLC-load-misses \
-p <PID> sleep 10

CPI(Cycles Per Instruction)の解釈

CPI = cycles / instructions

CPI < 1.0  → 効率的(スーパースカラで並列実行)
CPI 1〜2   → 通常の範囲
CPI 2〜4   → やや非効率(キャッシュミスや分岐予測ミスが多い可能性)
CPI > 4    → 非効率(メモリアクセス待ちやストールが多い)

CPU 関連の問題パターンと対処

① CPU 使用率が高い

# 犯人プロセスを特定
pidstat 1 10

# どの関数が重いか
perf record -F 99 -g -p <PID> sleep 30
perf report --stdio | head -30

# フレームグラフで全体像を把握
perf script | ./FlameGraph/stackcollapse-perf.pl | ./FlameGraph/flamegraph.pl > flame.svg

② 特定コアだけ高い(偏り)

mpstat -P ALL 1
# 1コアだけ 100% = シングルスレッドのボトルネック
# マルチスレッド化が必要、または IRQ アフィニティの問題

# NIC の割り込みが1コアに集中していないか
cat /proc/interrupts | grep eth

③ iowait が高い(I/O待ちでCPUがアイドル)

# これは CPU 問題ではなくディスク問題
iostat -xz 1
# → ch09(ディスク分析)へ

④ コンテキストスイッチが多い

vmstat 1 5  # cs 列
pidstat -w 1 5  # cswch/s(自発的)/ nvcswch/s(非自発的)

# 非自発的が多い → CPU が足りずに奪われている
# 自発的が多い → I/O 待ちやロック待ちが多い

⑤ steal time が高い(仮想化環境)

vmstat 1 5  # st 列
# st > 5〜10% → ホストの CPU 過負荷(ノイジーネイバー)
# → ch11(クラウド)へ

出典: 詳解 システム・パフォーマンス 第2版 Brendan Gregg著