結論
51.25GB の1本のファイルを検索するとき、rg --no-mmap が既定より速くなることがあります。
ただし、OS と検索の中身で答えが割れます。
| 50GB・rg・コールド | 既定(--mmap) |
--no-mmap |
効き目 |
|---|---|---|---|
| Windows 11・固定文字列 | 83.74秒 | 68.50秒 | 1.22倍 速い |
| Windows 11・正規表現+除外 | 282.84秒 | 97.83秒 | 2.89倍 速い |
| macOS・固定文字列 | 55.38秒 | 55.70秒 | 変わらない |
| macOS・正規表現+除外 | 59.40秒 | 58.47秒 | 変わらない |
| Linux VM(8GB)・固定文字列 | 約83秒 | 約100秒 | 約1.2倍 遅い |
| Linux VM(8GB)・正規表現+除外 | 約172秒 | 約105秒 | 1.64倍 速い |
6通りのうち 3つで速くなり、2つで変わらず、1つで遅くなりました。
- macOS: 何もしなくてよい。既定で最善が出ている
- Windows: 51GB では既定が不利。とくに重い検索で3倍近く損をする
-
Linux: 検索の中身で逆転する。軽い検索は既定、重い検索は
--no-mmap
測った条件
- ファイル: OpenStreetMap 日本の XML、51,254,526,392 バイトの1本
- 検索1:
rg -n -F '東京' <file>— 94,979 ヒット - 検索2:
rg -n -v '^ +<' <file>— 3 ヒット - ripgrep 15.2.0(Linux のみ 15.1.0)
-
毎回キャッシュを破棄して10秒待ってからコールド計測
(macOSsudo purge/ Linuxdrop_caches/ Windows は RAMMap-Etを管理者権限で) - 出力の行数が
--mmapと--no-mmapで一致することを毎回確認
| 機械 | |
|---|---|
| macOS | Apple M4 / 32GB / 外付け USB SSD |
| Windows 11 | Core i7-1165G7(4C8T・15W級)/ 15.6GB / Intel Optane H20 with SSD |
| Linux | 上記 Mac 上の VMware・仮想2コア / 8GB |
秒数は機械をまたいで比較しないでください。 見るのは同じ機械の中の2本です。
犯人はディスクでも CPU でもなかった
Windows で最初に疑ったのは、ファイルの置き場所と断片化でした。違いました。
ツールを通さずに同じ 3GiB を読むと、51GB ファイルの先頭 1159 MB/s・中間 1134 MB/s・末尾 1168 MB/s。
このディスクは素で 1.1GB/s 出るので、51.25GB を読むだけなら約45秒が下限です。
次に疑ったのが CPU の熱だれ。15W の薄型ノートなら5分の連続負荷で落ちてもおかしくない。これも違いました。
CurrentClockSpeed は開始前も終了後も 2803MHz。3GB の同じ検索を5回続けても 7.1秒前後で一定です。
残ったのが読み方でした。--no-mmap を付けると 282.84秒が 97.83秒になります。
なぜこうなるのか(ここからは推測)
メモリマップは、ページに触るたびに OS がディスクから読み込む仕組みです。
ファイルがメモリに収まっていれば、コピーが1回減るぶん効率的です。
収まらないときが問題で、51.25GB は Windows 機の 15.6GB にも Mac の 32GB にも収まりません。
読んでいるあいだ中、ページを入れては捨てを繰り返すことになります。
この出し入れの代償が OS によって違うのだろう、というのが現時点の見立てです。
ただし測定結果から逆算した説明で、確かめたわけではありません。
とくに Linux が「軽い検索だと既定が速く、重い検索だと --no-mmap が速い」と逆転する理由は説明できていません。
ご存じの方がいたら教えてください。
自分の環境で確かめる
# 1回目(既定)
rg --mmap -n -F '探す語' huge.log > /dev/null
# キャッシュを捨てる
# macOS : sudo purge
# Linux : sync && sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'
# Windows: RAMMap64.exe -accepteula -Et (管理者権限)
# 2回目
rg --no-mmap -n -F '探す語' huge.log > /dev/null
キャッシュを捨てずに測ると、2回目が速く出るだけで何も分かりません。 ここは省かないでください。
そして両方で出力の行数が一致することを確かめてください。違っていたら、測り方のほうが違っています。
付記
この計測は、自分が作っている巨大ファイル用の CLI(uvf)を ripgrep と比べる過程で出てきたものです。
uvf は mmap を使わず順次読みなので3環境で挙動が同じですが、裏を返せば Linux で mmap が有利な場面を取りこぼしていることになります。
そこは宿題です。
条件と全データはこちらにまとめてあります。