-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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 disabling Ref.Emit in System.Linq.Expressions on WASM #38439
Comments
Tagging subscribers to this area: @cston |
I'm sad every time I see System.Linq.Expressions in the default template of size sensitive workloads. It might be worth checking how to make that conditional in Blazor.
I think it'd be better to have this instead of compile-time constant use feature-switch
We actually switched from interpreter to SRE a few years ago for Mono profile due to performance improvements but it's possible that for NET Core libraries the situation will be different. However, we need to test if the behaviour is the same and where we stand on performance. |
Seems to be coming from Microsoft.Extensions.DependencyInjection 😞 |
Might need correct flags setting for WASM? Lines 11 to 15 in ed78fad
|
Ah, I meant - the reference to Linq.Expressions is coming from DependencyInjection. The fact that DependencyInjection can also use Ref.Emit is new information to me, but makes perfect sense (if you want bad startup time and DI by itself is still not slow enough, might want to insure it's really bad by adding Ref.Emit to the mix). |
😂 I think @migueldeicaza would sympathize with this position |
Per Steve Sanderson, Blazor WASM is going to bring in a dependency on expressions as soon as someone drops a form into their app: https://github.com/dotnet/aspnetcore/blob/master/src/Components/Web/src/Forms/InputBase.cs#L51 |
I still think the best option is to have both options in and control it via RuntimeFeature.IsDynamicCodeCompiled. I believe we do it in other parts of libraries as well, for example for regular expressions. |
I'm really curious about RuntimeFeature.IsDynamicCodeCompiled here. I added its use into regex based on such a recommendation, but it actually seems like the wrong choice when running with an interpreter. Often reflection emit (or S.L.Expressions) is used when there's some general implementation and then a very specific (and thus faster / more tuned) implementation can be emitted for a specific use case. That's what happens with regex. Now, if the choice is between using a compiled version of the general path and an interpreted version of the specific path, it's really hard to say which is going to be better. But if the choice is between using an interpreted version of the general path and an interpreted version of the specific path, in general I'd expect the latter to win. After all, with something like regex, is it better for the interpreter to execute the interpreter's IL interpreting the regex instructions, or is it better for the interpreter to execute the IL specific to that regex. There's still the overhead of doing the IL generation, but that's the case whether the IL generation path is interpreted or compiled. Do we need a RuntimeFeature.IsInterpreting, or some such thing? |
This was the same case for Json serialization. See my perf results when I tested using Ref.Emit vs. Reflection to get/set properties and create objects. The Ref.Emit case (after warm-up) was 15-20% faster.
What decisions would we make off that property that we wouldn't make with |
It is even more complex once you throw the fact that some code may be compiled (JIT or AOT) and some code may be interpreted. We are not there today, but it is where we want to be with wasm eventually. There is typically transition cost between interpreting and running compiled code. So whether the regex compiled into IL running on interpreter is going to be faster than the built-in regex interpretation is also going to depend on how chatty is the interaction between the regex IL and static libraries that are likely to be compiled. The interpreter is always going to be a low-throughput configuration. I think we should make it simple and prioritize size over speed for the interpreter. The high-throughput option for Wasm would be full AOT. |
Let's take regex as an example.
|
That's not how you should look at it with the tech we have today. The interpreter is quite limited in how much optimizations/propagations can do. So whether the code is ref-emit generated or precompiled does not matter, what matters is how much code needs to process. In the simple view, you can say that every IL instruction cost you 1 us to execute, if you can write a program in the way that it will be 100 IL instructions without ref-emit and 150 with ref-emit (ignoring the ref-emit generation part) the winner will be no-ref-emit version. |
Yes, and for Regex for example, there are in general many fewer IL instructions spit out for the ref emit version than need to be executed for the interpreted version. There are fewer IL instructions to execute in the ref emited IL. That's exactly my point. |
Moving to 'Future' as this isn't high priority for 6. |
If the |
I was surprised the default Blazor WASM template depends on Reflection.Emit. This is because of System.Linq.Expressions.
System.Linq.Expressions can be compiled in a way that removes the Ref.Emit dependency (use interpreter only) - to do this set the
IsInterpreting
property in System.Linq.Expressions.csproj totrue
.Compiling without Ref.Emit support saves 112 kB uncompressed and 44 kB compressed on System.Linq.Expressions.dll alone. I expect there will be more savings possible in CoreLib (the Ref.Emit implementation).
#38438 fixes some bitrot in System.Linq.Expressions that is necessary to build this way.
Cc @marek-safar @eerhardt
The text was updated successfully, but these errors were encountered: