サーバーが突然重くなった!アプリケーションのレスポンスが遅い!
そんな時、皆さんはどんなツールを使って原因を調べていますか?
多くのエンジニアがまず思い浮かべるのは、topやhtop、vmstatといった基本的な監視ツールですよね。これらのツールも確かに有用ですが、実は「なぜ遅いのか」という根本的な原因までは教えてくれません。
そこで登場するのが「perf」です!
perfは、Linuxカーネルに標準で含まれているパフォーマンス分析ツールで、従来のツールでは見えない深い部分まで詳細に分析できます。特に、CPUプロファイリングやメモリアクセスパターンの解析において、その威力を発揮します。
今回は、そんなperfコマンドを使ったプロファイリングの実践的な活用術について、分かりやすく解説していきます。
なぜperfプロファイリングが重要なのか
従来の監視ツールでは見えない部分
topやhtopコマンドを使ったことがある方なら分かると思いますが、これらのツールで分かるのは「どのプロセスがCPUを使っているか」という表面的な情報だけです。
例えば、以下のような状況を考えてみてください:
# topコマンドで確認
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1234 apache 20 0 500000 50000 10000 R 95.0 2.5 5:23.45 httpd
この結果を見ると「httpdプロセスがCPUを95%使っている」ことは分かります。でも、なぜそんなにCPUを使っているのでしょうか?
- 計算処理が重いのか?
- メモリアクセスが多発しているのか?
- I/O待機が発生しているのか?
- それとも、プログラム内の特定の関数がボトルネックになっているのか?
従来のツールでは、この「なぜ」の部分が見えないんです。
perfが実現する詳細なプロファイリング
perfツールを使うと、以下のような詳細な情報を取得できます:
1. 関数レベルでの実行時間分析
- どの関数が最も時間を消費しているか
- プログラム内のホットスポット特定
2. ハードウェアレベルでの分析
- CPUキャッシュミス率
- メモリアクセスパターン
- 分岐予測の成功率
3. システムコール分析
- どのシステムコールが頻繁に呼ばれているか
- I/O待機の詳細な内訳
この分野を本格的に学びたい方には、Brendan Gregg氏の「詳解 システム・パフォーマンス 第2版」が最適な学習書籍です。
この書籍では、perfを含む様々なパフォーマンス分析ツールの使い方が、実践的な事例とともに詳しく解説されています。特に、プロファイリングの理論的背景から実際の運用まで、体系的に学べる貴重な資料です。
perfコマンドの基本操作をマスターしよう
インストールと初期設定
まずは、perfコマンドを使える環境を整えましょう。
Ubuntu/Debianの場合:
# perfツールのインストール
sudo apt update
sudo apt install linux-tools-common linux-tools-generic
# カーネルバージョンに対応したperfツールをインストール
sudo apt install linux-tools-$(uname -r)
CentOS/RHELの場合:
# perfツールのインストール
sudo yum install perf
# または、新しいバージョンでは
sudo dnf install perf
権限設定の確認:
perfを一般ユーザーで実行するには、カーネルパラメータの調整が必要な場合があります:
# 現在の設定確認
cat /proc/sys/kernel/perf_event_paranoid
# 設定変更(一時的)
echo 1 | sudo tee /proc/sys/kernel/perf_event_paranoid
# 永続的な設定変更
echo 'kernel.perf_event_paranoid = 1' | sudo tee -a /etc/sysctl.conf
基本的なサブコマンドの使い分け
perfには多くのサブコマンドがありますが、まずは以下の主要なものから覚えましょう:
1. perf top – リアルタイム監視
# システム全体のリアルタイム分析
perf top
# 特定のプロセスのみ監視
perf top -p [PID]
# 特定のCPUコアのみ監視
perf top -C 0,1
2. perf record – プロファイルデータ収集
# システム全体のプロファイル収集(10秒間)
perf record -g sleep 10
# 特定のコマンド実行時のプロファイル
perf record -g ./my_program
# 特定のプロセスを指定時間監視
perf record -g -p [PID] sleep 30
3. perf report – 収集データの分析
# 収集したデータの詳細分析
perf report
# より詳細な表示
perf report --stdio
# コールグラフ表示
perf report -g graph
4. perf stat – 統計情報取得
# 基本的なパフォーマンス統計
perf stat ./my_program
# 詳細なハードウェア統計
perf stat -e cache-misses,cache-references,cycles,instructions ./my_program
CPU プロファイリングの実践テクニック
perf top でリアルタイム分析
perf topは、システムで実行中の関数をリアルタイムで表示するツールです。topコマンドのperf版だと考えると分かりやすいでしょう。
基本的な使い方:
# システム全体の分析開始
perf top
実行すると、以下のような画面が表示されます:
Samples: 1K of event 'cycles:ppp', Event count (approx.): 324673
Overhead Shared Object Symbol
15.00% [kernel] [k] _raw_spin_lock
10.50% [kernel] [k] __schedule
8.75% libpthread.so.0 [.] __pthread_mutex_lock
7.25% [kernel] [k] copy_user_enhanced_fast_string
5.50% [kernel] [k] page_fault
この結果の読み方:
- Overhead: 全体のCPU時間に占める割合
- Shared Object: 実行ファイルやライブラリ名
- Symbol: 関数名
- [k]: カーネル空間の関数
- [.]: ユーザー空間の関数
便利なオプション:
# 関数名でフィルタリング
perf top -s symbol --symbol-filter=malloc
# 特定のCPUコアのみ監視
perf top -C 0
# カーネル関数を除外
perf top --hide_kernel_symbols
perf record/report による詳細分析
より詳細な分析を行いたい場合は、perf recordでデータを収集し、perf reportで分析します。
プロファイルデータの収集:
# システム全体を10秒間プロファイリング
perf record -g sleep 10
# 特定のプロセスを30秒間プロファイリング
perf record -g -p 1234 sleep 30
# CPU集約的なプログラムの実行時プロファイリング
perf record -g ./cpu_intensive_program
収集したデータの分析:
# 基本的な分析結果表示
perf report
# より詳細な情報をテキスト形式で表示
perf report --stdio
# 特定の関数でフィルタリング
perf report --symbol-filter=function_name
コールグラフ分析でボトルネック特定
コールグラフ分析は、関数の呼び出し関係とそれぞれの実行時間を可視化する機能です。これにより、どの処理パスがボトルネックになっているかを特定できます。
# コールグラフ付きでプロファイリング
perf record -g --call-graph dwarf ./my_program
# コールグラフ表示
perf report -g graph,0.5,caller
コールグラフの読み方:
- 45.00% 10.00% my_program my_program [.] main
- 35.00% main
- 30.00% process_data
- 25.00% calculate_result
+ 20.00% heavy_computation
+ 5.00% memory_access
+ 5.00% file_io
+ 10.00% __libc_start_main
この結果から、heavy_computation
関数が全体の20%の時間を消費していることが分かります。
perfを使った詳細なプロファイリング手法については、「詳解 システム・パフォーマンス 第2版」の第6章「CPU」で詳しく学ぶことができます。
特に、フレームグラフの作成方法や、マイクロベンチマークとの組み合わせ技術は、実際の業務で非常に役立つ内容です。
メモリアクセスとI/O プロファイリング
キャッシュミスとメモリアクセスパターン解析
現代のCPUでは、メモリアクセスがパフォーマンスに大きな影響を与えます。perfを使うと、キャッシュミス率やメモリアクセスパターンを詳細に分析できます。
キャッシュ関連の統計情報取得:
# L1/L2/L3キャッシュの統計
perf stat -e L1-dcache-loads,L1-dcache-load-misses,LLC-loads,LLC-load-misses ./my_program
# より詳細なメモリ統計
perf stat -e cache-references,cache-misses,dTLB-loads,dTLB-load-misses ./my_program
結果の例:
Performance counter stats for './memory_test':
1,234,567 L1-dcache-loads
45,678 L1-dcache-load-misses # 3.70% of all L1-dcache hits
234,567 LLC-loads
12,345 LLC-load-misses # 5.26% of all LL-cache hits
2.345678 seconds time elapsed
この結果から、L1キャッシュミス率が3.70%、ラストレベルキャッシュ(LLC)ミス率が5.26%であることが分かります。
メモリアクセスパターンの詳細分析:
# メモリアクセスに特化したプロファイリング
perf record -e cache-misses -g ./my_program
perf report --sort=symbol,dso
# NUMA関連の分析
perf record -e node-loads,node-load-misses -g ./my_program
ディスクI/O プロファイリングの実践
I/O関連のパフォーマンス問題も、perfで詳細に分析できます。
I/O関連イベントの監視:
# ファイルシステム関連のシステムコール監視
perf record -e 'syscalls:sys_enter_read,syscalls:sys_enter_write' ./io_program
# ブロックI/O関連イベント
perf record -e 'block:block_rq_issue,block:block_rq_complete' ./disk_intensive_program
ページフォルト分析:
# ページフォルト詳細分析
perf record -e page-faults -g ./memory_hungry_program
perf report --sort=symbol
# マイナーフォルトとメジャーフォルト
perf stat -e page-faults,minor-faults,major-faults ./my_program
I/O待機時間の分析:
# スケジューラ関連イベント
perf record -e 'sched:sched_switch,sched:sched_stat_sleep' -g ./my_program
# I/O待機プロセスの特定
perf record -e 'sched:sched_stat_iowait' -g sleep 10
実際のトラブルシューティング事例
高CPU使用率の原因分析
実際の現場でよくある「CPU使用率が異常に高い」問題を、perfを使って解決する手順を見てみましょう。
ステップ1: 現状把握
# まず基本的な統計情報を確認
perf stat -a sleep 5
# リアルタイムでホットスポットを確認
perf top
ステップ2: 詳細プロファイリング
# システム全体を30秒間プロファイリング
perf record -g -a sleep 30
# 結果分析
perf report --stdio > profile_analysis.txt
ステップ3: 特定プロセスの詳細分析
# 問題のプロセスIDが1234の場合
perf record -g -p 1234 sleep 60
# コールグラフで詳細分析
perf report -g graph,0.5,caller
事例:Webサーバーの性能問題
あるWebサーバーでCPU使用率が90%を超える問題が発生しました。perfで分析した結果:
# perf top の結果(一部抜粋)
Overhead Shared Object Symbol
25.00% libssl.so.1.1 [.] EVP_EncryptUpdate
20.00% [kernel] [k] _raw_spin_lock
15.00% httpd [.] ap_process_request
10.00% libpcre.so.1 [.] pcre_exec
この結果から、SSL暗号化処理(EVP_EncryptUpdate)が全体の25%を占めていることが判明。さらに詳細分析により、不適切な暗号化アルゴリズムの選択が原因であることが分かりました。
アプリケーションレスポンス遅延の解決
レスポンス遅延の問題では、I/O待機や不適切なメモリアクセスパターンが原因となることが多いです。
分析手順:
# I/O関連の詳細分析
perf record -e 'syscalls:sys_enter_*' -g ./slow_application
# メモリアクセスパターン分析
perf record -e cache-misses,page-faults -g ./slow_application
# スケジューライベント分析
perf record -e 'sched:*' -g ./slow_application
事例:データベースアプリケーションの遅延
データベース検索が異常に遅い問題を分析した結果:
# perf report の結果(主要部分)
35.00% mysql [.] join_read_next
25.00% mysql [.] filesort
15.00% [kernel] [k] __memcpy
10.00% mysql [.] ha_innobase::index_read
join_read_nextとfilesortが大部分を占めており、JOINクエリの最適化とインデックスの見直しが必要であることが分かりました。
このような実践的なトラブルシューティング手法は、「詳解 システム・パフォーマンス 第2版」で数多くの事例とともに学ぶことができます。
特に第13章「アプリケーション」では、様々なアプリケーションタイプでの具体的な分析手法が詳しく解説されています。
プロファイリング結果の効果的な活用法
チームでの情報共有とレポート作成
perfで得られたプロファイリング結果を、チーム内で効果的に共有する方法を見てみましょう。
1. 可視化ツールの活用
フレームグラフは、プロファイリング結果を直感的に理解できる優れた可視化手法です:
# フレームグラフ用データの生成
perf record -g ./my_program
perf script > perf.data.txt
# FlameGraphツールでの可視化(要事前インストール)
git clone https://github.com/brendangregg/FlameGraph
cd FlameGraph
./stackcollapse-perf.pl ../perf.data.txt | ./flamegraph.pl > flame_graph.svg
2. レポート形式での出力
# 詳細なテキストレポート生成
perf report --stdio --percent-limit=1 > performance_report.txt
# CSV形式での出力(スクリプト処理向け)
perf report --stdio --field-separator=, > performance_data.csv
# 特定関数に焦点を当てたレポート
perf report --symbol-filter=function_name --stdio > function_analysis.txt
3. 継続的な監視設定
# 定期的なプロファイリングスクリプト例
#!/bin/bash
DATE=$(date +%Y%m%d_%H%M%S)
LOGDIR="/var/log/performance"
# 5分間のプロファイリング
perf record -o ${LOGDIR}/perf_${DATE}.data -g sleep 300
# 結果の自動解析
perf report -i ${LOGDIR}/perf_${DATE}.data --stdio > ${LOGDIR}/report_${DATE}.txt
# 閾値チェック(例:特定関数のCPU使用率が10%を超えた場合)
if grep -q "heavy_function.*[1-9][0-9]\." ${LOGDIR}/report_${DATE}.txt; then
echo "Performance alert: heavy_function is consuming high CPU" | \
mail -s "Performance Alert" admin@example.com
fi
継続的なパフォーマンス改善への活用
perfプロファイリングを単発で終わらせず、継続的な改善サイクルに組み込むことが重要です。
1. ベースライン測定
まず、現在のパフォーマンス状況をベースラインとして記録します:
# ベースライン測定
perf stat -r 10 ./my_program > baseline_stats.txt
perf record -g ./my_program
perf report --stdio > baseline_profile.txt
2. 改善後の効果測定
# 改善後の測定
perf stat -r 10 ./optimized_program > optimized_stats.txt
perf record -g ./optimized_program
perf report --stdio > optimized_profile.txt
# 差分比較
diff baseline_stats.txt optimized_stats.txt
3. A/Bテスト的な比較
# 複数のバージョンを比較
for version in v1 v2 v3; do
echo "Testing $version"
perf stat -r 5 ./program_$version 2>&1 | grep "seconds time elapsed" >> comparison.txt
done
4. 自動化された継続監視
# systemdサービスとしての定期実行例
# /etc/systemd/system/perf-monitoring.service
[Unit]
Description=Performance Monitoring
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/perf_monitor.sh
# /etc/systemd/system/perf-monitoring.timer
[Unit]
Description=Run performance monitoring every hour
Requires=perf-monitoring.service
[Timer]
OnCalendar=hourly
Persistent=true
[Install]
WantedBy=timers.target
さらなるスキルアップのために
今回は、perfコマンドを使ったLinuxパフォーマンス分析の実践的な活用術について解説してきました。
perfの基本的な使い方から、実際のトラブルシューティング事例、チームでの活用方法まで一通り見てきましたが、パフォーマンス分析の世界はまだまだ奥が深いものです。
perfで学んだスキルを更に発展させるには:
- 他の分析ツールとの組み合わせ
- strace、ltrace、gdb等のデバッグツール
- iotop、nethogs等の専門的監視ツール
- Grafana、Prometheusとの連携
- カーネルレベルでの理解を深める
- eBPF(Extended Berkeley Packet Filter)の活用
- ftrace、kprobesとの連携
- カスタムトレースポイントの作成
- アプリケーション固有の最適化
- プログラミング言語固有のプロファイラとの連携
- JVMやPython等のランタイム最適化
- コンパイラ最適化オプションとの関係
これらの高度なテクニックを体系的に学びたい方は、ぜひ「詳解 システム・パフォーマンス 第2版」を手に取ってみてください。
この書籍では、perfを含む60以上のパフォーマンス分析ツールが詳しく解説されており、実際の本番環境での活用事例も豊富に掲載されています。特に:
- 第6章「CPU」: perfを使ったCPU分析の詳細手法
- 第7章「メモリ」: メモリ関連パフォーマンス分析
- 第8章「ファイルシステム」: I/O性能分析の実践
- 第12章「カーネル」: カーネルレベルでの高度な分析技術
といった章では、今回の記事で触れた内容をさらに深く、実践的に学ぶことができます。
perfコマンドは、一度覚えてしまえば様々な場面で活用できる非常に強力なツールです。ぜひ実際の環境で試しながら、パフォーマンス分析のスキルを向上させていってください!
皆さんのシステムが快適に動作するよう、応援しています。
コメント