Skip to content

[dotnet] Enable AOT generic instantiation deduplication when PrepareAssemblies=true - #25894

Merged
rolfbjarne merged 2 commits into
mainfrom
dev/rolf/assembly-preparer-speed
Jul 1, 2026
Merged

[dotnet] Enable AOT generic instantiation deduplication when PrepareAssemblies=true#25894
rolfbjarne merged 2 commits into
mainfrom
dev/rolf/assembly-preparer-speed

Conversation

@rolfbjarne

Copy link
Copy Markdown
Member

When the assembly-preparer is used to post-process assemblies
(PrepareAssemblies/PostProcessAssemblies=true), the set of assemblies that gets
AOT-compiled - and which is used to detect AOT generic instantiation
deduplication - is computed from ResolvedFileToPublish (via the assembly-preparer's
ComputeAOTArguments step) instead of from the linker's own in-memory assembly
collection.

The dedup container assembly (aot-instances.dll) is only added to the linker's
assembly collection (ManagedAssemblyToLink/TrimmerRootAssembly in
_CreateAOTDedupAssembly), so it was never part of ResolvedFileToPublish. As a
result, the assembly-preparer never saw the dedup assembly, deduplication was
disabled, and every assembly was AOT-compiled with 'full' (compiling all generic
instantiations redundantly) instead of 'dedup-skip'. This roughly doubled the AOT
compiler's work (e.g. _AOTCompile for monotouch-test went from ~48s to ~76s).

Fix this with two changes:

  • Add the dedup assembly to ResolvedFileToPublish when the assembly-preparer
    post-process path is used and deduplication is enabled, so it's included in the
    set of assemblies the assembly-preparer processes (and AOT-compiles). The add is
    guarded so it doesn't duplicate an entry that's already present.

  • Set Assembly.IsDedupAssembly in the assembly-preparer's
    PopulateApplicationAssembliesStep, exactly like LoadNonSkippedAssembliesStep does
    in the ILLink path, so the dedup container is recognized as AOT-compiled and gets
    the 'dedup-include' flag (while the other assemblies get 'dedup-skip').

Also improved the perf test.

Before build times:

Project Runtime identifier Link mode Disabled (average) Enabled (average) Difference (of average)
monotouch-test ios-arm64 None 00:02:07.0742190 00:02:48.9871886 00:00:41.9129696
monotouch-test ios-arm64 SdkOnly 00:01:20.4693850 00:01:56.3924870 00:00:35.9231020
monotouch-test iossimulator-arm64 None 00:01:37.4725223 00:02:16.4294141 00:00:38.9568918
monotouch-test iossimulator-arm64 SdkOnly 00:01:11.8543345 00:01:27.3413050 00:00:15.4869705
MySimpleApp ios-arm64 None 00:01:18.7859068 00:01:54.7023664 00:00:35.9164596
MySimpleApp ios-arm64 SdkOnly 00:00:21.7704550 00:00:53.0059895 00:00:31.2355345
MySimpleApp iossimulator-arm64 None 00:00:54.6666308 00:01:26.3723282 00:00:31.7056974
MySimpleApp iossimulator-arm64 SdkOnly 00:00:19.7740878 00:00:34.5455132 00:00:14.7714254

After build times:

Project Runtime identifier Link mode Disabled (average) Enabled (average) Difference (of average)
monotouch-test ios-arm64 None 00:02:05.4666859 00:02:09.6491832 00:00:04.1824973
monotouch-test ios-arm64 SdkOnly 00:01:20.1368215 00:01:45.1826245 00:00:25.0458030
monotouch-test iossimulator-arm64 None 00:01:34.2666644 00:01:38.9737062 00:00:04.7070418
monotouch-test iossimulator-arm64 SdkOnly 00:01:06.9120929 00:01:18.3662064 00:00:11.4541135
MySimpleApp ios-arm64 None 00:01:20.3001297 00:01:23.2613776 00:00:02.9612479
MySimpleApp ios-arm64 SdkOnly 00:00:20.4954960 00:00:47.6480467 00:00:27.1525507
MySimpleApp iossimulator-arm64 None 00:00:53.6472697 00:00:55.3882440 00:00:01.7409743
MySimpleApp iossimulator-arm64 SdkOnly 00:00:19.2538091 00:00:31.0467173 00:00:11.7929082

…ssemblies=true

When the assembly-preparer is used to post-process assemblies
(PrepareAssemblies/PostProcessAssemblies=true), the set of assemblies that gets
AOT-compiled - and which is used to detect AOT generic instantiation
deduplication - is computed from ResolvedFileToPublish (via the assembly-preparer's
ComputeAOTArguments step) instead of from the linker's own in-memory assembly
collection.

The dedup container assembly (aot-instances.dll) is only added to the linker's
assembly collection (ManagedAssemblyToLink/TrimmerRootAssembly in
_CreateAOTDedupAssembly), so it was never part of ResolvedFileToPublish. As a
result, the assembly-preparer never saw the dedup assembly, deduplication was
disabled, and every assembly was AOT-compiled with 'full' (compiling all generic
instantiations redundantly) instead of 'dedup-skip'. This roughly doubled the AOT
compiler's work (e.g. _AOTCompile for monotouch-test went from ~48s to ~76s).

Fix this with two changes:

* Add the dedup assembly to ResolvedFileToPublish when the assembly-preparer
  post-process path is used and deduplication is enabled, so it's included in the
  set of assemblies the assembly-preparer processes (and AOT-compiles). The add is
  guarded so it doesn't duplicate an entry that's already present.

* Set Assembly.IsDedupAssembly in the assembly-preparer's
  PopulateApplicationAssembliesStep, exactly like LoadNonSkippedAssembliesStep does
  in the ILLink path, so the dedup container is recognized as AOT-compiled and gets
  the 'dedup-include' flag (while the other assemblies get 'dedup-skip').

Also improved the perf test.

Before build times:

| Project        | Runtime identifier | Link mode | Disabled (average) | Enabled (average) | Difference (of average) |
| -------------- | ------------------ | --------- | ------------------ | ----------------- | ----------------------- |
| monotouch-test | ios-arm64          | None      | 00:02:07.0742190   | 00:02:48.9871886  | 00:00:41.9129696        |
| monotouch-test | ios-arm64          | SdkOnly   | 00:01:20.4693850   | 00:01:56.3924870  | 00:00:35.9231020        |
| monotouch-test | iossimulator-arm64 | None      | 00:01:37.4725223   | 00:02:16.4294141  | 00:00:38.9568918        |
| monotouch-test | iossimulator-arm64 | SdkOnly   | 00:01:11.8543345   | 00:01:27.3413050  | 00:00:15.4869705        |
| MySimpleApp    | ios-arm64          | None      | 00:01:18.7859068   | 00:01:54.7023664  | 00:00:35.9164596        |
| MySimpleApp    | ios-arm64          | SdkOnly   | 00:00:21.7704550   | 00:00:53.0059895  | 00:00:31.2355345        |
| MySimpleApp    | iossimulator-arm64 | None      | 00:00:54.6666308   | 00:01:26.3723282  | 00:00:31.7056974        |
| MySimpleApp    | iossimulator-arm64 | SdkOnly   | 00:00:19.7740878   | 00:00:34.5455132  | 00:00:14.7714254        |

After build times:

| Project        | Runtime identifier | Link mode | Disabled (average) | Enabled (average) | Difference (of average) |
| -------------- | ------------------ | --------- | ------------------ | ----------------- | ----------------------- |
| monotouch-test | ios-arm64          | None      | 00:02:05.4666859   | 00:02:09.6491832  | 00:00:04.1824973        |
| monotouch-test | ios-arm64          | SdkOnly   | 00:01:20.1368215   | 00:01:45.1826245  | 00:00:25.0458030        |
| monotouch-test | iossimulator-arm64 | None      | 00:01:34.2666644   | 00:01:38.9737062  | 00:00:04.7070418        |
| monotouch-test | iossimulator-arm64 | SdkOnly   | 00:01:06.9120929   | 00:01:18.3662064  | 00:00:11.4541135        |
| MySimpleApp    | ios-arm64          | None      | 00:01:20.3001297   | 00:01:23.2613776  | 00:00:02.9612479        |
| MySimpleApp    | ios-arm64          | SdkOnly   | 00:00:20.4954960   | 00:00:47.6480467  | 00:00:27.1525507        |
| MySimpleApp    | iossimulator-arm64 | None      | 00:00:53.6472697   | 00:00:55.3882440  | 00:00:01.7409743        |
| MySimpleApp    | iossimulator-arm64 | SdkOnly   | 00:00:19.2538091   | 00:00:31.0467173  | 00:00:11.7929082        |

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@rolfbjarne
rolfbjarne marked this pull request as ready for review July 1, 2026 17:56
Copilot AI review requested due to automatic review settings July 1, 2026 17:56
@rolfbjarne
rolfbjarne enabled auto-merge (squash) July 1, 2026 17:58

Copilot AI 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

Enables AOT generic instantiation deduplication in the PrepareAssemblies=true + PostProcessAssemblies=true pipeline by ensuring the dedup container assembly (aot-instances.dll) is part of the assembly-preparer’s input set and is correctly identified as the dedup assembly during assembly-preparer processing.

Changes:

  • Add aot-instances.dll to ResolvedFileToPublish for the post-processing assembly-preparer path when deduplication is enabled.
  • Teach the assembly-preparer path to mark the dedup container as IsDedupAssembly, aligning behavior with the ILLink path.
  • Expand the performance test to report per-RID and per-link-mode results with a markdown report (including binlog paths).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
tools/assembly-preparer/PopulateApplicationAssembliesStep.cs Marks the dedup container assembly via IsDedupAssembly so AOT arguments can correctly use dedup-include/dedup-skip.
dotnet/targets/Xamarin.Shared.Sdk.targets Ensures aot-instances.dll is present in ResolvedFileToPublish for the post-process path so assembly-preparer sees it and deduplication isn’t disabled.
tests/dotnet/UnitTests/PerformanceTests.cs Improves the PrepareAssemblies perf test to cover multiple RIDs/link modes and emits a structured markdown report.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ [PR Build #588609d] Build passed (Detect API changes) ✅

Pipeline on Agent
Hash: 588609d1d7df1bd4da0dd0aa590cc12f7901c78c [PR build]

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ [PR Build #588609d] Build passed (Build macOS tests) ✅

Pipeline on Agent
Hash: 588609d1d7df1bd4da0dd0aa590cc12f7901c78c [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ [PR Build #588609d] Build passed (Build packages) ✅

Pipeline on Agent
Hash: 588609d1d7df1bd4da0dd0aa590cc12f7901c78c [PR build]

@vs-mobiletools-engineering-service2

This comment has been minimized.

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

✅ API diff for current PR / commit

NET (empty diffs)

✅ API diff vs stable

NET (empty diffs)

ℹ️ Generator diff

Generator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes)

Pipeline on Agent
Hash: 588609d1d7df1bd4da0dd0aa590cc12f7901c78c [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

🚀 [CI Build #588609d] Test results 🚀

Test results

✅ All tests passed on VSTS: test results.

🎉 All 199 tests passed 🎉

Tests counts

✅ assembly-processing: All 1 tests passed. Html Report (VSDrops) Download
✅ cecil: All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (iOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (MacCatalyst): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (macOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (Multiple platforms): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (tvOS): All 1 tests passed. Html Report (VSDrops) Download
✅ framework: All 2 tests passed. Html Report (VSDrops) Download
✅ fsharp: All 4 tests passed. Html Report (VSDrops) Download
✅ generator: All 5 tests passed. Html Report (VSDrops) Download
✅ interdependent-binding-projects: All 4 tests passed. Html Report (VSDrops) Download
✅ introspection: All 4 tests passed. Html Report (VSDrops) Download
✅ linker (iOS): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (MacCatalyst): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (macOS): All 21 tests passed. Html Report (VSDrops) Download
✅ linker (tvOS): All 15 tests passed. Html Report (VSDrops) Download
✅ monotouch (iOS): All 18 tests passed. Html Report (VSDrops) Download
✅ monotouch (MacCatalyst): All 17 tests passed. Html Report (VSDrops) Download
✅ monotouch (macOS): All 18 tests passed. Html Report (VSDrops) Download
✅ monotouch (tvOS): All 18 tests passed. Html Report (VSDrops) Download
✅ msbuild: All 2 tests passed. Html Report (VSDrops) Download
✅ sharpie: All 1 tests passed. Html Report (VSDrops) Download
✅ windows: All 3 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 4 tests passed. Html Report (VSDrops) Download
✅ xtro: All 1 tests passed. Html Report (VSDrops) Download

macOS tests

✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Ventura (13): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sonoma (14): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sequoia (15): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Tahoe (26): All 5 tests passed. Html Report (VSDrops) Download

Linux Build Verification

Linux build succeeded

Pipeline on Agent
Hash: 588609d1d7df1bd4da0dd0aa590cc12f7901c78c [PR build]

@rolfbjarne
rolfbjarne merged commit 5bebeb4 into main Jul 1, 2026
56 checks passed
@rolfbjarne
rolfbjarne deleted the dev/rolf/assembly-preparer-speed branch July 1, 2026 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants