大きなテキストファイルをawkで処理するときにcatで投げ込むと速い理由のような事象が発生する原因についての推察。
自信はあまりない!
- __do_page_cache_readaheadは、次にreadaheadを実行すべきページについてのみReadaheadフラグをたてる
- 次にreadaheadを実行すべきページ「以降の全てのページ」ではない
- do_generic_file_readはReadaheadフラグの立っているページをreadするタイミングでpage_cache_async_readaheadを呼ぶ
- page_cache_async_readaheadはBDI_sync_congestedが立っている場合はreadaheadしない
- Linuxは書き込みを遅延しているが、一定の条件下において、BDI_sync_congestedフラグをセットして書き込みを行うことがある?(要確認)
- dirty pageの比率が高くなったり一定時間がたったら強制フラッシュをしてるはずだけど、その際の内部ステートがどうなってるか、という話
参考: readahead.c - On-demand readahead design.
- awkのread(2)サイズは4KB(つまりページサイズと同一)
- 当該ベンチマークは、読み込みと同時にawkの出力をファイル書き込んでいる
- 書き込み量は不明だが、ベンチマークに50秒以上かかっていることを考えると、ベンチマーク実行中にディスクに対するwrite i/oが発生していると推測できる
- この書き込みがBDI_sync_congestedフラグをセットしているとすると、同フラグがセットされた状態でread(2)がReadAheadフラグのたっているページを読んだ場合、非同期のreadaheadは実行されない
- 非同期のreadaheadが実行されないままフラグの立っていたページを通過した場合、page missが発生するまでreadaheadは行われない
- 以上が
awk file > out
という使い方において、i/o waitが発生する原因と考えられる
dd if=file bs=4k | awk > out
のように、(2MBもあるReadAheadバッファと比べて)少量のバッファを用いるだけでi/o waitが消え去るのは、上述のように非同期のReadAheadに失敗していた場合において、catのread(2)がブロックする間も、パイプのバッファに入っているデータの処理をawkが続けることが可能だからである。