Go言語でmmapシステムコールを使ったファイル読み込みの高速化検討とC言語のコンパイラの話
2013.10.14 追記
@kazuho さんからご指摘いただきました!
mmapのほうがreadより速いという迷信について - kazuhoのメモ置き場 -
長いタイトル…。
こないだ書いたgorepっていう検索ツール、もうちょっと速くしたいなと思ってファイル読み込みの部分をmmap()
で置き換える検討中。(ちょっぱやのagもmmap()
を使っている)
mmap()
での高速化確認用にCとGoで簡単なコード書いて実験していたら、以下のことがわかった。
処理速度比較の準備
比較用に書いたのは、open()
/read()
と、open()
/mmap()
、そしてfopen()
/fread()
を行うCとGoのコード。
Goのfread()
は、bufio.Read()
で置き換えている。
- C:
- Go
- open/read https://gist.github.com/ryochack/6021257
- open/mmap https://gist.github.com/ryochack/6020725
- fopen/fread(bufio.Read) https://gist.github.com/ryochack/6021642
Cのコンパイラには以下3つを用意し、最適化オプションは全て-O3
を使用。(実行環境はMac OS X Lion / MacBook Late2008)
- LLVM-GCC4.2 (Xcode付属)
- GCC4.9
- LLVM-Clang3.4
GoはVersion 1.1.1を使用。
ビルドしてできたそれぞれの実行ファイルに、以下の方法で用意した1GBのファイルを読み込ませて、処理時間を測った。
入力データ作成 (1GB) $ dd if=/dev/random of=huge.dat bs=512 count=2097152
実行結果
処理時間の詳細。(10回実行した平均)
open+read | open+mmap | fopen+fread | |
---|---|---|---|
LLVM-GCC4.2 | 2.7149 [s] | 1.8465 [s] | 2.7040 [s] |
GCC4.9 | 2.8684 [s] | 2.0105 [s] | 2.8631 [s] |
LLVM-Clang3.4 | 1.6956 [s] | 0.8303 [s] | 1.6946 [s] |
Go Compiler (ver1.1.1) | 2.4115 [s] | 1.4925 [s] | 2.3830 [s] |
期待どおりに、CでもGoでもopen/read
よりもopen/mmap
の方が速くなってる。
で、コンパイラによる違いについて。
Clangビルドでの処理速度がズバ抜けてる…!
Goの処理速度がLLVM-GCCとGCCよりも速いってのも驚き。
Cのコードがコンパイラによってここまで極端に速度の差が出るとは思っていなかった。