grabやagは本当にgrepよりも速い?

grepよりも高速なgrepの実装「grab」、grabよりも高速な「ag」。すなわち、grep < grab < ag。それを信じてgrepからgrabやagに移行する人がいるらしい。

ag (The Silver Searcher) の作者は、自らベンチマークを行いagがgrabよりも30倍高速であることを示したそうです。

そこで、agやgrabがどれくらい高速なのか試してみました。

grabのビルド

画面の右側にある「Download ZIP」よりソースコードをダウンロードし、コンパイルしました。

$ wget https://github.com/stealth/grab/archive/master.zip
$ unzip -q master.zip
$ cd grab-master
$ make

agのビルド

画面の右側にある「Download ZIP」よりソースコードをダウンロードし、コンパイルしました。

$ wget https://github.com/ggreer/the_silver_searcher/archive/master.zip
$ unzip -q master.zip
$ cd the_silver_searcher-master
$ ./build.sh

パフォーマンス比較

/etcディレクトリ配下を再帰的に検索してみました。公平に測定するため、Cロケールで比較しています。grepRed Hat Enterprise Linux 6にバンドルされているgrep-2.6.3、grabとagは本稿執筆時点でのgitバージョンです。

$ export LANG=C
$ time -p /bin/grep -r http /etc >/dev/null
real 2.21
user 1.89
sys 0.31
$ time -p ./grab -r http /etc/ >/dev/null
real 0.08
user 0.05
sys 0.02
$ time -p ./ag http /etc/ >/dev/null
real 0.48
user 0.09
sys 0.67

言われているように、grabやagはgrep-2.6.3よりもかなり速いという結果になりました。

しかし、その後の調査で、grep-2.6.3だけはシンボリック・リンクを追跡することが判明しました。grep-2.11までは、-rと-Rは同じで、どちらもシンボリック・リンクを追跡する動作となっています。grep-2.12からは、grabやagと同様に-rはシンボリック・リンクを追跡しないように動作変更されています。

これでは不公平なので、grep-2.21で再検証してみました。

$ export LANG=C
$ time -p grep -r http /etc/ >/dev/null
real 0.04
user 0.01
sys 0.02

結果はgrepの勝利でした。続いて別のディレクトリ/usr/share/doc配下を検索してみましたが、やはりgrepが勝利しました。

$ time -p grep -r http /usr/share/doc/ >/dev/null
real 0.31
user 0.19
sys 0.11
$ time -p ./ag http /usr/share/doc/ >/dev/null
real 4.92
user 1.26
sys 7.33
$ time -p ../grab-master/grab -r http /usr/share/doc/ >/dev/null
real 0.74
user 0.52
sys 0.22

ということで、予想に反してgrep > grab > agとなりました。