Skip to content

Elf2: create a new linker from scratch#25299

Merged
andrewrk merged 1 commit into
ziglang:masterfrom
jacobly0:elfv2
Sep 21, 2025
Merged

Elf2: create a new linker from scratch#25299
andrewrk merged 1 commit into
ziglang:masterfrom
jacobly0:elfv2

Conversation

@jacobly0

Copy link
Copy Markdown
Member

This iteration already has significantly better incremental support. In fact, this PR also enables every incremental test for x86_64-linux-selfhosted and already passes all of them with this linker.

Closes #24110

@andrewrk andrewrk added release notes This PR should be mentioned in the release notes. linking labels Sep 19, 2025
@andrewrk

Copy link
Copy Markdown
Member

Can you copy paste those perf data points into the PR writeup for release notes later?

This iteration already has significantly better incremental support.

Closes ziglang#24110
@andrewrk
andrewrk merged commit f58200e into ziglang:master Sep 21, 2025
13 of 14 checks passed
@andrewrk

Copy link
Copy Markdown
Member

Release Notes

The new linker can be used with -fnew-linker in the CLI, or by setting exe.use_new_linker = true in a build script.

It is already the default when passing -fincremental and targeting ELF.

The performance is fast enough that there's no longer much of a benefit to exposing a -Dno-bin build step. You might as well keep codegen and linking always enabled because the compilation speed difference is negligible, and then you get an executable at the end.

Performance Data Points

Old linker, building Zig compiler, then making a single-line change to a function, and then another:

Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 18s


Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 754ms


Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 858ms

New linker, building Zig compiler, then making a single-line change to a function, and then another:

Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 18s
      └─ options success


Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 73ms


Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 72ms

Disabling the backend and linker entirely, building Zig compiler (type checking only), then making a single-line change to a function, and then another:

Build Summary: 3/3 steps succeeded
install success
└─ compile exe zig Debug native success 17s


Build Summary: 3/3 steps succeeded
install success
└─ compile exe zig Debug native success 70ms


Build Summary: 3/3 steps succeeded
install success
└─ compile exe zig Debug native success 69ms

In summary:

  • incremental updates are 11 times faster.
  • with the new linker, there is only a 4% slowdown compared to skipping code generation and linking entirely

@jacobly0

Copy link
Copy Markdown
Member Author

The previous benchmarks were misleading due to the incomplete nature of the new linker, more accurate numbers reflecting the current progress are:

Old linker, building Zig compiler, then making a single-line change to a function, and then another:

Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 14s


Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 194ms


Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 191ms

New linker, building Zig compiler, then making a single-line change to a function, and then another:

Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 14s


Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 65ms


Build Summary: 4/4 steps succeeded
install success
└─ install zig success
   └─ compile exe zig Debug native success 64ms

Disabling the backend and linker entirely, building Zig compiler (type checking only), then making a single-line change to a function, and then another:

Build Summary: 3/3 steps succeeded
install success
└─ compile exe zig Debug native success 14s


Build Summary: 3/3 steps succeeded
install success
└─ compile exe zig Debug native success 62ms


Build Summary: 3/3 steps succeeded
install success
└─ compile exe zig Debug native success 62ms

Similar conclusion as before, just not as extreme.


Non-incremental comparison only shows an insignificant speedup:

Benchmark 1 (13 runs): release/bin/zig build-exe -fstrip -fno-new-linker ...
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          9.96s  ± 44.4ms    9.91s  … 10.1s           0 ( 0%)        0%
  peak_rss            766MB ± 5.82MB     754MB …  774MB          0 ( 0%)        0%
  cpu_cycles         87.1G  ±  358M     86.7G  … 87.9G           0 ( 0%)        0%
  instructions        209G  ± 12.0M      209G  …  209G           1 ( 8%)        0%
  cache_references   7.23G  ± 15.2M     7.21G  … 7.27G           0 ( 0%)        0%
  cache_misses        293M  ± 6.30M      286M  …  307M           0 ( 0%)        0%
  branch_misses       312M  ± 2.19M      310M  …  317M           0 ( 0%)        0%
Benchmark 2 (13 runs): release/bin/zig build-exe -fstrip -fnew-linker ...
  measurement          mean ± σ            min … max           outliers         delta
  wall_time          9.85s  ± 21.7ms    9.83s  … 9.90s           0 ( 0%)          -  1.1% ±  0.3%
  peak_rss            857MB ± 8.54MB     842MB …  868MB          0 ( 0%)        💩+ 11.9% ±  0.8%
  cpu_cycles         87.8G  ±  105M     87.7G  … 88.0G           0 ( 0%)          +  0.8% ±  0.2%
  instructions        211G  ± 16.1M      211G  …  211G           0 ( 0%)        💩+  1.1% ±  0.0%
  cache_references   7.22G  ± 11.5M     7.20G  … 7.25G           2 (15%)          -  0.1% ±  0.2%
  cache_misses        295M  ± 2.06M      290M  …  297M           0 ( 0%)          +  0.5% ±  1.3%
  branch_misses       314M  ±  730K      314M  …  316M           0 ( 0%)          +  0.7% ±  0.4%

@andrewrk

Copy link
Copy Markdown
Member

Oops, looks like my mistake was not passing strip to old linker because I didn't realize debug info was not implemented yet

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

linking release notes This PR should be mentioned in the release notes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

incremental: some tests fail due to corrupted output debug info

2 participants