microsoft / microsoft-ui-xaml

Windows UI Library: the latest Windows 10 native controls and Fluent styles for your applications
MIT License
6.36k stars 679 forks source link

Discussion: Dependency property is much slower in WinUI 3 than in WPF #1633

Closed Xarlot closed 11 months ago

Xarlot commented 5 years ago

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?

jevansaks commented 5 years ago

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.

Austin-Lamb commented 4 years ago

@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.

Xarlot commented 4 years ago

any news?

stevenbrix commented 4 years ago

@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.

ranjeshj commented 4 years ago

tagging @bartekk8 since this is related to perf.

danzil commented 4 years ago

@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.

Austin-Lamb commented 4 years ago

@stevenbrix - this is about runtime perf rather than build perf, so I'm going to assign it over to @bartekk8

stevenbrix commented 4 years ago

@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

stevenbrix commented 4 years ago

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.

MikeHillberg commented 4 years ago

This in part is likely boxing overhead, the kind of thing that would be helped by using XamlDirect.GetInt32Property rather than DependencyObject.GetValue.

stevenbrix commented 4 years ago

@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.

stevenbrix commented 4 years ago

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

MikeHillberg commented 4 years ago

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.

stevenbrix commented 4 years ago

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.

Xarlot commented 4 years ago

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

ranjeshj commented 4 years ago

Still an issue in Preview bits per linked issue.

BorzillaR commented 3 years ago

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

sjb-sjb commented 3 years ago

Is this getting fixed? Really seems like a killer issue for WinUI 3.

AlexanderEgorov commented 3 years ago

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::

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();
    }
}
jtorjo commented 3 years ago

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?

MrDeej commented 3 years ago

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

nikolayvpavlov commented 2 years ago

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.

pubtom commented 2 years ago

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

gmurray81 commented 2 years ago

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.

gmurray81 commented 2 years ago

Views expressed here are my own, but bear in mind this is the POV of another component vendor person.

sylveon commented 2 years ago

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.

sjb-sjb commented 2 years ago

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?

nikolayvpavlov commented 2 years ago

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.

jtorjo commented 2 years ago

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).

LutzFritsche commented 2 years ago

Please rate this as a high priority performance bug.

nikolayvpavlov commented 2 years ago

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.

hez2010 commented 2 years ago

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
AlexanderEgorov commented 2 years ago

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.

jamers99 commented 1 year ago

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!!

ADD-Eugenio-Lopez commented 1 year ago

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.

SeRgI1982 commented 1 year ago

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."

ADD-Eugenio-Lopez commented 1 year ago

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.

SeRgI1982 commented 1 year ago

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).

ruben2s commented 1 year ago

So, we should stick with WPF for performance? Plus some library to make the app look more modern such as wpfui?

sjb-sjb commented 1 year ago

@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?

zadjii-msft commented 1 year ago

(I'm not actually on the XAML team so don't @ me, but...) I did find the following internal work items tracking this:

(I however don't understand the internals of XAML enough to really be able to parse those threads)