vmstatはcpu waをどうやって算出しているのか

はじめに

vmstatには'cpu wa'フィールドがあります. このフィールドの値はどっからでてきているのでしょうか. それをソースコードの面で探求したストーリー. 出張カーネル読書会の前座として発表させていただきました.

資料

発表に利用したプレゼンテーション資料のPDF版(540k).

Linux kernel 2.6.11 のソースコードとDebian sidのprocpsに入っているvmstatのソースコード をgonzui 0.9を利用して解析してみたときの記録です.

発表トランスクリプト

西尾さんからのいただきものです.ありがとうございます.

わたしは、上川と申します。Debianのデベロッパーやってます。今日は前座と
して、思いつきでvmstatでお話します。vmstatでいろんな項目出てきますけど、
これってどういう意味だろうというのを調べてみようと思って、力尽きてioの
waitの部分だけを調べてきました(笑)。初心者なのでいろいろ言われる困るん
ですけど、、、カーネル読書会を行いたいと思います。

vmstatとは何か。皆さんもご存知だとは思うんですけど、どれぐらい(の人
が)vmstatを使ったことがありますか。。。ではですね、vmstatの出力を見て今
日のマシンは機嫌が悪いとか分かる方はどれくらいいますか(笑)。vmstatの出
力はこんな感じになってまして、ディスクIOがガリガリやっているのか、CPUの
負荷がガリガリやっているのか、メモリ負荷があってメモリが足りないのか、
といったことが大体分かるようになっています。ザーッと眺めていて、アプリ
を動かしていたらどこら辺がボトルネックになっているのかというのを、おお
まかにざっくりと教えてくれるツールとして、結構便利で、おそらく使われて
いると思われます。

最近、なんかvmstatでcpuのwaitという項目が増えました。最近というか、ここ
数年ぐらいで増えています。このCPUのwaitっていったい何の数字を教えてくれ
ているのでしょう、ということを調べてみました。

さて、それをどうやって調べるのでしょうか。まずはユーザランド、アプリケー
ションのvmstatコマンドのソースを見てみよう。つまり、この発想自体がハッ
カーなんですけれども。。。ではvmstatのコマンドは何処だ。例えばdebianであ
ればdpkg -Sとかでvmstatのパッケージ名とかを探します。後はauto-apt
searchとかで。。。とりあえずこんなコマンドを打つと、どうやらprocpsとい
うパッケージに入っているらしい。それでもってprocpsのソースってどこにあ
るんだというのを探すと、debianだとapt-get source procpsとすると、、、な
んかソースが入ってきます。このパッケージはパッチ管理システムを使っているみたいなので、
debian/rules patchするとprocpsのソースコードが手に入ります。

じゃあ、これからどうしようか。ソースコードが見つかりました。しかし、脱
線してみました(笑)。。。そこで最近話題のgonzuiを導入してみました。
gonzuiというのはソースコード検索エンジンだそうです。このgonzuiというの
に、例えばgonzui-impor-apt procpsというのを打ち込みますと、procpsの
ソースコードをapt経由で取得してgonzuiのデータベースに入れてくれます。そ
したら、gonzui-serverって打ち込んでやるとWEBサーバが立ち上がりまして、
そのWEBサーバにアクセスすると、こんなgonzuiという、なんかどこはかとなく
ちょっとgoogleに似ているようなインターフェースが立ち上がります。gonzui
を導入した時点でちょっとgonzui自体のpatchを書いたりとかで時間が過ぎてい
くんですけれども。。。

それでvmstatのどういうところで何をしているのかというのを頑張って探しま
す。gonzuiでいろいろ検索してみると、なんとこのvmstatのバイナリは
vmstat.cの中で何かしているらしい。それを見るとここら辺だなと、
getstat()という関数を読み出していて、そのgetstat()という関数はどうやら
ここら辺のCPUの情報とかを全部ガーッと集めてくるだけということを、
gonzuiのインターフェースで見てみました。gonzuiだとまったく問題ないんで
すけれども。。。getstatのところをクリックすると、ページが飛びまして
getstat()の定義というところに飛んでくれるんですね。で、getstatの関数定
義元を探してみました。そうするとproc_sysinfo.cというところにgetstat()が
定義されているらしいということが分かります。

getstat()を意気揚々と見にいくとですね、open("/proc/stat"...)とかやって
まして、どうやら/proc/statというファイルを読み込んでそれを処理している
だけだということに驚愕します(笑)。こんなんだったらカーネルソースを読ま
ないと何もできないじゃないか(笑)ということで。。。

vmstatのソースを見た結論としまして、vmstat.cからvmstatというバイナリが
できているみたいなんだけれども、それでgetstat()という関数はどうやら
/proc/statの値を見ているだけなんで、カーネルソース読めということです。


カーネル初心者はカーネルソースをどきどきしながら、じゃあ/proc/statは何
処で提供しているのか、それは過去の経験でfs/proc/proc_misc.cだろうと後は
やることを見つけます。いろいろ考えたんですけど、検索でこのファイルに当
たるのはすごく難しくて、procで検索してもstatで検索してもヒットが多すぎ
て、/proc/statで検索しても全然違うものしか当たらないので、これは過去の
経験しかなかったです。

(質問:三浦さん)iowaitで検索したらどうだったんだろう?
(回答)
それだったら微妙に、proc_miscに、、、vmstatで検索したらいけたんです。コ
メントに書いてあったりしたので、、、これはちょっとダサかったんですが。

このファイルは結構巨大なファイルです。ザーッと見ると、何処から見たかと
いいますと、まずこの下から探しました。proc/statで表示される文字列で検索
するとshow_stat()で使用する文字列を作っているということで、show_stat()
を呼んでいるのはstat_open()という関数で、stat_open()というのは
proc_stat_operationという構造体で、それはcreate_seq_entry("stat"...)と
いうので作成されているようで、どうやらこれは/proc/statというのを作ると
きに、ファイルをオープンしたらこれを呼べというような話になっているんじゃ
ないだろうかというような、どうやらshow_stat()を解読すればいいんじゃない
かというところまでgonzuiの力を借りてやってみました。

で、cpu_statとは何者かということでいろいろ検索すると---なんかローカルに
google持っているような勢いなんですが---include/linux/kernel_stat.hとい
うのにあって、どうやらkernel_statというのはCPUごとに持っていますよと。
その中にcpu_statというのがあって、cpustat.user/mice/とかなんとかいろん
な値を持っています。じゃあ、果たしてそれって何処で更新しているんだろう
というので、頑張って検索します。

これは検索しやすかった。それで検索すると、なんとkernel/sched.c の
scheduler_tickというのがそれっぽいと。。。これは怖い。これはどこかで見
たことがあるようなスケジューラの超巨大なファイルではないでしょうか。と
りあえずそれでも恐れずに、それを見回すと、どうやら1サイクルごとに1回、
1(エイチゼット)ごと、例えば今でしたら千分の1秒とかそんなタイミングで割
り込みが発生しますけれど、その割り込みごとにどうやらuser_ticksもしくは
sys_ticksが1になるように呼び出されています。これは細かい話なんでいいん
ですけれども。。。そこのところで、現在システムがユーザプロセスを1個も動
かしてなくてidleである場合にio書きの状態であるプロセスが1個でもあった場
合には、iowaitという値を増やしていきます。そうでなければidleとみなしま
す。そのiowaitというのは、つまりio書きの状態であるというのは、とりあえ
ずiowaitの状態のやつが一人でもいればiowaitというのを増やしますよという
か、どうやらそうらしいというのが分かりました。では、このiowaitの状態と
いうのはどういう意味なんだというのを調べるとio_schedule_timeoutもしくは
io_scheduleで増やしたり減らしたりしているので、io経由とかで待ち処理をし
ている人がいればiowaitは上るらしい。。。

io_scheduleで検索してみると、ザーッと出てきました。ザーッとファイル名と
か眺めてみると、う〜ん、どうやらファイルシステム関連もしくはディスク書
き込み関連っぽいところで利用されています。例えばディスクの書き込みで待っ
ているときに、io_scheduleというのでcpuをリードしてあげるとなんとなく
disk busyでこのプロセッサは待ってますよということが分かります。これでもっ
と気になっていたのが、ディスクアクセスが中心に呼ばれていますので、ネッ
トワークとかで待っているときは全然呼ばれませんねというのが分かりました。

おまけで、ネットワーク関係で待つのって大体selectあたりで待つのかなと思っ
てるんですけど、selectはscheduler_timeoutを呼んでいるんですけど、
io_schedule_timeoutではないのでiowaitにはならないようです。

ということでdebianでアプリケーションからカーネル部分まで追跡する方法ま
で説明してみました。それで、追跡に無駄にgonzuiを活用してみました。結果
としてディスク関連の動作でどうやらcpu waitの値が増加するらしいというこ
とが分かりました。ネットワークのほうではどうやら増加しないような雰囲気
です。確信はありません。(以下:質疑応答)
    

参考文献


Junichi Uekawa

$Id: 200503-vmstat.html.ja,v 1.5 2007/05/19 00:13:14 dancer Exp $