Trim unused CoreCLR native components from dotnet-linker-tests build - #131666

Merged
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf
Aug 7, 2026
Merged

Trim unused CoreCLR native components from dotnet-linker-tests build#131666
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf

Conversation

@sbomer

@sbomersbomer commented Jul 31, 2026

Copy link
Copy Markdown
Member

The Runtime_Release jobs in the dotnet-linker-tests pipeline build the clr subset. That expands to a list of CoreCLR subsets (eng/Subsets.props, DefaultCoreClrSubsets) which includes clr.native, and clr.native performs a full CoreCLR native build. That pulls in components the trimming and NativeAOT tests never use — most notably the cross-target alt-JITs and SuperPMI.

This PR narrows the subset list to what those tests actually need, and fixes a Windows/Unix asymmetry in the JIT install rules that blocked doing so.

1. src/coreclr/jit/CMakeLists.txt — install the target-specific JIT into the jit component on Windows

crossgen2 and ILC don't load clrjit; they load the JIT named for the target they're compiling for, e.g. clrjit_win_x64_x64 when targeting win-x64.

On Unix that JIT is already installed into the jit component alongside clrjit:

if (CLR_CMAKE_TARGET_UNIX)
...install_clr(TARGETSclrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME}DESTINATIONS.COMPONENTjit)
endif()

Windows had no equivalent rule, so there the target-specific JIT was only ever installed as part of alljits. Any Windows build that selects native components individually rather than doing a full native build therefore produces a crossgen2 that fails as soon as it runs:

EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1

This mirrors the existing Unix rule for Windows targets. Full native builds are unaffected, since alljits already installed these JITs — it only makes the jit component self-contained on Windows the way it already is on Unix.

2. eng/pipelines/runtime-linker-tests.yml — narrow the subset list

clr.native is replaced by clr.runtime + clr.nativeaotruntime (the runtime and nativeaot CMake components). src/coreclr/components.cmake shows runtime already depends on jit, iltools, debug and hosts, and with the fix above jit now also carries the JIT crossgen2/ILC need.

Dropped as a result:

  • alljits — the cross-target alt-JITs. On win-x64 only clrjit and clrjit_win_x64_x64 are now built; on linux-x64 only clrjit and clrjit_unix_x64_x64.
  • spmi — SuperPMI and its shims.
  • clr.packages — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL nupkgs, referenced solely by eng/Publishing.props for official-build publishing. Packing them takes ~2.5s, so this is a cleanliness change, not a perf one.
  • clr.crossarchtools — redundant here: _BuildCrossComponents is already set whenever ClrRuntimeBuildSubsets is non-empty for CoreCLR, and the cross-tool build is gated on _BuildAnyCrossArch, which is false for native windows-x64/linux-x64. Verified that no cross-arch build directory is produced either way.

Measurements

Measured on CI, comparing build 1538104 (this PR) against 1534932 (a recent PR build of the unchanged pipeline):

ninja targets"Build product"
windows-x64 (critical path)2646 → 1901 (−28.2%)40.0m → 35.4m (−4.6m)
linux-x642837 → 2132 (−24.8%)31.7m → 29.0m (−2.7m)
browser-wasmunaffected (builds mono)26.0m → 26.7m

The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build wall clock went from 75.0m to 68.0m, though that figure includes queue variance across runs — the "Build product" numbers are the reliable ones. linux-x64 saves time too but stays off the critical path.

Locally, isolating just the CoreCLR native build on linux-x64 at ninja -j 4 (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%, consistent with the CI result.

Validation

Locally, from a clean tree with the narrowed subsets:

  • Trimming tests: 88 tests pass
  • NativeAOT test apps: 57 tests pass
  • Artifacts verified: libcoreclr.so, ilc, crossgen2, ilasm/ildasm, DAC/mscordbi and the aotsdk all still present; superpmi and the unused alt-JITs gone

On CI, all three dotnet-linker-tests jobs (windows-x64, linux-x64, browser-wasm) pass, including the trimming and NativeAOT test app steps, with no change in test counts or coverage.

Two unrelated failures show up on this PR and are not caused by it:

  • runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped) — fails with NETSDK1203 on every recent PR (sampled 6/6); the leg only passes on main because rolling builds run it as Release.
  • System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert on linux-arm64 — known flaky, tracked by Disable TLS resume in SslStreamServer_RejectsClientCert_ClientObservesAlert #131755 (44 hits in the last month).

Note

This content was created with assistance from AI.

The Runtime_Release jobs in the dotnet-linker-tests pipeline built the
`clr` subset, which expands to `clr.native` and therefore performs a full
CoreCLR native build. That includes several components the trimming and
NativeAOT tests never use, most notably the `alljits` component (six
cross-target alt-JITs) and `spmi` (SuperPMI and its shims).
Narrow the subset list to just the components the tests need. This drops
703 of 2837 ninja targets (~25%) from the CoreCLR native build. Measured
locally at `ninja -j 4`, matching the parallelism CI uses, the native
build goes from 4m03s to 3m05s (-24%).
Also drop two subsets that were pulled in by `clr` but are not needed:
* `clr.packages` only produces the ILAsm, ILDAsm, TestHost and Sdk.IL
nupkgs, which are consumed solely by official-build publishing.
* `clr.crossarchtools` is redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64 and linux-x64.
Validated from a clean tree with the narrowed subsets: the trimming tests
(88) and the NativeAOT test apps (57) all pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the runtime-linker-tests Azure Pipelines definition to build a narrower set of CoreCLR subsets for the Runtime_Release jobs, aiming to avoid building unused native components during trimming and NativeAOT test runs.

Changes:

  • Replaces -s clr+... with an explicit subset list centered on clr.runtime plus NativeAOT/tooling subsets.
  • Adds inline pipeline comments documenting why alljits and spmi are intentionally excluded.
Show a summary per file
FileDescription
eng/pipelines/runtime-linker-tests.ymlSwitches the CoreCLR build from clr to an explicit subset list intended to avoid building unused native components for linker/NativeAOT tests.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment threadeng/pipelines/runtime-linker-tests.yml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 31, 2026 19:17

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new

crossgen2 and ILC don't load clrjit; they load the JIT named for the
target they are compiling for, e.g. clrjit_win_x64_x64 when targeting
win-x64. On Unix that JIT is already installed into the `jit` component
alongside clrjit, so a build that requests only `-component runtime`
(which depends on `jit`) can run them. Windows had no equivalent rule, so
the target-specific JIT was only ever installed as part of `alljits`.
The result is that a Windows build which selects CoreCLR native
components individually, rather than doing a full native build, produces
a crossgen2 that fails at runtime with "Dll was not found" as soon as it
is invoked, for example while R2R compiling System.Private.CoreLib.
Mirror the existing Unix rule for Windows targets. Full native builds are
unaffected since `alljits` already installed these JITs; this only makes
the `jit` component self-contained on Windows the way it already is on
Unix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
CopilotAI review requested due to automatic review settings August 3, 2026 20:40

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Suppressed comments (1)

eng/pipelines/runtime-linker-tests.yml:119

  • The comment is slightly inaccurate: the clr subset expands to the full $(DefaultCoreClrSubsets) list (which includes clr.native among others), not to clr.native alone. Rewording avoids confusion for future maintainers reading the pipeline.
 # This replaces the previous `clr` subset (which expands to `clr.native` and builds every native component)
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 7 pipeline(s).
9 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@sbomer
sbomer merged commit b7130aa into dotnet:mainAug 7, 2026
217 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-rc1 milestone Aug 7, 2026
@sbomer
sbomer deleted the runtime-linker-test-perf branch August 10, 2026 16:23
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Aug 11, 2026
…otnet#131666)
The `Runtime_Release` jobs in the `dotnet-linker-tests` pipeline build
the `clr` subset. That expands to a list of CoreCLR subsets
(`eng/Subsets.props`, `DefaultCoreClrSubsets`) which includes
`clr.native`, and `clr.native` performs a *full* CoreCLR native build.
That pulls in components the trimming and NativeAOT tests never use —
most notably the cross-target alt-JITs and SuperPMI.
This PR narrows the subset list to what those tests actually need, and
fixes a Windows/Unix asymmetry in the JIT install rules that blocked
doing so.
## 1. `src/coreclr/jit/CMakeLists.txt` — install the target-specific JIT
into the `jit` component on Windows
crossgen2 and ILC don't load `clrjit`; they load the JIT named for the
target they're compiling for, e.g. `clrjit_win_x64_x64` when targeting
win-x64.
On Unix that JIT is already installed into the `jit` component alongside
`clrjit`:
```cmake
if (CLR_CMAKE_TARGET_UNIX)
...
install_clr(TARGETS clrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME} DESTINATIONS . COMPONENT jit)
endif()
```
Windows had no equivalent rule, so there the target-specific JIT was
only ever installed as part of `alljits`. Any Windows build that selects
native components individually rather than doing a full native build
therefore produces a crossgen2 that fails as soon as it runs:
```
EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1
```
This mirrors the existing Unix rule for Windows targets. **Full native
builds are unaffected**, since `alljits` already installed these JITs —
it only makes the `jit` component self-contained on Windows the way it
already is on Unix.
## 2. `eng/pipelines/runtime-linker-tests.yml` — narrow the subset list
`clr.native` is replaced by `clr.runtime` + `clr.nativeaotruntime` (the
`runtime` and `nativeaot` CMake components).
`src/coreclr/components.cmake` shows `runtime` already depends on `jit`,
`iltools`, `debug` and `hosts`, and with the fix above `jit` now also
carries the JIT crossgen2/ILC need.
Dropped as a result:
- **`alljits`** — the cross-target alt-JITs. On win-x64 only `clrjit`
and `clrjit_win_x64_x64` are now built; on linux-x64 only `clrjit` and
`clrjit_unix_x64_x64`.
- **`spmi`** — SuperPMI and its shims.
- **`clr.packages`** — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL
nupkgs, referenced solely by `eng/Publishing.props` for official-build
publishing. Packing them takes ~2.5s, so this is a cleanliness change,
not a perf one.
- **`clr.crossarchtools`** — redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64/linux-x64. Verified that no cross-arch
build directory is produced either way.
## Measurements
Measured on CI, comparing build
[1538104](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1538104)
(this PR) against
[1534932](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1534932)
(a recent PR build of the unchanged pipeline):
| | ninja targets | "Build product" |
|---|---|---|
| **windows-x64** (critical path) | 2646 → **1901** (−28.2%) | 40.0m →
**35.4m** (−4.6m) |
| linux-x64 | 2837 → **2132** (−24.8%) | 31.7m → **29.0m** (−2.7m) |
| browser-wasm | unaffected (builds `mono`) | 26.0m → 26.7m |
The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build
wall clock went from 75.0m to 68.0m, though that figure includes queue
variance across runs — the "Build product" numbers are the reliable
ones. linux-x64 saves time too but stays off the critical path.
Locally, isolating just the CoreCLR native build on linux-x64 at `ninja
-j 4` (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%,
consistent with the CI result.
## Validation
Locally, from a clean tree with the narrowed subsets:
- Trimming tests: **88 tests pass**
- NativeAOT test apps: **57 tests pass**
- Artifacts verified: `libcoreclr.so`, `ilc`, `crossgen2`,
`ilasm`/`ildasm`, DAC/mscordbi and the `aotsdk` all still present;
superpmi and the unused alt-JITs gone
On CI, all three `dotnet-linker-tests` jobs (windows-x64, linux-x64,
browser-wasm) pass, including the trimming and NativeAOT test app steps,
with no change in test counts or coverage.
Two unrelated failures show up on this PR and are not caused by it:
- `runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped)` — fails with
`NETSDK1203` on every recent PR (sampled 6/6); the leg only passes on
`main` because rolling builds run it as Release.
-
`System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert`
on linux-arm64 — known flaky, tracked by dotnet#131755 (44 hits in the last
month).
> [!NOTE]
> This content was created with assistance from AI.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
MichalStrehovsky added a commit that referenced this pull request Aug 24, 2026
After #131666 we should be able to get away with clr.jit. If one needs
to crossbuild, they'll need to add clr.alljits, but that's not a
mainstream scenario. Should shave the same number of minutes as what is
in #131666.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@sbomer@jkoritzinsky@jtschuster
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Trim unused CoreCLR native components from dotnet-linker-tests build - #131666

Merged
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf
Aug 7, 2026
Merged

Trim unused CoreCLR native components from dotnet-linker-tests build#131666
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf

Conversation

@sbomer

@sbomersbomer commented Jul 31, 2026

Copy link
Copy Markdown
Member

The Runtime_Release jobs in the dotnet-linker-tests pipeline build the clr subset. That expands to a list of CoreCLR subsets (eng/Subsets.props, DefaultCoreClrSubsets) which includes clr.native, and clr.native performs a full CoreCLR native build. That pulls in components the trimming and NativeAOT tests never use — most notably the cross-target alt-JITs and SuperPMI.

This PR narrows the subset list to what those tests actually need, and fixes a Windows/Unix asymmetry in the JIT install rules that blocked doing so.

1. src/coreclr/jit/CMakeLists.txt — install the target-specific JIT into the jit component on Windows

crossgen2 and ILC don't load clrjit; they load the JIT named for the target they're compiling for, e.g. clrjit_win_x64_x64 when targeting win-x64.

On Unix that JIT is already installed into the jit component alongside clrjit:

if (CLR_CMAKE_TARGET_UNIX)
...install_clr(TARGETSclrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME}DESTINATIONS.COMPONENTjit)
endif()

Windows had no equivalent rule, so there the target-specific JIT was only ever installed as part of alljits. Any Windows build that selects native components individually rather than doing a full native build therefore produces a crossgen2 that fails as soon as it runs:

EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1

This mirrors the existing Unix rule for Windows targets. Full native builds are unaffected, since alljits already installed these JITs — it only makes the jit component self-contained on Windows the way it already is on Unix.

2. eng/pipelines/runtime-linker-tests.yml — narrow the subset list

clr.native is replaced by clr.runtime + clr.nativeaotruntime (the runtime and nativeaot CMake components). src/coreclr/components.cmake shows runtime already depends on jit, iltools, debug and hosts, and with the fix above jit now also carries the JIT crossgen2/ILC need.

Dropped as a result:

  • alljits — the cross-target alt-JITs. On win-x64 only clrjit and clrjit_win_x64_x64 are now built; on linux-x64 only clrjit and clrjit_unix_x64_x64.
  • spmi — SuperPMI and its shims.
  • clr.packages — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL nupkgs, referenced solely by eng/Publishing.props for official-build publishing. Packing them takes ~2.5s, so this is a cleanliness change, not a perf one.
  • clr.crossarchtools — redundant here: _BuildCrossComponents is already set whenever ClrRuntimeBuildSubsets is non-empty for CoreCLR, and the cross-tool build is gated on _BuildAnyCrossArch, which is false for native windows-x64/linux-x64. Verified that no cross-arch build directory is produced either way.

Measurements

Measured on CI, comparing build 1538104 (this PR) against 1534932 (a recent PR build of the unchanged pipeline):

ninja targets"Build product"
windows-x64 (critical path)2646 → 1901 (−28.2%)40.0m → 35.4m (−4.6m)
linux-x642837 → 2132 (−24.8%)31.7m → 29.0m (−2.7m)
browser-wasmunaffected (builds mono)26.0m → 26.7m

The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build wall clock went from 75.0m to 68.0m, though that figure includes queue variance across runs — the "Build product" numbers are the reliable ones. linux-x64 saves time too but stays off the critical path.

Locally, isolating just the CoreCLR native build on linux-x64 at ninja -j 4 (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%, consistent with the CI result.

Validation

Locally, from a clean tree with the narrowed subsets:

  • Trimming tests: 88 tests pass
  • NativeAOT test apps: 57 tests pass
  • Artifacts verified: libcoreclr.so, ilc, crossgen2, ilasm/ildasm, DAC/mscordbi and the aotsdk all still present; superpmi and the unused alt-JITs gone

On CI, all three dotnet-linker-tests jobs (windows-x64, linux-x64, browser-wasm) pass, including the trimming and NativeAOT test app steps, with no change in test counts or coverage.

Two unrelated failures show up on this PR and are not caused by it:

  • runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped) — fails with NETSDK1203 on every recent PR (sampled 6/6); the leg only passes on main because rolling builds run it as Release.
  • System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert on linux-arm64 — known flaky, tracked by Disable TLS resume in SslStreamServer_RejectsClientCert_ClientObservesAlert #131755 (44 hits in the last month).

Note

This content was created with assistance from AI.

The Runtime_Release jobs in the dotnet-linker-tests pipeline built the
`clr` subset, which expands to `clr.native` and therefore performs a full
CoreCLR native build. That includes several components the trimming and
NativeAOT tests never use, most notably the `alljits` component (six
cross-target alt-JITs) and `spmi` (SuperPMI and its shims).
Narrow the subset list to just the components the tests need. This drops
703 of 2837 ninja targets (~25%) from the CoreCLR native build. Measured
locally at `ninja -j 4`, matching the parallelism CI uses, the native
build goes from 4m03s to 3m05s (-24%).
Also drop two subsets that were pulled in by `clr` but are not needed:
* `clr.packages` only produces the ILAsm, ILDAsm, TestHost and Sdk.IL
nupkgs, which are consumed solely by official-build publishing.
* `clr.crossarchtools` is redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64 and linux-x64.
Validated from a clean tree with the narrowed subsets: the trimming tests
(88) and the NativeAOT test apps (57) all pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the runtime-linker-tests Azure Pipelines definition to build a narrower set of CoreCLR subsets for the Runtime_Release jobs, aiming to avoid building unused native components during trimming and NativeAOT test runs.

Changes:

  • Replaces -s clr+... with an explicit subset list centered on clr.runtime plus NativeAOT/tooling subsets.
  • Adds inline pipeline comments documenting why alljits and spmi are intentionally excluded.
Show a summary per file
FileDescription
eng/pipelines/runtime-linker-tests.ymlSwitches the CoreCLR build from clr to an explicit subset list intended to avoid building unused native components for linker/NativeAOT tests.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment threadeng/pipelines/runtime-linker-tests.yml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 31, 2026 19:17

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new

crossgen2 and ILC don't load clrjit; they load the JIT named for the
target they are compiling for, e.g. clrjit_win_x64_x64 when targeting
win-x64. On Unix that JIT is already installed into the `jit` component
alongside clrjit, so a build that requests only `-component runtime`
(which depends on `jit`) can run them. Windows had no equivalent rule, so
the target-specific JIT was only ever installed as part of `alljits`.
The result is that a Windows build which selects CoreCLR native
components individually, rather than doing a full native build, produces
a crossgen2 that fails at runtime with "Dll was not found" as soon as it
is invoked, for example while R2R compiling System.Private.CoreLib.
Mirror the existing Unix rule for Windows targets. Full native builds are
unaffected since `alljits` already installed these JITs; this only makes
the `jit` component self-contained on Windows the way it already is on
Unix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
CopilotAI review requested due to automatic review settings August 3, 2026 20:40

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Suppressed comments (1)

eng/pipelines/runtime-linker-tests.yml:119

  • The comment is slightly inaccurate: the clr subset expands to the full $(DefaultCoreClrSubsets) list (which includes clr.native among others), not to clr.native alone. Rewording avoids confusion for future maintainers reading the pipeline.
 # This replaces the previous `clr` subset (which expands to `clr.native` and builds every native component)
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 7 pipeline(s).
9 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@sbomer
sbomer merged commit b7130aa into dotnet:mainAug 7, 2026
217 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-rc1 milestone Aug 7, 2026
@sbomer
sbomer deleted the runtime-linker-test-perf branch August 10, 2026 16:23
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Aug 11, 2026
…otnet#131666)
The `Runtime_Release` jobs in the `dotnet-linker-tests` pipeline build
the `clr` subset. That expands to a list of CoreCLR subsets
(`eng/Subsets.props`, `DefaultCoreClrSubsets`) which includes
`clr.native`, and `clr.native` performs a *full* CoreCLR native build.
That pulls in components the trimming and NativeAOT tests never use —
most notably the cross-target alt-JITs and SuperPMI.
This PR narrows the subset list to what those tests actually need, and
fixes a Windows/Unix asymmetry in the JIT install rules that blocked
doing so.
## 1. `src/coreclr/jit/CMakeLists.txt` — install the target-specific JIT
into the `jit` component on Windows
crossgen2 and ILC don't load `clrjit`; they load the JIT named for the
target they're compiling for, e.g. `clrjit_win_x64_x64` when targeting
win-x64.
On Unix that JIT is already installed into the `jit` component alongside
`clrjit`:
```cmake
if (CLR_CMAKE_TARGET_UNIX)
...
install_clr(TARGETS clrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME} DESTINATIONS . COMPONENT jit)
endif()
```
Windows had no equivalent rule, so there the target-specific JIT was
only ever installed as part of `alljits`. Any Windows build that selects
native components individually rather than doing a full native build
therefore produces a crossgen2 that fails as soon as it runs:
```
EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1
```
This mirrors the existing Unix rule for Windows targets. **Full native
builds are unaffected**, since `alljits` already installed these JITs —
it only makes the `jit` component self-contained on Windows the way it
already is on Unix.
## 2. `eng/pipelines/runtime-linker-tests.yml` — narrow the subset list
`clr.native` is replaced by `clr.runtime` + `clr.nativeaotruntime` (the
`runtime` and `nativeaot` CMake components).
`src/coreclr/components.cmake` shows `runtime` already depends on `jit`,
`iltools`, `debug` and `hosts`, and with the fix above `jit` now also
carries the JIT crossgen2/ILC need.
Dropped as a result:
- **`alljits`** — the cross-target alt-JITs. On win-x64 only `clrjit`
and `clrjit_win_x64_x64` are now built; on linux-x64 only `clrjit` and
`clrjit_unix_x64_x64`.
- **`spmi`** — SuperPMI and its shims.
- **`clr.packages`** — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL
nupkgs, referenced solely by `eng/Publishing.props` for official-build
publishing. Packing them takes ~2.5s, so this is a cleanliness change,
not a perf one.
- **`clr.crossarchtools`** — redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64/linux-x64. Verified that no cross-arch
build directory is produced either way.
## Measurements
Measured on CI, comparing build
[1538104](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1538104)
(this PR) against
[1534932](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1534932)
(a recent PR build of the unchanged pipeline):
| | ninja targets | "Build product" |
|---|---|---|
| **windows-x64** (critical path) | 2646 → **1901** (−28.2%) | 40.0m →
**35.4m** (−4.6m) |
| linux-x64 | 2837 → **2132** (−24.8%) | 31.7m → **29.0m** (−2.7m) |
| browser-wasm | unaffected (builds `mono`) | 26.0m → 26.7m |
The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build
wall clock went from 75.0m to 68.0m, though that figure includes queue
variance across runs — the "Build product" numbers are the reliable
ones. linux-x64 saves time too but stays off the critical path.
Locally, isolating just the CoreCLR native build on linux-x64 at `ninja
-j 4` (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%,
consistent with the CI result.
## Validation
Locally, from a clean tree with the narrowed subsets:
- Trimming tests: **88 tests pass**
- NativeAOT test apps: **57 tests pass**
- Artifacts verified: `libcoreclr.so`, `ilc`, `crossgen2`,
`ilasm`/`ildasm`, DAC/mscordbi and the `aotsdk` all still present;
superpmi and the unused alt-JITs gone
On CI, all three `dotnet-linker-tests` jobs (windows-x64, linux-x64,
browser-wasm) pass, including the trimming and NativeAOT test app steps,
with no change in test counts or coverage.
Two unrelated failures show up on this PR and are not caused by it:
- `runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped)` — fails with
`NETSDK1203` on every recent PR (sampled 6/6); the leg only passes on
`main` because rolling builds run it as Release.
-
`System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert`
on linux-arm64 — known flaky, tracked by dotnet#131755 (44 hits in the last
month).
> [!NOTE]
> This content was created with assistance from AI.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
MichalStrehovsky added a commit that referenced this pull request Aug 24, 2026
After #131666 we should be able to get away with clr.jit. If one needs
to crossbuild, they'll need to add clr.alljits, but that's not a
mainstream scenario. Should shave the same number of minutes as what is
in #131666.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@sbomer@jkoritzinsky@jtschuster
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Trim unused CoreCLR native components from dotnet-linker-tests build - #131666

Merged
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf
Aug 7, 2026
Merged

Trim unused CoreCLR native components from dotnet-linker-tests build#131666
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf

Conversation

@sbomer

@sbomersbomer commented Jul 31, 2026

Copy link
Copy Markdown
Member

The Runtime_Release jobs in the dotnet-linker-tests pipeline build the clr subset. That expands to a list of CoreCLR subsets (eng/Subsets.props, DefaultCoreClrSubsets) which includes clr.native, and clr.native performs a full CoreCLR native build. That pulls in components the trimming and NativeAOT tests never use — most notably the cross-target alt-JITs and SuperPMI.

This PR narrows the subset list to what those tests actually need, and fixes a Windows/Unix asymmetry in the JIT install rules that blocked doing so.

1. src/coreclr/jit/CMakeLists.txt — install the target-specific JIT into the jit component on Windows

crossgen2 and ILC don't load clrjit; they load the JIT named for the target they're compiling for, e.g. clrjit_win_x64_x64 when targeting win-x64.

On Unix that JIT is already installed into the jit component alongside clrjit:

if (CLR_CMAKE_TARGET_UNIX)
...install_clr(TARGETSclrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME}DESTINATIONS.COMPONENTjit)
endif()

Windows had no equivalent rule, so there the target-specific JIT was only ever installed as part of alljits. Any Windows build that selects native components individually rather than doing a full native build therefore produces a crossgen2 that fails as soon as it runs:

EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1

This mirrors the existing Unix rule for Windows targets. Full native builds are unaffected, since alljits already installed these JITs — it only makes the jit component self-contained on Windows the way it already is on Unix.

2. eng/pipelines/runtime-linker-tests.yml — narrow the subset list

clr.native is replaced by clr.runtime + clr.nativeaotruntime (the runtime and nativeaot CMake components). src/coreclr/components.cmake shows runtime already depends on jit, iltools, debug and hosts, and with the fix above jit now also carries the JIT crossgen2/ILC need.

Dropped as a result:

  • alljits — the cross-target alt-JITs. On win-x64 only clrjit and clrjit_win_x64_x64 are now built; on linux-x64 only clrjit and clrjit_unix_x64_x64.
  • spmi — SuperPMI and its shims.
  • clr.packages — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL nupkgs, referenced solely by eng/Publishing.props for official-build publishing. Packing them takes ~2.5s, so this is a cleanliness change, not a perf one.
  • clr.crossarchtools — redundant here: _BuildCrossComponents is already set whenever ClrRuntimeBuildSubsets is non-empty for CoreCLR, and the cross-tool build is gated on _BuildAnyCrossArch, which is false for native windows-x64/linux-x64. Verified that no cross-arch build directory is produced either way.

Measurements

Measured on CI, comparing build 1538104 (this PR) against 1534932 (a recent PR build of the unchanged pipeline):

ninja targets"Build product"
windows-x64 (critical path)2646 → 1901 (−28.2%)40.0m → 35.4m (−4.6m)
linux-x642837 → 2132 (−24.8%)31.7m → 29.0m (−2.7m)
browser-wasmunaffected (builds mono)26.0m → 26.7m

The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build wall clock went from 75.0m to 68.0m, though that figure includes queue variance across runs — the "Build product" numbers are the reliable ones. linux-x64 saves time too but stays off the critical path.

Locally, isolating just the CoreCLR native build on linux-x64 at ninja -j 4 (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%, consistent with the CI result.

Validation

Locally, from a clean tree with the narrowed subsets:

  • Trimming tests: 88 tests pass
  • NativeAOT test apps: 57 tests pass
  • Artifacts verified: libcoreclr.so, ilc, crossgen2, ilasm/ildasm, DAC/mscordbi and the aotsdk all still present; superpmi and the unused alt-JITs gone

On CI, all three dotnet-linker-tests jobs (windows-x64, linux-x64, browser-wasm) pass, including the trimming and NativeAOT test app steps, with no change in test counts or coverage.

Two unrelated failures show up on this PR and are not caused by it:

  • runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped) — fails with NETSDK1203 on every recent PR (sampled 6/6); the leg only passes on main because rolling builds run it as Release.
  • System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert on linux-arm64 — known flaky, tracked by Disable TLS resume in SslStreamServer_RejectsClientCert_ClientObservesAlert #131755 (44 hits in the last month).

Note

This content was created with assistance from AI.

The Runtime_Release jobs in the dotnet-linker-tests pipeline built the
`clr` subset, which expands to `clr.native` and therefore performs a full
CoreCLR native build. That includes several components the trimming and
NativeAOT tests never use, most notably the `alljits` component (six
cross-target alt-JITs) and `spmi` (SuperPMI and its shims).
Narrow the subset list to just the components the tests need. This drops
703 of 2837 ninja targets (~25%) from the CoreCLR native build. Measured
locally at `ninja -j 4`, matching the parallelism CI uses, the native
build goes from 4m03s to 3m05s (-24%).
Also drop two subsets that were pulled in by `clr` but are not needed:
* `clr.packages` only produces the ILAsm, ILDAsm, TestHost and Sdk.IL
nupkgs, which are consumed solely by official-build publishing.
* `clr.crossarchtools` is redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64 and linux-x64.
Validated from a clean tree with the narrowed subsets: the trimming tests
(88) and the NativeAOT test apps (57) all pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the runtime-linker-tests Azure Pipelines definition to build a narrower set of CoreCLR subsets for the Runtime_Release jobs, aiming to avoid building unused native components during trimming and NativeAOT test runs.

Changes:

  • Replaces -s clr+... with an explicit subset list centered on clr.runtime plus NativeAOT/tooling subsets.
  • Adds inline pipeline comments documenting why alljits and spmi are intentionally excluded.
Show a summary per file
FileDescription
eng/pipelines/runtime-linker-tests.ymlSwitches the CoreCLR build from clr to an explicit subset list intended to avoid building unused native components for linker/NativeAOT tests.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment threadeng/pipelines/runtime-linker-tests.yml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 31, 2026 19:17

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new

crossgen2 and ILC don't load clrjit; they load the JIT named for the
target they are compiling for, e.g. clrjit_win_x64_x64 when targeting
win-x64. On Unix that JIT is already installed into the `jit` component
alongside clrjit, so a build that requests only `-component runtime`
(which depends on `jit`) can run them. Windows had no equivalent rule, so
the target-specific JIT was only ever installed as part of `alljits`.
The result is that a Windows build which selects CoreCLR native
components individually, rather than doing a full native build, produces
a crossgen2 that fails at runtime with "Dll was not found" as soon as it
is invoked, for example while R2R compiling System.Private.CoreLib.
Mirror the existing Unix rule for Windows targets. Full native builds are
unaffected since `alljits` already installed these JITs; this only makes
the `jit` component self-contained on Windows the way it already is on
Unix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
CopilotAI review requested due to automatic review settings August 3, 2026 20:40

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Suppressed comments (1)

eng/pipelines/runtime-linker-tests.yml:119

  • The comment is slightly inaccurate: the clr subset expands to the full $(DefaultCoreClrSubsets) list (which includes clr.native among others), not to clr.native alone. Rewording avoids confusion for future maintainers reading the pipeline.
 # This replaces the previous `clr` subset (which expands to `clr.native` and builds every native component)
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 7 pipeline(s).
9 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@sbomer
sbomer merged commit b7130aa into dotnet:mainAug 7, 2026
217 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-rc1 milestone Aug 7, 2026
@sbomer
sbomer deleted the runtime-linker-test-perf branch August 10, 2026 16:23
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Aug 11, 2026
…otnet#131666)
The `Runtime_Release` jobs in the `dotnet-linker-tests` pipeline build
the `clr` subset. That expands to a list of CoreCLR subsets
(`eng/Subsets.props`, `DefaultCoreClrSubsets`) which includes
`clr.native`, and `clr.native` performs a *full* CoreCLR native build.
That pulls in components the trimming and NativeAOT tests never use —
most notably the cross-target alt-JITs and SuperPMI.
This PR narrows the subset list to what those tests actually need, and
fixes a Windows/Unix asymmetry in the JIT install rules that blocked
doing so.
## 1. `src/coreclr/jit/CMakeLists.txt` — install the target-specific JIT
into the `jit` component on Windows
crossgen2 and ILC don't load `clrjit`; they load the JIT named for the
target they're compiling for, e.g. `clrjit_win_x64_x64` when targeting
win-x64.
On Unix that JIT is already installed into the `jit` component alongside
`clrjit`:
```cmake
if (CLR_CMAKE_TARGET_UNIX)
...
install_clr(TARGETS clrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME} DESTINATIONS . COMPONENT jit)
endif()
```
Windows had no equivalent rule, so there the target-specific JIT was
only ever installed as part of `alljits`. Any Windows build that selects
native components individually rather than doing a full native build
therefore produces a crossgen2 that fails as soon as it runs:
```
EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1
```
This mirrors the existing Unix rule for Windows targets. **Full native
builds are unaffected**, since `alljits` already installed these JITs —
it only makes the `jit` component self-contained on Windows the way it
already is on Unix.
## 2. `eng/pipelines/runtime-linker-tests.yml` — narrow the subset list
`clr.native` is replaced by `clr.runtime` + `clr.nativeaotruntime` (the
`runtime` and `nativeaot` CMake components).
`src/coreclr/components.cmake` shows `runtime` already depends on `jit`,
`iltools`, `debug` and `hosts`, and with the fix above `jit` now also
carries the JIT crossgen2/ILC need.
Dropped as a result:
- **`alljits`** — the cross-target alt-JITs. On win-x64 only `clrjit`
and `clrjit_win_x64_x64` are now built; on linux-x64 only `clrjit` and
`clrjit_unix_x64_x64`.
- **`spmi`** — SuperPMI and its shims.
- **`clr.packages`** — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL
nupkgs, referenced solely by `eng/Publishing.props` for official-build
publishing. Packing them takes ~2.5s, so this is a cleanliness change,
not a perf one.
- **`clr.crossarchtools`** — redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64/linux-x64. Verified that no cross-arch
build directory is produced either way.
## Measurements
Measured on CI, comparing build
[1538104](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1538104)
(this PR) against
[1534932](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1534932)
(a recent PR build of the unchanged pipeline):
| | ninja targets | "Build product" |
|---|---|---|
| **windows-x64** (critical path) | 2646 → **1901** (−28.2%) | 40.0m →
**35.4m** (−4.6m) |
| linux-x64 | 2837 → **2132** (−24.8%) | 31.7m → **29.0m** (−2.7m) |
| browser-wasm | unaffected (builds `mono`) | 26.0m → 26.7m |
The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build
wall clock went from 75.0m to 68.0m, though that figure includes queue
variance across runs — the "Build product" numbers are the reliable
ones. linux-x64 saves time too but stays off the critical path.
Locally, isolating just the CoreCLR native build on linux-x64 at `ninja
-j 4` (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%,
consistent with the CI result.
## Validation
Locally, from a clean tree with the narrowed subsets:
- Trimming tests: **88 tests pass**
- NativeAOT test apps: **57 tests pass**
- Artifacts verified: `libcoreclr.so`, `ilc`, `crossgen2`,
`ilasm`/`ildasm`, DAC/mscordbi and the `aotsdk` all still present;
superpmi and the unused alt-JITs gone
On CI, all three `dotnet-linker-tests` jobs (windows-x64, linux-x64,
browser-wasm) pass, including the trimming and NativeAOT test app steps,
with no change in test counts or coverage.
Two unrelated failures show up on this PR and are not caused by it:
- `runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped)` — fails with
`NETSDK1203` on every recent PR (sampled 6/6); the leg only passes on
`main` because rolling builds run it as Release.
-
`System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert`
on linux-arm64 — known flaky, tracked by dotnet#131755 (44 hits in the last
month).
> [!NOTE]
> This content was created with assistance from AI.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
MichalStrehovsky added a commit that referenced this pull request Aug 24, 2026
After #131666 we should be able to get away with clr.jit. If one needs
to crossbuild, they'll need to add clr.alljits, but that's not a
mainstream scenario. Should shave the same number of minutes as what is
in #131666.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@sbomer@jkoritzinsky@jtschuster
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Trim unused CoreCLR native components from dotnet-linker-tests build - #131666

Merged
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf
Aug 7, 2026
Merged

Trim unused CoreCLR native components from dotnet-linker-tests build#131666
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf

Conversation

@sbomer

@sbomersbomer commented Jul 31, 2026

Copy link
Copy Markdown
Member

The Runtime_Release jobs in the dotnet-linker-tests pipeline build the clr subset. That expands to a list of CoreCLR subsets (eng/Subsets.props, DefaultCoreClrSubsets) which includes clr.native, and clr.native performs a full CoreCLR native build. That pulls in components the trimming and NativeAOT tests never use — most notably the cross-target alt-JITs and SuperPMI.

This PR narrows the subset list to what those tests actually need, and fixes a Windows/Unix asymmetry in the JIT install rules that blocked doing so.

1. src/coreclr/jit/CMakeLists.txt — install the target-specific JIT into the jit component on Windows

crossgen2 and ILC don't load clrjit; they load the JIT named for the target they're compiling for, e.g. clrjit_win_x64_x64 when targeting win-x64.

On Unix that JIT is already installed into the jit component alongside clrjit:

if (CLR_CMAKE_TARGET_UNIX)
...install_clr(TARGETSclrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME}DESTINATIONS.COMPONENTjit)
endif()

Windows had no equivalent rule, so there the target-specific JIT was only ever installed as part of alljits. Any Windows build that selects native components individually rather than doing a full native build therefore produces a crossgen2 that fails as soon as it runs:

EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1

This mirrors the existing Unix rule for Windows targets. Full native builds are unaffected, since alljits already installed these JITs — it only makes the jit component self-contained on Windows the way it already is on Unix.

2. eng/pipelines/runtime-linker-tests.yml — narrow the subset list

clr.native is replaced by clr.runtime + clr.nativeaotruntime (the runtime and nativeaot CMake components). src/coreclr/components.cmake shows runtime already depends on jit, iltools, debug and hosts, and with the fix above jit now also carries the JIT crossgen2/ILC need.

Dropped as a result:

  • alljits — the cross-target alt-JITs. On win-x64 only clrjit and clrjit_win_x64_x64 are now built; on linux-x64 only clrjit and clrjit_unix_x64_x64.
  • spmi — SuperPMI and its shims.
  • clr.packages — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL nupkgs, referenced solely by eng/Publishing.props for official-build publishing. Packing them takes ~2.5s, so this is a cleanliness change, not a perf one.
  • clr.crossarchtools — redundant here: _BuildCrossComponents is already set whenever ClrRuntimeBuildSubsets is non-empty for CoreCLR, and the cross-tool build is gated on _BuildAnyCrossArch, which is false for native windows-x64/linux-x64. Verified that no cross-arch build directory is produced either way.

Measurements

Measured on CI, comparing build 1538104 (this PR) against 1534932 (a recent PR build of the unchanged pipeline):

ninja targets"Build product"
windows-x64 (critical path)2646 → 1901 (−28.2%)40.0m → 35.4m (−4.6m)
linux-x642837 → 2132 (−24.8%)31.7m → 29.0m (−2.7m)
browser-wasmunaffected (builds mono)26.0m → 26.7m

The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build wall clock went from 75.0m to 68.0m, though that figure includes queue variance across runs — the "Build product" numbers are the reliable ones. linux-x64 saves time too but stays off the critical path.

Locally, isolating just the CoreCLR native build on linux-x64 at ninja -j 4 (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%, consistent with the CI result.

Validation

Locally, from a clean tree with the narrowed subsets:

  • Trimming tests: 88 tests pass
  • NativeAOT test apps: 57 tests pass
  • Artifacts verified: libcoreclr.so, ilc, crossgen2, ilasm/ildasm, DAC/mscordbi and the aotsdk all still present; superpmi and the unused alt-JITs gone

On CI, all three dotnet-linker-tests jobs (windows-x64, linux-x64, browser-wasm) pass, including the trimming and NativeAOT test app steps, with no change in test counts or coverage.

Two unrelated failures show up on this PR and are not caused by it:

  • runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped) — fails with NETSDK1203 on every recent PR (sampled 6/6); the leg only passes on main because rolling builds run it as Release.
  • System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert on linux-arm64 — known flaky, tracked by Disable TLS resume in SslStreamServer_RejectsClientCert_ClientObservesAlert #131755 (44 hits in the last month).

Note

This content was created with assistance from AI.

The Runtime_Release jobs in the dotnet-linker-tests pipeline built the
`clr` subset, which expands to `clr.native` and therefore performs a full
CoreCLR native build. That includes several components the trimming and
NativeAOT tests never use, most notably the `alljits` component (six
cross-target alt-JITs) and `spmi` (SuperPMI and its shims).
Narrow the subset list to just the components the tests need. This drops
703 of 2837 ninja targets (~25%) from the CoreCLR native build. Measured
locally at `ninja -j 4`, matching the parallelism CI uses, the native
build goes from 4m03s to 3m05s (-24%).
Also drop two subsets that were pulled in by `clr` but are not needed:
* `clr.packages` only produces the ILAsm, ILDAsm, TestHost and Sdk.IL
nupkgs, which are consumed solely by official-build publishing.
* `clr.crossarchtools` is redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64 and linux-x64.
Validated from a clean tree with the narrowed subsets: the trimming tests
(88) and the NativeAOT test apps (57) all pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the runtime-linker-tests Azure Pipelines definition to build a narrower set of CoreCLR subsets for the Runtime_Release jobs, aiming to avoid building unused native components during trimming and NativeAOT test runs.

Changes:

  • Replaces -s clr+... with an explicit subset list centered on clr.runtime plus NativeAOT/tooling subsets.
  • Adds inline pipeline comments documenting why alljits and spmi are intentionally excluded.
Show a summary per file
FileDescription
eng/pipelines/runtime-linker-tests.ymlSwitches the CoreCLR build from clr to an explicit subset list intended to avoid building unused native components for linker/NativeAOT tests.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment threadeng/pipelines/runtime-linker-tests.yml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 31, 2026 19:17

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new

crossgen2 and ILC don't load clrjit; they load the JIT named for the
target they are compiling for, e.g. clrjit_win_x64_x64 when targeting
win-x64. On Unix that JIT is already installed into the `jit` component
alongside clrjit, so a build that requests only `-component runtime`
(which depends on `jit`) can run them. Windows had no equivalent rule, so
the target-specific JIT was only ever installed as part of `alljits`.
The result is that a Windows build which selects CoreCLR native
components individually, rather than doing a full native build, produces
a crossgen2 that fails at runtime with "Dll was not found" as soon as it
is invoked, for example while R2R compiling System.Private.CoreLib.
Mirror the existing Unix rule for Windows targets. Full native builds are
unaffected since `alljits` already installed these JITs; this only makes
the `jit` component self-contained on Windows the way it already is on
Unix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
CopilotAI review requested due to automatic review settings August 3, 2026 20:40

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Suppressed comments (1)

eng/pipelines/runtime-linker-tests.yml:119

  • The comment is slightly inaccurate: the clr subset expands to the full $(DefaultCoreClrSubsets) list (which includes clr.native among others), not to clr.native alone. Rewording avoids confusion for future maintainers reading the pipeline.
 # This replaces the previous `clr` subset (which expands to `clr.native` and builds every native component)
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 7 pipeline(s).
9 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@sbomer
sbomer merged commit b7130aa into dotnet:mainAug 7, 2026
217 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-rc1 milestone Aug 7, 2026
@sbomer
sbomer deleted the runtime-linker-test-perf branch August 10, 2026 16:23
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Aug 11, 2026
…otnet#131666)
The `Runtime_Release` jobs in the `dotnet-linker-tests` pipeline build
the `clr` subset. That expands to a list of CoreCLR subsets
(`eng/Subsets.props`, `DefaultCoreClrSubsets`) which includes
`clr.native`, and `clr.native` performs a *full* CoreCLR native build.
That pulls in components the trimming and NativeAOT tests never use —
most notably the cross-target alt-JITs and SuperPMI.
This PR narrows the subset list to what those tests actually need, and
fixes a Windows/Unix asymmetry in the JIT install rules that blocked
doing so.
## 1. `src/coreclr/jit/CMakeLists.txt` — install the target-specific JIT
into the `jit` component on Windows
crossgen2 and ILC don't load `clrjit`; they load the JIT named for the
target they're compiling for, e.g. `clrjit_win_x64_x64` when targeting
win-x64.
On Unix that JIT is already installed into the `jit` component alongside
`clrjit`:
```cmake
if (CLR_CMAKE_TARGET_UNIX)
...
install_clr(TARGETS clrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME} DESTINATIONS . COMPONENT jit)
endif()
```
Windows had no equivalent rule, so there the target-specific JIT was
only ever installed as part of `alljits`. Any Windows build that selects
native components individually rather than doing a full native build
therefore produces a crossgen2 that fails as soon as it runs:
```
EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1
```
This mirrors the existing Unix rule for Windows targets. **Full native
builds are unaffected**, since `alljits` already installed these JITs —
it only makes the `jit` component self-contained on Windows the way it
already is on Unix.
## 2. `eng/pipelines/runtime-linker-tests.yml` — narrow the subset list
`clr.native` is replaced by `clr.runtime` + `clr.nativeaotruntime` (the
`runtime` and `nativeaot` CMake components).
`src/coreclr/components.cmake` shows `runtime` already depends on `jit`,
`iltools`, `debug` and `hosts`, and with the fix above `jit` now also
carries the JIT crossgen2/ILC need.
Dropped as a result:
- **`alljits`** — the cross-target alt-JITs. On win-x64 only `clrjit`
and `clrjit_win_x64_x64` are now built; on linux-x64 only `clrjit` and
`clrjit_unix_x64_x64`.
- **`spmi`** — SuperPMI and its shims.
- **`clr.packages`** — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL
nupkgs, referenced solely by `eng/Publishing.props` for official-build
publishing. Packing them takes ~2.5s, so this is a cleanliness change,
not a perf one.
- **`clr.crossarchtools`** — redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64/linux-x64. Verified that no cross-arch
build directory is produced either way.
## Measurements
Measured on CI, comparing build
[1538104](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1538104)
(this PR) against
[1534932](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1534932)
(a recent PR build of the unchanged pipeline):
| | ninja targets | "Build product" |
|---|---|---|
| **windows-x64** (critical path) | 2646 → **1901** (−28.2%) | 40.0m →
**35.4m** (−4.6m) |
| linux-x64 | 2837 → **2132** (−24.8%) | 31.7m → **29.0m** (−2.7m) |
| browser-wasm | unaffected (builds `mono`) | 26.0m → 26.7m |
The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build
wall clock went from 75.0m to 68.0m, though that figure includes queue
variance across runs — the "Build product" numbers are the reliable
ones. linux-x64 saves time too but stays off the critical path.
Locally, isolating just the CoreCLR native build on linux-x64 at `ninja
-j 4` (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%,
consistent with the CI result.
## Validation
Locally, from a clean tree with the narrowed subsets:
- Trimming tests: **88 tests pass**
- NativeAOT test apps: **57 tests pass**
- Artifacts verified: `libcoreclr.so`, `ilc`, `crossgen2`,
`ilasm`/`ildasm`, DAC/mscordbi and the `aotsdk` all still present;
superpmi and the unused alt-JITs gone
On CI, all three `dotnet-linker-tests` jobs (windows-x64, linux-x64,
browser-wasm) pass, including the trimming and NativeAOT test app steps,
with no change in test counts or coverage.
Two unrelated failures show up on this PR and are not caused by it:
- `runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped)` — fails with
`NETSDK1203` on every recent PR (sampled 6/6); the leg only passes on
`main` because rolling builds run it as Release.
-
`System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert`
on linux-arm64 — known flaky, tracked by dotnet#131755 (44 hits in the last
month).
> [!NOTE]
> This content was created with assistance from AI.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
MichalStrehovsky added a commit that referenced this pull request Aug 24, 2026
After #131666 we should be able to get away with clr.jit. If one needs
to crossbuild, they'll need to add clr.alljits, but that's not a
mainstream scenario. Should shave the same number of minutes as what is
in #131666.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@sbomer@jkoritzinsky@jtschuster
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Trim unused CoreCLR native components from dotnet-linker-tests build - #131666

Merged
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf
Aug 7, 2026
Merged

Trim unused CoreCLR native components from dotnet-linker-tests build#131666
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf

Conversation

@sbomer

@sbomersbomer commented Jul 31, 2026

Copy link
Copy Markdown
Member

The Runtime_Release jobs in the dotnet-linker-tests pipeline build the clr subset. That expands to a list of CoreCLR subsets (eng/Subsets.props, DefaultCoreClrSubsets) which includes clr.native, and clr.native performs a full CoreCLR native build. That pulls in components the trimming and NativeAOT tests never use — most notably the cross-target alt-JITs and SuperPMI.

This PR narrows the subset list to what those tests actually need, and fixes a Windows/Unix asymmetry in the JIT install rules that blocked doing so.

1. src/coreclr/jit/CMakeLists.txt — install the target-specific JIT into the jit component on Windows

crossgen2 and ILC don't load clrjit; they load the JIT named for the target they're compiling for, e.g. clrjit_win_x64_x64 when targeting win-x64.

On Unix that JIT is already installed into the jit component alongside clrjit:

if (CLR_CMAKE_TARGET_UNIX)
...install_clr(TARGETSclrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME}DESTINATIONS.COMPONENTjit)
endif()

Windows had no equivalent rule, so there the target-specific JIT was only ever installed as part of alljits. Any Windows build that selects native components individually rather than doing a full native build therefore produces a crossgen2 that fails as soon as it runs:

EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1

This mirrors the existing Unix rule for Windows targets. Full native builds are unaffected, since alljits already installed these JITs — it only makes the jit component self-contained on Windows the way it already is on Unix.

2. eng/pipelines/runtime-linker-tests.yml — narrow the subset list

clr.native is replaced by clr.runtime + clr.nativeaotruntime (the runtime and nativeaot CMake components). src/coreclr/components.cmake shows runtime already depends on jit, iltools, debug and hosts, and with the fix above jit now also carries the JIT crossgen2/ILC need.

Dropped as a result:

  • alljits — the cross-target alt-JITs. On win-x64 only clrjit and clrjit_win_x64_x64 are now built; on linux-x64 only clrjit and clrjit_unix_x64_x64.
  • spmi — SuperPMI and its shims.
  • clr.packages — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL nupkgs, referenced solely by eng/Publishing.props for official-build publishing. Packing them takes ~2.5s, so this is a cleanliness change, not a perf one.
  • clr.crossarchtools — redundant here: _BuildCrossComponents is already set whenever ClrRuntimeBuildSubsets is non-empty for CoreCLR, and the cross-tool build is gated on _BuildAnyCrossArch, which is false for native windows-x64/linux-x64. Verified that no cross-arch build directory is produced either way.

Measurements

Measured on CI, comparing build 1538104 (this PR) against 1534932 (a recent PR build of the unchanged pipeline):

ninja targets"Build product"
windows-x64 (critical path)2646 → 1901 (−28.2%)40.0m → 35.4m (−4.6m)
linux-x642837 → 2132 (−24.8%)31.7m → 29.0m (−2.7m)
browser-wasmunaffected (builds mono)26.0m → 26.7m

The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build wall clock went from 75.0m to 68.0m, though that figure includes queue variance across runs — the "Build product" numbers are the reliable ones. linux-x64 saves time too but stays off the critical path.

Locally, isolating just the CoreCLR native build on linux-x64 at ninja -j 4 (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%, consistent with the CI result.

Validation

Locally, from a clean tree with the narrowed subsets:

  • Trimming tests: 88 tests pass
  • NativeAOT test apps: 57 tests pass
  • Artifacts verified: libcoreclr.so, ilc, crossgen2, ilasm/ildasm, DAC/mscordbi and the aotsdk all still present; superpmi and the unused alt-JITs gone

On CI, all three dotnet-linker-tests jobs (windows-x64, linux-x64, browser-wasm) pass, including the trimming and NativeAOT test app steps, with no change in test counts or coverage.

Two unrelated failures show up on this PR and are not caused by it:

  • runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped) — fails with NETSDK1203 on every recent PR (sampled 6/6); the leg only passes on main because rolling builds run it as Release.
  • System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert on linux-arm64 — known flaky, tracked by Disable TLS resume in SslStreamServer_RejectsClientCert_ClientObservesAlert #131755 (44 hits in the last month).

Note

This content was created with assistance from AI.

The Runtime_Release jobs in the dotnet-linker-tests pipeline built the
`clr` subset, which expands to `clr.native` and therefore performs a full
CoreCLR native build. That includes several components the trimming and
NativeAOT tests never use, most notably the `alljits` component (six
cross-target alt-JITs) and `spmi` (SuperPMI and its shims).
Narrow the subset list to just the components the tests need. This drops
703 of 2837 ninja targets (~25%) from the CoreCLR native build. Measured
locally at `ninja -j 4`, matching the parallelism CI uses, the native
build goes from 4m03s to 3m05s (-24%).
Also drop two subsets that were pulled in by `clr` but are not needed:
* `clr.packages` only produces the ILAsm, ILDAsm, TestHost and Sdk.IL
nupkgs, which are consumed solely by official-build publishing.
* `clr.crossarchtools` is redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64 and linux-x64.
Validated from a clean tree with the narrowed subsets: the trimming tests
(88) and the NativeAOT test apps (57) all pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the runtime-linker-tests Azure Pipelines definition to build a narrower set of CoreCLR subsets for the Runtime_Release jobs, aiming to avoid building unused native components during trimming and NativeAOT test runs.

Changes:

  • Replaces -s clr+... with an explicit subset list centered on clr.runtime plus NativeAOT/tooling subsets.
  • Adds inline pipeline comments documenting why alljits and spmi are intentionally excluded.
Show a summary per file
FileDescription
eng/pipelines/runtime-linker-tests.ymlSwitches the CoreCLR build from clr to an explicit subset list intended to avoid building unused native components for linker/NativeAOT tests.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment threadeng/pipelines/runtime-linker-tests.yml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 31, 2026 19:17

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new

crossgen2 and ILC don't load clrjit; they load the JIT named for the
target they are compiling for, e.g. clrjit_win_x64_x64 when targeting
win-x64. On Unix that JIT is already installed into the `jit` component
alongside clrjit, so a build that requests only `-component runtime`
(which depends on `jit`) can run them. Windows had no equivalent rule, so
the target-specific JIT was only ever installed as part of `alljits`.
The result is that a Windows build which selects CoreCLR native
components individually, rather than doing a full native build, produces
a crossgen2 that fails at runtime with "Dll was not found" as soon as it
is invoked, for example while R2R compiling System.Private.CoreLib.
Mirror the existing Unix rule for Windows targets. Full native builds are
unaffected since `alljits` already installed these JITs; this only makes
the `jit` component self-contained on Windows the way it already is on
Unix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
CopilotAI review requested due to automatic review settings August 3, 2026 20:40

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Suppressed comments (1)

eng/pipelines/runtime-linker-tests.yml:119

  • The comment is slightly inaccurate: the clr subset expands to the full $(DefaultCoreClrSubsets) list (which includes clr.native among others), not to clr.native alone. Rewording avoids confusion for future maintainers reading the pipeline.
 # This replaces the previous `clr` subset (which expands to `clr.native` and builds every native component)
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 7 pipeline(s).
9 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@sbomer
sbomer merged commit b7130aa into dotnet:mainAug 7, 2026
217 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-rc1 milestone Aug 7, 2026
@sbomer
sbomer deleted the runtime-linker-test-perf branch August 10, 2026 16:23
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Aug 11, 2026
…otnet#131666)
The `Runtime_Release` jobs in the `dotnet-linker-tests` pipeline build
the `clr` subset. That expands to a list of CoreCLR subsets
(`eng/Subsets.props`, `DefaultCoreClrSubsets`) which includes
`clr.native`, and `clr.native` performs a *full* CoreCLR native build.
That pulls in components the trimming and NativeAOT tests never use —
most notably the cross-target alt-JITs and SuperPMI.
This PR narrows the subset list to what those tests actually need, and
fixes a Windows/Unix asymmetry in the JIT install rules that blocked
doing so.
## 1. `src/coreclr/jit/CMakeLists.txt` — install the target-specific JIT
into the `jit` component on Windows
crossgen2 and ILC don't load `clrjit`; they load the JIT named for the
target they're compiling for, e.g. `clrjit_win_x64_x64` when targeting
win-x64.
On Unix that JIT is already installed into the `jit` component alongside
`clrjit`:
```cmake
if (CLR_CMAKE_TARGET_UNIX)
...
install_clr(TARGETS clrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME} DESTINATIONS . COMPONENT jit)
endif()
```
Windows had no equivalent rule, so there the target-specific JIT was
only ever installed as part of `alljits`. Any Windows build that selects
native components individually rather than doing a full native build
therefore produces a crossgen2 that fails as soon as it runs:
```
EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1
```
This mirrors the existing Unix rule for Windows targets. **Full native
builds are unaffected**, since `alljits` already installed these JITs —
it only makes the `jit` component self-contained on Windows the way it
already is on Unix.
## 2. `eng/pipelines/runtime-linker-tests.yml` — narrow the subset list
`clr.native` is replaced by `clr.runtime` + `clr.nativeaotruntime` (the
`runtime` and `nativeaot` CMake components).
`src/coreclr/components.cmake` shows `runtime` already depends on `jit`,
`iltools`, `debug` and `hosts`, and with the fix above `jit` now also
carries the JIT crossgen2/ILC need.
Dropped as a result:
- **`alljits`** — the cross-target alt-JITs. On win-x64 only `clrjit`
and `clrjit_win_x64_x64` are now built; on linux-x64 only `clrjit` and
`clrjit_unix_x64_x64`.
- **`spmi`** — SuperPMI and its shims.
- **`clr.packages`** — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL
nupkgs, referenced solely by `eng/Publishing.props` for official-build
publishing. Packing them takes ~2.5s, so this is a cleanliness change,
not a perf one.
- **`clr.crossarchtools`** — redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64/linux-x64. Verified that no cross-arch
build directory is produced either way.
## Measurements
Measured on CI, comparing build
[1538104](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1538104)
(this PR) against
[1534932](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1534932)
(a recent PR build of the unchanged pipeline):
| | ninja targets | "Build product" |
|---|---|---|
| **windows-x64** (critical path) | 2646 → **1901** (−28.2%) | 40.0m →
**35.4m** (−4.6m) |
| linux-x64 | 2837 → **2132** (−24.8%) | 31.7m → **29.0m** (−2.7m) |
| browser-wasm | unaffected (builds `mono`) | 26.0m → 26.7m |
The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build
wall clock went from 75.0m to 68.0m, though that figure includes queue
variance across runs — the "Build product" numbers are the reliable
ones. linux-x64 saves time too but stays off the critical path.
Locally, isolating just the CoreCLR native build on linux-x64 at `ninja
-j 4` (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%,
consistent with the CI result.
## Validation
Locally, from a clean tree with the narrowed subsets:
- Trimming tests: **88 tests pass**
- NativeAOT test apps: **57 tests pass**
- Artifacts verified: `libcoreclr.so`, `ilc`, `crossgen2`,
`ilasm`/`ildasm`, DAC/mscordbi and the `aotsdk` all still present;
superpmi and the unused alt-JITs gone
On CI, all three `dotnet-linker-tests` jobs (windows-x64, linux-x64,
browser-wasm) pass, including the trimming and NativeAOT test app steps,
with no change in test counts or coverage.
Two unrelated failures show up on this PR and are not caused by it:
- `runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped)` — fails with
`NETSDK1203` on every recent PR (sampled 6/6); the leg only passes on
`main` because rolling builds run it as Release.
-
`System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert`
on linux-arm64 — known flaky, tracked by dotnet#131755 (44 hits in the last
month).
> [!NOTE]
> This content was created with assistance from AI.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
MichalStrehovsky added a commit that referenced this pull request Aug 24, 2026
After #131666 we should be able to get away with clr.jit. If one needs
to crossbuild, they'll need to add clr.alljits, but that's not a
mainstream scenario. Should shave the same number of minutes as what is
in #131666.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@sbomer@jkoritzinsky@jtschuster
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Trim unused CoreCLR native components from dotnet-linker-tests build - #131666

Merged
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf
Aug 7, 2026
Merged

Trim unused CoreCLR native components from dotnet-linker-tests build#131666
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf

Conversation

@sbomer

@sbomersbomer commented Jul 31, 2026

Copy link
Copy Markdown
Member

The Runtime_Release jobs in the dotnet-linker-tests pipeline build the clr subset. That expands to a list of CoreCLR subsets (eng/Subsets.props, DefaultCoreClrSubsets) which includes clr.native, and clr.native performs a full CoreCLR native build. That pulls in components the trimming and NativeAOT tests never use — most notably the cross-target alt-JITs and SuperPMI.

This PR narrows the subset list to what those tests actually need, and fixes a Windows/Unix asymmetry in the JIT install rules that blocked doing so.

1. src/coreclr/jit/CMakeLists.txt — install the target-specific JIT into the jit component on Windows

crossgen2 and ILC don't load clrjit; they load the JIT named for the target they're compiling for, e.g. clrjit_win_x64_x64 when targeting win-x64.

On Unix that JIT is already installed into the jit component alongside clrjit:

if (CLR_CMAKE_TARGET_UNIX)
...install_clr(TARGETSclrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME}DESTINATIONS.COMPONENTjit)
endif()

Windows had no equivalent rule, so there the target-specific JIT was only ever installed as part of alljits. Any Windows build that selects native components individually rather than doing a full native build therefore produces a crossgen2 that fails as soon as it runs:

EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1

This mirrors the existing Unix rule for Windows targets. Full native builds are unaffected, since alljits already installed these JITs — it only makes the jit component self-contained on Windows the way it already is on Unix.

2. eng/pipelines/runtime-linker-tests.yml — narrow the subset list

clr.native is replaced by clr.runtime + clr.nativeaotruntime (the runtime and nativeaot CMake components). src/coreclr/components.cmake shows runtime already depends on jit, iltools, debug and hosts, and with the fix above jit now also carries the JIT crossgen2/ILC need.

Dropped as a result:

  • alljits — the cross-target alt-JITs. On win-x64 only clrjit and clrjit_win_x64_x64 are now built; on linux-x64 only clrjit and clrjit_unix_x64_x64.
  • spmi — SuperPMI and its shims.
  • clr.packages — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL nupkgs, referenced solely by eng/Publishing.props for official-build publishing. Packing them takes ~2.5s, so this is a cleanliness change, not a perf one.
  • clr.crossarchtools — redundant here: _BuildCrossComponents is already set whenever ClrRuntimeBuildSubsets is non-empty for CoreCLR, and the cross-tool build is gated on _BuildAnyCrossArch, which is false for native windows-x64/linux-x64. Verified that no cross-arch build directory is produced either way.

Measurements

Measured on CI, comparing build 1538104 (this PR) against 1534932 (a recent PR build of the unchanged pipeline):

ninja targets"Build product"
windows-x64 (critical path)2646 → 1901 (−28.2%)40.0m → 35.4m (−4.6m)
linux-x642837 → 2132 (−24.8%)31.7m → 29.0m (−2.7m)
browser-wasmunaffected (builds mono)26.0m → 26.7m

The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build wall clock went from 75.0m to 68.0m, though that figure includes queue variance across runs — the "Build product" numbers are the reliable ones. linux-x64 saves time too but stays off the critical path.

Locally, isolating just the CoreCLR native build on linux-x64 at ninja -j 4 (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%, consistent with the CI result.

Validation

Locally, from a clean tree with the narrowed subsets:

  • Trimming tests: 88 tests pass
  • NativeAOT test apps: 57 tests pass
  • Artifacts verified: libcoreclr.so, ilc, crossgen2, ilasm/ildasm, DAC/mscordbi and the aotsdk all still present; superpmi and the unused alt-JITs gone

On CI, all three dotnet-linker-tests jobs (windows-x64, linux-x64, browser-wasm) pass, including the trimming and NativeAOT test app steps, with no change in test counts or coverage.

Two unrelated failures show up on this PR and are not caused by it:

  • runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped) — fails with NETSDK1203 on every recent PR (sampled 6/6); the leg only passes on main because rolling builds run it as Release.
  • System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert on linux-arm64 — known flaky, tracked by Disable TLS resume in SslStreamServer_RejectsClientCert_ClientObservesAlert #131755 (44 hits in the last month).

Note

This content was created with assistance from AI.

The Runtime_Release jobs in the dotnet-linker-tests pipeline built the
`clr` subset, which expands to `clr.native` and therefore performs a full
CoreCLR native build. That includes several components the trimming and
NativeAOT tests never use, most notably the `alljits` component (six
cross-target alt-JITs) and `spmi` (SuperPMI and its shims).
Narrow the subset list to just the components the tests need. This drops
703 of 2837 ninja targets (~25%) from the CoreCLR native build. Measured
locally at `ninja -j 4`, matching the parallelism CI uses, the native
build goes from 4m03s to 3m05s (-24%).
Also drop two subsets that were pulled in by `clr` but are not needed:
* `clr.packages` only produces the ILAsm, ILDAsm, TestHost and Sdk.IL
nupkgs, which are consumed solely by official-build publishing.
* `clr.crossarchtools` is redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64 and linux-x64.
Validated from a clean tree with the narrowed subsets: the trimming tests
(88) and the NativeAOT test apps (57) all pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the runtime-linker-tests Azure Pipelines definition to build a narrower set of CoreCLR subsets for the Runtime_Release jobs, aiming to avoid building unused native components during trimming and NativeAOT test runs.

Changes:

  • Replaces -s clr+... with an explicit subset list centered on clr.runtime plus NativeAOT/tooling subsets.
  • Adds inline pipeline comments documenting why alljits and spmi are intentionally excluded.
Show a summary per file
FileDescription
eng/pipelines/runtime-linker-tests.ymlSwitches the CoreCLR build from clr to an explicit subset list intended to avoid building unused native components for linker/NativeAOT tests.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment threadeng/pipelines/runtime-linker-tests.yml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 31, 2026 19:17

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new

crossgen2 and ILC don't load clrjit; they load the JIT named for the
target they are compiling for, e.g. clrjit_win_x64_x64 when targeting
win-x64. On Unix that JIT is already installed into the `jit` component
alongside clrjit, so a build that requests only `-component runtime`
(which depends on `jit`) can run them. Windows had no equivalent rule, so
the target-specific JIT was only ever installed as part of `alljits`.
The result is that a Windows build which selects CoreCLR native
components individually, rather than doing a full native build, produces
a crossgen2 that fails at runtime with "Dll was not found" as soon as it
is invoked, for example while R2R compiling System.Private.CoreLib.
Mirror the existing Unix rule for Windows targets. Full native builds are
unaffected since `alljits` already installed these JITs; this only makes
the `jit` component self-contained on Windows the way it already is on
Unix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
CopilotAI review requested due to automatic review settings August 3, 2026 20:40

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Suppressed comments (1)

eng/pipelines/runtime-linker-tests.yml:119

  • The comment is slightly inaccurate: the clr subset expands to the full $(DefaultCoreClrSubsets) list (which includes clr.native among others), not to clr.native alone. Rewording avoids confusion for future maintainers reading the pipeline.
 # This replaces the previous `clr` subset (which expands to `clr.native` and builds every native component)
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 7 pipeline(s).
9 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@sbomer
sbomer merged commit b7130aa into dotnet:mainAug 7, 2026
217 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-rc1 milestone Aug 7, 2026
@sbomer
sbomer deleted the runtime-linker-test-perf branch August 10, 2026 16:23
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Aug 11, 2026
…otnet#131666)
The `Runtime_Release` jobs in the `dotnet-linker-tests` pipeline build
the `clr` subset. That expands to a list of CoreCLR subsets
(`eng/Subsets.props`, `DefaultCoreClrSubsets`) which includes
`clr.native`, and `clr.native` performs a *full* CoreCLR native build.
That pulls in components the trimming and NativeAOT tests never use —
most notably the cross-target alt-JITs and SuperPMI.
This PR narrows the subset list to what those tests actually need, and
fixes a Windows/Unix asymmetry in the JIT install rules that blocked
doing so.
## 1. `src/coreclr/jit/CMakeLists.txt` — install the target-specific JIT
into the `jit` component on Windows
crossgen2 and ILC don't load `clrjit`; they load the JIT named for the
target they're compiling for, e.g. `clrjit_win_x64_x64` when targeting
win-x64.
On Unix that JIT is already installed into the `jit` component alongside
`clrjit`:
```cmake
if (CLR_CMAKE_TARGET_UNIX)
...
install_clr(TARGETS clrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME} DESTINATIONS . COMPONENT jit)
endif()
```
Windows had no equivalent rule, so there the target-specific JIT was
only ever installed as part of `alljits`. Any Windows build that selects
native components individually rather than doing a full native build
therefore produces a crossgen2 that fails as soon as it runs:
```
EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1
```
This mirrors the existing Unix rule for Windows targets. **Full native
builds are unaffected**, since `alljits` already installed these JITs —
it only makes the `jit` component self-contained on Windows the way it
already is on Unix.
## 2. `eng/pipelines/runtime-linker-tests.yml` — narrow the subset list
`clr.native` is replaced by `clr.runtime` + `clr.nativeaotruntime` (the
`runtime` and `nativeaot` CMake components).
`src/coreclr/components.cmake` shows `runtime` already depends on `jit`,
`iltools`, `debug` and `hosts`, and with the fix above `jit` now also
carries the JIT crossgen2/ILC need.
Dropped as a result:
- **`alljits`** — the cross-target alt-JITs. On win-x64 only `clrjit`
and `clrjit_win_x64_x64` are now built; on linux-x64 only `clrjit` and
`clrjit_unix_x64_x64`.
- **`spmi`** — SuperPMI and its shims.
- **`clr.packages`** — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL
nupkgs, referenced solely by `eng/Publishing.props` for official-build
publishing. Packing them takes ~2.5s, so this is a cleanliness change,
not a perf one.
- **`clr.crossarchtools`** — redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64/linux-x64. Verified that no cross-arch
build directory is produced either way.
## Measurements
Measured on CI, comparing build
[1538104](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1538104)
(this PR) against
[1534932](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1534932)
(a recent PR build of the unchanged pipeline):
| | ninja targets | "Build product" |
|---|---|---|
| **windows-x64** (critical path) | 2646 → **1901** (−28.2%) | 40.0m →
**35.4m** (−4.6m) |
| linux-x64 | 2837 → **2132** (−24.8%) | 31.7m → **29.0m** (−2.7m) |
| browser-wasm | unaffected (builds `mono`) | 26.0m → 26.7m |
The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build
wall clock went from 75.0m to 68.0m, though that figure includes queue
variance across runs — the "Build product" numbers are the reliable
ones. linux-x64 saves time too but stays off the critical path.
Locally, isolating just the CoreCLR native build on linux-x64 at `ninja
-j 4` (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%,
consistent with the CI result.
## Validation
Locally, from a clean tree with the narrowed subsets:
- Trimming tests: **88 tests pass**
- NativeAOT test apps: **57 tests pass**
- Artifacts verified: `libcoreclr.so`, `ilc`, `crossgen2`,
`ilasm`/`ildasm`, DAC/mscordbi and the `aotsdk` all still present;
superpmi and the unused alt-JITs gone
On CI, all three `dotnet-linker-tests` jobs (windows-x64, linux-x64,
browser-wasm) pass, including the trimming and NativeAOT test app steps,
with no change in test counts or coverage.
Two unrelated failures show up on this PR and are not caused by it:
- `runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped)` — fails with
`NETSDK1203` on every recent PR (sampled 6/6); the leg only passes on
`main` because rolling builds run it as Release.
-
`System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert`
on linux-arm64 — known flaky, tracked by dotnet#131755 (44 hits in the last
month).
> [!NOTE]
> This content was created with assistance from AI.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
MichalStrehovsky added a commit that referenced this pull request Aug 24, 2026
After #131666 we should be able to get away with clr.jit. If one needs
to crossbuild, they'll need to add clr.alljits, but that's not a
mainstream scenario. Should shave the same number of minutes as what is
in #131666.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@sbomer@jkoritzinsky@jtschuster
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Trim unused CoreCLR native components from dotnet-linker-tests build - #131666

Merged
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf
Aug 7, 2026
Merged

Trim unused CoreCLR native components from dotnet-linker-tests build#131666
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf

Conversation

@sbomer

@sbomersbomer commented Jul 31, 2026

Copy link
Copy Markdown
Member

The Runtime_Release jobs in the dotnet-linker-tests pipeline build the clr subset. That expands to a list of CoreCLR subsets (eng/Subsets.props, DefaultCoreClrSubsets) which includes clr.native, and clr.native performs a full CoreCLR native build. That pulls in components the trimming and NativeAOT tests never use — most notably the cross-target alt-JITs and SuperPMI.

This PR narrows the subset list to what those tests actually need, and fixes a Windows/Unix asymmetry in the JIT install rules that blocked doing so.

1. src/coreclr/jit/CMakeLists.txt — install the target-specific JIT into the jit component on Windows

crossgen2 and ILC don't load clrjit; they load the JIT named for the target they're compiling for, e.g. clrjit_win_x64_x64 when targeting win-x64.

On Unix that JIT is already installed into the jit component alongside clrjit:

if (CLR_CMAKE_TARGET_UNIX)
...install_clr(TARGETSclrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME}DESTINATIONS.COMPONENTjit)
endif()

Windows had no equivalent rule, so there the target-specific JIT was only ever installed as part of alljits. Any Windows build that selects native components individually rather than doing a full native build therefore produces a crossgen2 that fails as soon as it runs:

EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1

This mirrors the existing Unix rule for Windows targets. Full native builds are unaffected, since alljits already installed these JITs — it only makes the jit component self-contained on Windows the way it already is on Unix.

2. eng/pipelines/runtime-linker-tests.yml — narrow the subset list

clr.native is replaced by clr.runtime + clr.nativeaotruntime (the runtime and nativeaot CMake components). src/coreclr/components.cmake shows runtime already depends on jit, iltools, debug and hosts, and with the fix above jit now also carries the JIT crossgen2/ILC need.

Dropped as a result:

  • alljits — the cross-target alt-JITs. On win-x64 only clrjit and clrjit_win_x64_x64 are now built; on linux-x64 only clrjit and clrjit_unix_x64_x64.
  • spmi — SuperPMI and its shims.
  • clr.packages — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL nupkgs, referenced solely by eng/Publishing.props for official-build publishing. Packing them takes ~2.5s, so this is a cleanliness change, not a perf one.
  • clr.crossarchtools — redundant here: _BuildCrossComponents is already set whenever ClrRuntimeBuildSubsets is non-empty for CoreCLR, and the cross-tool build is gated on _BuildAnyCrossArch, which is false for native windows-x64/linux-x64. Verified that no cross-arch build directory is produced either way.

Measurements

Measured on CI, comparing build 1538104 (this PR) against 1534932 (a recent PR build of the unchanged pipeline):

ninja targets"Build product"
windows-x64 (critical path)2646 → 1901 (−28.2%)40.0m → 35.4m (−4.6m)
linux-x642837 → 2132 (−24.8%)31.7m → 29.0m (−2.7m)
browser-wasmunaffected (builds mono)26.0m → 26.7m

The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build wall clock went from 75.0m to 68.0m, though that figure includes queue variance across runs — the "Build product" numbers are the reliable ones. linux-x64 saves time too but stays off the critical path.

Locally, isolating just the CoreCLR native build on linux-x64 at ninja -j 4 (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%, consistent with the CI result.

Validation

Locally, from a clean tree with the narrowed subsets:

  • Trimming tests: 88 tests pass
  • NativeAOT test apps: 57 tests pass
  • Artifacts verified: libcoreclr.so, ilc, crossgen2, ilasm/ildasm, DAC/mscordbi and the aotsdk all still present; superpmi and the unused alt-JITs gone

On CI, all three dotnet-linker-tests jobs (windows-x64, linux-x64, browser-wasm) pass, including the trimming and NativeAOT test app steps, with no change in test counts or coverage.

Two unrelated failures show up on this PR and are not caused by it:

  • runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped) — fails with NETSDK1203 on every recent PR (sampled 6/6); the leg only passes on main because rolling builds run it as Release.
  • System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert on linux-arm64 — known flaky, tracked by Disable TLS resume in SslStreamServer_RejectsClientCert_ClientObservesAlert #131755 (44 hits in the last month).

Note

This content was created with assistance from AI.

The Runtime_Release jobs in the dotnet-linker-tests pipeline built the
`clr` subset, which expands to `clr.native` and therefore performs a full
CoreCLR native build. That includes several components the trimming and
NativeAOT tests never use, most notably the `alljits` component (six
cross-target alt-JITs) and `spmi` (SuperPMI and its shims).
Narrow the subset list to just the components the tests need. This drops
703 of 2837 ninja targets (~25%) from the CoreCLR native build. Measured
locally at `ninja -j 4`, matching the parallelism CI uses, the native
build goes from 4m03s to 3m05s (-24%).
Also drop two subsets that were pulled in by `clr` but are not needed:
* `clr.packages` only produces the ILAsm, ILDAsm, TestHost and Sdk.IL
nupkgs, which are consumed solely by official-build publishing.
* `clr.crossarchtools` is redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64 and linux-x64.
Validated from a clean tree with the narrowed subsets: the trimming tests
(88) and the NativeAOT test apps (57) all pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the runtime-linker-tests Azure Pipelines definition to build a narrower set of CoreCLR subsets for the Runtime_Release jobs, aiming to avoid building unused native components during trimming and NativeAOT test runs.

Changes:

  • Replaces -s clr+... with an explicit subset list centered on clr.runtime plus NativeAOT/tooling subsets.
  • Adds inline pipeline comments documenting why alljits and spmi are intentionally excluded.
Show a summary per file
FileDescription
eng/pipelines/runtime-linker-tests.ymlSwitches the CoreCLR build from clr to an explicit subset list intended to avoid building unused native components for linker/NativeAOT tests.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment threadeng/pipelines/runtime-linker-tests.yml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 31, 2026 19:17

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new

crossgen2 and ILC don't load clrjit; they load the JIT named for the
target they are compiling for, e.g. clrjit_win_x64_x64 when targeting
win-x64. On Unix that JIT is already installed into the `jit` component
alongside clrjit, so a build that requests only `-component runtime`
(which depends on `jit`) can run them. Windows had no equivalent rule, so
the target-specific JIT was only ever installed as part of `alljits`.
The result is that a Windows build which selects CoreCLR native
components individually, rather than doing a full native build, produces
a crossgen2 that fails at runtime with "Dll was not found" as soon as it
is invoked, for example while R2R compiling System.Private.CoreLib.
Mirror the existing Unix rule for Windows targets. Full native builds are
unaffected since `alljits` already installed these JITs; this only makes
the `jit` component self-contained on Windows the way it already is on
Unix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
CopilotAI review requested due to automatic review settings August 3, 2026 20:40

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Suppressed comments (1)

eng/pipelines/runtime-linker-tests.yml:119

  • The comment is slightly inaccurate: the clr subset expands to the full $(DefaultCoreClrSubsets) list (which includes clr.native among others), not to clr.native alone. Rewording avoids confusion for future maintainers reading the pipeline.
 # This replaces the previous `clr` subset (which expands to `clr.native` and builds every native component)
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 7 pipeline(s).
9 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@sbomer
sbomer merged commit b7130aa into dotnet:mainAug 7, 2026
217 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-rc1 milestone Aug 7, 2026
@sbomer
sbomer deleted the runtime-linker-test-perf branch August 10, 2026 16:23
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Aug 11, 2026
…otnet#131666)
The `Runtime_Release` jobs in the `dotnet-linker-tests` pipeline build
the `clr` subset. That expands to a list of CoreCLR subsets
(`eng/Subsets.props`, `DefaultCoreClrSubsets`) which includes
`clr.native`, and `clr.native` performs a *full* CoreCLR native build.
That pulls in components the trimming and NativeAOT tests never use —
most notably the cross-target alt-JITs and SuperPMI.
This PR narrows the subset list to what those tests actually need, and
fixes a Windows/Unix asymmetry in the JIT install rules that blocked
doing so.
## 1. `src/coreclr/jit/CMakeLists.txt` — install the target-specific JIT
into the `jit` component on Windows
crossgen2 and ILC don't load `clrjit`; they load the JIT named for the
target they're compiling for, e.g. `clrjit_win_x64_x64` when targeting
win-x64.
On Unix that JIT is already installed into the `jit` component alongside
`clrjit`:
```cmake
if (CLR_CMAKE_TARGET_UNIX)
...
install_clr(TARGETS clrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME} DESTINATIONS . COMPONENT jit)
endif()
```
Windows had no equivalent rule, so there the target-specific JIT was
only ever installed as part of `alljits`. Any Windows build that selects
native components individually rather than doing a full native build
therefore produces a crossgen2 that fails as soon as it runs:
```
EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1
```
This mirrors the existing Unix rule for Windows targets. **Full native
builds are unaffected**, since `alljits` already installed these JITs —
it only makes the `jit` component self-contained on Windows the way it
already is on Unix.
## 2. `eng/pipelines/runtime-linker-tests.yml` — narrow the subset list
`clr.native` is replaced by `clr.runtime` + `clr.nativeaotruntime` (the
`runtime` and `nativeaot` CMake components).
`src/coreclr/components.cmake` shows `runtime` already depends on `jit`,
`iltools`, `debug` and `hosts`, and with the fix above `jit` now also
carries the JIT crossgen2/ILC need.
Dropped as a result:
- **`alljits`** — the cross-target alt-JITs. On win-x64 only `clrjit`
and `clrjit_win_x64_x64` are now built; on linux-x64 only `clrjit` and
`clrjit_unix_x64_x64`.
- **`spmi`** — SuperPMI and its shims.
- **`clr.packages`** — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL
nupkgs, referenced solely by `eng/Publishing.props` for official-build
publishing. Packing them takes ~2.5s, so this is a cleanliness change,
not a perf one.
- **`clr.crossarchtools`** — redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64/linux-x64. Verified that no cross-arch
build directory is produced either way.
## Measurements
Measured on CI, comparing build
[1538104](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1538104)
(this PR) against
[1534932](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1534932)
(a recent PR build of the unchanged pipeline):
| | ninja targets | "Build product" |
|---|---|---|
| **windows-x64** (critical path) | 2646 → **1901** (−28.2%) | 40.0m →
**35.4m** (−4.6m) |
| linux-x64 | 2837 → **2132** (−24.8%) | 31.7m → **29.0m** (−2.7m) |
| browser-wasm | unaffected (builds `mono`) | 26.0m → 26.7m |
The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build
wall clock went from 75.0m to 68.0m, though that figure includes queue
variance across runs — the "Build product" numbers are the reliable
ones. linux-x64 saves time too but stays off the critical path.
Locally, isolating just the CoreCLR native build on linux-x64 at `ninja
-j 4` (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%,
consistent with the CI result.
## Validation
Locally, from a clean tree with the narrowed subsets:
- Trimming tests: **88 tests pass**
- NativeAOT test apps: **57 tests pass**
- Artifacts verified: `libcoreclr.so`, `ilc`, `crossgen2`,
`ilasm`/`ildasm`, DAC/mscordbi and the `aotsdk` all still present;
superpmi and the unused alt-JITs gone
On CI, all three `dotnet-linker-tests` jobs (windows-x64, linux-x64,
browser-wasm) pass, including the trimming and NativeAOT test app steps,
with no change in test counts or coverage.
Two unrelated failures show up on this PR and are not caused by it:
- `runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped)` — fails with
`NETSDK1203` on every recent PR (sampled 6/6); the leg only passes on
`main` because rolling builds run it as Release.
-
`System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert`
on linux-arm64 — known flaky, tracked by dotnet#131755 (44 hits in the last
month).
> [!NOTE]
> This content was created with assistance from AI.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
MichalStrehovsky added a commit that referenced this pull request Aug 24, 2026
After #131666 we should be able to get away with clr.jit. If one needs
to crossbuild, they'll need to add clr.alljits, but that's not a
mainstream scenario. Should shave the same number of minutes as what is
in #131666.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@sbomer@jkoritzinsky@jtschuster
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Trim unused CoreCLR native components from dotnet-linker-tests build - #131666

Merged
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf
Aug 7, 2026
Merged

Trim unused CoreCLR native components from dotnet-linker-tests build#131666
sbomer merged 3 commits into
dotnet:mainfrom
sbomer:runtime-linker-test-perf

Conversation

@sbomer

@sbomersbomer commented Jul 31, 2026

Copy link
Copy Markdown
Member

The Runtime_Release jobs in the dotnet-linker-tests pipeline build the clr subset. That expands to a list of CoreCLR subsets (eng/Subsets.props, DefaultCoreClrSubsets) which includes clr.native, and clr.native performs a full CoreCLR native build. That pulls in components the trimming and NativeAOT tests never use — most notably the cross-target alt-JITs and SuperPMI.

This PR narrows the subset list to what those tests actually need, and fixes a Windows/Unix asymmetry in the JIT install rules that blocked doing so.

1. src/coreclr/jit/CMakeLists.txt — install the target-specific JIT into the jit component on Windows

crossgen2 and ILC don't load clrjit; they load the JIT named for the target they're compiling for, e.g. clrjit_win_x64_x64 when targeting win-x64.

On Unix that JIT is already installed into the jit component alongside clrjit:

if (CLR_CMAKE_TARGET_UNIX)
...install_clr(TARGETSclrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME}DESTINATIONS.COMPONENTjit)
endif()

Windows had no equivalent rule, so there the target-specific JIT was only ever installed as part of alljits. Any Windows build that selects native components individually rather than doing a full native build therefore produces a crossgen2 that fails as soon as it runs:

EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1

This mirrors the existing Unix rule for Windows targets. Full native builds are unaffected, since alljits already installed these JITs — it only makes the jit component self-contained on Windows the way it already is on Unix.

2. eng/pipelines/runtime-linker-tests.yml — narrow the subset list

clr.native is replaced by clr.runtime + clr.nativeaotruntime (the runtime and nativeaot CMake components). src/coreclr/components.cmake shows runtime already depends on jit, iltools, debug and hosts, and with the fix above jit now also carries the JIT crossgen2/ILC need.

Dropped as a result:

  • alljits — the cross-target alt-JITs. On win-x64 only clrjit and clrjit_win_x64_x64 are now built; on linux-x64 only clrjit and clrjit_unix_x64_x64.
  • spmi — SuperPMI and its shims.
  • clr.packages — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL nupkgs, referenced solely by eng/Publishing.props for official-build publishing. Packing them takes ~2.5s, so this is a cleanliness change, not a perf one.
  • clr.crossarchtools — redundant here: _BuildCrossComponents is already set whenever ClrRuntimeBuildSubsets is non-empty for CoreCLR, and the cross-tool build is gated on _BuildAnyCrossArch, which is false for native windows-x64/linux-x64. Verified that no cross-arch build directory is produced either way.

Measurements

Measured on CI, comparing build 1538104 (this PR) against 1534932 (a recent PR build of the unchanged pipeline):

ninja targets"Build product"
windows-x64 (critical path)2646 → 1901 (−28.2%)40.0m → 35.4m (−4.6m)
linux-x642837 → 2132 (−24.8%)31.7m → 29.0m (−2.7m)
browser-wasmunaffected (builds mono)26.0m → 26.7m

The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build wall clock went from 75.0m to 68.0m, though that figure includes queue variance across runs — the "Build product" numbers are the reliable ones. linux-x64 saves time too but stays off the critical path.

Locally, isolating just the CoreCLR native build on linux-x64 at ninja -j 4 (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%, consistent with the CI result.

Validation

Locally, from a clean tree with the narrowed subsets:

  • Trimming tests: 88 tests pass
  • NativeAOT test apps: 57 tests pass
  • Artifacts verified: libcoreclr.so, ilc, crossgen2, ilasm/ildasm, DAC/mscordbi and the aotsdk all still present; superpmi and the unused alt-JITs gone

On CI, all three dotnet-linker-tests jobs (windows-x64, linux-x64, browser-wasm) pass, including the trimming and NativeAOT test app steps, with no change in test counts or coverage.

Two unrelated failures show up on this PR and are not caused by it:

  • runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped) — fails with NETSDK1203 on every recent PR (sampled 6/6); the leg only passes on main because rolling builds run it as Release.
  • System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert on linux-arm64 — known flaky, tracked by Disable TLS resume in SslStreamServer_RejectsClientCert_ClientObservesAlert #131755 (44 hits in the last month).

Note

This content was created with assistance from AI.

The Runtime_Release jobs in the dotnet-linker-tests pipeline built the
`clr` subset, which expands to `clr.native` and therefore performs a full
CoreCLR native build. That includes several components the trimming and
NativeAOT tests never use, most notably the `alljits` component (six
cross-target alt-JITs) and `spmi` (SuperPMI and its shims).
Narrow the subset list to just the components the tests need. This drops
703 of 2837 ninja targets (~25%) from the CoreCLR native build. Measured
locally at `ninja -j 4`, matching the parallelism CI uses, the native
build goes from 4m03s to 3m05s (-24%).
Also drop two subsets that were pulled in by `clr` but are not needed:
* `clr.packages` only produces the ILAsm, ILDAsm, TestHost and Sdk.IL
nupkgs, which are consumed solely by official-build publishing.
* `clr.crossarchtools` is redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64 and linux-x64.
Validated from a clean tree with the narrowed subsets: the trimming tests
(88) and the NativeAOT test apps (57) all pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 5 pipeline(s).
11 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke, @dotnet/ilc-contrib
See info in area-owners.md if you want to be subscribed.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the runtime-linker-tests Azure Pipelines definition to build a narrower set of CoreCLR subsets for the Runtime_Release jobs, aiming to avoid building unused native components during trimming and NativeAOT test runs.

Changes:

  • Replaces -s clr+... with an explicit subset list centered on clr.runtime plus NativeAOT/tooling subsets.
  • Adds inline pipeline comments documenting why alljits and spmi are intentionally excluded.
Show a summary per file
FileDescription
eng/pipelines/runtime-linker-tests.ymlSwitches the CoreCLR build from clr to an explicit subset list intended to avoid building unused native components for linker/NativeAOT tests.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 1

Comment threadeng/pipelines/runtime-linker-tests.yml Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
CopilotAI review requested due to automatic review settings July 31, 2026 19:17

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

  • Files reviewed: 1/1 changed files
  • Comments generated: 0 new

crossgen2 and ILC don't load clrjit; they load the JIT named for the
target they are compiling for, e.g. clrjit_win_x64_x64 when targeting
win-x64. On Unix that JIT is already installed into the `jit` component
alongside clrjit, so a build that requests only `-component runtime`
(which depends on `jit`) can run them. Windows had no equivalent rule, so
the target-specific JIT was only ever installed as part of `alljits`.
The result is that a Windows build which selects CoreCLR native
components individually, rather than doing a full native build, produces
a crossgen2 that fails at runtime with "Dll was not found" as soon as it
is invoked, for example while R2R compiling System.Private.CoreLib.
Mirror the existing Unix rule for Windows targets. Full native builds are
unaffected since `alljits` already installed these JITs; this only makes
the `jit` component self-contained on Windows the way it already is on
Unix.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
Assisted-by: Copilot:claude-opus-5
CopilotAI review requested due to automatic review settings August 3, 2026 20:40

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot's findings

Suppressed comments (1)

eng/pipelines/runtime-linker-tests.yml:119

  • The comment is slightly inaccurate: the clr subset expands to the full $(DefaultCoreClrSubsets) list (which includes clr.native among others), not to clr.native alone. Rewording avoids confusion for future maintainers reading the pipeline.
 # This replaces the previous `clr` subset (which expands to `clr.native` and builds every native component)
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 7 pipeline(s).
9 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@sbomer
sbomer merged commit b7130aa into dotnet:mainAug 7, 2026
217 checks passed
@dotnet-milestone-botdotnet-milestone-botBot added this to the 11.0-rc1 milestone Aug 7, 2026
@sbomer
sbomer deleted the runtime-linker-test-perf branch August 10, 2026 16:23
jtschuster pushed a commit to jtschuster/runtime that referenced this pull request Aug 11, 2026
…otnet#131666)
The `Runtime_Release` jobs in the `dotnet-linker-tests` pipeline build
the `clr` subset. That expands to a list of CoreCLR subsets
(`eng/Subsets.props`, `DefaultCoreClrSubsets`) which includes
`clr.native`, and `clr.native` performs a *full* CoreCLR native build.
That pulls in components the trimming and NativeAOT tests never use —
most notably the cross-target alt-JITs and SuperPMI.
This PR narrows the subset list to what those tests actually need, and
fixes a Windows/Unix asymmetry in the JIT install rules that blocked
doing so.
## 1. `src/coreclr/jit/CMakeLists.txt` — install the target-specific JIT
into the `jit` component on Windows
crossgen2 and ILC don't load `clrjit`; they load the JIT named for the
target they're compiling for, e.g. `clrjit_win_x64_x64` when targeting
win-x64.
On Unix that JIT is already installed into the `jit` component alongside
`clrjit`:
```cmake
if (CLR_CMAKE_TARGET_UNIX)
...
install_clr(TARGETS clrjit_unix_${ARCH_TARGET_NAME}_${ARCH_HOST_NAME} DESTINATIONS . COMPONENT jit)
endif()
```
Windows had no equivalent rule, so there the target-specific JIT was
only ever installed as part of `alljits`. Any Windows build that selects
native components individually rather than doing a full native build
therefore produces a crossgen2 that fails as soon as it runs:
```
EXEC : error : Dll was not found. [src\coreclr\crossgen-corelib.proj]
error MSB3073: ...crossgen2.exe ... System.Private.CoreLib.dll ... exited with code 1
```
This mirrors the existing Unix rule for Windows targets. **Full native
builds are unaffected**, since `alljits` already installed these JITs —
it only makes the `jit` component self-contained on Windows the way it
already is on Unix.
## 2. `eng/pipelines/runtime-linker-tests.yml` — narrow the subset list
`clr.native` is replaced by `clr.runtime` + `clr.nativeaotruntime` (the
`runtime` and `nativeaot` CMake components).
`src/coreclr/components.cmake` shows `runtime` already depends on `jit`,
`iltools`, `debug` and `hosts`, and with the fix above `jit` now also
carries the JIT crossgen2/ILC need.
Dropped as a result:
- **`alljits`** — the cross-target alt-JITs. On win-x64 only `clrjit`
and `clrjit_win_x64_x64` are now built; on linux-x64 only `clrjit` and
`clrjit_unix_x64_x64`.
- **`spmi`** — SuperPMI and its shims.
- **`clr.packages`** — only produces the ILAsm/ILDAsm/TestHost/Sdk.IL
nupkgs, referenced solely by `eng/Publishing.props` for official-build
publishing. Packing them takes ~2.5s, so this is a cleanliness change,
not a perf one.
- **`clr.crossarchtools`** — redundant here: `_BuildCrossComponents` is
already set whenever `ClrRuntimeBuildSubsets` is non-empty for CoreCLR,
and the cross-tool build is gated on `_BuildAnyCrossArch`, which is
false for native windows-x64/linux-x64. Verified that no cross-arch
build directory is produced either way.
## Measurements
Measured on CI, comparing build
[1538104](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1538104)
(this PR) against
[1534932](https://dev.azure.com/dnceng-public/cbb18261-c48f-4abb-8651-8cdcb5474649/_build/results?buildId=1534932)
(a recent PR build of the unchanged pipeline):
| | ninja targets | "Build product" |
|---|---|---|
| **windows-x64** (critical path) | 2646 → **1901** (−28.2%) | 40.0m →
**35.4m** (−4.6m) |
| linux-x64 | 2837 → **2132** (−24.8%) | 31.7m → **29.0m** (−2.7m) |
| browser-wasm | unaffected (builds `mono`) | 26.0m → 26.7m |
The windows-x64 job as a whole goes from 62.4m to 56.5m. Total build
wall clock went from 75.0m to 68.0m, though that figure includes queue
variance across runs — the "Build product" numbers are the reliable
ones. linux-x64 saves time too but stays off the critical path.
Locally, isolating just the CoreCLR native build on linux-x64 at `ninja
-j 4` (the parallelism CI uses) gives 4m03s → 3m05s, i.e. −24%,
consistent with the CI result.
## Validation
Locally, from a clean tree with the narrowed subsets:
- Trimming tests: **88 tests pass**
- NativeAOT test apps: **57 tests pass**
- Artifacts verified: `libcoreclr.so`, `ilc`, `crossgen2`,
`ilasm`/`ildasm`, DAC/mscordbi and the `aotsdk` all still present;
superpmi and the unused alt-JITs gone
On CI, all three `dotnet-linker-tests` jobs (windows-x64, linux-x64,
browser-wasm) pass, including the trimming and NativeAOT test app steps,
with no change in test counts or coverage.
Two unrelated failures show up on this PR and are not caused by it:
- `runtime (Build openbsd-x64 Debug CoreCLR_Bootstrapped)` — fails with
`NETSDK1203` on every recent PR (sampled 6/6); the leg only passes on
`main` because rolling builds run it as Release.
-
`System.Net.Security.Tests.TlsSessionTests.SslStreamServer_RejectsClientCert_ClientObservesAlert`
on linux-arm64 — known flaky, tracked by dotnet#131755 (44 hits in the last
month).
> [!NOTE]
> This content was created with assistance from AI.
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot-Session: ce99ab84-7dd0-4307-8dbe-47d695b514de
MichalStrehovsky added a commit that referenced this pull request Aug 24, 2026
After #131666 we should be able to get away with clr.jit. If one needs
to crossbuild, they'll need to add clr.alljits, but that's not a
mainstream scenario. Should shave the same number of minutes as what is
in #131666.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants

@sbomer@jkoritzinsky@jtschuster