perf on Ubuntu — LinuxパフォーマンスプロファイリングツールCLI完全ガイド

Linux知識

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 でも同様の手順で動作します(インストールコマンドが若干異なります)。

目次

  1. perf とは何か
  2. インストール手順
  3. perf list — 計測できるイベントを確認する
  4. perf stat — プログラムの実行コストを測る
  5. perf stat の応用オプション
  6. perf record + perf report — ボトルネック関数を特定する
  7. perf top — ライブモニタリング
  8. よくあるエラーと解決策
  9. まとめ

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:パッケージリストを更新する




ubuntu@linuxlab: ~
$ sudo apt update
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 では、動作中のカーネルバージョンに合わせたパッケージを指定します。




ubuntu@linuxlab: ~
$ sudo apt install -y linux-tools-common linux-tools-generic linux-tools-$(uname -r)
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
linux-tools-generic のインストール実ログと perf version 6.8.12 の確認
linux-tools-generic のインストール実ログと perf version 6.8.12 の確認

Ubuntu 24.04 LTS の場合

Ubuntu 24.04 LTS では linux-tools-generic だけで動作します。$(uname -r) の指定は不要です。




ubuntu@linuxlab: ~ (Ubuntu 24.04 の場合)
$ sudo apt install -y linux-tools-common linux-tools-generic
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
Ubuntu 22.04 vs 24.04 の perf インストール方法と実測バージョン比較
Ubuntu 22.04 vs 24.04 の perf インストール方法と実測バージョン比較

perf list — 計測できるイベントを確認する

perf list で計測可能なイベントの一覧を確認できます。引数なしで実行すると大量に出てくるので、まずソフトウェアイベント(sw)から見てみましょう。




ubuntu@linuxlab: ~
$ 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]
perf list sw の実出力(ソフトウェアイベント一覧)
perf list sw の実出力(ソフトウェアイベント一覧)

ソフトウェアイベントはカーネルが管理する統計情報なので、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を使ったか」を一発で確認できます。

①基本的な使い方




ubuntu@linuxlab: ~
$ perf stat -e cpu-clock,task-clock,page-faults,context-switches \
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
bash ループ 100万回の perf stat 実測結果
bash ループ 100万回の perf stat 実測結果

この結果から読み取れることがあります。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 がデフォルトイベントセットを自動選択します。




ubuntu@linuxlab: ~
$ perf stat ls /usr/bin | head -5
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回だけの計測より信頼性が高まります。




ubuntu@linuxlab: ~
$ perf stat -r 3 -e cpu-clock,task-clock,page-faults \
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% )
perf stat -r 3 の実測値と変動幅
perf stat -r 3 の実測値と変動幅

この結果で興味深いのは、page-faults の変動幅が ±0.21% と非常に安定しているのに対し、elapsed time の変動幅が ±5.42% と大きい点です。dd コマンドのメモリ確保パターンは毎回同じですが、実際のCPU割り当てタイミングはスケジューラに依存するためブレが出ます。

②-p PID で実行中プロセスを計測する




ubuntu@linuxlab: ~
$ sudo perf stat -p $(pgrep nginx) -e cpu-clock,page-faults sleep 5
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 でサンプリングデータを収集する




ubuntu@linuxlab: ~
$ sudo perf record -e cpu-clock -g -F 99 -o perf.data ./my_program
[ 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 で結果を表示する




ubuntu@linuxlab: ~
$ perf report –stdio –no-pager -i perf.data | head -30
# 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 でコールスタックを追う




ubuntu@linuxlab: ~
$ perf report –stdio –call-graph flat,0.5 -i perf.data | head -40
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 toptop コマンドのように、システム全体のホットスポット関数をリアルタイム表示します。問題が起きているときに真っ先に使えます。




ubuntu@linuxlab: ~
$ sudo perf top -e cpu-clock
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 list sw と perf stat -r 3 のターミナルセッション
perf list sw と perf stat -r 3 のターミナルセッション
perf stat bash ループ 100万回のターミナルセッション実測
perf stat bash ループ 100万回のターミナルセッション実測

よくあるエラーと解決策

①「perf not found for kernel X.X.X」




ubuntu@linuxlab: ~
WARNING: perf not found for kernel 6.8.0-83

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

カーネルバージョン専用のパッケージが不足しています。エラーメッセージに書いてあるパッケージをそのままインストールすれば解決します。




ubuntu@linuxlab: ~
$ sudo apt install linux-tools-$(uname -r)

②「perf_event_open syscall returned with 1」(権限エラー)

ハードウェアカウンタ(cpu-cycles など)を一般ユーザーで使おうとすると発生します。2つの解決策があります。

方法A:root で実行する(一時的な計測に向く)




ubuntu@linuxlab: ~
$ sudo perf stat -e cycles ./my_program

方法B:perf_event_paranoia を緩める(開発環境向け)




ubuntu@linuxlab: ~
$ cat /proc/sys/kernel/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 を上げるか、計測対象のコマンドをもっと長い処理にしてください。




ubuntu@linuxlab: ~
# 悪い例:処理が一瞬で終わる
$ 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/ の手順でサーバーを立ち上げてから試すとホストの影響を排除できます。

コメント

タイトルとURLをコピーしました