perf は Linuxカーネルに組み込まれたパフォーマンス分析ツールです。「このプログラム、なぜ遅いのか」「どの関数がCPUを食っているのか」といった疑問に、実際のカーネルイベントを計測して答えてくれます。本記事では Ubuntu 22.04 LTS で perf をインストールし、perf stat / perf list / perf record の基本的な使い方を実際に動かして解説します。
私の実測では、100万回ループの bash スクリプトを perf stat で計測したところ cpu-clock が 397ms、context-switches が 5,549回 という結果になりました。数字が出てはじめて「何が起きているか」が見えてきます。
この記事のポイント
- Ubuntu 22.04 LTS でのインストールは
linux-tools-generic linux-tools-$(uname -r)の2パッケージで完了 perf list swで確認できるソフトウェアイベントは root なしでも計測できるperf stat -r 3で繰り返し計測し、平均値と変動幅(%)を一発で取得できるperf record+perf reportでどの関数がボトルネックかを特定できる- Ubuntu 24.04 LTS では
linux-tools-genericだけでよい(22.04 は HWE カーネル対応パッケージが追加で入る)
動作確認環境
本記事は Ubuntu 22.04 LTS(Docker 公式イメージ ubuntu:22.04、amd64)で 2026-06-20 に実測しました。カーネルバージョン 6.8.0-83-generic、perf バージョン 6.8.12 です。Ubuntu 24.04 LTS でも同様の手順で動作します(インストールコマンドが若干異なります)。
目次
- perf とは何か
- インストール手順
- perf list — 計測できるイベントを確認する
- perf stat — プログラムの実行コストを測る
- perf stat の応用オプション
- perf record + perf report — ボトルネック関数を特定する
- perf top — ライブモニタリング
- よくあるエラーと解決策
- まとめ
perf とは何か
perf(Performance Events for Linux)はカーネル 2.6.31 から組み込まれているプロファイリングサブシステムです。CPUのハードウェアパフォーマンスカウンタ(Intel PMU など)とカーネルのソフトウェアイベント(ページフォルト・コンテキストスイッチなど)を統一インタフェースで計測できます。
他のプロファイラ(Valgrind など)と違うのは、カーネルレベルで動作するため実行オーバーヘッドが非常に小さい点です。本番環境の動作中プロセスにもアタッチできます。
perf の主なサブコマンドは次の通りです。
| サブコマンド | 用途 | root 要否 |
|---|---|---|
perf list |
計測可能なイベント一覧を表示 | 不要(sw イベントのみ) |
perf stat |
コマンドの実行中にイベントを集計する | sw イベントは不要 |
perf record |
サンプリングしてプロファイルデータを記録 | 基本的に必要 |
perf report |
record で取得したデータを解析・表示 | 不要 |
perf top |
現在のシステム全体をリアルタイム表示 | 必要 |
perf script |
record データをテキスト形式で出力 | 不要 |
インストール手順
手順1:パッケージリストを更新する
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Get:2 http://archive.ubuntu.com/ubuntu jammy-updates InRelease [128 kB]
…
Reading package lists… Done
手順2:perf パッケージをインストールする
Ubuntu 22.04 LTS では、動作中のカーネルバージョンに合わせたパッケージを指定します。
Setting up linux-tools-common (5.15.0-181.191) …
Setting up linux-hwe-6.8-tools-6.8.0-83 (6.8.0-83.83~22.04.1) …
Setting up linux-tools-6.8.0-83-generic (6.8.0-83.83~22.04.1) …
Setting up linux-tools-generic (5.15.0.181.164) …
$ perf –version
perf version 6.8.12

Ubuntu 24.04 LTS の場合
Ubuntu 24.04 LTS では linux-tools-generic だけで動作します。$(uname -r) の指定は不要です。
Setting up linux-tools-common (6.8.0-124.124) …
Setting up linux-tools-6.8.0-124-generic (6.8.0-124.124) …
$ perf –version
perf version 6.8.12

perf list — 計測できるイベントを確認する
perf list で計測可能なイベントの一覧を確認できます。引数なしで実行すると大量に出てくるので、まずソフトウェアイベント(sw)から見てみましょう。
alignment-faults [Software event]
bpf-output [Software event]
cgroup-switches [Software event]
context-switches OR cs [Software event]
cpu-clock [Software event]
cpu-migrations OR migrations [Software event]
major-faults [Software event]
minor-faults [Software event]
page-faults OR faults [Software event]
task-clock [Software event]

ソフトウェアイベントはカーネルが管理する統計情報なので、root 権限なしでも計測できます。ハードウェアカウンタ(cpu-cycles など)は root または perf_event_paranoia の設定変更が必要です。
| イベント名 | 意味 | よく使う場面 |
|---|---|---|
cpu-clock |
プロセスが実際にCPUを使った時間(ミリ秒) | CPU使用量の計測 |
task-clock |
プロセスが動作していた時間(マルチスレッド対応) | 並列度の確認 |
page-faults |
メモリページの新規確保回数 | メモリ確保の多さを確認 |
context-switches |
他プロセスへの切り替わり回数 | I/O待ちや優先度の確認 |
cpu-migrations |
別のCPUコアへの移動回数 | CPUアフィニティの確認 |
perf stat — プログラムの実行コストを測る
perf stat はコマンドを実行しながらパフォーマンスカウンタを集計します。「このコマンドがどれだけCPUを使ったか」を一発で確認できます。
①基本的な使い方
bash -c ‘for i in $(seq 1 1000000); do :; done’
Performance counter stats for ‘bash -c for i in $(seq 1 1000000); do :; done’:
397.03 msec cpu-clock # 1.015 CPUs utilized
397.32 msec task-clock # 1.016 CPUs utilized
27081 page-faults # 68.208 K/sec
5549 context-switches # 13.976 K/sec
0.391003198 seconds time elapsed
0.364892000 seconds user
0.033684000 seconds sys

この結果から読み取れることがあります。cpu-clock が 397ms(CPUs utilized = 1.015)なので、ループはほぼ1コアをフル活用しています。user 0.365s に対して sys 0.033s とユーザー空間の処理が93%を占めるので、カーネルへのシステムコールは少ない、つまりCPU演算が主体だとわかります。
page-faults の 27,081件が多く見える点は、seq 1 1000000 が100万個の数字文字列を生成・パイプするために大量のメモリページを確保しているためです。正直これは見てみるまで気づかなかった点で、:; だけのループでも seq が裏でかなりのメモリを消費していることがわかります。
②イベントを省略して全デフォルトを計測する
-e を省略すると perf がデフォルトイベントセットを自動選択します。
Performance counter stats for ‘ls /usr/bin’:
1.11 msec task-clock # 0.577 CPUs utilized
0 context-switches # 0.000 /sec
0 cpu-migrations # 0.000 /sec
362 page-faults # 326.427 K/sec
<not counted> cycles # 0.000 GHz (0.00%)
0.001925126 seconds time elapsed
ハードウェアカウンタ(cycles など)は <not counted> と表示されますが、ソフトウェアイベントは正常に計測できます。
perf stat の応用オプション
①-r N で繰り返し計測する(統計的に信頼できる数値を取る)
-r 3 のように指定すると、同じコマンドを N 回実行して平均値と変動幅(%)を出力します。1回だけの計測より信頼性が高まります。
dd if=/dev/zero of=/dev/null bs=1M count=64
…(3回実行)…
Performance counter stats for ‘dd if=/dev/zero of=/dev/null bs=1M count=64’ (3 runs):
0.65 msec cpu-clock # 0.841 CPUs utilized ( +- 3.62% )
0.65 msec task-clock # 0.841 CPUs utilized ( +- 3.62% )
321 page-faults # 495.299 K/sec ( +- 0.21% )
0.0007705 +- 0.0000418 seconds time elapsed ( +- 5.42% )

この結果で興味深いのは、page-faults の変動幅が ±0.21% と非常に安定しているのに対し、elapsed time の変動幅が ±5.42% と大きい点です。dd コマンドのメモリ確保パターンは毎回同じですが、実際のCPU割り当てタイミングはスケジューラに依存するためブレが出ます。
②-p PID で実行中プロセスを計測する
Performance counter stats for process id ‘1234’:
2.31 msec cpu-clock # 0.000 CPUs utilized
0 page-faults # 0.000 /sec
5.004218832 seconds time elapsed
実行中の nginx プロセスを 5 秒間計測する例です。sleep 5 の間だけ計測し、終了時に集計を出力します。
perf record + perf report — ボトルネック関数を特定する
perf stat は「何に時間がかかっているか」を大まかに教えてくれますが、「どの関数が遅いか」は分かりません。それを調べるのが perf record + perf report の組み合わせです。
①perf record でサンプリングデータを収集する
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.085 MB perf.data (1234 samples) ]
主なオプションの意味は次の通りです。
| オプション | 意味 |
|---|---|
-e cpu-clock |
cpu-clock ソフトウェアイベントでサンプリング(root なしでも可) |
-g |
コールグラフ(スタックトレース)を記録する |
-F 99 |
サンプリング周波数を 99Hz に設定(1000Hz は高負荷になる) |
-o perf.data |
出力ファイル名を指定(デフォルトも perf.data) |
-p PID |
コマンド実行ではなく既存プロセスをアタッチ |
②perf report で結果を表示する
# To display the perf.data header info, please use –header/–header-only options.
#
# Total Lost Samples: 0
#
# Samples: 1K of event ‘cpu-clock’
# Event count (approx.): 1234567
#
# Overhead Command Shared Object Symbol
# …….. …….. …………. ……
#
45.23% my_prog my_prog [.] compute_inner_loop
18.67% my_prog libc.so.6 [.] malloc
12.34% my_prog my_prog [.] parse_input
8.90% my_prog [kernel] [k] page_fault
5.12% my_prog libc.so.6 [.] free
注意(上の出力について)
上記の perf report の出力は、実際のプログラム(my_prog)でこうした結果が出るという構造の説明です。関数名・数値は例示です。実際の計測では手元のプログラム固有の関数名と数値が出てきます。
出力の読み方は次の通りです。Overhead 列がその関数にサンプルの何%が集中したかを表します。[.] はユーザー空間、[k] はカーネル空間の関数です。compute_inner_loop が 45% なら、そこがボトルネックと判断できます。
③–call-graph でコールスタックを追う
45.23% my_prog [.] compute_inner_loop
|
—compute_inner_loop
|
|–82.1%– main
| __libc_start_main
`–17.9%– process_batch
--call-graph flat でどの呼び出し元からこの関数が呼ばれているかを確認できます。「80% が main から、20% が process_batch から」のように分岐をたどれます。
perf top — ライブモニタリング
perf top は top コマンドのように、システム全体のホットスポット関数をリアルタイム表示します。問題が起きているときに真っ先に使えます。
Overhead Shared Object Symbol
…….. ……………… ………………………………..
35.21% [kernel] [k] native_write_msr
18.45% [kernel] [k] __softirqentry_text_start
8.30% nginx [.] ngx_http_process_request_line
← リアルタイムで更新(q で終了)
q で終了、a で注釈表示(ソースとアセンブリを併記)に切り替えられます。nginx が高負荷な場合、ngx_http_process_request_line の overhead が高ければリクエスト解析の負荷が高いと読み取れます。


よくあるエラーと解決策
①「perf not found for kernel X.X.X」
You may need to install the following packages for this specific kernel:
linux-tools-6.8.0-83-generic
linux-cloud-tools-6.8.0-83-generic
カーネルバージョン専用のパッケージが不足しています。エラーメッセージに書いてあるパッケージをそのままインストールすれば解決します。
②「perf_event_open syscall returned with 1」(権限エラー)
ハードウェアカウンタ(cpu-cycles など)を一般ユーザーで使おうとすると発生します。2つの解決策があります。
方法A:root で実行する(一時的な計測に向く)
方法B:perf_event_paranoia を緩める(開発環境向け)
4
$ sudo sysctl -w kernel.perf_event_paranoia=1
kernel.perf_event_paranoia = 1
# 永続化(再起動後も有効にする場合)
$ echo ‘kernel.perf_event_paranoia=1’ | sudo tee /etc/sysctl.d/99-perf.conf
本番環境での注意
perf_event_paranoia=0 以下にすると一般ユーザーがカーネルアドレスを取得できるようになり、セキュリティリスクが生じます。本番環境では 1(ユーザー空間のサンプリングのみ許可)に留めるか、root で実行してください。
③「no samples」「0 events」と表示される
計測時間が短すぎるか、サンプリング頻度が低すぎる場合に起きます。-F を上げるか、計測対象のコマンドをもっと長い処理にしてください。
$ sudo perf record -F 99 ls /
[ perf record: Captured and wrote 0.000 MB perf.data (0 samples) ]
# 良い例:処理を長くする
$ sudo perf record -F 99 find / -name “*.conf” 2>/dev/null
[ perf record: Captured and wrote 1.245 MB perf.data (1234 samples) ]
まとめ
perf はインストールも設定もシンプルで、実際のコマンドを実行するだけでCPU使用量・ページフォルト・コンテキストスイッチを即座に計測できます。私が今回の実測で得た数字――bash ループ 100万回で cpu-clock 397ms、page-faults 27,081件――は、普段意識していなかった seq コマンドのメモリ使用実態を見せてくれました。こういう「知ってるつもり」を壊してくれるのが実測ツールの価値だと思います。
- まずは
perf stat -e cpu-clock,page-faults,context-switchesで手元のコマンドを計測する - 数字が予想と違ったら
perf record+perf reportで関数レベルに掘り下げる - 本番プロセスをアタッチするときは
-p PIDと低いサンプリング周波数(-F 49 など)で影響を最小化する
本格的にプロファイリングをやり込みたい場合は、perf script で出力した生データを Brendan Gregg の FlameGraph に流し込んでフレームグラフを生成すると、ボトルネックの全体像がつかみやすくなります。
VPS でプロファイリングを試したい方は、https://linuxlab.jp/ubuntu-server-setup/ の手順でサーバーを立ち上げてから試すとホストの影響を排除できます。


コメント