iowaitはいつ見えなくなるか
先日twitter(X)でiowaitが云々で盛り上がっていて、それ自体は別にどうという話でもなかったのですが、iowaitって今実際どうなってるんだろう?というところを少し実験してみました。
目的
I/Oボトルネックのプログラム動作中にvmstatのiowaitがいつ見えなくなるか調べる
iowait?
iowaitが分かるのはtopコマンドやvmstatです。Ubuntuではどちらもprocpsパッケージに含まれています。このパッケージは以前も調べてるので調べ方は以下を参考にしてください。
vmstatのiowaitに使用されているのは、/proc/statファイルのiowaitでした。procps-3.3.17/vmstat.cの306行目で呼ばれているgetstat()がprocps-3.3.17/proc/sysinfo.cにあり、そこで読まれているのをデバッガで確認しました。
/proc/statファイルのiowaitはman procfsを参照してください。
man procfsiowait (since Linux 2.5.41) (5) Time waiting for I/O to complete. This value is not reliable, for the following reasons: 1. The CPU will not wait for I/O to complete; iowait is the time that a task is waiting for I/O to complete. When a CPU goes into idle state for outstanding task I/O, another task will be scheduled on this CPU. 2. On a multi-core CPU, the task waiting for I/O to complete is not running on any CPU, so the iowait of each CPU is difficult to calculate. 3. The value in this field may decrease in certain conditions.
ようはI/O待ちしてる時間なんだが、待っているタスクの他に実行してるタスクがあればそちらがCPU使って減っていくもので、信用ならんそうです。
なので今回は、どう減っていくのか? を検証したいと思います。
検証
コードは以下のリポジトリにあります。
https://git.elephantcat.work/first_user/iowait_test
I/O待ちを行うプロセス
I/O待ちを行うプロセスを可能な限り原始的に作ったのが以下です。
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdint>
int main() {
int f = open("hoge.txt", O_CREAT|O_SYNC|O_RDWR, 0644);
uint8_t data[4096] = {0};
while(true) {
write(f, data, 4096);
lseek(f, 0, SEEK_SET);
}
close(f);
return 0;
}
O_SYNC(データの書き込みが終わるまでブロックされる)で開いたファイルを4KB書き込み、終わったら先頭からそれを繰り返すだけのプログラムです。無限ループするので、終了にはCtrl+Cなどが必要です。
これをg++ -g hoge.cpp -o hogeなどしてビルドし、端末上で実行しながら、別端末でvmstatをかけると以下のような結果になります。
$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 1 82952 383260 158132 1915032 0 2 35 88 497 359 3 1 90 6 0
0 1 82952 383260 158152 1915068 0 0 0 128 1180 881 1 2 49 49 0
0 1 82952 383260 158176 1915056 0 0 0 632 1093 964 1 1 49 49 0
0 1 82952 383260 158220 1915064 0 0 0 192 1107 945 2 1 48 49 0
0 1 82952 383260 158236 1915068 0 0 0 144 1161 954 1 2 48 49 0
1 1 82952 383260 158264 1915060 0 0 0 152 1144 933 1 1 49 49 0
^C
$
VirtualBoxで2コア割り当てたUbuntuなので、49%のI/O WAITが発生しています。もう約半分の49%がIDLEですね。ふむふむ、確かにI/O待ちが見えています。
段々忙しくして、vmstatの変化を見る
cat >hoge.cpp <<EOF
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdint>
int main() {
int f = open("hoge.txt", O_CREAT|O_SYNC|O_RDWR, 0644);
uint8_t data[4096] = {0};
while(true) {
write(f, data, 4096);
lseek(f, 0, SEEK_SET);
}
close(f);
return 0;
}
EOF
g++ -g hoge.cpp -o hoge
for pcount in $(seq 0 $(nproc --all)); do
echo "[dummy process count: $pcount]"
/usr/bin/time ./hoge&
pid_time=$!
pid_dummy=''
for i in $(seq $pcount); do
sh -c 'while :;do :;done'&
pid_dummy="$pid_dummy $!"
done
vmstat 1 10
pid_hoge=$(ps -o pid= --ppid $pid_time)
kill $pid_hoge $pid_dummy
wait
done
今度は先のプログラムを吐き出してコンパイルし、それを動かしながら、ただビジーループするシェルスクリプトをCPU/コア数分だけ実行するシェルスクリプトです。nproc –allがCPU/コア数を取得するコマンドで、/usr/bin/timeは時間測定用のコマンドです。それ以外は説明が必要なほどではないと思います。
これを2CPU/コアの環境で実行すると以下のようになります。
[dummy process count: 0]
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 1 82952 433764 160024 1893676 0 2 34 88 498 360 3 1 90 6 0
0 1 82952 433640 160056 1893780 0 0 0 216 1189 874 2 2 49 48 0
0 1 82952 433640 160088 1893788 0 0 0 148 1236 881 1 1 49 49 0
0 2 82952 433640 160108 1893780 0 0 0 172 1203 969 2 2 41 56 0
0 1 82952 433640 160140 1893784 0 0 0 252 1338 1059 1 2 28 69 0
0 1 82952 433640 160176 1893780 0 0 0 140 1109 895 1 1 49 49 0
0 1 82952 433640 160196 1893784 0 0 0 80 993 790 1 1 49 49 0
0 1 82952 433640 160224 1893780 0 0 0 112 1250 983 1 1 49 49 0
1 1 82952 433144 160256 1893784 0 0 0 84 1184 896 1 2 49 48 0
1 0 82952 433020 160300 1893776 0 0 0 392 1153 979 1 1 49 49 0
Command terminated by signal 15
0.00user 0.01system 0:09.17elapsed 0%CPU (0avgtext+0avgdata 896maxresident)k
0inputs+544outputs (0major+61minor)pagefaults 0swaps
[dummy process count: 1]
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 2 82952 432400 160312 1894064 0 2 34 88 498 360 3 1 90 6 0
1 1 82952 432276 160336 1893804 0 0 0 144 854 835 52 1 3 45 0
1 1 82952 432276 160372 1893804 0 0 0 220 845 1016 52 1 0 47 0
1 1 82952 432276 160428 1893784 0 0 0 160 853 1208 52 1 0 47 0
1 1 82952 432276 160476 1893792 0 0 0 144 844 1198 52 1 0 48 0
1 1 82952 432276 160480 1893816 0 0 0 144 813 1103 53 1 0 46 0
1 1 82952 432276 160480 1893816 0 0 0 132 791 998 52 1 0 48 0
1 1 82952 432276 160512 1893796 0 0 0 136 873 1184 52 0 0 48 0
1 1 82952 432276 160536 1893800 0 0 0 80 795 1170 51 1 0 48 0
1 1 82952 432276 160560 1893812 0 0 0 612 816 1223 52 1 0 47 0
Command terminated by signal 15
0.00user 0.01system 0:09.18elapsed 0%CPU (0avgtext+0avgdata 896maxresident)k
0inputs+512outputs (0major+60minor)pagefaults 0swaps
[dummy process count: 2]
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 1 82952 432276 160564 1893808 0 2 34 88 498 360 3 1 90 6 0
3 1 82952 432028 160608 1893788 0 0 0 480 926 847 100 1 0 0 0
2 1 82952 432028 160640 1893804 0 0 0 168 901 835 100 0 0 0 0
2 1 82952 432028 160692 1893792 0 0 0 220 983 882 100 0 0 0 0
2 1 82952 432028 160744 1893784 0 0 0 128 909 885 100 0 0 0 0
2 1 82952 432028 160772 1893804 0 0 0 112 976 797 100 1 0 0 0
2 1 82952 432028 160816 1893788 0 0 0 320 829 850 100 0 0 0 0
2 1 82952 432028 160872 1893780 0 0 0 144 809 823 100 1 0 0 0
2 1 82952 432028 160900 1893804 0 0 0 144 931 912 100 1 0 0 0
2 1 82952 432028 160900 1893824 0 0 0 112 1004 838 100 0 0 0 0
Command terminated by signal 15
0.00user 0.00system 0:09.12elapsed 0%CPU (0avgtext+0avgdata 896maxresident)k
0inputs+576outputs (0major+62minor)pagefaults 0swaps
1つダミープロセスを動かしたらIDLEがなくなり、もう1つ動かしたらI/O WAITもなくなりましたね。そして、/usr/bin/timeに至っては、最初からCPUは0%と言っています。
まとめ
vmstatのiowaitはCPUが全部使われるようになったら見えなくなってしまう。I/OのIN/OUTの量は見えているので、I/Oを気にするならそちらを見よう。
ディスカッション
コメント一覧
まだ、コメントがありません