Benchmarking Wild vs Mold

54 points by goldstein a day ago on lobsters | 10 comments

0x2ba22e11 | 21 hours ago

The linked paper about the design of Mold at https://arxiv.org/pdf/2608.23228 is also really interesting reading, too. I hope that at some point Wild's authors also publish some bragging writing about how their software works and what makes it fast. ❤️

I am wondering whether there's strong interest by the authors if these new fast linkers in changing how compilers interface with them to speed up the linking stage. The first thing that comes to mind would be cooperating on file formats that might be cheaper for the compiler to produce and/or for the linker to consume. A second idea might be to have the compiler start feeding input to the linker as soon as partial input is available, so that linking can be partially pipelined with compilation.

[OP] goldstein | 20 hours ago

MaskRay | 7 hours ago

"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." lld also lacks such tweaks.

In addition, I don't like forking as the default behavior. mold/wild stops being a well-behaved process for anything that reasons about process trees:

  • getrusage(RUSAGE_CHILDREN), /usr/bin/time -v, shell time - all report the parent, which did nothing. Peak RSS in particular is meaningless.
  • perf stat, strace -f, gdb need extra care or --no-fork.
  • With ninja -j N, the scheduler frees the job slot while the orphan still holds its full RSS. Several concurrent links can leave you with a peak memory footprint well above what the build system thinks it has committed.

MaskRay | 7 hours ago

(cargo build --release, system malloc)

% hyperfine -w 1 -r 10 -c 'rm -f /dev/shm/a.out' -n wild0 'numactl -C 0-7 /data/code/wild/target/release/wild --no-fork --threads=8 @response.txt -o /dev/shm/a.out' -n mold1 'numactl -C 0,2,4,6,8,10,12,14 /data/code/wild/target/release/wild --no-fork --threads=8 @response.txt -o /dev/shm/a.out'
Benchmark 1: wild0
  Time (mean ± σ):     899.2 ms ±  21.5 ms    [User: 4574.9 ms, System: 1367.9 ms]
  Range (min … max):   873.8 ms … 938.1 ms    10 runs

Benchmark 2: mold1
  Time (mean ± σ):     708.9 ms ±  12.2 ms    [User: 3373.1 ms, System: 1077.5 ms]
  Range (min … max):   695.8 ms … 728.5 ms    10 runs

Summary
  mold1 ran
    1.27 ± 0.04 times faster than wild0

(using system libmimalloc.so.3.5, LLVM_ENABLE_PIC=off)

% hyperfine -w 1 -r 10 -c 'rm -f /dev/shm/a.out' -n lld0 'numactl -C 0-7 /tmp/out/custom1/bin/ld.lld --threads=8 @response.txt -o /dev/shm/a.out' -n lld1 'numactl -C 0,2,4,6,8,10,12,14  /tmp/out/custom1/bin/ld.lld --threads=8 @response.txt -o /dev/shm/a.out'
Benchmark 1: lld0
  Time (mean ± σ):      1.766 s ±  0.034 s    [User: 4.204 s, System: 1.154 s]
  Range (min … max):    1.734 s …  1.826 s    10 runs

Benchmark 2: lld1
  Time (mean ± σ):      1.756 s ±  0.024 s    [User: 3.881 s, System: 0.895 s]
  Range (min … max):    1.721 s …  1.784 s    10 runs

Summary
  lld1 ran
    1.01 ± 0.02 times faster than lld0

I maintain lld, and my reaction to the 2.4x+ range in the mold paper was that it reads harsher than what I see day to day. In my own use lld time is typically below 2x mold; I don't think I've ever observed 4x.

Two of the largest ratios come from specific lld deficiencies rather than from its architecture:

  • --version-script matching was not parallel. This is what makes TensorFlow/PyTorch shared objects look catastrophic. I've parallelized it in https://github.com/llvm/llvm-project/pull/223208 (will be included in lld 24) arxiv
  • --icf=all is slow. In Chromium configurations that enable it, about half of lld's link time goes to ICF. I have a patch pending.

reivilibre | an hour ago

Is the difference in numactl args intentional in your first comparison between wild/mold. I'm not familiar but to the untrained eye it looks like for mold you have maybe allocated threads not sharing physical CPUs but for wild you have not?

MaskRay | 32 minutes ago

The first hyperfine command has a typo. It compares numactl -C 0-7 (8 threads on 4 P-cores using hyper-threading) and numactl -C 0,2,4,6,8,10,12,14 (8 threads on 8 distinct P-cores).

Both mold and wild drop by ~30–40% when forced to share SMT pairs rather than dedicated cores. ld.lld shows no real SMT sensitivity since it doesn't saturate thread capacity. Note that lld isn't as slow as the mold paper implies. Reaching an lld/mold time ratio greater than 2x is difficult in real-world testing.

gold, wild, mold ... i'm starting to see a pattern here :^)

grep '^..ld$' /usr/share/dict/words|tr A-Z a-z|uniq

any predictions for the next one?

[OP] goldstein | 16 hours ago

paid version of mold (used to?) be called sold

5d22b | 15 hours ago

The pattern starts with the standard Unix linker being named ld and also includes the LLVM linker being named lld.

Yep, aware