[dotnet] Enable AOT generic instantiation deduplication when PrepareAssemblies=true - #25894
Conversation
…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>
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
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.dlltoResolvedFileToPublishfor 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. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
✅ [PR Build #588609d] Build passed (Detect API changes) ✅Pipeline on Agent |
This comment has been minimized.
This comment has been minimized.
✅ [PR Build #588609d] Build passed (Build macOS tests) ✅Pipeline on Agent |
✅ [PR Build #588609d] Build passed (Build packages) ✅Pipeline on Agent |
This comment has been minimized.
This comment has been minimized.
✅ API diff for current PR / commitNET (empty diffs)✅ API diff vs stableNET (empty diffs)ℹ️ Generator diffGenerator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes) Pipeline on Agent |
🚀 [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 macOS tests✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download Linux Build VerificationPipeline on Agent |
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:
After build times: