Skip to content
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

Optimize render tree building via RenderTreeFrameArrayBuilder #24484

Merged
merged 23 commits into from
Aug 3, 2020

Conversation

SteveSandersonMS
Copy link
Member

@SteveSandersonMS SteveSandersonMS commented Jul 31, 2020

Implementation of #24464

I'm seeing a 20% improvement for wall clock times on the FastGrid benchmark with this. The gain comes down to (1) making RenderTreeFrame mutable so we no longer have to copy frames every time we close elements/regions/components etc., and (2) creating a specialised variant of ArrayBuilder that knows how to append instances of that struct without going through the factory methods that have to copy on assignment.

We could now also remove all the With... methods on RenderTreeFrame, plus technically all its static factory methods and probably all its constructors too. They are all internal/private. However that would cause quite a bit of noise across our test code, so I don't want to make this PR that much bigger, or make the tests more laborious to write. We can always clean these away any time in the future if we want.

@SteveSandersonMS SteveSandersonMS added the area-blazor Includes: Blazor, Razor Components label Jul 31, 2020
@SteveSandersonMS SteveSandersonMS requested a review from a team July 31, 2020 18:38
@SteveSandersonMS SteveSandersonMS force-pushed the stevesa/perf-rendertreearraybuilder branch from 5fb52e2 to c2af97e Compare July 31, 2020 18:39
@SteveSandersonMS SteveSandersonMS marked this pull request as ready for review August 1, 2020 07:15
@SteveSandersonMS SteveSandersonMS marked this pull request as draft August 1, 2020 07:19
@SteveSandersonMS SteveSandersonMS force-pushed the stevesa/perf-rendertreearraybuilder branch from 456b848 to 98a23ac Compare August 3, 2020 10:51
@SteveSandersonMS
Copy link
Member Author

In the end I decided I was uncomfortable with exposing the new mutability of RenderTreeFrame publicly, so what I've done is convert all the newly-writable fields to internal with the suffix Field on their name, plus for each added a corresponding public readonly property that will read its value. The reason for exposing the underlying backing fields via internal (and not having internal set on the accessor properties) is to avoid introducing extra overhead given that this is central to the most perf-critical paths on WebAssembly.

This is technically a binary-breaking change because what was a field before is now a property, but it's not a breaking change for anyone recompiling their code (you can still read the same set of values with the same names). Plus the whole RenderTreeFrame type is pubternal-ish - there's an analyzer warning people not to use it directly, even though some people do. Since this won't affect anyone who recompiles their code, I don't think this is problematic.

@SteveSandersonMS SteveSandersonMS marked this pull request as ready for review August 3, 2020 12:05
@@ -48,153 +48,181 @@ namespace Microsoft.AspNetCore.Components.RenderTree
// Common
// --------------------------------------------------------------------------------

[FieldOffset(0)] internal int SequenceField;
[FieldOffset(4)] internal RenderTreeFrameType FrameTypeField;
Copy link
Member

Choose a reason for hiding this comment

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

Is the goal that we don't "break" the entire world with this change?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, this change won't be breaking for any code that either (a) is recompiled after this change goes in, or (b) doesn't use RenderTreeFrame directly (like our analyzer tells people).

Copy link
Member

Choose a reason for hiding this comment

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

I'm thinking of things like bUnit and so on, they'll likely ignore your warning :)

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes I strongly expect so. I was going to contact @egil about this directly.

Copy link
Member

@javiercn javiercn left a comment

Choose a reason for hiding this comment

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

Changes are pretty mechanic.

Looks great! I don't have major concerns since most of the API is internal.

If you want to remove methods in the future, file a follow-up issue so that we don't loose track of it.

@SteveSandersonMS
Copy link
Member Author

If you want to remove methods in the future, file a follow-up issue so that we don't loose track of it.

I'm not saying I definitely do want to remove them. They aren't harmful, and being internal/private, they aren't a liability. I'll leave it to future-us to make this determination.

@SteveSandersonMS SteveSandersonMS self-assigned this Aug 3, 2020
@SteveSandersonMS SteveSandersonMS merged commit 38e166f into master Aug 3, 2020
@SteveSandersonMS SteveSandersonMS deleted the stevesa/perf-rendertreearraybuilder branch August 3, 2020 17:42
@egil egil mentioned this pull request Aug 4, 2020
3 tasks
@egil egil mentioned this pull request Aug 12, 2020
10 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-blazor Includes: Blazor, Razor Components
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants