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

Blazor performance optimizations #22432

Closed
23 of 31 tasks
mkArtakMSFT opened this issue Jun 1, 2020 · 12 comments
Closed
23 of 31 tasks

Blazor performance optimizations #22432

mkArtakMSFT opened this issue Jun 1, 2020 · 12 comments
Assignees
Labels
area-blazor Includes: Blazor, Razor Components Done This issue has been fixed enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-blazor-wasm This issue is related to and / or impacts Blazor WebAssembly
Milestone

Comments

@mkArtakMSFT
Copy link
Member

mkArtakMSFT commented Jun 1, 2020

Battle plan:

  • Quantify 3.2.0 perf
    • ... for selected scenarios:
      • 3rd-party unoptimized code (ComplexTable)
      • 3rd-party optimized code (PlainTable)
      • 1st-party optimized code (FastGrid)
    • ... providing useful breakdowns of:
      • ... time in .NET rendering logic (BuildRenderTree calls, diffing, etc.)
      • ... time in the JS DOM-updating logic
  • Identify and implement optimizations, in each case quantifying the change:
    • Inside Blazor code
      • ... inside the Razor compiler, to reduce the amount of stuff we render at runtime
      • ... inside the .NET rendering logic
      • ... inside the JS DOM-updating logic
    • Inside Mono interpreter (have provided scenarios to Vlad for this effort)
    • In browser's WASM engine (this is something Vlad/Zoltan are leading and might not complete before 5.0 ships) Out of scope for this issue.
    • In 3rd-party code
      • ... by providing more guidance/docs Covered below
      • ... by providing performant base classes (virtualization, base grid) Covered in Virtualization support #24179
    • As a result of switching to CoreFX for 5.0
  • Consider backporting optimizations to 3.2.x if they yield big benefits without involving changes to user code

Update: Results of investigation

After a very extensive investigation, here are things I think we should do to complete this for 5.0:

  • Write up the main findings from the investigation
    • Exactly how perf differs between 3.2.0 and 5.0 Preview 8
    • Why the perf numbers for FastGrid/PlainTable/ComplexTable are what they are. That is, provide breakdowns showing how use of each feature adds to the totals, explaining the differences in perf in ways that justify the perf advice we will give.
  • Ensure we can keep collecting useful profiling data in the future (not just on my machine)
    • Add the ConsoleRunner project to the repo so we can easily run Blazor scenarios on the desktop interpreter
    • Begin a discussion with @BrzVlad and others responsible for the .NET interpreter about how we could merge in something like the trace collection logic so others can get profiling data in the future without needing a custom build of the runtime. Filed Consider adding profile trace export to Mono interpreter runtime#40617
  • Implement optimizations inside Blazor
  • Write up docs on how to write better-performing Blazor WebAssembly apps. For example:
    • How much overhead you should expect from each extra layer of components you add, and each extra parameter you pass. Hence you should consider inlining child components if you're rendering a large number of them.
    • Why it's so important to use IsFixed when cascading values to large numbers of receivers.
    • That @attributes is relatively expensive
    • Why, for perf-criticial components, you should consider implementing your own manual parameter assignment logic on SetParameterAsync, and how to do it efficiently.
    • How and why to use <Virtualize>

The specific optimizations I've listed above aren't the only ones I'm aware of. I've tried many things based on the profiling data. These optimizations are the ones that have the biggest impact for the least cost.

@mkArtakMSFT mkArtakMSFT added investigate area-blazor Includes: Blazor, Razor Components feature-blazor-wasm This issue is related to and / or impacts Blazor WebAssembly labels Jun 1, 2020
@mkArtakMSFT mkArtakMSFT added this to the Next sprint planning milestone Jun 1, 2020
@yugabe
Copy link

yugabe commented Jun 3, 2020

Would it be possible to create "native" WebAssembly benchmarks to test Blazor against? Just to be able to decide whether any given performance related issues are present because of WebAssembly (/JS interop DOM manipulation) or because of the Blazor runtime?

@shawnshaddock

This comment has been minimized.

@pranavkm

This comment has been minimized.

@mkArtakMSFT mkArtakMSFT changed the title Investigate ways to improve Blazor WebAssembly performance Blazor performance optimizations Jun 4, 2020
@mkArtakMSFT mkArtakMSFT added enhancement This issue represents an ask for new feature or an enhancement to an existing one and removed investigate labels Jun 4, 2020
@Lupusa87
Copy link
Contributor

@yugabe When I have critical performance requirement and default blazor is slow I generate result html by myself dinamically, sent it to js using fast low level mono api and update dom from js.
It helps because it shows much faster render, about 10x faster depending on case.
I think it can be good for comparison too, until this way renders faster than blazor we have slow performance compared to js not wasm.
I think we can't really compare against wasm because wasm can't manipulate dom without js for now.
If you wonder how this technique works please check this video

@yugabe
Copy link

yugabe commented Jun 10, 2020

@Lupusa87 I understand, but I feel it to be obvious that in the long run you have to have an out-of-the-box performant framework instead of a good enough manual workaround. It kind of defeats the purpose of Blazor itself to build a whole component in HTML and send the whole diff to JavaScript (you are overwriting a whole DOM subtree without considering which elements to keep, if I understood correctly). It is a good workaround, but it won't fix Blazor WASM on mobile. Have you tried using the @key attribute to speed up rendering though?

Now, Blazor WebAssembly performance is not quite good on mobile devices. Mostly just what you said: DOM manipulation is slow because there is no way to manipulate the DOM without using JS interop. If I know correctly, direct DOM manipulation is on the roadmap for WASM vNext. If someone is competent enough to help out the WASM guys a little, I'm sure it will be greatly appreciated to speed up the delivery of that feature.

@Lupusa87
Copy link
Contributor

@yugabe I use this technique only in critical parts and when it makes sense (when whole most part of dom is changing and no sense to analize changes which makes blazor slower) and shows better performance.
I do not like to do extra work and override blazor intended behavior but I am forced to do so in some cases, sure it is fast workaround and not solution but it works for me for now.

@Lupusa87
Copy link
Contributor

@SteveSandersonMS
I think blazor component should have option to re-render from scratch meaning not to do diffing, just remove old dom fragment and insert new one, it will save some time.
When blazor developer knows that some component on update has major changes he/she can turn this mode on.
Not sure if it is good idea but seems to be from my perspective.

something like this statehaschanged(true), statehaschanged can have bool parameter with default value false and if true is provided component will re-render full dom skipping diff calculations.

@yugabe
Copy link

yugabe commented Jun 10, 2020

@Lupusa87 Now I understand your point. What you outlined just now could help in scenarios where a full component rerender could be preferred over diffing. This sounds a good compromise if no performance gains are available otherwise, a sort of band-aid, if you like. I feel it should be an advanced only scenario though, as the vast majority of the time you shouldn't have to worry about performance so much. Like now, when you are developing, say, an ASP.NET Core backend, you are going to have about 1% of the code being performance-critical, and 99% of the time "it just works". I feel something like this should be a baseline. Now, unfortunately, performance is sub-par, but the framework and foundation are very solid.

That's why I would recommend writing test applications using different alternative frameworks (Angular, React, plain JS, plain WASM) and compare performance to Blazor to find bottlenecks and possible optimization opportunities. I think that's the same method the ASP.NET Core backend team used to compare to NodeJS (but I'm just guessing).

Should the full component rerender be put into a separate issue?

@Lupusa87
Copy link
Contributor

Yes it is for advanced scenario and can be used in 1% of cases but it does not reduce it's importance.
Any framework's strengt is measured fow it can handle advanced scenarios, trivial ones can do everyone :)
Re dedicated issue I am not sure it makes sense bucause as I remember I am not saying this first time and probably the idea will be declined again with some right arguments which are hidden to my eyes.

@radderz
Copy link

radderz commented Jul 7, 2020

For what Lupusa is saying, why not have a way to flag a component as render always with no diff built into the framework? Then for anything where performance is key, that attribute could be applied to force full render and replacement without doing any diffing? Or is this not really possible?

@SteveSandersonMS
Copy link
Member

@radderz Perhaps it would be best not to get too deep in the details of this one particular scenario here, since this issue is meant to be tracking the whole range of perf-related work.

If you have a specific scenario that you want to optimize, could you please post a new separate issue rather than on this thread, giving an example of the code that you're trying to make faster, and what data you have that suggests that the problem is something specific (e.g., diffing)? Thanks very much!

@Liander
Copy link

Liander commented Jul 7, 2020

@radderz @SteveSandersonMS There is a proposal (with unclear fate...) of having ability to provide control logic when to render at builder-API-level here: #21915 (further comment: #13610 (comment))

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-blazor Includes: Blazor, Razor Components Done This issue has been fixed enhancement This issue represents an ask for new feature or an enhancement to an existing one feature-blazor-wasm This issue is related to and / or impacts Blazor WebAssembly
Projects
None yet
Development

No branches or pull requests

8 participants