[assembly-preparer] Speed up InlineDlfcnMethodsStep.#26039
Conversation
InlineDlfcnMethodsStep iterated every type and every method (and every instruction of every method with a body) in every assembly, looking for calls to ObjCRuntime.Dlfcn to inline. Two changes make this cheaper: * Skip whole assemblies that can't contain Dlfcn calls. Dlfcn lives in the product assembly, so an assembly that neither is nor references the product assembly (the BCL, most third-party code) can't call it. Check that (cheapest first: the assembly references, then whether it's the product assembly, then finally whether it references the Dlfcn type) once per assembly and skip the whole thing - types, methods and instructions - otherwise. * Check the declaring type's simulator availability once per type in ProcessType instead of once per method. It only depends on the type, so recomputing it for every method (each call scans the type's availability attributes) was wasteful. For monotouch-test's assemblies (MySimpleApp, ios simulator) this cut the time spent in InlineDlfcnMethodsStep roughly in half for link None (2.85s -> 1.65s, dominated by the un-skippable product assembly) and ~6x for SdkOnly (1.58s -> 0.27s). Verified with monotouch-test on iOS (0 failed) with the inline-dlfcn-methods-strict and inline-dlfcn-methods-compat variations (which exercise the actual inlining) as well as release|linksdk. Build performance on iOS (MonoVM): | Project | Runtime identifier | Link mode | PrepareAssemblies=false | PrepareAssemblies=true | Difference | | -------------- | ------------------ | --------- | ----------------------- | ---------------------- | ------------ | | monotouch-test | ios-arm64 | None | 00:02:19.76 | 00:02:13.53 | -00:00:06.23 | | monotouch-test | ios-arm64 | SdkOnly | 00:01:26.94 | 00:01:47.17 | 00:00:20.22 | | monotouch-test | iossimulator-arm64 | None | 00:01:45.58 | 00:01:43.90 | -00:00:01.68 | | monotouch-test | iossimulator-arm64 | SdkOnly | 00:01:18.42 | 00:01:23.84 | 00:00:05.42 | | MySimpleApp | ios-arm64 | None | 00:01:14.39 | 00:01:16.94 | 00:00:02.54 | | MySimpleApp | ios-arm64 | SdkOnly | 00:00:22.02 | 00:00:45.90 | 00:00:23.87 | | MySimpleApp | iossimulator-arm64 | None | 00:00:53.94 | 00:00:54.32 | 00:00:00.37 | | MySimpleApp | iossimulator-arm64 | SdkOnly | 00:00:19.17 | 00:00:25.65 | 00:00:06.47 | Build performance on macOS (CoreCLR): | Project | Runtime identifier | Link mode | PrepareAssemblies=false | PrepareAssemblies=true | Difference | | -------------- | ------------------ | --------- | ----------------------- | ---------------------- | ------------ | | monotouch-test | osx-arm64 | None | 00:00:56.09 | 00:00:51.21 | -00:00:04.87 | | monotouch-test | osx-arm64 | SdkOnly | 00:00:53.56 | 00:00:52.37 | -00:00:01.18 | | MySimpleApp | osx-arm64 | None | 00:00:09.83 | 00:00:09.50 | -00:00:00.33 | | MySimpleApp | osx-arm64 | SdkOnly | 00:00:09.44 | 00:00:08.84 | -00:00:00.60 | Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Optimizes the assembly-preparer linker step InlineDlfcnMethodsStep to reduce unnecessary scanning work when inlining ObjCRuntime.Dlfcn calls, improving overall link/prepare performance. Also updates performance tests to cover the intended runtime split (MonoVM on iOS, CoreCLR on macOS).
Changes:
- Skip processing entire assemblies that cannot contain
ObjCRuntime.Dlfcncalls by checking product-assembly relationship and type references once per assembly. - Cache simulator-availability checks at the type level (once per type) instead of repeating them for every method.
- Split the
PrepareAssembliesperformance test into separate MonoVM and CoreCLR test entry points.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| tools/dotnet-linker/Steps/InlineDlfcnMethodsStep.cs | Avoids type/method/IL iteration for assemblies that cannot reference ObjCRuntime.Dlfcn, and reduces repeated simulator-availability checks. |
| tests/dotnet/UnitTests/PerformanceTests.cs | Splits performance coverage into MonoVM (iOS) and CoreCLR (macOS) test cases while reusing shared logic. |
✅ 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 #bf45f88] 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 |
InlineDlfcnMethodsStep iterated every type and every method (and every
instruction of every method with a body) in every assembly, looking for calls to
ObjCRuntime.Dlfcn to inline. Two changes make this cheaper:
Skip whole assemblies that can't contain Dlfcn calls. Dlfcn lives in the
product assembly, so an assembly that neither is nor references the product
assembly (the BCL, most third-party code) can't call it. Check that (cheapest
first: the assembly references, then whether it's the product assembly, then
finally whether it references the Dlfcn type) once per assembly and skip the
whole thing - types, methods and instructions - otherwise.
Check the declaring type's simulator availability once per type in ProcessType
instead of once per method. It only depends on the type, so recomputing it for
every method (each call scans the type's availability attributes) was wasteful.
For monotouch-test's assemblies (MySimpleApp, ios simulator) this cut the time
spent in InlineDlfcnMethodsStep roughly in half for link None (2.85s -> 1.65s,
dominated by the un-skippable product assembly) and ~6x for SdkOnly (1.58s ->
0.27s).
Verified with monotouch-test on iOS (0 failed) with the inline-dlfcn-methods-strict
and inline-dlfcn-methods-compat variations (which exercise the actual inlining)
as well as release|linksdk.
Build performance on iOS (MonoVM):
Build performance on macOS (CoreCLR):