Linuxにsplice/tee/vmspliceというシステムコールができていたことに最近気がついた。入ったのは最近というわけではなくて、2.6.17とかの頃ですね。
実際これらは良いものなのかどうか。パイプを介してどんなファイルディスクリプタにもデータを飛ばせるのでsendfileよりは使いでがあるように思う。
これらを使うとしたら、、、
- sendfileの代わり
- readやwriteの高速化
- (ファイルやディスクの)コピーの高速化
くらいか。
sendfileの代わりとしてはまあ、インタフェースがちょっと変わるくらいですね。ただソケットに直接投げられないので、そのぶん面倒になり、sendfileよりも高速になるとはあまり思えないな。
readやwriteについては、コピーを使わずにバッファキャッシュがそのままユーザに見えるというイメージかな。速度的には普通、メモリの速度はI/Oと比べると圧倒的に速いので、あまり高速になるとは思えないな。やはり高速ネットワーク向けか、SSD系のデバイスがもっと高速になれば使われるかもしれない。広く(?)使われてきたO_DIRECTの代替になってくる可能性はある。
ファイルやディスクのコピーについては、高速化を考えるともともとreaderとwriterを別スレッドに分けて回すという構造が必須だ。read待ちの間にwriteをして、write待ちの間にreadをするようにしなければ充分高速にコピーすることはできないのです。読み側と書き側が同じデバイス上のファイルの場合は効果はないですが、別デバイスの場合は双方のデバイスが同時に動くように工夫しなければなりません。
それを踏まえて、spliceでreaderとwriterに分けられるかと考えると、readerとwriterがパイプを共有し、readerがspliceでパイプにデータを流して流れたデータ長を更新(加算)、writerはデータ長を見てspliceでパイプからデータを持ってきて、残りデータ長を更新(減算)ということになるだろう。まあ、バッファ列をキュー状にしてreader/writer間で受け渡すよりもspliceのパイプ経由のほうが書きやすいかもしれないですね。暇を見つけて、この方針でddもどきを書いてみようかな。
vmspliceとteeに関しては、これは趣味の領域であって実用にはならないという感じがします。私の想像力に欠陥があるのかもしれませんが、teeは正直なところ使い道がtee(1)くらいしか思いつきません。teeで性能が気になるというのは…パケットキャプチャみたいなものくらい?? vmspliceもパイプにしか使えないのでspliceとの併用でwritev(iovecを食うのでwriteよりは上?)の代わりということになりますが、結局バッファを使ってwriteすると思えば普通にwriteするのと変わらないような気がします。やはり高速ネットワーク向けなのかな。バッファを使わないダイレクトI/Oならもともとコピーは起きないのでvmspliceの出番はないですよね。
あとは、ディスクI/Oに使うのであれば非同期インタフェースも欲しいですね。そのうちio_submitがspliceに対応してくれて、libaioに定義が入るかもしれないですね。