Discussion: Dependency property is much slower in WinUI 3 than in WPF
Xarlot opened this issue Β· 41 comments
Based on my quick test WinUI 3 dependency property nearly 50 times slower than in WPF.
https://github.com/Xarlot/dependencypropertytest
Do you have any plans to improve this behavior?
Great feedback, thanks for calling this out! Closing gaps like this with WPF is certainly a goal. @Austin-Lamb is on the hook to investigate.
@Xarlot - thank you for making such a minimal repro, that is greatly appreciated :) I'm about to go on vacation for Thanksgiving, so I won't be able to get to this until early December, but I'm putting it in my queue and will get back to you.
any news?
@danzil are you aware of the issue of not being able to build Release apps?
@Austin-Lamb are you alright if I take this? I'd be hesitant on doing any further investigation at the moment. Debug builds don't use the .NET Native toolchain, so the better comparison would be to use UWP w/o WinUI and test Release vs Release. However, that might even be a moot point because the current plan of record is to move to .NET5, which has a different interop layer, and we need to be cognizant of the perf implications of that.
I'd also be curious to see what the time is for a c++ app and whether the C++/C# boundary is causing major issues in a test like this.
@stevenbrix Are you referring to the issue that when you target SDK 10.0.17763.0 you get an internal compiler error when building release (this test project targets that SDK and fails to build Release)? I have not seen that error previously, but if you build against a newer SDK like 10.0.18362.0 it works fine.
@stevenbrix - this is about runtime perf rather than build perf, so I'm going to assign it over to @bartekk8
@Austin-Lamb i'm not sure this is runtime perf. in a regular c++ app i'm seeing it's much faster (by about 10x). I'm thinking this might be because of the interop layer, which is something that I'm looking into validating we don't regress with CS/WinRT
I think we may want 2 issues. We are definitely slow, a C++ app is around 400ms, which we can definitely improve on. But a C# app is about 3500-4000ms on my machine, so we need to make sure the interop layer is much more efficient.
This in part is likely boxing overhead, the kind of thing that would be helped by using XamlDirect.GetInt32Property rather than DependencyObject.GetValue.
@MikeHillberg, @AaronRobinsonMSFT looked at this the other day and found that there is a lot of GC overhead that we are causing, most likely due to the high amount of allocations. Hopefully with cs/winrt we can improve this, although unlikely in the WinUI3.0 timeframe.
I've created #2028 so we can track the managed interop layer. We should move any discussion about that there, and let this issue stay related to DependencyObject.SetValue
perf, which was still much worse for native WinUI apps than WPF
You're seeing GC overhead even when using XamlDirect.GetInt32Property instead of GetValue? GetInt32Property is typed so that boxing isn't necessary, which saves a lot of allocations.
You're seeing GC overhead even when using XamlDirect.GetInt32Property instead of GetValue?
No, just with DependencyObject.SetValue
. Let's continue discussion on the other issue, so this can stay focused on DependencyObject.SetValue
perf and not related to interop overhead.
We definitely can use more efficient API. Thanks for the hint.
However, we expect the new framework to be faster and more efficient. What the point of the new framework if it`s slower than 10+ years old predecessor (WPF)? ;)
Looking forward to net core 5 integration
Still an issue in Preview bits per linked issue.
I have updated the project in repo to Preview 3. The performance is still very slow.
My results now the folfowing
Scenario | WPF | WinUI p3 |
---|---|---|
Set 200K times | 42 | 11905 |
Read 200K times | 7 | 1465 |
See updated project here
Is this getting fixed? Really seems like a killer issue for WinUI 3.
What can we expect from the performance of DependencyProperties in WinUI?
We understand that the entire WinUI platform is built as a set of WinRT components, so every platform operation leads to interop.
But, somehow, the TextBlock.Text property works much faster than others.
What is different about TextBlock.Text, and will you be able to optimize other properties to make them as fast as TextBlock.Text? Is there any chance to improve DependencyProperty performance even higher? Can AOT compilation contribute to better DependencyProperty performance?
The following table lists measurements of getting/setting value of DependencyProperties in comparison to WPF (DependencyPropertyTests.zip):
These are not real benchmark tests, so results are approximate
Test | WPF | WinUI |
---|---|---|
Get | 19 ns | 2023 ns |
Set | 135 ns | 4272 ns |
Set (DP with property change handler) | 139 ns | 20431 ns |
Set the same value | 89 ns | 4150 ns |
Set TextBlock.Text | 253 ns | 725 ns |
Set Border.Background | 248 ns | 2412 ns |
We have even tried to test DepenedencyProperties in C++, and yes, the performance of setting Border.Background is two times faster β but anyway itβs not enough.
Why this is important
We (at DevExpress) are working on a set of C# components for WinUI. In the latest release, we minimized amount of Dependency Property changes during virtualized scrolling in our Data Grid. This helped us make the initial loading time and scrolling performance much faster:
Test | DevExpress WinUI Data Grid v21.2 | DevExpress WinUI Data Grid v21.1 | WinUI Community Toolkit Data Grid |
---|---|---|---|
Cold Startup | 1.01 s | 2.49 s | 1.44 s |
Hot Startup | 0.36 s | 1.64 s | 1.24 s |
Vertical Scrolling | 53 fps* | 33 fps* | 14 fps* |
Horizontal Scrolling | 42 fps* | 13 fps* | 7 fps* |
However, the DevExpress WinUI Data Grid still has slower scrolling speed than its WPF counterpart, even though it has significantly less features. An extreme test with 2000 text cells on screen (34 columns and 59 rows) shows that the DevExpress WPF Data Grid is three times more responsive::
- Vertical Scrolling - DevExpress WinUI Data Grid: 4 fps*
- Vertical Scrolling - DevExpress WPF Data Grid: 12 fps*
These results are for text cells without any formatting (remember, the TextBlock.Text property is faster than others). For cells with different backgrounds, or for example, Check Box cells, the difference is even higher and will be noticeable in regular apps.
Any improvements in DependencyProperty performance can help us (and other UI component developers) create controls that are closer to WinForms and WPF in terms of performance (or even surpass them). This will certainly increase the appeal of WinUI as the primary desktop development platform.
*FPS values in above tests are the number of layout cycles per second during scrolling - measured by the following code in both platforms (WinUI and WPF):
public static async Task<string> VerticalScrollingTest() {
... //initializing
double allFramesTime = 0;
int framesCount = 0;
for(int z = 0; z < 20; z++) {
for(int i = 0; i < 10; i++) {
var s = Stopwatch.StartNew();
grid.ScrollDown(80);
await CompositionTargetHelper.WaitRendering();
s.Stop();
allFramesTime += s.Elapsed.TotalSeconds;
framesCount++;
}
for(int i = 0; i < 10; i++) {
var s = Stopwatch.StartNew();
grid.ScrollUp(80);
await CompositionTargetHelper.WaitRendering();
s.Stop();
allFramesTime += s.Elapsed.TotalSeconds;
framesCount++;
}
}
return $"Fps {framesCount / allFramesTime}";
}
class CompositionTargetHelper {
static CompositionTargetHelper() {
CompositionTarget.Rendering += OnRendering;
}
public static Task WaitRendering() {
return task?.Task ?? (task = new TaskCompletionSource()).Task;
}
static TaskCompletionSource task;
static void OnRendering(object sender, object e) {
var t = task;
task = null;
t?.SetResult();
}
}
What can we expect from the performance of DependencyProperties in WinUI?
Wow, awesome write up!
Hey Microsoft, we definitely need faster WinUI3! How can you expect us to move to WinUI3 if it's so slow?
How come it is so hard to build good scrolling in datagrid on an Windows App. If we look towards games and such, the scrolling is always perfect even though it has millions of more objects to appear on the screen.
We have been plagued by this issue for years, and for our need we still have horrible scrolling performance. We have converted this app from WPF to UWP and now to WinUI, more info on this stackoverflow post:
https://stackoverflow.com/questions/50693689/slow-interaction-with-ui-when-not-virtualized-items
What is most worrying is that two years later we still do not have a fix to this problem. Performance is a key advantage to native apps vs. web / Electon ones. Failing to optimize WinUI and Windows App Sdk is a very poor message to developers who need to choose a technology for their next desktop project.
We need to consider modernization of a WPF app. Following the progress of WinUI, I am really unconvinced that WinUI is the right chose.
If you need .NET>5 in UWP please give a vote on this: https://developercommunity.visualstudio.com/t/Add-NET-678-support-to-UWP/1596483
It's things like this that make me wonder if you made a good decision to put the interop layer up at the level of all these winmd components. When it comes down to it, most of your component vendors and customers are going to be writing C# applications, not C++ applications. It's going to wind up being a bad idea to tax their every interaction with the API surface. Did you want this tech to be DOA for C# developers? If you want this to be a feasible tech for customers, you're going to have to reduce the interop tax to extremely low levels OR refocus the WINUI API to be a .NET based API, I would think. Either of those tasks needs to be treated with highest possible priority.
Views expressed here are my own, but bear in mind this is the POV of another component vendor person.
I disagree. Making WinUI .NET-only would once again relegate C++ devs like me to ugly Common Controls-based UI frameworks, or writing my entire UI on my own, or using UWP XAML Islands (which are not a good idea at this point because all the investment is going into WinUI 3). WinUI 3 finally gives us something new after > 20 years. Just because you don't use C++ doesn't mean nobody does.
The interop tax was also much lower when WinRT interop was built-in to .NET, so the .NET team is to blame for removing it in favor of C#/WinRT. The team working on C#/WinRT is continuously working on improvements. Even then, it's most likely not the source of these major performance differences, WinUI 3 itself has performance problems. Making it .NET only would not magically solve these issues.
Can MS start treating this as a bug, please, instead of just a βdiscussionβ? How do we get the labels changed on this problem and get some action on it?
I agree with @sylveon that C++ must not be left out in the cold. I don't care what the solution should be, as long as this grave issue is addressed. Performance and stability are absolute "must-have"s.
I honestly don't care whether this will work for C++ and for WinUI3, what really matters is getting it fixed.
Issues constantly pile up on WinUI3, and it seems a decent version of WinUI3 will never see the light of day.
As many others have said, MS doesn't seem to be invested in this AT ALL, it's just doing it to save face. While, once again, leaving developers guess what's actually happening (if anything is, ever).
Please rate this as a high priority performance bug.
On the latest community call, Microsoft were very unconvincing. Devs first pretended not to understand the question, then half-heartedly admitted that there is an issue with performance and they were to implement different tools to measure it. Really, guys. I felt as if the people we saw were the whole team working on Windows Apps SDK.
Got some new numbers with WASDK 1.1-preview2, it's faster but still far away from WPF.
Test suite 1 mentioned before:
Scenario | WPF | WinUI |
---|---|---|
Set 200K times | 18 | 1148 |
Read 200K times | 8 | 51 |
Test suite 2 mentioned before:
Test | WPF | WinUI |
---|---|---|
Get | 33ns | 275ns |
Set | 102ns | 3440ns |
Set (with handler) | 107ns | 11397ns |
Set (the same value) | 83ns | 3334ns |
Set TextBlock.Text | 199ns | 690ns |
Set Border.Background | 426ns | 1621ns |
Thank you for the update. I conducted more performance tests for dependency properties to compare WinAppSDK 1.0.3 and WinAppSDK 1.1.0-preview2:
Dependency Properties test
Test | WPF | WinAppSDK 1.0.3 | WinAppSDK 1.1.0-preview2 |
---|---|---|---|
Get | 18ns | 984ns | 453ns |
Set | 132ns | 4515ns | 3426ns |
Set (DP with property change handler) | 141ns | 13034ns | 11708ns |
Set the same value | 86ns | 4245ns | 3180ns |
Set TextBlock.Text | 249ns | 859ns | 596ns |
Set Border.Background | 241ns | 2370ns | 1449ns |
RegisterPropertyChangedCallback | 2466ns | 1154ns |
From what I gather, there was a significant improvement in CsWinRT which made interop more effective.
I would also like to share our performance tests with more complex controls, such as the Data Grid. Here are some numbers:
Upcoming DevExpress WinUI Grid 22.1
1000 rows, 50 columns, 21 visible rows, 9 visible columns, text cells without formatting
Test | DXGrid v21.2 | DXGrid v22.1 (WinAppSDK 1.0.3) | DXGrid v22.1 (WinAppSDK 1.1.0-preview2) |
---|---|---|---|
~ Cold Startup | 1.01s | 0.89s | 0.86s |
~ Hot Startup | 0.36s | 0.17s | 0.12s |
Vertical Scrolling | 49fps | 46fps | 49fps |
Horizontal Scrolling | 43fps | 38fps | 41fps |
*FPS in the tests above is the number of layout cycles per second during scrolling. It's not a real FPS, whose max value is 60.
There is a noticeable improvement in hot startup, because the initialization process contains many interop methods that work faster now. We also minimized the visual tree in the new version (v22.1): CellControl and RowControl are now inherited from StackPanel instead of Panel. The StackPanel includes Border functionality, so we removed the Border element from cells and rows.
At first glance, scrolling became a bit slower compared to the previous version (v21.2). However, this occurred because we added new features and restructured our code. In WinAppSDK 1.1.0-preview2, it returned to the previous level. Take a look at our blog post for more optimization techniques: WinUI 3 Performance Boost
All these changes push WinUI to the right direction, but there is still a room for improvement. We look forward to further performance enhancements.
Is there any plans to improve the dependency property performance? Our app is crippling slow at first load of controls with dependency properties. It improves as they get cached or something, but it's still unacceptable. We are coming from UWP and we used dependency properties pretty heavily and our app was quite snappy in UWP.
While we're trying to cut our dependency property usages in WinUI down, I'm not sure we'll be able to get it down to an acceptable level. Please fix this if at all possible!!
The performance issue is very important because when an application has a large number of controls on a form, this time is unacceptable for users.
This problem must be fixed to consider WinUI as a platform on which to develop applications.
I think it's important enough to rethink a functional desktop alternative.
Could someone from Microsoft comment on this discussion?
People invest a lot of time, energy, and above all, money.
After a year and a half of investing in a project written using WinUI, decision-makers are wondering if it was really a good idea.
I bet that discussions like this are happening not only in my project.
As people who have trusted you, we deserve a few words that will calm our nerves.
Concrete details provided in the present, not an indefinite future.
Something like this could give us more than no comments from your side:
"I apologize, guys, we messed up, but we know where the problem lies, and we will work on resolving it by version 1.5"
or
"It's not up to us; it depends on another team that plans to address it in the coming six months, which will make WinUI faster."
Our problems of performance will be solved with the new version of Windows App SDK 1.3.2 (1.3.230602002), specifically with the application initialization and openening new forms. The speed increase has been drastic.
I recommend trying teh new version Windows App SDK 1.3.2.
Our problems of performance will be solved with the new version of Windows App SDK 1.3.2 (1.3.230602002), specifically with the application initialization and openening new forms. The speed increase has been drastic.
I recommend trying teh new version Windows App SDK 1.3.2.
Thank you @ADD-Eugenio-Lopez for the quick response.
Currently, we use ver. 1.3.230502000 and opening a Page with grouped data inside DataGrid takes ages (it is only one example).
So, we should stick with WPF for performance? Plus some library to make the app look more modern such as wpfui?
@MikeHillberg @Austin-Lamb @stevenbrix @BorzillaR where is Microsoft on this issue? Most of the recent comments seem to be from users in the community rather than status updates from Microsoft. Is MS taking action on this?
(I'm not actually on the XAML team so don't @ me, but...) I did find the following internal work items tracking this:
- MSFT:32447326
- MSFT:27845732
- MSFT:29010461
(I however don't understand the internals of XAML enough to really be able to parse those threads)