Wild対Moldのベンチマーク
Benchmarking Wild vs. Mold (davidlattimore.github.io)
要約
この記事では、リンカー(リンクエディタ)であるWildとMoldのパフォーマンスベンチマーク結果の差異について調査しています。Moldが最近発表したベンチマーク結果ではWildが遅いと示されましたが、これはWildが以前発表した結果と大きく異なっていました。著者は、ベンチマーク設定(出力ファイルの扱い、ファイルシステム、フォークの有無など)の違いが原因であることを特定し、Moldのベンチマーク結果を再現することに成功しました。また、Moldが最近大幅に高速化していることも示唆されています。
全文翻訳
WildとMoldのベンチマーク比較
David Lattimore - 2026-09-18
Moldは最近、リンカベンチマークを更新し、初めてWildを含めました。これらのベンチマークでは、Wildが以前のリリース(8月4日)で公開されたベンチマークと比較して、Moldよりも著しく遅いという結果が出ています。この記事では、ベンチマーク結果にこれほど大きな差がある理由を理解しようと試みます。
Moldのベンチマークは2台のマシンで実行されました。
- 64コア(128スレッド)Threadripper、Ubuntu 24.04実行
- Apple M1 Ultra(16パフォーマンスコア)、Asahi Linux実行
Wildの直近のベンチマークは1台のマシンで実行されました。
- 16コア(32スレッド)Ryzen 9955hx、Ubuntu 26.04実行
ベンチマーク設定における顕著な違いの一つは、出力ファイルに関連しています。私たちのベンチマークでは、出力ファイルはリンカの以前の実行から既に存在している状態で実行されます。Moldのベンチマークでは、リンカの呼び出し間に、出力ファイルは削除されます。これはリンカのパフォーマンスに大きな違いをもたらす可能性があります。その違いがどれほど影響するかは、ファイルシステムにも大きく依存します。Wildのベンチマークは、ノイズを減らしSSDの摩耗を避けるために、歴史的にtmpfsで実行されてきました。今振り返ると、これはおそらく間違いでした。なぜなら、ほとんどのユーザーはtmpfsでビルドを行う可能性は低いからです。Moldのベンチマークではext4を使用しており、これはより妥当な選択です。今後、両方を組み合わせた方法で行うことになるでしょう。
もう一つの違いは、Moldのベンチマークでは--no-forkが渡され、起動時のフォーク(シャットダウンコストを削減するため)というデフォルトの動作が上書きされていることです。Wildのベンチマークでは、時間を測定する際にはこの設定をデフォルトのままにし、メモリ消費量を測定する場合にのみ--no-forkを渡します。
次に、Moldのベンチマーク結果のサブセットを、私たちが実行するベンチマークに合わせて再現してみます。Moldのベンチマークと同様に、2026-08-28時点での両リンカのリリースビルドを使用しました。結果を可能な限り似せるために、出力ファイルをext4に配置し、各実行間でファイルを削除し、--no-forkを渡しました。
まず、私たちが実行するベンチマークに対するMoldのベンチマーク結果のサブセットを以下に示します。
| Program | Wild (s) | Mold (s) | Wild/Mold |
|---|---|---|---|
| blender-debug | 1.81 | 1.56 | 1.2x |
| godot-debug | 0.81 | 0.62 | 1.3x |
| blender-release | 0.20 | 0.25 | 0.8x |
| clang-release | 0.15 | 0.14 | 1.0x |
そして、こちらが私たちの結果です。
| Benchmark | Wild (s) | Mold (s) | Wild/Mold |
|---|---|---|---|
| blender-debug | 2.23 | 1.79 | 1.2x |
| godot-debug | 1.11 | 0.89 | 1.2x |
| blender-release | 0.30 | 0.33 | 0.9x |
| clang-release | 0.21 | 0.20 | 1.0x |
Wild/Moldの比率を一つの表にまとめます。
| Program | Mold benchmark | This benchmark |
|---|---|---|
| blender-debug | 1.2x | 1.2x |
| godot-debug | 1.3x | 1.2x |
| blender-release | 0.8x | 0.9x |
| clang-release | 1.0x | 1.0x |
異なるCPUアーキテクチャ、キャッシュサイズ、RAMなどを実行していることを考えると、結果は予想される限り近いものです。
これでMoldのベンチマークが示す結果と似た結果を再現できたので、Wildが1ヶ月前よりも前に公開したベンチマーク結果と比べて、なぜこれほど大きな違いがあるのかを少し掘り下げてみましょう。
Wildが公開したベンチマークセットに含まれるclang-releaseベンチマークに焦点を当てます。Moldのベンチマークが使用する設定(ext4+delete+no-fork)から始め、Wildが歴史的に使用してきた設定(tmpfs+no-delete+fork)で終わるまで、いくつかの異なる構成を試します。
| Benchmark | Wild (s) | Mold (s) | Wild/Mold |
|---|---|---|---|
| clang-release.ext4-delete-no-fork | 0.21 | 0.20 | 1.0x |
| clang-release.ext4-no-delete-no-fork | 0.14 | 0.20 | 0.7x |
| clang-release.tmpfs-delete-no-fork | 0.16 | 0.20 | 0.8x |
| clang-release.tmpfs-no-delete-no-fork | 0.14 | 0.19 | 0.7x |
| clang-release.tmpfs-no-delete-fork | 0.11 | 0.19 | 0.6x |
この記事の残りの部分では、tmpfs+no-delete+forkの設定を使用します。
Wildは、少なくともここでベンチマークされたバージョンでは、フォークを許可し、出力が既に存在し、tmpfs上にある場合に最も良いパフォーマンスを発揮します。つまり、Moldのベンチマークで使用される設定とは逆です。しかし、これは主にWildが、tmpfs以外のファイルシステムでの新しいファイルの作成と書き込みを高速化するOS固有の最適化を欠いているためです。Moldの作者は、論文mold: A Massively Parallel Linkerでこれらの最適化について説明しています。具体的には、fallocateを使用してファイルのスペースを事前に割り当て、hugepagesを使用してファイルをマッピングします。これらの2つの変更は既にWildに実装されており、次のリリースに含まれる予定です。
しかし、Wildの8月4日のベンチマークとMoldの8月28日のベンチマークの間には、まだかなりのパフォーマンス差があります。そこで、過去1年ほどのMoldとWildの各リリースについて、それぞれベンチマークを行いました。ここでは再びclang-releaseをベンチマークします。このベンチマークでは、Wild 0.6.0が引数ファイルと通常のコマンドライン引数を混在させることをサポートしていなかったため、私自身のリリースビルドのclangを使用しました。また、空のsframeに遭遇した場合のエラーを回避するために、moldに--discard-section=.sframeを渡しました。これは修正済みですが、修正されていないmoldバージョンでベンチマークを実行したかったのです。実質的には、上記のclang-releaseとは異なる、しかし類似したベンチマークと見なすべきです。
[画像: Time to link clang-release by linker release]
ここから、Moldが最近著しく高速化したことがわかります。Wildの8月4日のベンチマークは、Moldの2.42.0および2.42.1リリース前に行われたもので、そこで主な改善が見られました。
記事の冒頭で、MoldのM1 Macでのベンチマーク結果に似た結果を、ある程度再現することに成功しました。しかし、Threadripperの結果は再現できていません。私はそのようなハードウェアを持っていません。私の16コアRyzen 9955hx(92GiB RAM)はローエンドマシンとは程遠いですが、384GiB RAMを搭載した64コアThreadripperではありません。私の推測では、上記の違いを超えた、ここでの非常に大きな違いは、Wildが128スレッドで実行し、Moldが32スレッドで実行していることによる可能性が高いです。私の16コア(32スレッド)マシンでは、Wildは24スレッドから32スレッドに移行する際に(下のグラフを参照)、パフォーマンスが向上し続けています(ただし、わずかですが)。このため、スレッドキャップのようなものは導入していません。しかし、これは本当に推測です。もしThreadripperを持っていて、異なるスレッド数でWildのベンチマークを試したい方がいれば、教えてください。
[画像: Time to link clang-release by thread count]