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

Discussion: WinUI 3.0 and XAML Performance #1517

Closed
mdtauk opened this issue Oct 31, 2019 · 32 comments
Closed

Discussion: WinUI 3.0 and XAML Performance #1517

mdtauk opened this issue Oct 31, 2019 · 32 comments
Labels

Comments

@mdtauk
Copy link
Contributor

mdtauk commented Oct 31, 2019

Discussion: WinUI 3.0 and XAML Performance

During the WinUI community call, there was a comment about improvements coming to the performance of XAML Rendering with WinUI 3.0

I thought I would start a discussion thread where people could collate performance quirks they have come up against, but for my own view, I would just like to ask if the team working on it, could write up some blog posts talking about what improvements are being made, along with the Alpha release, as well as how the process extracting the stack from the OS, enables ongoing improvements in the future.

@mdtauk mdtauk added the discussion General discussion label Oct 31, 2019
@salmanmkc
Copy link
Contributor

This may be completely irrelevant, but retargeting the SDK takes forever for the XAML UI project, this may be a performance issue for VS itself though, not sure where it lies. I had my reasons for retargeting, I know it may sound really weird.

@jtorjo
Copy link

jtorjo commented Nov 1, 2019

Here are my performance issues, when it comes to UWP:

  1. uwp: compilation times are insanely slow! (pretty much, 6 times slower that WPF - i'm using target version build 1809 - build 17783)
  2. I know StorageFolder file enumeration API is not part of UWP, but that is insanely slow. The UWP sandbox (at least on Windows Desktop) is hurting more than helping.
  3. async programming is fun, but in UWP, when an exception happens, it's somehow eaten by the UWP code, and then later break in debugger, with all the stack context lost. Sometimes, I do have the stack context inside the thrown exception itself, but not always.
  4. Profiling UWP code is close to impossible. Event dotTrace instantly breaks when trying to do it.

@charlesroddie
Copy link

charlesroddie commented Nov 1, 2019

Please don't use XAML ambiguously in discussions. "XAML Performance" could refer to the parsing of XAML files or it could refer to the performance of the WinUI framework. My guess is that this thread is about the latter.

On UWP performance, this is very good at the moment in release mode using .Net Native. I expect that with .Net 5 it will be similarly fast using AOT. I am concerned that in the meantime with .Net Core 3.0 it will become slow again. It would be great if UWP with .Net Core 3.0 would work with CoreRT which is very similar to .Net Native.

@jtorjo
Copy link

jtorjo commented Nov 1, 2019

@charlesroddie Your comment is about the initial discussion, or my comment?

@charlesroddie
Copy link

About the initial post and title, but applies to a lot of threads in this repo.

@lukasf
Copy link

lukasf commented Nov 2, 2019

@jtorjo

Here are my performance issues, when it comes to UWP:

  1. uwp: compilation times are insanely slow! (pretty much, 6 times slower that WPF - i'm using target version build 1809 - build 17783)

I guess you are talking about Release build times right? The Release build is so slow because of .NET Native. It makes build times much slower, but gives you major improvements in startup times, XAML rendering (data binding) and memory usage. In Debug mode, apps should usually build pretty fast, so this does not really affect development cycles that much IMO. At least, I usually only build Release every now and then, so for me this is not a problem (I am a big fan of .NET Native performance gains).

  1. I know StorageFolder file enumeration API is not part of UWP, but that is insanely slow. The UWP sandbox (at least on Windows Desktop) is hurting more than helping.

I agree that StorageFolder/StorageFile API is a major painpoint for any file driven application. I don't believe that this is caused by sandboxing, it is probably more a problem of how the API is designed. Every instance contains these properties: Attributes, DateCreated, DisplayName, DisplayType. In the old FileInfo API, these would only be retrieved on-demand on first access. But in UWP all of these properties are always retrieved as soon as an instance is created, which makes the API so much slower when you enumerate large folders. It works well if you only access files every now and then (like, open one file through file dialog). But apps that work with a lot of files and folders will have major performance hits due to the bad API design.

UWP really needs a fast, light-weight file API that pretty much only wraps the file name (and maybe some file permission token). Then there should be an async method to create the "fat" StorageFile/StorageFolder instances from it, or open streams directly, on demand.

  1. async programming is fun, but in UWP, when an exception happens, it's somehow eaten by the UWP code, and then later break in debugger, with all the stack context lost. Sometimes, I do have the stack context inside the thrown exception itself, but not always.

I have seen things like this, but I don't think that async is really the cause of these problems. Normally, exceptions from async code are handled very well. The bigger problem might be that you usually don't see any call stack from native platform code, so if the platform calls back into user code and things fail there, you sometimes don't even know why or how things have failed, where in WPF you would always see a clear stack trace of how your code was invoked.

  1. Profiling UWP code is close to impossible. Event dotTrace instantly breaks when trying to do it.

Did you try with VS performance tools? They work very well for me.

@jtorjo
Copy link

jtorjo commented Nov 2, 2019

@lukasf Thanks for replying!

I guess you are talking about Release build times right? The Release build is so slow because of .NET Native.

I'm talking about Debug times, without .Net Native. For me .Net Native generated a weird crash a while ago, and I haven't tested it since. My project in Debug x86 (it is slightly faster than Debug x64), usually takes 30-40 seconds to compile.

Once again, this is build 17783 - I have read on the internet that lower builds generate faster time - I think it's on your uservoice forum.

I agree that StorageFolder/StorageFile API is a major painpoint for any file driven application. ....UWP really needs a fast, light-weight file API that pretty much only wraps the file name (and maybe some file permission token).

I couldn't agree more. Or, much simpler maybe - just allow access to System.IO for all HDD ;) That would simplify things a lot.

My app displays photos/videos from user's folders, making it easy for him/her to select his favorites to edit them to create another video - in WPF, this fast simply insanely fast. In UWP, this is beyond slow.

... so if the platform calls back into user code and things fail there, you sometimes don't even know why or how things have failed, where in WPF you would always see a clear stack trace of how your code was invoked.

It is possible that this is the issue, but it does make debugging a huge pain...

Did you try with VS performance tools? They work very well for me.

I will definitely try them. I used dotTrace a low with WPF, and isolated errors insanely fast. Will definitely try the VS performance tools - just read an article about them, seems they should fit my needs.

@asierpn
Copy link

asierpn commented Nov 2, 2019

In our case we are using UWP for a LOB app and we have found big performance issues in two common scenarios:

  1. We need to put a lot of data in some views, so we use use datagrid inside pivot or tab controls, this generates big visual trees of more than 5000 items which are hard to reduce more. The first load of the visual tree or when you switch from one tab to another is not smooth.

  2. Something similar happens with frame cache, we have it enabled so the state of our list views is keeped when you return from it's associated form, but if the page cached has a big visual tree the navigation when you go back is not smooth and hangs for a while. Moreover we notice a performance degradation when using the frame cache and you have navigated to a big number of views.

Things come worse in this scenarios if you don't have a powerfull machine or any other windows process is requiring CPU, most of our users are using i5 or i3 with 8Gb of RAM and the performance with this hardware is very bad, there is continuous hangs of several seconds on this environments

Here is a sample project which try to show this two issues:
App1.zip

@lukasf
Copy link

lukasf commented Nov 2, 2019

@jtorjo
The problem is that FileInfo APIs do not work well with permissions and sandboxing. If you can just create an instance from a file path, the system cannot know if/how you got access to that file. So I think a new file API is required, but one that is optimized for performance. One that does not query lots of data, when all you need is the plain folder+file names.

If you want good file performance, there is one thing you should be aware of: Enumerating files usually involves lots of async calls. Every single "await" on the UI thread is very slow and will cost you about 10ms. This is just the "await", with no actual work being done. So for bigger file operations, it is highly recommended to not await every single async call on the UI thread. You can do that by adding ConfigureAwait(false) on every async method call, or by running the whole file IO stuff on a background thread. I use the latter, since it is easier to implement:

// read files on background thread and await result only once on UI thread
var files = await Task.Run(() => ScanFilesAsync());

// now work with files on UI thread
ShowFiles(files)

Now all the countless await calls inside ReadFilesAsync will not be awaited on the UI thread but on the background thread (which is very fast). Only the final result is awaited once on the UI thread, and then it can be used on UI tread and for data binding. Be careful to not access UI stuff in ScanFilesAsync().

The same concept is useful for other complex file or stream operations, like reading or writing stuff in a loop, where you have lots of await calls. Put that in a background task or use ConfigureAwait(false) and you will have much better performance, close to classic .NET APIs.

@jtorjo
Copy link

jtorjo commented Nov 2, 2019

@lukasf Thanks for the advice. I wish that were true. That was also my idea - to just do it in another thread. But in my tests, the gain is close to 0%.

About a new file API is required: I just don't understand why MS won't simply allow System.IO over all HDD, once you've requested broadSystemAccess. It's clearly possible, since if I write a Desktop Bridge app, I can use System.IO all over the place, and it's fast as hell.

Best,
John

@dbeavon
Copy link

dbeavon commented Nov 4, 2019

uwp: compilation times are insanely slow! (pretty much, 6 times slower that WPF - i'm using target version build 1809 - build 17783)

I agree. I started to reply, but decided it makes sense to take this to another discussion (specifically related to compilation performance):

Related links.

@stevenbrix
Copy link
Contributor

I couldn't agree more. Or, much simpler maybe - just allow access to System.IO for all HDD ;) That would simplify things a lot.

@jtoro I have heard this from customers that this would be preferable (and I have to agree). I think the appropriate place to have this discussion is in the xlang project, and I opened this issue a while back for this exact issue https://github.com/microsoft/xlang/issues/484. Please go comment/upvote if you'd like to see that 😄

@jevansaks jevansaks added the team-Controls Issue for the Controls team label Nov 7, 2019
@msft-github-bot msft-github-bot added the needs-triage Issue needs to be triaged by the area owners label Nov 7, 2019
@jevansaks jevansaks removed needs-triage Issue needs to be triaged by the area owners team-Controls Issue for the Controls team labels Nov 7, 2019
@msft-github-bot msft-github-bot added the needs-triage Issue needs to be triaged by the area owners label Nov 8, 2019
@jevansaks jevansaks removed the needs-triage Issue needs to be triaged by the area owners label Nov 11, 2019
@asierpn
Copy link

asierpn commented Nov 21, 2019

nobody talks about navigation performance of cached pages with a large visual tree? Why a cached page needs so much time to be rendered again? For us this is more important than shadows, lights, or rounded corners... @jevansaks you pointed me to start a discussion here, but I don't see any interest in improving performance, and I think there is a lot of work to be done in this area.

@zenjia
Copy link

zenjia commented Feb 26, 2020

Just as as jtorjo mentioned, the compiling of UWP/C# projects is many times slower than WPF(even in release mode and the .NET Native checkbox is unchecked), which is very frustrating for me. Hope WinUi can change this.

@ranjeshj
Copy link
Contributor

@danzil @fabiant3-zz - FYI for compiler/tooling performance. @bartekk8 @Austin-Lamb - FYI for runtime performance.

Looks like there is another discussion on compiler performance here.

@asierpn If you have a specific scenario (navigation) that is not performant, can you please open an issue with a repro so it can be investigated independenty ?

@danzil
Copy link

danzil commented Feb 26, 2020

We're well aware that UWP/WinUI project compile performance, including full and incremental builds, can be way better and we're taking steps to make it so. Issue #1535 that Ranjesh mentioned tracks that.

@asierpn
Copy link

asierpn commented Feb 26, 2020

@ranjesh I've opened the issue #2032 explaining better our scenario and with a sample app.

@jtorjo
Copy link

jtorjo commented Feb 26, 2020

@danzil As an FYI, the more recent of a Windows version you're targeting, the worse the compile time.

Right now, I'm targeting 1903, and just the deployment itself takes 6+ seconds! (no building at all). On 1809, deploment was less than 1 second.

Here are a few other notes:

  • if I have a project, say edit_ui, and another project depends on it, say test_ui. If I modify anything in the xaml part of edit_ui, I will need to recompile test_ui, or otherwise, I can get exceptions (if I modify something in the implementation, that is not needed). In my mind, this should not happen.
  • sometimes some projects get recompiled even if I haven't done anything (can't repro consistently)
  • compilation times are very very slow, and I don't see anything as "incremental build". In other words, my main UI project takes roughly 10-15 seconds to compile. If I modify basically nothing (I just type an Enter, in a .cs class file), it will take the same amount of time.
  • I don't understand why xaml files get recompiled even if I haven't touched them

@danzil
Copy link

danzil commented Feb 26, 2020

@jtorjo thanks for adding your experience! We've got all these issues in mind as we're designing the upcoming performance improvements in XAML compilation.

@jtorjo
Copy link

jtorjo commented Feb 26, 2020

@danzil Cool! Trust me, I'm more than looking forward to any improvements you guys may have. Probably on a daily basis, I'm wasting at least 45 minutest just compiling/deploying stuff.

@jtorjo
Copy link

jtorjo commented Mar 16, 2020

@danzil Any ETA on this? Compile times are simply insane...

Me, and I'm sure anyone doing UWP, would love anything -- like, gradual improvements! And we'd be the first to test them. Thanks!

@danzil
Copy link

danzil commented Mar 16, 2020

I totally understand it's painful and I'm sorry I can't give you better news. Right now, my understanding is that it will likely take several more months before the team could start working on an implementation for this problem. @LucasHaines may be able to help with a more precise ETA or plan.

@jtorjo
Copy link

jtorjo commented Mar 16, 2020

@LucasHaines Could you please share an ETA? Thanks!

@Noemata
Copy link

Noemata commented Mar 31, 2021

@danzil, @stevenbrix, as noted here: https://github.com/Noemata/XamlBenchmark

UWP has slipped behind WPF in rendering performance. I didn't think that was possible?? Clearly, a lot can be done to improve performance. Why is WPF now faster? Why have we not seen any performance gains in UWP of late? Why is WinUI so very slow?

Despite the .Net Native compiler being slow, I'm still a big fan. With a rational code segregation scheme when designing a larger app, it's possible to greatly diminish the pain of a rebuild for release. So for those experiencing lengthy rebuilds, you probably need a better understanding of your apps dependency tree in order to fix your rebuild issue. .Net Native is surprisingly good at this stage.

Everything but UI should live in .Net Standard libs. Take a look here for how this helps: https://github.com/Noemata/FakePOS

@jtorjo
Copy link

jtorjo commented Mar 31, 2021

UWP has slipped behind WPF in rendering performance.

I second that. When I upgraded to the lasted WinUI 2.5, my app started 8 times slower! (compiled 3 times slower)

I simply had to revert to WinUI 2.3 to make this bearable again.

@charlesroddie
Copy link

Very useful benchmarks @Noemata

Why is WPF now faster?

Your WPF is dotnet5 non-AOT while UWP is netnative (AOT based on netframework), and netframework -> dotnet5 gives more of a performance boost than non-AOT -> AOT. Ideally we would have dotnet5 + AOT.

@Noemata
Copy link

Noemata commented Apr 1, 2021

@charlesroddie , WPF's performance gains are quite impressive indeed. I opted to remove one part out of the benchmark, and that's raw compute, since it's not a fair comparison. .Net Native still outpaces .Net 5.x when compiled for release. So the performance picture is more complicated than can be gleaned by looking at the surface details. Not sure what all the tweaks consisted of (jitter, libs, etc.), but .Net 5.x + WPF is more than the sum of its parts. It's also quite impressive how the .Net team managed to maintain stability throughout the different releases.

Given that most of the benchmark is happening at the rendering layer which is mostly driven by machine code (shoud be seeing way more GPU activity), I would expect UWP to be fastest. Clearly, UWP has not gotten as much attention lately. The .Net Native compiler has received some needed tweaks of late and is looking pretty good. It's not flawed as much as it is limited to constraints that require careful design choices when using reflection. It's a shame it's not being progressed further.

Fingers crossed that WinUI will some day reach WPF+.Net 5 level of stability. Microsoft will need to re-invest in UWP. At least until they come up with a better alternative to CsWinRT.

@Noemata
Copy link

Noemata commented Apr 7, 2021

It's a bit embarrassing, but I got the tests results for WinUI and UWP wrong. I won't make any excuses, should have known better than to do all my testing inside the debugger. VS2019 has a significant performance drag on both UWP and WinUI (about the same for both). When running outside of VS2019, UWP is still fastest. About 3 times faster than WinUI. WinUI's numbers are a lot better, but still sluggish compared to UWP. WPF perf is respectable nonetheless. I've revised my posted results.

@ranjeshj
Copy link
Contributor

ranjeshj commented Apr 7, 2021

UWP has slipped behind WPF in rendering performance.

I second that. When I upgraded to the lasted WinUI 2.5, my app started 8 times slower! (compiled 3 times slower)

I simply had to revert to WinUI 2.3 to make this bearable again.

@jtorjo could you collect some traces for your case in both 2.3 and 2.5 ?

Here are the instructions.

  1. Install ADK. You only need Windows Performance Toolkit option to be selected.
  2. Execute wprui.exe (Windows Performance Recorder UI).
  3. Click on More options to reveal recording profiles and then select the following:
    • For CPU trace:
      • First level triage
      • CPU usage
      • Disk I/O activity
      • XAML activity
    • For memory usage trace:
      • First level triage
      • Heap usage
      • VirtualAlloc usage
      • Reference Set analysis
      • XAML activity
  4. Click on Start.
  5. Run your scenario.
  6. Click Save and follow the prompts. If you'd like to look at the trace right away, after it's saved click on Open in WPA.
  7. WPA is a great tool for analyzing traces. For intro on how to use it take a look here.

@bartekk8 as FYI.

@Noemata
Copy link

Noemata commented Apr 7, 2021

@ranjeshj , thanks for the info. What I was looking for was an apples to apples performance comparison to see how WinUI fairs when compared to UWP. Performance tooling can be used to evaluate perf, but first you need a well constructed test scenario that touches the areas of interest in a way that doesn't skew results. Initially, I was only looking to evaluate basic XAML rendering times for WPF/UWP/WinUI; XAML primitives only. I'll leave it to experts like yourself to do the nuanced analysis. I'm only looking for big picture real world applicable results.

Here's another example of a tool I put together to do LOB related sorts of testing: https://github.com/Noemata/RosettaNavigation

I'm more interested in the performance/validation suites Microsoft uses. I find those more telling because I can see the API surface being traversed during the test. API interactions are often quite surprising.

@jtorjo
Copy link

jtorjo commented Apr 8, 2021

@ranjeshj Yes, will do, but it will be a good few days before I can do that. I'm already behind everything on launching my app. As soon as I have a few hours, I'll do it.

As a side note, the first thing I wanted to do was to do some profiling, but I ran into the other Windows bug (https://developercommunity.visualstudio.com/t/No-Data-in-CPU-Usage-Tool-Windows-Updat/1384519). I lost several hours getting my system back into a decent state, I got insanely nervous and reverted everything.

So, I will do this ASAP, since I clearly want this fixed -- for me upgrading with these performance drops is simply out of the question.

UWP has slipped behind WPF in rendering performance.

I second that. When I upgraded to the lasted WinUI 2.5, my app started 8 times slower! (compiled 3 times slower)
I simply had to revert to WinUI 2.3 to make this bearable again.

@jtorjo could you collect some traces for your case in both 2.3 and 2.5 ?

@github-actions
Copy link

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 5 days.

@github-actions github-actions bot closed this as not planned Won't fix, can't repro, duplicate, stale Aug 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests