Uh oh!
There was an error while loading. Please reload this page.
[release/8.0] [DependencyInjection] introduce feature switch to disable S.R.E - #91352
Conversation
When recording a new AOT profile for .NET MAUI apps running on Android, we noticed that System.Reflection.Emit work was being done on a background thread. The call seen in `dotnet-trace` output: 11.32ms microsoft.extensions.dependencyinjection!Microsoft.Extensions.DependencyInjection.ServiceLookup.ILEmitResolverBuilder.GenerateMethodBody(Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceCallSite,System.Reflection.Emit.ILGenerator) .NET Android apps are unique in that there is a JIT, `RuntimeFeature.IsDynamicCodeCompiled` is true, System.Reflection.Emit is possible -- S.R.E is however, not great for startup performance. Starting threads on Android during startup can also be slow, as Android will commonly put all but a single core to sleep for battery saving purposes. We try to avoid starting threads on startup for "hello world" applications on Android. To solve this for now, introduce a new feature flag: Microsoft.Extensions.DependencyInjection.DisableDynamicEngine Which, we will provide a value in either the Android or .NET MAUI optional workload via an MSBuild property. To test, I put this in my app's `.csproj` file: <RuntimeHostConfigurationOption Include="Microsoft.Extensions.DependencyInjection.DisableDynamicEngine" Condition="'$(DisableDynamicEngine)' != ''" Value="$(DisableDynamicEngine)" Trim="true" /> Customers *could* opt to change this flag, but we don't think it will particularly useful. An example of services realized by .NET MAUI at startup, via some logging added: 08-25 13:21:55.647 16530 16530 I DOTNET : RealizeService called: System.Collections.Generic.IEnumerable`1[Microsoft.Maui.Hosting.IMauiInitializeService] 08-25 13:21:55.664 16530 16530 I DOTNET : RealizeService called: System.Collections.Generic.IEnumerable`1[Microsoft.Maui.Hosting.IMauiInitializeScopedService] 08-25 13:21:55.665 16530 16530 I DOTNET : RealizeService called: Microsoft.Maui.Dispatching.IDispatcher 08-25 13:21:55.668 16530 16530 I DOTNET : RealizeService called: System.Collections.Generic.IEnumerable`1[Microsoft.Maui.LifecycleEvents.LifecycleEventRegistration] 08-25 13:21:56.057 16530 16530 I DOTNET : RealizeService called: System.Collections.Generic.IEnumerable`1[Microsoft.Maui.Hosting.HandlerMauiAppBuilderExtensions+HandlerRegistration] 08-25 13:21:56.115 16530 16530 I DOTNET : RealizeService called: Microsoft.Extensions.DependencyInjection.IServiceScopeFactory 08-25 13:21:56.670 16530 16530 I DOTNET : RealizeService called: Microsoft.Maui.Controls.HideSoftInputOnTappedChangedManager 08-25 13:21:56.712 16530 16530 I DOTNET : RealizeService called: System.Collections.Generic.IEnumerable`1[Microsoft.Maui.Hosting.ImageSourcesMauiAppBuilderExtensions+ImageSourceRegistration] 08-25 13:21:57.700 16530 16530 I DOTNET : RealizeService using S.R.E: Microsoft.Maui.Controls.HideSoftInputOnTappedChangedManager `HideSoftInputOnTappedChangedManager` would be realized once per page, which would not be a huge payoff to use S.R.E for. So the only way the S.R.E codepath could be useful on Android would be if the customer is registering lots of services themselves. They might be better off just using `new()` in that case? An example of the startup time Android reports with the new flag on/off: DisableDynamicEngine=false 08-25 14:31:37.462 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +733ms 08-25 14:31:39.394 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +737ms 08-25 14:31:41.326 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +730ms DisableDynamicEngine=true 08-25 14:32:20.233 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +724ms 08-25 14:32:22.137 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +727ms 08-25 14:32:24.042 2090 2330 I ActivityTaskManager: Displayed com.companyname.testmaui/crc643c09abdeec717b83.MainActivity: +716ms This was a `dotnet new maui` project, using dotnet/maui/main on a Pixel 5 device.
Co-authored-by: Eric Erhardt <eric.erhardt@microsoft.com>
ghost
commented
Aug 30, 2023
Tagging subscribers to this area: @dotnet/area-extensions-dependencyinjection Issue DetailsBackport of #91133 to release/8.0 /cc @steveharter@jonathanpeppers@jeffhandley Customer ImpactMicrosoft.Extensions usage in .NET MAUI applications on Android can impact startup time. An example call seen in .NET Android apps are unique in that there is a JIT, To solve this for now, introduce a new feature flag: TestingTo test, I put this in my .NET MAUI app's An example of the startup time Android reports with the new flag on/off: This was a RiskLow. Flag is off by default and will only be enabled in the IMPORTANT: If this backport is for a servicing release, please verify that:
|
carlossanlop
commented
Aug 31, 2023
@jeffhandley do we have your approval? @steveharter can you also sign-off this backport? |
jeffhandley
left a comment
There was a problem hiding this comment.
This is approved for RC2. It improves an end-to-end scenario for Android related to new features in .NET 8 by offering an opt-out switch.
Backport of #91133 to release/8.0
/cc @steveharter@jonathanpeppers@jeffhandley
Customer Impact
Microsoft.Extensions usage in .NET MAUI applications on Android can impact startup time.
An example call seen in
dotnet-traceoutput:.NET Android apps are unique in that there is a JIT,
RuntimeFeature.IsDynamicCodeCompiledis true, System.Reflection.Emit is possible -- S.R.E is however, not great for startup performance.To solve this for now, introduce a new feature flag:
Testing
To test, I put this in my .NET MAUI app's
.csprojfile:An example of the startup time Android reports with the new flag on/off:
This was a
dotnet new mauiproject, using dotnet/maui/main on a Pixel 5 device.Risk
Low. Flag is off by default and will only be enabled in the
androidoptional workload for now.IMPORTANT: If this backport is for a servicing release, please verify that:
The PR target branch is
release/X.0-staging, notrelease/X.0.If the change touches code that ships in a NuGet package, you have added the necessary package authoring and gotten it explicitly reviewed.