Skip to content

[release/8.0] [DependencyInjection] introduce feature switch to disable S.R.E - #91352

Merged
carlossanlop merged 2 commits into
release/8.0from
backport/pr-91133-to-release/8.0
Aug 31, 2023
Merged

[release/8.0] [DependencyInjection] introduce feature switch to disable S.R.E#91352
carlossanlop merged 2 commits into
release/8.0from
backport/pr-91133-to-release/8.0

Conversation

@github-actions

@github-actionsgithub-actionsBot commented Aug 30, 2023

Copy link
Copy Markdown
Contributor

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-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.

To solve this for now, introduce a new feature flag:

Microsoft.Extensions.DependencyInjection.DisableDynamicEngine

Testing

To test, I put this in my .NET MAUI app's .csproj file:

<RuntimeHostConfigurationOption Include="Microsoft.Extensions.DependencyInjection.DisableDynamicEngine"
Condition="'$(DisableDynamicEngine)' != ''"
Value="$(DisableDynamicEngine)"
Trim="true" />

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.

Risk

Low. Flag is off by default and will only be enabled in the android optional workload for now.

IMPORTANT: If this backport is for a servicing release, please verify that:

  • The PR target branch is release/X.0-staging, not release/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.

jonathanpeppersand others added 2 commits August 30, 2023 19:52
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

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/area-extensions-dependencyinjection
See info in area-owners.md if you want to be subscribed.

Issue Details

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-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.

To solve this for now, introduce a new feature flag:

Microsoft.Extensions.DependencyInjection.DisableDynamicEngine

Testing

To test, I put this in my .NET MAUI app's .csproj file:

<RuntimeHostConfigurationOption Include="Microsoft.Extensions.DependencyInjection.DisableDynamicEngine"
Condition="'$(DisableDynamicEngine)' != ''"
Value="$(DisableDynamicEngine)"
Trim="true" />

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.

Risk

Low. Flag is off by default and will only be enabled in the android optional workload for now.

IMPORTANT: If this backport is for a servicing release, please verify that:

  • The PR target branch is release/X.0-staging, not release/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.

Author:github-actions[bot]
Assignees:-
Labels:

area-Extensions-DependencyInjection

Milestone:-

@carlossanlop

Copy link
Copy Markdown
Contributor

@jeffhandley do we have your approval?

@steveharter can you also sign-off this backport?

@carlossanlopcarlossanlop added the Servicing-consider Issue for next servicing release review label Aug 31, 2023
@carlossanlopcarlossanlop added this to the 8.0.0 milestone Aug 31, 2023

@jeffhandleyjeffhandley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.

@jeffhandleyjeffhandley added Servicing-approved Approved for servicing release and removed Servicing-consider Issue for next servicing release review labels Aug 31, 2023
@carlossanlop
carlossanlop merged commit 399f37c into release/8.0Aug 31, 2023
@carlossanlop
carlossanlop deleted the backport/pr-91133-to-release/8.0 branch August 31, 2023 22:27
@radicalradical mentioned this pull request Sep 26, 2023
@ghostghost locked as resolved and limited conversation to collaborators Oct 1, 2023
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@carlossanlop@jeffhandley@jonathanpeppers