こんにちは. adingoで検索周りの仕事をしているHと申します. 検索エンジンやデータベースなどのディスクI/Oが多いアプリケーションでは, いかにI/Oを抑えるかがパフォーマンスの決め手になります. 今回はアプリケーションが出したI/Oリクエスト一つ一つがどのようにデバイスドライバに渡るかをトレースするblktraceというツールを簡単に紹介します. blktraceはlinux kernel 2.6におけるツールとなっており, 2.6.17-rc1以降ではカーネルにパッチを当てることなく利用可能です. (ツール自体はインストールする必要があります.)
何がトレースされる?
linuxカーネルではI/Oリクエストは多数のレイヤーを通じて実際にデバイスに要求が出されます. ざっくり書くと, アプリケーションから発行されたI/Oリクエストは以下のようなパスを通りデバイスへと辿りつきます. ([...] はカーネルの範囲を表しています.)
アプリケーション -> [ファイルシステム -> ページキャッシュ -> ブロックI/Oレイヤ -> デバイスドライバ] -> デバイス
blktraceがトレースするのは, "ブロックI/Oレイヤ"の部分になります. ブロックI/Oレイヤでは, I/OスケジューラによりI/Oリクエストの並び換えや連接ブロックへのI/Oリクエストのマージ等が行われているため, ブロックI/Oレイヤの入口と出口ではI/Oリクエストの順番が異なります. つまり, blktraceはブロックI/Oレイヤの入口と出口, そして内部でのI/Oリクエストの状態をトレースすることができるツールとなります.
インストール
通常は, ディストリビューションのパッケージ管理システムからインストールが可能だと思います. 私が試した範囲では, CentOS(yum), Debian(apt), openSUSE(yast) では可能でした. 一応, CentOS(yum)での例を載せておきます.
% sudo yum install blktrace
使い方
私も使い方が詳しい訳ではないので, 一番基本的な使い方のみ紹介します. とりあえずこれだけでも何とかなると思います.
% blktrace -d /dev/sda -o - | blkparse -i > trace.out
blktraceは実際にトレースを行うプログラムで, blkparseが見やすく整形してくれるツールとなります. 上のコマンドでは監視するデバイス(上では/dev/sda)とトレースログの出力先(上ではtrace.out)を指定すれば良いことになります. これを実行し, 別のシェルなどでI/Oを発行するプログラムを実行すると, そのプログラムのI/Oをトレースすることができます. 実際には, カーネルやその他の動作中のアプリケーションすべてのI/Oが捕捉されてしまうため, 注意が必要です. (また, ファイルにトレース結果を書き込んでしまうため, その分のI/Oも捕捉されてしまいます. blktraceのオプションで別のマシンにネットワーク経由で転送するモードもあるので, それにより回避できます.)
以下に, 自分のsortした時の出力の一部を載せておきます.
8,0 5 1 0.073660305 21678 A R 280968474 + 32 <- (8,3) 263971704
8,1 5 2 0.073660507 21678 Q R 280968474 + 32 [zsh]
8,1 5 3 0.073662783 21678 G R 280968474 + 32 [zsh]
8,1 5 4 0.073664230 21678 P N [zsh]
8,1 5 5 0.073665153 21678 I R 280968474 + 32 [zsh]
8,1 5 6 0.073666419 21678 U N [zsh] 1
8,1 5 7 0.073667496 21678 D R 280968474 + 32 [zsh]
8,0 5 8 0.078350794 21678 A R 280968506 + 8 <- (8,3) 263971736
8,1 5 9 0.078350962 21678 Q R 280968506 + 8 [zsh]
8,1 5 10 0.078351973 21678 G R 280968506 + 8 [zsh]
8,1 5 11 0.078352571 21678 P N [zsh]
8,1 5 12 0.078353001 21678 I R 280968506 + 8 [zsh]
結果は左から, 1:デバイス番号, 2:CPU, 3:シーケンス番号, 4:タイムスタンプ, 5:PID, 6:イベント名, 7:リクエストタイプ, 8:開始ブロック(セクタ番号(LBA)) + ブロック(セクタ)数, 9:プロセス名 となります. どのプロセス(5)のどのブロック(8)のI/Oリクエストが, どの状態であるか(6)を見ることができます. イベント名には, I(I/Oスケジューラのキューに挿入された), D(ブロックI/Oレイヤからデバイスドライバに送られた), C(I/Oが完了した)などがあります. 詳しくはマニュアルをご確認ください.
まとめ
linux kernel 2.6から導入されたI/Oトレースのツールを紹介しました. このツールの出力結果を解析して, カーネルのI/Oスケジューリングアルゴリズムを修正する人は少ないと思いますが, 既存スケジューリングアルゴリズムやカーネルのパラメータを調整する場合などは一つの指標になると思います. また, 内部の動作を見てみるのは単純に面白いものです. blktrace自体ができることや, 詳しい使い方は以下のマニュアルやプレゼン資料を見てください.