Benchmarking Wild vs Mold
Benchmarking Wild vs Mold
Wild 与 Mold 的基准测试对比
David Lattimore - 2026-09-18 David Lattimore - 2026年9月18日
Mold 最近更新了其链接器(linker)的基准测试,并首次加入了 Wild。与我们在 8 月 4 日发布的上一版基准测试结果相比,这些测试显示 Wild 的速度明显慢于 Mold。本文旨在探讨为何基准测试结果会出现如此大的差异。 Mold recently updated their linker benchmarks and included Wild for the first time. These benchmarks show Wild being substantially slower than Mold in contrast to Wild’s most recently published benchmarks from our last release on August 4th. This post is an attempt to understand why there’s such a difference in the benchmark results.
Mold 的基准测试在两台机器上运行:一台运行 Ubuntu 24.04 的 64 核(128 线程)Threadripper,以及一台运行 Asahi Linux 的 Apple M1 Ultra(16 个性能核心)。Wild 最近的基准测试则是在一台运行 Ubuntu 26.04 的 16 核(32 线程)Ryzen 9955hx 上运行的。 Mold’s benchmarks were run on two machines: A 64 core (128 thread) Threadripper running Ubuntu 24.04 An Apple M1 Ultra (16 performance cores) running Asahi Linux Wild’s most recent benchmarks were run on one machine: A 16 core (32 thread) Ryzen 9955hx running Ubuntu 26.04
基准测试配置的一个重大差异与输出文件有关。我们的基准测试是在链接器上一次运行产生的输出文件已存在的情况下进行的;而 Mold 的基准测试会在每次链接器调用之间删除输出文件。这会对链接器的性能产生重大影响,且这种影响在很大程度上取决于文件系统。 One substantial difference in benchmark configuration is related to the output file. Our benchmarks run with the output file already present from a previous run of the linker. Mold’s benchmarks delete the output file between linker invocations. This can make a substantial difference to the performance of the linker. What difference it makes is also very filesystem dependent.
Wild 的基准测试历来在 tmpfs 上运行,这样做是为了减少测试噪声并避免磨损 SSD。回想起来,这可能是一个错误,因为大多数用户不太可能在 tmpfs 上进行构建。Mold 的基准测试使用了 ext4,这是一个更合理的选择。展望未来,我可能会采取两者结合的方式。 Wild’s benchmarks have historically been run on tmpfs, which was done to reduce noise in benchmarks and to avoid wearing out the SSD. In retrospect, this was probably a mistake, since most users are unlikely to be doing their builds on tmpfs. Mold’s benchmarks use ext4, which is a more sensible choice. Going forward, I’ll probably do a mix of both.
另一个区别是,Mold 的基准测试传递了 --no-fork 参数,覆盖了默认行为(即在启动时 fork 以降低关闭成本)。Wild 的基准测试在测量时间时保持此设置为默认值,仅在测量内存消耗时才传递 --no-fork。
Another difference is that Mold’s benchmarks pass —no-fork, overriding the default behaviour which is to fork on startup in order to reduce shutdown costs. Wild’s benchmarks leave this setting at its default when measuring time and only pass —no-fork when measuring memory consumption.
现在,我们将尝试在 16 核 Apple M1 上复现与 Mold 基准测试类似的结果。与 Mold 的测试一样,我们使用了截至 2026 年 8 月 28 日两个链接器的发布版本。为了使结果尽可能相似,我们将输出文件放在 ext4 上,在每次运行之间删除文件,并传递 --no-fork 参数。
We’ll now attempt to reproduce results similar to what Mold’s benchmarks show on the 16 core Apple M1. As with Mold’s benchmarks, we’ve done release builds of both linkers as of 2026-08-28. To make the results as similar as possible, we put the output file on ext4 and delete the file between each run and pass —no-fork.
首先,这是我们要运行的 Mold 基准测试结果的子集: First, here is the subset of Mold’s benchmark results for the benchmarks we’re going to run:
| 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 |
以下是我们的结果: And here are our results:
| 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 的比率汇总到一张表中: Putting the Wild/Mold ratios together into the one table:
| 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 架构、缓存大小、内存等的机器上运行,结果已经达到了我们预期的接近程度。既然我们已经成功复现了一些类似的结果,我们可以深入挖掘一下,看看为什么基准测试结果与 Wild 不到一个月前发布的数据有如此大的差异。 Given that we’re running on a different CPU architecture with different cache sizes, RAM etc, the results are about as close as we could expect. Now that we’ve managed to reproduce some similar results, we can dig a bit to see why the benchmark results are so different from what Wild published less than a month beforehand.
我们将重点关注 clang-release 基准测试,因为这是 Wild 已发布基准测试集中的一个。我们尝试了几种不同的配置,从 Mold 基准测试使用的配置(ext4+delete+no-fork)开始,到 Wild 历来使用的配置(tmpfs+no-delete+fork)结束。
We’ll focus on the clang-release benchmark since that’s one that Wild has in its published benchmark set. We try several different configurations, starting with the configuration the Mold benchmarks use (ext4+delete+no-fork) and finishing with what Wild has historically used (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(至少是此处测试的版本)在允许 fork、输出文件已存在且位于 tmpfs 上时表现最佳,即与 Mold 基准测试中使用的配置正好相反。但这在很大程度上是因为 Wild 缺乏针对特定操作系统的优化,而这些优化能使在非 tmpfs 文件系统上创建和写入新文件变得更快。
For the remainder of this post, we’ll use a tmpfs+no-delete+fork configuration. Wild, at least the version benchmarked here, does best when allowed to fork and when the output already exists and is on tmpfs. i.e. the opposite of the configuration used in the Mold benchmarks. But this is largely due to Wild lacking the OS-specific tweaks that make creation and writing of a new file on non-tmpfs filesystems fast.
Mold 的作者在《mold: A Massively Parallel Linker》论文中描述了这些优化。具体来说,是使用 fallocate 预分配文件空间,并使用 hugepages 来映射文件。这两项更改已经应用到 Wild 中,并将包含在下一个版本中。
Mold’s author describes these in the paper mold: A Massively Parallel Linker. Specifically using fallocate to pre-allocate space for the file and use hugepages to map the file. These two changes have already been made to Wild and will be included in the next release.
但 Wild 在 8 月 4 日发布的基准测试与 Mold 在 8 月 28 日发布的基准测试之间,仍然存在相当大的性能差异。为了弄清楚发生了什么,我测试了过去一年多里 Mold 和 Wild 的每一个发布版本。我们再次对 clang-release 进行了基准测试。
But there’s still quite a bit of a performance difference between Wild’s benchmarks published on August 4th and Mold’s benchmarks published on August 28th. To see what’s happening there, I benchmarked each release of both Mold and Wild for the last year and a bit. We again benchmark clang-release.
对于此基准测试,我使用了自己构建的 clang 发布版本,因为 Wild 0.6.0 不支持将参数文件与常规命令行参数混合使用。我还向 mold 传递了 --discard-section=.sframe 以规避遇到空 sframe 时的错误。虽然这个问题已经修复,但我希望使用没有该修复的 mold 版本进行测试。实际上,这应该被视为与上述 clang-release 不同的、但类似的基准测试。
For this benchmark I used my own release build of clang, since Wild 0.6.0 didn’t support mixing argument files with regular command-line arguments. I also passed —discard-section=.sframe to mold to work around a failure when encountering an empty sframe. This has been fixed, but I wanted to run the benchmark with mold versions that don’t have the fix. Effectively, this should be considered a separate, but similar benchmark to the clang-release above.
由此可见,Mold 最近的速度有了显著提升。Wild 的 8 月 4 日基准测试是在 Mold 的 2.42.0 和 2.42.1 版本发布之前进行的,而主要的性能提升正是在这两个版本中实现的。 From this, we can see that Mold has recently gotten considerably faster. Wild’s August 4th benchmarks were done before Mold’s 2.42.0 and 2.42.1 releases, where the main gains occurred.
在本文开头,我们设法或多或少地复现了 Mold 在 M1 Mac 上产生的类似结果。然而,我们并没有复现 Threadripper 的结果。我没有那种硬件。我的 16 核 Ryzen 9955hx 配备 92GiB 内存,远非低端机器,但它毕竟不是配备 384GiB 内存的 64 核 Threadripper。 At the start of this post, we managed to more or less replicate results similar to what Mold’s benchmarks on the M1 Mac produced. We haven’t however replicated the Threadripper results. I don’t have that sort of hardware. My 16 core Ryzen 9955hx with 92GiB RAM is far from a low-end machine, but it’s not a 64 core Threadripper with 384GiB of RAM.
我的猜测是,除了上述讨论的差异外,这里巨大的差异可能是因为 Wild 在 128 个线程下运行,而 Mold 在 32 个线程下运行。在我自己的 16 核(32 线程)机器上,Wild 从 24 线程增加到 32 线程时,速度仍在提升(尽管幅度很小,见下图)。正因如此,我没有设置任何线程上限。但这纯属猜测。如果有人拥有 Threadripper 并想尝试用不同的线程数对 Wild 进行基准测试,请告诉我。 My guess is that the extra large difference here, beyond the differences discussed above is possibly due to Wild running with 128 threads while Mold runs with 32. On my own 16 core (32 thread) machine, Wild continues to get faster (although only marginally) when going from 24 threads to 32 (see graph below). Because of this, I haven’t instituted any sort of thread cap. But this is really guesswork. If anyone has a Threadripper and wants to try benchmarking Wild with different thread counts, let me know.