-
Notifications
You must be signed in to change notification settings - Fork 647
Pipeline optimizations #6237
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
Pipeline optimizations #6237
Conversation
f5376bd to
0bbafa5
Compare
a199591 to
f74b2fc
Compare
|
This is good to go now |
|
I'm aware that this is post merge commit. I want to mention though that the array accessor for .NETCore could be ported from so it could be included in .NETCore build (AFAIK, NSB targets 3.1). Not sure though that it would be reasonable for 3-5% gains as @danielmarbach described. |
|
I have done another round on this code as promised. It is now possible because we dropped the .NET Core 3.1 target. |
TLDR:
Today, even a simple pipeline like
creates the following code
notice the display class and func allocations throughout the pipeline which are going to happen for every pipeline invocation. This PR introduces an internal backing property on the context bag that contains all the behaviors for a given pipeline stage or the parent stage (in case the current stage has no pipeline) and then extracts the behaviors from the context. So in essence the PR would turn the above pseudocode from
into
which then leads to the following code being compiled
notice the display class and func allocations are gone. The changes introduced here are safe because the order of behaviors are calculate once and then stored in the right order into an array. The position of the behavior in the area as well as the type of the behavior is known at "baking" time of the expression tree and can just be expressed by a constant integer pointing to the location in the array.
For every pipeline execution, the behaviors need to be reassigned to the context instance to make that state available during the pipeline execution of the fresh context instances. Parent walking is necessary for pipeline stages that are part of a parent pipeline.
Alternatives to exposing the state
The extension bag cannot be used directly because the access to the extension dictionary and the associated allocations would undermine the performance improvements.
Further tweaks
Faster casting
It would be possible to save some on the casting by using
Unsafe.Asby for example replacingwith
which could lead to further speed improvements as shown below
yet as the highlighted changes show depending on the depth of the pipeline this optimization could be slower than directly accessing casting I figured I'll leave it out for now. For future reference, the expression tree code would look like
Remove the bound checks with .NET 6
By talking to @Scooletz we figured it would be possible to remove the bound checks around the array access. This would look like the following if combined with
Unsafe.Asthe expression tree code looks something like
or by using calling a helper
This can lead to 3-5% additional gains but only works on NET6 which we don't target yet in core.
Benchmarks
Pipeline Execution
Pipeline Exception
Pipeline Warmup