Improves performance on BindableProperty#17756
Improves performance on BindableProperty#17756StephaneDelcroix merged 18 commits intodotnet:net9.0from
Conversation
|
Hey there @albyrock87! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
9e5afa6 to
d2403e5
Compare
d2403e5 to
31647c9
Compare
31647c9 to
eb29423
Compare
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
66717b7 to
9a5ed3a
Compare
|
@StephaneDelcroix @jonathanpeppers I've updated PR with some more improvements on the binding part and a general cleanup + documentation on the |
jonathanpeppers
left a comment
There was a problem hiding this comment.
I think we need some review from @StephaneDelcroix about the general idea of packing into a ulong.
| #if NETSTANDARD | ||
| return Keys[index]; | ||
| #else | ||
| return GetKeyAtIndex(index); |
There was a problem hiding this comment.
Do you have an idea how much time is spent now in GetKeyAtIndex()?
I was using dotnet-trace on this app: https://github.com/jonathanpeppers/lols
There was a problem hiding this comment.
The same time required to access a TKey[] array index, so it shouldn't be a concern.
https://github.com/dotnet/runtime/blob/main/src/libraries/System.Collections/src/System/Collections/Generic/SortedList.cs#L561-L566
On the opposite side, in NETSTANDARD that Keys[index] has some overhead because it creates a wrapper object to access keys as an IList<TKey> which we could solve via reflection considering that those private properties cannot change due to serialization matters.
public class SortedList<TKey, TValue> :
IDictionary<TKey, TValue>, IDictionary, IReadOnlyDictionary<TKey, TValue> where TKey : notnull
{
private TKey[] keys; // Do not rename (binary serialization)
private TValue[] values; // Do not rename (binary serialization)Anyway I think that with MAUI the goal is always to use the latest target framework available, so I think the current implementation is acceptable.
There was a problem hiding this comment.
.NET Standard is not really a supported platform and is just used by the Visual Studio IDE for the analyzers and/or compilers. All other systems should be using the netX.0 TFMs.
There was a problem hiding this comment.
Do you have an idea how much time is spent now in GetKeyAtIndex()?
The reason I ask, is because SortedList usage shows up quite a bit in dotnet-trace for me in the past. Before #17527, like ~1.4% of time in my LOLs sample was spent just iterating a SortedList.
These were the old .speedscope files:
There was a problem hiding this comment.
I got rid of 1, 2 and 3 by eliminating Linq.
7 and 8 can be eliminated by giving a initial capacity to the sorted list.
Anyway, there is some space for improvement, I'm working on a benchmark project to get the best result possible.
I'll get back to you in a couple of days. Thanks.
There was a problem hiding this comment.
The .zip file above has files you can open in https://speedscope.app/
When you finish your next iteration, I should have some time to dotnet-trace these changes and compare. Thanks!
There was a problem hiding this comment.
@jonathanpeppers I've finished up doing an ad hoc implementation which brings great results.
You can see benchmark results in this repo.
I've updated the PR and also the description above with new benchmark results.
I've added a section under #if DEBUG in SetterSpecificity to simplify debugging.
I've also added all required unit tests to verify the new ad-hoc implementation.
I've also tried to include Lols page inside MAUI solution in order to try it out directly LolsPage.zip, but the number of lols/s keeps decreasing every time I enter the page, which is weird (it makes me think of memory leaks somewhere).
One last consideration regarding NET8 GA: a general practice (for example with buttons) is to define a style with the BG color and then use VSM to change it when pressed or disabled.
This makes 3 setters:
- default
- style
- VSM
Which unfortunately with the current implemention would hit the usage of SortedList.
There was a problem hiding this comment.
(Thank you for working on this!)
There was a problem hiding this comment.
Today I've also added on the other repo an implementation based on an unordered linked list.
https://github.com/albyrock87/setter-specificity-list-benchmarks/blob/master/SetterSpecificityListAdHocLinked.cs
It looks better from performance side.
That's probably due to the low number of Setters but putting it here gave me a worse result in terms of memory usage on the first benchmark (129KB vs 121KB).
| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|---|---|---|---|---|---|---|
| SettersFromDifferentSources | 147.9 us | 1.84 us | 1.72 us | 20.9961 | 8.3008 | 129.39 KB |
| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|---|---|---|---|---|---|---|
| BindName | 19.68 us | 0.423 us | 1.248 us | 1.6785 | 1.6479 | 10.31 KB |
| BindChild | 30.06 us | 0.601 us | 1.255 us | 2.5940 | 2.5635 | 16.02 KB |
| BindChildIndexer | 54.53 us | 1.068 us | 1.663 us | 4.1504 | 4.0894 | 25.55 KB |
What really makes the difference between the two implementations in terms of speed is basically the Array.Copy which apparently costs more than iterating on a few items (Log(N) vs N is not that relevant with low numbers).
The last benchmark there has a huge difference in terms of speed: 1,654.5us vs 772.2us.
I'll leave this choice up to you: for now I've kept the AdHoc implementation similar to a SortedList.
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
9a5ed3a to
09a520c
Compare
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
09a520c to
28876c0
Compare
* Test ignore * Test off-by-one * Test print out missing category * Cleanup --------- Co-authored-by: Mike Corsaro <mikecorsaro@microsoft.com>
avalable -> available
### Description of Change Replace Wait() calls with method which Asserts the results of the Task<bool> so we have a clearer idea where the tests fail; remove extra post-Wait() assertions. Move non-extension methods to AssertHelpers. Remove random timings. ### Issues Fixed Fixes dotnet#19376
* [iOS] Fix Flyout Header breaking clicking over items The Flyout Header height was being defined as `ArrangedHeaderViewHeightWithNoMargin` + `HeaderTopMargin`, but the `HeaderView.MeasuredHeight` (value on which `ArrangedHeaderViewHeightWithNoMargin` is based on) does include the margin so we were accounting for it twice and making the header go over the items below it, making them not clickable. When there is no margin, `HeaderTopMargin` represents the safe area and it should not be accounted for either. Fixes dotnet#17965 * Rename confusing properties Rename `ArrangedHeaderViewHeightWithNoMargin` and `MeasuredHeaderViewHeightWithNoMargin`, to `ArrangedHeaderViewHeightWithMargin` and `MeasuredHeaderViewHeightWithMargin`, since both include the top margin value: https://github.com/dotnet/maui/blob/main/src/Core/src/Layouts/LayoutExtensions.cs#L27. * Fix tests * Fix safe area margin bottom value * Fix margins * Polish flyout header and content offsets * Remove extra space * Simplify content layout * Small code cleanup * Fix condition * Simplify test * More tests * Test fix * Add ArrangedHeaderViewHeightWithOutMargin * Broken * Fix scrollview inset * Fix all tests * Fix scroll view content inset and expand tests * Fix new test cases for Android * Skip FlyoutHeaderContentAndFooterAllMeasureCorrectly for Android since there is a bug that makes tests fail * Enable more tests for iOS * Honor IgnoreSafeArea * Add missing null check * Fix CollectionView support * Add check by ItemsView for CV * Add tests scrolling using different content control types * Log more info on new tests * Use requested value for assertion * Consider epsilon for scrolled position * Better test logging * Fix spacing * Another indenting issue * Fix namespaces
… a relative position (dotnet#19371) * Fix * Test * Apply feedback * Switch Button to BoxView * - fix tests * - add upper limit constraints * - switch to wait for element * Update src/Controls/samples/Controls.Sample.UITests/Issues/Issue19329.xaml Co-authored-by: MartyIX <203266+MartyIX@users.noreply.github.com> * - switch to click for catalyst * Update src/Controls/tests/UITests/Tests/Issues/Issue19329.cs Co-authored-by: MartyIX <203266+MartyIX@users.noreply.github.com> * - add comments --------- Co-authored-by: Shane Neuville <shneuvil@microsoft.com> Co-authored-by: Shane Neuville <shane94@hotmail.com>
Disables the native cell recycling mechanisms in favor of the renderer/handler reuse that's already built into .NET MAUI. Adds special casing to ensure that the behavior changes only apply to TableView; similar problems may exist in ListView, but that's beyond the scope of this change. These changes also break down the TableView's cell creation methods for easier maintenance.
* Update dependencies from https://github.com/dotnet/xharness build 20231220.1 Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 9.0.0-prerelease.23616.1 -> To Version 9.0.0-prerelease.23620.1 * Update dependencies from https://github.com/dotnet/xharness build 20231220.1 Microsoft.DotNet.XHarness.CLI , Microsoft.DotNet.XHarness.TestRunners.Common , Microsoft.DotNet.XHarness.TestRunners.Xunit From Version 9.0.0-prerelease.23616.1 -> To Version 9.0.0-prerelease.23620.1 * Try update catalyst to use the xharness installed --------- Co-authored-by: dotnet-maestro[bot] <dotnet-maestro[bot]@users.noreply.github.com> Co-authored-by: Rui Marinho <me@ruimarinho.net>
|
I'm not yet 100% sure that's where we want to go, but it's all internal cooking, doesn't prevent us for going in any other direction in the future, and solves a real problem. I'll give it a test and eventually merge. thanks for the hard work |
- Rewrite `SetterSpecificity` to be stored as UInt64 - Rewrite `SetterSpecificityList` with a faster implementation - Use `SetterSpecificityList` on `Bindings` too - Minor improvements in `BindingExpression.SetupPart` - Fixes `BindingCondition.TearDown` trying to remove `Manual` setter instead of Binding one - Fixes `GridLayoutManagerTests` on non-US cultures - Improves performance of `VisualStateManager.GoToState` - Added more benchmarks
85bf14a to
2285dd8
Compare
|
FYI I changed this PR to target the |
|
They are merging /cc @rmarinho |
|
/rebase |

Description of Change
Trying to improve Bindable
Set/GetValueand bindings performance a little bit moreImproves BindableProperty performance
SetterSpecificityto be stored asUInt64SetterSpecificityListagain to useSortedListbut this time using its methods instead of LinqSetterSpecificityListonBindingstooBindingExpressionSetupPartVisualStateManger(especiallyGoToStateby avoiding reading property context multiple times)Benchmarks Executed with
SpecificitySetter Benchmark (~58% CPU Time reduction, 48% memory reduction)
Before:
After:
Binding Benchmark (some small improvements also here)
Before:
After:
TypedBindingBenchmarker
Before:
After:
Conclusions
Original PR introducing
SetterSpecificity#13818