はじめに
time
コマンドみたいに、実行したコマンド(子プロセス含む)の I/O の読み込み量や書き込み量が知りたいなーと思ったので作ってみました。作ったと言っても /proc/<PID>/io
を読み取って可能な限り正確な情報になるように調整して、あとメモリキャッシュのクリアなどを少し簡単に行えるようにしただけですが。
リポジトリはこちら https://github.com/ko1nksm/io
動作環境
Linux などの procfs が実装されているシステムでしか動作しません。WSL1 は procfs は実装されていますが /proc/<PID>/io
がないので動作しません。WSL2 では動作します。
macOS では procfs 自体がないので動作しません。もし macOS でコマンドが使用した I/O 使用量の取得方法を知っている方がいましたらコメントください。🙏
使い方
# $ base64 -w 999 /dev/urandom | head -n 10000 > data.txt
# $ wc data.txt
# 10000 10000 10000000 data.txt
$ export IOCLEANUP='sudo sh -c "echo 1 > /proc/sys/vm/drop_caches"'
$ export IOWARMUP='sort --version'
$ io sort data.txt > /tmp/output.txt
io: cleanup: sudo sh -c "echo 1 > /proc/sys/vm/drop_caches"
io: warmup: sort --version
rchar: 10005365
wchar: 10000001
syscr: 124
syscw: 2443
read_bytes: 10002432
write_bytes: 10002432
cancelled_write_bytes: 0
各項目の意味は man procfs
(日本語 /io
でページ検索) で調べることができます。
使い方は time
コマンドと同じように io
コマンドを使うだけですが、環境変数 IOCLEANUP
と IOWARMUP
で計測前に実行する処理を指定できるようにしています。
環境変数 IOCLEANUP
は主にメモリキャッシュをクリアするために使います。ファイルがメモリにキャッシュされている場合、キャッシュをクリアしないと実際に読み込む量を正しく計測できません。ただし一度使ったファイルはメモリにキャッシュされているのが普通なので必ずしもキャッシュをクリアして計測すべきとは限りません。
メモリのキャッシュをクリアしないようにして計測するとこのようになります。ファイルがメモリにキャッシュされており読み込む必要がないので read_bytes
が 0 になっていますね。
$ IOCLEANUP= io sort data.txt > /tmp/output.txt
io: warmup: sort --version
rchar: 10005360
wchar: 10000001
syscr: 119
syscw: 2443
read_bytes: 0
write_bytes: 10002432
cancelled_write_bytes: 0
もう一つの環境変数 IOWARMUP
は主にコマンドをメモリにキャッシュさせるために使います。IOCLEANUP
でメモリキャッシュをクリアすると、コマンド、上記の例では sort
コマンドの実行ファイル自体もメモリキャッシュから削除されてしまいます。通常はコマンドが使用するデータ量のみを知りたいはずなので sort --version
のように無害なコマンドを実行させることでコマンドをメモリに再キャッシュさせることができます。
あとはコマンドの実行前と実行後の /proc/<PID>/io
の値を読み取り、差分を取ってより正確な値を出力しています。
補足 GNU time
GNU 版の time
コマンドでもファイルの読み込み量と書き込み量を知ることができます。実行時間やメモリ使用量など多くの情報を出力できますが、I/O の情報に限れば /proc/<PID/io
の方が多いようです。使い方は env time -v <COMMAND>
(または env time
の代わりに /usr/bin/time
)です。ただの time
だと bash 等のシェルにビルトインされている方の time
コマンドが呼び出されるので注意してください。