Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

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

Question: Why is WinUI so slow? #4597

Closed
Noemata opened this issue Mar 20, 2021 · 31 comments
Closed

Question: Why is WinUI so slow? #4597

Noemata opened this issue Mar 20, 2021 · 31 comments

Comments

@Noemata
Copy link

Noemata commented Mar 20, 2021

Based on the tests done here: https://github.com/Noemata/XamlBenchmark

WinUI performance is extremely slow? Why?

@ghost ghost added the needs-triage Issue needs to be triaged by the area owners label Mar 20, 2021
@huoyaoyuan
Copy link

It should be because drawing in C# is doing interop every time. It is slower than pure managed implementation.
Honestly, this isn't the designed usage. I didn't do a serious benchmark, but when resizing a window with complex xaml, WinUI is fast.

@Noemata
Copy link
Author

Noemata commented Mar 21, 2021

@huoyaoyuan , I completely disagree. The performance issues have nothing to do with interop. If WPF outperforms WinUI by a significant margin, there is a big problem given WPF has a very similar interop model.

It's reasonable to expect WinUI to be slower at present because the UWP compositing layer hasn't yet been hoisted out of the OS. It's also likely there are several other optimizations missing at this stage. Overall, progress with WinUI has been OK. I'm more concerned with Microsoft's posture which has consistently challenged the assertions of outsiders, performance being just one example.

In the last two community calls, Microsoft staffers questioned the prospect of performance issues in WinUI. This is either a problematic lack of knowledge, or a serious level of disingenuousness. Neither is acceptable given Microsoft is completely in the drivers seat until the project goes Open Source.

I seriously doubt Microsoft is unaware of the performance issues with WinUI. They have some of the best profiling tech in the industry. So what's the real deal?

UWP can't become another Silverlight fiasco. Such a result would be too costly for all of us, Microsoft included.

@maxkatz6
Copy link
Contributor

given WPF has a very similar interop model

WPF works in managed world with rendering-layer interop (DirectX). There also might be some optimizations to minimize calls to the interop code.
WinUI is completely unmanaged, and you need to use interop for anything. CsWinRT can optimize it as much as possible, but it unlikely be as fast as managed only or unmanaged only code.

It's reasonable to expect WinUI to be slower at present because the UWP compositing layer hasn't yet been hoisted out of the OS.

It's reasonable to expect WinUI to be slower because of missing AOT compilation, that was the biggest reason of good enough performance in UWP. .NET Native is discontinued and alternative in .NET world wasn't released yet (NativeAOT probably will be one). .NET compilation side is not controlled by WinUI team.

I wonder if you actually can try to use WinUI 3 with UWP and .NET Native enabled. It might show interesting results, probably even comparable with UWP results.

@Noemata
Copy link
Author

Noemata commented Mar 22, 2021

I've added a results section to the repo: https://github.com/Noemata/XamlBenchmark

It really doesn't matter how anyone tries to spin these results. It won't fly for WinUI in its current "Preview" state.

@maxkatz6 , I respectfully disagree. Especially the "completely unmanaged" part of your statement???

Any decent rendering system does batching and pruning. Even a purely managed graphics layer can be made to render complex graphics with great speed. Just look at the pre IL2CPP versions of Unity for what's possible. The DirectX rendering layer is asynchronous to the C# side, so you can pull all kinds of batching tricks there.

You can even monitor the display list independent of the app code and tune for specific types of changes during the render pass.

@StephenLPeters StephenLPeters added area-Performance product-winui3 WinUI 3 issues and removed needs-triage Issue needs to be triaged by the area owners labels Mar 23, 2021
@StephenLPeters
Copy link
Contributor

@bartekk8 and @Austin-Lamb FYI

@Noemata
Copy link
Author

Noemata commented Mar 31, 2021

@StephenLPeters , @bartekk8 , @Austin-Lamb , any word on this? Performance hasn't changed with the GA release of WinUI. There is at least a 3x performance gap between WPF and UWP at present. Would be nice to get some sort of statement since this question has been asked in the community calls over the last couple months without any sort of reply.

Is the final release of WinUI expected to be roughly on par with UWP? Or will the final version of WinUI be 2x or more slower? Regardless of other capability/compatibility considerations, the memory and performance footprint will ultimately be major adoption considerations.

@asierpn
Copy link

asierpn commented Mar 31, 2021

We are also very concerned about performance issues of UWP, we are waiting for a long time the final realease of WinUI 3 hoping that these issues will be solved, but reading this it is not clear that it will happen. We have important performance issues in our LOB UWP app and migrating the app to WPF is a huge work that we can not assume.

There is a lot of feedback about these issues reported, here are a few samples:
#1517
#1633
#2028
#2032
#2707
https://stackoverflow.com/questions/49831807/do-all-uwp-apps-leak-memory-when-navigating-pages

@Noemata
Copy link
Author

Noemata commented Mar 31, 2021

@asierpn , it's looking like CsWinRT may be the achilles heel of WinUI. It seemed like a really bad idea from the get go. Hopefully, UWP won't get crippled because of the rejigging being done to accommodate WinUI at the OS level. WinUI is eating up a lot of resources that could have significantly moved UWP forward and it looks like hard design choices will soon need to be faced by Microsoft regarding WinUI.

It would have been far far easier to open up the Win32 API to UWP than the course Microsoft is on with WinUI. My two cents worth.

@asierpn
Copy link

asierpn commented Mar 31, 2021

@Noemata I am totally agree with you, UWP has more than 5 years at its shoulders and we have not seen any performance improvement in the last years, our last hope was WinUI 3, but at this moment we still don't see any improvement with the new library. There is a lot of good Microsoft employees working on this project now and they should be concerned about these issues and address them quickly, and if the solution to the performance issues requires to change completely the core of the UWP technology they should do it.

We need a way to migrate our current UWP apps to a performant framework without rewritting completly our apps.

@Noemata
Copy link
Author

Noemata commented Mar 31, 2021

@asierpn , UWP is very performant. It's hard to beat, in fact. I looked at your issues. They all have nice resolutions under UWP. Unfortunately, there is a black art around some of this. I looked at your sample app. You can fix the issues there with this.NavigationCacheMode = NavigationCacheMode.Enabled;

The docs are confusing around this. I don't understand why the Required flag doesn't work. One further consideration. Debug and Release builds behave differently. Performance and memory use is very good for a UWP Release build.

@asierpn
Copy link

asierpn commented Mar 31, 2021

@Noemata We use this.NavigationCacheMode = NavigationCacheMode.Enabled but it doesn't help, try this repro project
App1.zip, If you click the button in the right upper corner quickly and repeatedly you will freeze the app in a few seconds.

The same issue happens in Debug and Release (.NET Native).

I have reproduced the issue with the official Windows Community Toolkit Sample App navigating repeatedly to the Controls > DataGrid page, the memory used by the app grows and on my computer when it reaches 300 Mb it freezes.

Same happens with the XAML Controls Gallery app, I've opened every page several times, from start to the end, and the collection sample pages several times each one, after some time the UI starts freezing, very noticeable with the NavigationView, TabView or WebView sample pages, finally the app crashed.

@Noemata
Copy link
Author

Noemata commented Mar 31, 2021

@asierpn , I'll have to apologize, there are a few issues here. There is indeed a memory expansion problem happening to navigation. I was looking at the wrong process when I was looking at memory use. I had a few too many things on the go at the time I was looking at this.

That said, I did not have the problem you are seeing, but I was being well behaved. To clarify, I did let your data pages complete loading. I assumed your async loader method was written as is for expediency, and not for correctness. If you let your data pages completely load before navigating away, you will discover that you can navigate thousands of times before running into a memory stress situation.

That said, there is indeed a leak. I've revised your sample a bit further to make the navigation part correct in terms of how it is consuming memory.

App1.zip

If you run this version as is, provided you let your data pages fully load, you will not experience a hang. However, if you rapidly start navigation around without letting your data pages fully load, the app hangs. The code for managing data loading is not correct. void async methods lead to all sorts of grief.

So there are two concerns with your sample. One surfaces a legitimate memory growth issue. The other is due to a coding flaw.

I didn't correct the latter in the sample I just provided. If you block navigation during the data load cycle, your core problem will go away. That's just one way to fix that issue. Microsoft needs to have a look at the other leaking memory problem.

@Noemata
Copy link
Author

Noemata commented Mar 31, 2021

@asierpn , here's a more correct version of your sample:

App1.zip

I didn't bother with minimizing code duplication. The essential bit is the awaitable call during initialization.

@bartekk8
Copy link
Contributor

@Noemata How are you executing your benchmark? I tried running it (full-screen, without making any changes) with Reunion 0.5, release / x64 and results are WPF = 20.0s and WinUI = 29.1s. This is slower, but not to the degree you observed and documented in your project's description.

@Noemata
Copy link
Author

Noemata commented Mar 31, 2021

@bartekk8 , are you sure you were running the WinUI project. From the sounds of it, you were comparing against the UWP project. Make sure you've selected the correct startup project. The UWP run cycle is about what you are getting. WinUI is way slower.

image

@Noemata
Copy link
Author

Noemata commented Mar 31, 2021

@bartekk8 , please show the following screenshots:

WPF

wpf

UWP

UWP

WinUI

WinUI

@asierpn
Copy link

asierpn commented Apr 1, 2021

@Noemata Thanks for the updated sample, you are correct that the original sample was using the UI thread to load data and this is not optimal. Your workarround of disabling navigation during the page data loading can reduce the issue, and I will try it in our production app, but it worses the usability forcing user to wait if he wants to navigate to another page.

Unfortunately navigation issues is only a part of the problem, we also have issues staying on the same page and loading/unloading some complex XAML controls to keep a low number of items in our visual tree.

@Noemata
Copy link
Author

Noemata commented Apr 1, 2021

@asierpn , you did uncover a bug. I used your sample to file the issue here: #4713

Honestly, I thought this had been fixed.

As for navigation slow down, other than the initial hit on load, I think performance is snappy. I don't know what your application looks like, you can have a look here: https://github.com/Noemata/FakePOS

For ideas on how to minimize performance issues by leveraging the ShellView / ShellViewModel.

I stuff anything I want to be performant in my ShellViewModel, that way it's always there. You can also "fool" the user by using lazy load strategies giving the user only what they need to see.

Microsoft's LOB sample was a very good start. The changes made in FakePOS take some requisite design changes across the finish line. There's still room for improvement. I hacked through this somewhat quickly.

@Noemata
Copy link
Author

Noemata commented Apr 1, 2021

@asierpn , fortunately I was in the mood for a good April's fools joke today.

Here it is twice over, only it's not funny in your case: #4718 #4713

@bartekk8
Copy link
Contributor

bartekk8 commented Apr 2, 2021

@Noemata on one machine, the results are as I mentioned before:

gh-wpf

gh-winui

On my laptop, WinUI is worse, but still not as bad as your results:

gh-wpf2

gh-winui2

Let me dig into it to see why there's such a difference.

@Noemata
Copy link
Author

Noemata commented Apr 2, 2021

@bartekk8 , interesting. I can't explain the difference. I'm surprised your WPF times are slower than what I'm getting (desktop), yet WinUI is much faster on your setup. Initially I was worried that my quick tweaks to the project might be the issue, but since you're running with my project files, that can't be the case. Your setup is somehow faster by double for WinUI, and about 10% slower for WPF.

Did I grab the Nuget packages too early perhaps, and there was a behind the scenes tweak?

@Noemata
Copy link
Author

Noemata commented Apr 2, 2021

@bartekk8 , tried three different systems. Some with NVidia GPUs some with Intel. Very similar results to what I posted. The only difference, on my fastest system, UWP produced the fastest time compared to all others. I guess we need more people to chime in with their results to get a better picture.

For Microsoft staffers that may be looking, the posted results are from a Surface Book 2. So it's Microsoft all the way ...

@Noemata
Copy link
Author

Noemata commented Apr 2, 2021

Mystery solved ... you are right @bartekk8 , I was running the tests from Visual Studio. Looks like being attached to VS is bad for WinUI.

To remove the GPU side of things, here are the results running from a 4K RDP session on a very fast CPU and network.

UWP 18737
WPF 24933
WinUI 33290

What can I say, I made a bonehead move. Helps to have the input of others. Thank you. Will revise my posted results.

Results running against actual hardware have been updated: https://github.com/Noemata/XamlBenchmark

Fortunately, UWP and WinUI had a proportionally similar performance dip when attached to VS, so WinUI is still 3 times slower ... compared to UWP.

@bartekk8
Copy link
Contributor

bartekk8 commented Apr 5, 2021

@Noemata I'm glad we figured it out. I started looking at why there is such a difference between UWP and WinUI and so far I opened this. Thanks for your help finding these scenarios!

@Noemata
Copy link
Author

Noemata commented Apr 5, 2021

This issue has gotten a little overloaded, but that turned out to be a good thing. Because of @bartekk8's input, I noticed that Visual Studio 2019 contributes negatively to both performance and memory handling. It seems to contribute its own memory leak in certain scenarios.

For anyone arriving here, the TabView leak mentioned above does not exist when NavigationCacheMode="Enabled" provided you are running outside of VS2019, though it appears to be present when the flag is set to "Disabled". Would be helpful if others could have a look at the code below in case I got something wrong.

VS2019 also slows down navigation dramatically when running under debug. That's to be expected given how it wires into the app. Does anyone know how to disable this effect?

Here's a revised version of the TabView test code (run it outside of VS):

TabView1.zip

@bartekk8
Copy link
Contributor

@Noemata Regarding the VS issue, I think the reason you were seeing worse performance when debugger is attached to WinUI app is because of this code in NativeDrawLine method:

            try
            {
                element.StrokeDashArray = CurrentState.XamlDashArray;
            }
            catch (Exception exc)
            {
                Logger.Debug(exc);
            }

Throwing exception will cause a message to be written to Debug Output, which is very slow and will slow down execution of your benchmark (try commenting this code out). I also noticed a small improvement in execution time when I run it commented out in Release mode (exceptions are not free...).

@Noemata
Copy link
Author

Noemata commented Apr 15, 2021

@bartekk8 , that is indeed the case. However, I did revise my benchmarks after running the series without VS in the mix. WinUI was still significantly slower than UWP. I was generous in stating it was 3 times slower. I excluded any benchmarks that were obviously affected by memory leaks. I also excluded benchmarks that highlighted compute related tasks, since UWP has a clear advantage there.

For a taste of what a real world experience might look like for a user, run some of these as a release build without VS in the mix: https://github.com/Noemata/RosettaNavigation

Because of memory leaks, these apps progressively slow down, first becoming unusable and eventually crashing. I realize I am throttling the apps, but that's the point. Under load, presently, WinUI breaks. Given it's a v 0.5 designation release, I would be Ok with such issues except that there has been posturing on the part of key Microsoft staffers like Kevin Gallo that the current release may be used in production. Perhaps if you have a 128 GB system with multiple CPUs and GPUs, like he has for development, you can run WinUI all day without crashing. In the real world, WinUI turns out to be far more fragile at present.

Obviously, a lot of these issues will be sorted out. I worry that Microsoft is being way too premature with some of its messaging. It's perfectly acceptable to have "prerelease" problems. If it's dubbed as a "production grade" release, expectations are legitimately very high. Microsoft Betas used to be much better than this. Some old school thinking needs to be brought back.

@KenionX
Copy link

KenionX commented Aug 1, 2021

Ony my machine I reach 8000 ms ~ on WPF and UWP
WinUi takes 46000ms~

@JamesLear92
Copy link

When not debugging, I'm getting ~11250ms for WPF, and ~18500ms for SKD 1.0 Preview 3.
That's pretty sad to see considering that WPF was already so much slower than Winforms.

I also notice a very worrying quirk of WinUI. You can see the CPU on the UI thread is very high when moving your mouse quickly over the UI.

@lukeblevins
Copy link
Contributor

lukeblevins commented Dec 18, 2021

When running this rather synthetic benchmark again, but updated to the Windows App SDK v0.8.6, the measured performance gap from UWP improves by ~20%. Keep it coming!

FYI @StephenLPeters

@Mohsens22
Copy link

Mohsens22 commented Dec 29, 2021

https://github.com/mohsens22/XamlBenchmark/

I have updated the projects to the latest .NET and WinUI version (also updating MAUI bits) and the performance is promising!

( UWP .NET Native) Elapsed: 10004 ms, Passes: 1200
( WPF .NET 6 Ready to Run ) Elapsed: 10164 ms, Passes: 1200
( WinUI 1.0 .NET 6 ) Elapsed: 13530 ms, Passes: 1200

@microsoft microsoft locked and limited conversation to collaborators Jun 30, 2023
@bpulliam bpulliam converted this issue into discussion #8595 Jun 30, 2023

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Projects
None yet
Development

No branches or pull requests