-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consider updating ActivatorUtilities.CreateFactory to use ILEmit when possible #66153
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
FYI @eerhardt |
Tagging subscribers to this area: @dotnet/area-extensions-dependencyinjection Issue DetailsAdditional Context: dotnet/aspnetcore#40521. In 7.0-preview2, Blazor was updated to type activate component types using Given that ServiceProvider's default implementation in .NET (not-NativeAOT) apps is to use ILEmit, we could avoid the size hit to Blazor by updating Note that Blazor is rolling back the change to type activate components until we can ensure it can be accommodated without the size regression i.e. until this issue is resolved.
|
I believe CreateFactory is just trying to find and invoke a constuctor. In that case, we should consider extending the |
It is a little more than that. Specifically it is how to get the arguments to pass into the constructor. If the argument isn't passed into the Lines 234 to 261 in 1a37caf
|
I've updated the main description to include the proposed plan. |
UPDATED (Steve Harter):
Current plan is to avoid adding new emit-based logic (which should be considered a last resort) and instead use reflection with new, faster APIs. It is possible that we can also completely remove the usage of LINQ\compiled expressions pending perf and tradeoffs. NativeAOT would also use this faster reflection path (NativeAOT doesn't support emit and LINQ is not used since it is slower than standard reflection when LINQ is in "reflection fallback" mode).
Also note that when this issue was logged, there was not a reflection path. See #81262.
Steps in the plan:
Update: below are CorClr\Windows with the "before" is compiled expressions in latest v8 and "after" is reflection in latest v8+PR above. The "injection" reflection scenarios are now ~1.1x (10%) slower than expressions and the "explicit" scenario is ~1.9x slower than expressions. So reflection went from 5.4->1.9x slower (explicit) and 2.4->1.1x (injected) slower than compiled expressions and comparing against the original above shows ~3.1 \ ~1.9x improvement and with no extra allocs. Disclaimer: perf improvements are "fast path" scenarios of <= 4 args and meet other constraints; otherwise perf gain will be less; also Mono+Blazor and NativeAot will have different perf characteristics, but all reflection optimizations were also applied there.
However, the perf gains on Mono interpreter not as significant; they are ~1.3-1.5x faster:
which are still 1.4x slower than the LINQ expressions for injection and 3.4x slower for the direct case:
It appears overhead of lambda-capture methods is more significant on Mono interpreter than CoreClr; this needs more investigation. Reflection itself does not seem to be the bottleneck anymore.
Original
Additional Context: dotnet/aspnetcore#40521.
In 7.0-preview2, Blazor was updated to type activate component types using
ActivatorUtilities.CreateFactory
. The implementation of this API uses ExpressionTrees, and results in about a 100kb size increase to Blazor WebAssembly apps by default.Given that ServiceProvider's default implementation in .NET (not-NativeAOT) apps is to use ILEmit, we could avoid the size hit to Blazor by updating
ActivatorUtilities.CreateFactory
to use ILEmit too when possible.Note that Blazor is rolling back the change to type activate components until we can ensure it can be accommodated without the size regression i.e. until this issue is resolved.
The text was updated successfully, but these errors were encountered: