[controls] improve perf of "merged" ResourceDictionary lookups#21334
Merged
StephaneDelcroix merged 1 commit intodotnet:mainfrom Mar 27, 2024
Merged
Conversation
Applies to: dotnet#18505 Context: https://github.com/dotnet/maui/files/13251041/MauiCollectionView.zip I profiled the above sample with `dotnet-trace` with the following PRs applied locally: * dotnet#21229 * dotnet#21291 While scrolling, a lot of time is spent in `ResourceDictionary` lookups on an Android Pixel 5 device: 2.0% Microsoft.Maui.Controls!Microsoft.Maui.Controls.ResourceDictionary.TryGetValue(string,object&) Drilling in, I can see System.Linq's `Reverse()` method: 0.56% System.Linq!System.Linq.Enumerable.ReverseIterator<TSource_REF>.MoveNext() 0.14% System.Linq!System.Linq.Enumerable.Reverse(System.Collections.Generic.IEnumerable`1<TSource_REF>) 0.04% System.Linq!System.Linq.Enumerable.ReverseIterator<TSource_REF>..ctor(System.Collections.Generic.IEnumerable`1<TSource_REF>) 0.04% System.Linq!System.Linq.Enumerable.ReverseIterator<TSource_REF>.Dispose() `Reverse()` can be problematic as it can sometimes create a copy of the entire collection, in order to sort in reverse. We can juse use a reverse `for`-loop instead. The indexer, we can also avoid a double-lookup: if (dict.ContainsKey(index)) return dict[index]; And instead do: if (dict.TryGetValue(index, out var value)) return value; The MAUI project template seems to setup a few "merged" `ResourceDictionary` as it contains `Styles.xaml`, so this is why this code path is being hit. I wrote a BenchmarkDotNet benchmark, and it indicates the collection is being copied, as the 872 bytes of allocation occur: | Method | key | Mean | Error | StdDev | Gen0 | Allocated | |------------ |------------ |----------:|---------:|---------:|-------:|----------:| | TryGetValue | key0 | 11.45 ns | 0.026 ns | 0.023 ns | - | - | | Indexer | key0 | 24.72 ns | 0.133 ns | 0.118 ns | - | - | | TryGetValue | merged99,99 | 117.06 ns | 2.334 ns | 2.497 ns | 0.1042 | 872 B | | Indexer | merged99,99 | 145.60 ns | 2.737 ns | 2.286 ns | 0.1042 | 872 B | With these changes in place, I see less time spent inside: 0.91% Microsoft.Maui.Controls!Microsoft.Maui.Controls.ResourceDictionary.TryGetValue(string,object&) The benchmark no longer allocates either: | Method | key | Mean | Error | StdDev | Allocated | |------------ |------------ |----------:|----------:|----------:|----------:| | TryGetValue | key0 | 11.92 ns | 0.094 ns | 0.084 ns | - | | Indexer | merged99,99 | 23.12 ns | 0.418 ns | 0.391 ns | - | | Indexer | key0 | 24.20 ns | 0.485 ns | 0.453 ns | - | | TryGetValue | merged99,99 | 29.09 ns | 0.296 ns | 0.262 ns | - | This should improve the performance "parenting" of any MAUI view on all platforms -- as well as scrolling `CollectionView`.
StephaneDelcroix
approved these changes
Mar 27, 2024
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Applies to: #18505
Context: https://github.com/dotnet/maui/files/13251041/MauiCollectionView.zip
I profiled the above sample with
dotnet-tracewith the following PRs applied locally:OnLayout()forLabel#21291While scrolling, a lot of time is spent in
ResourceDictionarylookups on an Android Pixel 5 device:Drilling in, I can see System.Linq's
Reverse()method:Reverse()can be problematic as it can sometimes create a copy of the entire collection, in order to sort in reverse. We can just use a reversefor-loop instead.The indexer, we can also avoid a double-lookup:
And instead do:
The MAUI project template seems to setup a few "merged"
ResourceDictionaryas it containsStyles.xaml, so this is why this code path is being hit.I wrote a BenchmarkDotNet benchmark, and it indicates the collection is being copied, as the 872 bytes of allocation occur:
With these changes in place, I see less time spent inside:
The benchmark no longer allocates either:
This should improve the performance "parenting" of any MAUI view on all platforms -- as well as scrolling
CollectionView.