Hatena::ブログ(Diary)

kazuhoのメモ置き場

2013-10-10

mmapのほうがreadより速いという迷信について

@ITに以下のような記事が出て、

 今回からしばらくの間は、まったく逆の例、つまり使うとプログラムの処理性能が上がるというシステムコールを紹介していく。システムコールを呼ぶ回数は少ない方が処理性能は高くなるという原則は変わらないが、呼び出しておくと処理性能が向上するシステムコールというものが存在するのだ。こうしたシステムコールを使わないでいることは、とてももったいない。

 今回紹介するシステムコールmmap(2)」だ。ここでは詳しく仕組みを解説しないが、mmap(2)は、プログラムの処理性能に必ず良い影響を与える

やはりあった? 高速化に効くシステムコール:知ってトクするシステムコール(3) - @IT

それを真に受けたのか、「Go言語でmmapシステムコールを使ったファイル読み込みの高速化検討とC言語のコンパイラの話 - ryochack.blog」のようなブログエントリも上がっている。

が、mmapだと必ず速くなる」なんて迷信ですから!!!

これらの記事で紹介されているベンチマークで read が mmap よりも遅く見えるのは、非常に大きなバッファを確保しているから。正しいコードを書けば、シーケンシャルアクセスを行うケースにおいて read(2) が mmap(2) より大幅に遅いということは、まず起こらない。むしろ、read(2) のほうが mmap(2) よりも速くなるというケースも実際には多い。

たとえば、上記のうち後者の記事の read を使うベンチマークを適切なバッファサイズを使うよう変更すると、僕の手元では read(2) を使う版(ソースコード)のほうが高速になる (MacBook Pro / Mountain Lion で計測、テストデータは32MB)。

アクセス方式処理時間
read0.028
mmap0.035

Linux でも mmap(2) がシーケンシャルアクセスの場合に性能が出ないという問題が知られていたという経緯があって、ガチャピンで知られる kosaki さんが 2.6.34 で入ったパッチを紹介する記事(革命の日々! 2.6.34のused once ページに対する改善をcopybenchで検証してみた)を過去に書いたりしている(が、この記事の時点でも、まだread/writeを使った方が速い)。

まあそういうものなので、迷信です。

ついでにいうと、mmap(2) でdisk I/Oページフォルトが起こるとスレッドが固まるので、その点からも、非同期プログラム*1では mmap を避けて非同期 I/O システムコールを使うべきです。

かっとなって書いたが後悔はしていない。

*1:Goって非同期プログラミングするための言語ですよね

通りすがり通りすがり 2013/10/11 07:05 WindowsだとReadやWriteは内部的にシステムがmmap相当のマッピングするらしいですよ。少なくともWindowsではメモリコピー分遅くなるのでは?
http://nyaruru.hatenablog.com/entries/2008/02/28
> Cached I/O 使用時は,OS が勝手にファイルのメモリマッピングを行っていると考えると分かりやすい.

kazuhookukazuhooku 2013/10/11 14:56 コメントありがとうございます。以下の理由により測定してみないとなんとも言えないとは思いますが、興味深いですね。

- readを使う場合のバッファはCPUの一次キャッシュに載るのでアクセスコストが小さい
-- だからバッファにコピーして作業したところでアクセスにかかるトータルコストが2倍3倍になるわけではない
- mmapの場合にreadと同レベルでOSの先読み予測が機能するか
- ページフォルトのコストとシステムコールによるmmapの差し替えコストは同等か
-- 特に32bit環境のことを考えると、Windowsでもファイル全域を常にmmapしているかは疑問

sodasoda 2013/10/11 15:14 昔はメモリコピーのコストが相対的に高かったんですが、今はディスクI/Oの100倍くらいメモリコピーの方が速いので(30年くらい前は同じくらいのバンド幅だったのが、だんだん開くトレンドです)実際に測ってみると、計測誤差に近いオーダーでしか関係してきません>メモリコピー。
これよりは、ファイル全域をmmapしてキャッシュから外れる効果のほうがずっと大きいです。
http://news.mynavi.jp/photo/special/2013/haswell/images/graph013l.jpg
を見ると分かりますが、L1キャッシュとD-RAMで、50倍くらい性能が違いますから。

NyaRuRuNyaRuRu 2013/10/12 16:02 mmap だとブロッキングが発生した時のタイムアウトが書けないのであまり好きではない派です.

なんか懐かしい記事が紹介されていたのでちょっとだけ.

> - mmapの場合にreadと同レベルでOSの先読み予測が機能するか

完全に同レベルかどうかは今すぐには調べられないですが,基本的には同程度に先読みしてくれたはずです.

> -- 特に32bit環境のことを考えると、Windowsでもファイル全域を常にmmapしているかは疑問

これは一部分のみです.『Inside Windows 第4版 下』"11.2 キャッシュ仮想メモリ管理" によれば 256 KB だそうで.さすがに第4版の内容は古いので注意ですね.
ただこれも良し悪しで,巨大なファイルをスキャンしていくとマップ領域を次々と変えていくことになり,その分 CPU コストはかかります.

何にせよ,Mark Russinovich 先生の元記事は面白いので一読の価値ありですかね.
http://blogs.technet.com/b/markrussinovich/archive/2008/02/04/2826167.aspx

ファイルコピーは本当に難しく,コピー完了(これも遅延書き込みまで含めると定義が難しい)までの時間予測はもっと難しく,Windows 8 でついにスループットの時間変化を見せるようになったんですよね.UI 的には敗北なのかもしれませんが,現実世界の難しさを実装者とユーザーの間で共有するためのアプローチとしては悪くない気がします.
http://blogs.msdn.com/b/b8/archive/2011/08/23/improving-our-file-management-basics-copy-move-rename-and-delete.aspx

kazuhookukazuhooku 2013/10/15 14:20 NyaRuRu さん、詳細な説明ありがとうございます。いただいた完璧な説明に付け加える何かを僕は持ちませんが、read/writeでも内部的にmmapするというのは、なるほどWindowsらしい設計だなと思いました。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証