Go言語でmmapシステムコールを使ったファイル読み込みの高速化検討とC言語のコンパイラの話

2013.10.14 追記

@kazuho さんからご指摘いただきました!
mmapのほうがreadより速いという迷信について - kazuhoのメモ置き場 -


長いタイトル…。

こないだ書いたgorepっていう検索ツール、もうちょっと速くしたいなと思ってファイル読み込みの部分をmmap()で置き換える検討中。(ちょっぱやのagmmap()を使っている)

mmap()での高速化確認用にCとGoで簡単なコード書いて実験していたら、以下のことがわかった。

  • ファイル読み込みをmmap()に置き換えると高速化が望めそう
  • Goのコンパイラの最適化はなかなか優秀で、CのGCCビルドよりも速くなることがありそう
  • LLVM-Clangは半端じゃない

処理速度比較の準備

比較用に書いたのは、open()/read()と、open()/mmap()、そしてfopen()/fread()を行うCとGoのコード。 Goのfread()は、bufio.Read()で置き換えている。


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

実行結果

f:id:ryochack:20130718200029p:plain


処理時間の詳細。(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-GCCGCCよりも速いってのも驚き。

Cのコードがコンパイラによってここまで極端に速度の差が出るとは思っていなかった。

参考