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

[core] use StringComparer for Dictionary/HashSet #14900

Merged

Conversation

jonathanpeppers
Copy link
Member

Context: #12130
Context: https://github.com/angelru/CvSlowJittering

When profiling the above customer app while scrolling, 4% of the time is spent doing dictionary lookups:

(4.0%) System.Private.CoreLib!System.Collections.Generic.Dictionary<TKey_REF,TValue_REF>.FindValue(TKey_REF)

Observing the call stack, some of these are coming from culture-aware string lookups in MAUI:

  • microsoft.maui!Microsoft.Maui.PropertyMapper.GetProperty(string)
  • microsoft.maui!Microsoft.Maui.WeakEventManager.AddEventHandler(System.EventHandler1<TEventArgs_REF>,string)`
  • microsoft.maui!Microsoft.Maui.CommandMapper.GetCommand(string)

Which show up as a mixture of string comparers:

(0.98%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.OrdinalComparer.GetHashCode(string)
(0.71%) System.Private.CoreLib!System.String.GetNonRandomizedHashCode()
(0.31%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.OrdinalComparer.Equals(string,stri
(0.01%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.GetStringComparer(object)

In cases of Dictionary<string, TValue> or HashSet<string>, we can use StringComparer.Ordinal for faster dictionary lookups.

Unfortunately, there is no code analyzer for this:

dotnet/runtime#52399

So, I manually went through the codebase and found all the places.

I now only see the fast string comparers in this sample:

(1.3%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.OrdinalComparer.GetHashCode(string)
(0.35%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.OrdinalComparer.Equals(string,stri

Which is about ~0.36% better than before.

This should slightly improve the performance of handlers & all controls on all platforms.

I also fixed Microsoft.Maui.Graphics.Text.TextColors to use StringComparer.OrdinalIgnoreCase -- and removed a ToUpperInvariant() call.

Context: dotnet#12130
Context: https://github.com/angelru/CvSlowJittering

When profiling the above customer app while scrolling, 4% of the time
is spent doing dictionary lookups:

    (4.0%) System.Private.CoreLib!System.Collections.Generic.Dictionary<TKey_REF,TValue_REF>.FindValue(TKey_REF)

Observing the call stack, some of these are coming from culture-aware
string lookups in MAUI:

* `microsoft.maui!Microsoft.Maui.PropertyMapper.GetProperty(string)`
* `microsoft.maui!Microsoft.Maui.WeakEventManager.AddEventHandler(System.EventHandler`1<TEventArgs_REF>,string)`
* `microsoft.maui!Microsoft.Maui.CommandMapper.GetCommand(string)`

Which show up as a mixture of `string` comparers:

    (0.98%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.OrdinalComparer.GetHashCode(string)
    (0.71%) System.Private.CoreLib!System.String.GetNonRandomizedHashCode()
    (0.31%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.OrdinalComparer.Equals(string,stri
    (0.01%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.GetStringComparer(object)

In cases of `Dictionary<string, TValue>` or `HashSet<string>`, we can
use `StringComparer.Ordinal` for faster dictionary lookups.

Unfortunately, there is no code analyzer for this:

dotnet/runtime#52399

So, I manually went through the codebase and found all the places.

I now only see the *fast* string comparers in this sample:

    (1.3%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.OrdinalComparer.GetHashCode(string)
    (0.35%) System.Private.CoreLib!System.Collections.Generic.NonRandomizedStringEqualityComparer.OrdinalComparer.Equals(string,stri

Which is about ~0.36% better than before.

This should slightly improve the performance of handlers & all
controls on all platforms.

I also fixed `Microsoft.Maui.Graphics.Text.TextColors` to use
`StringComparer.OrdinalIgnoreCase` -- and removed a
`ToUpperInvariant()` call.
@jonathanpeppers jonathanpeppers added the legacy-area-perf Startup / Runtime performance label May 2, 2023
@symbiogenesis
Copy link
Contributor

Maybe add a TODO comment in the editorconfig file to enforce an error whenever such a code analyzer shows up, and link that open issue.

@jonathanpeppers
Copy link
Member Author

@symbiogenesis since dotnet/runtime#52399 was opened in 2019, I don't know when (if ever) it will be completed.

Or is there a CA1234 warning for this and I just missed it? Thanks!

@jonathanpeppers jonathanpeppers marked this pull request as ready for review May 3, 2023 14:40
@jonathanpeppers jonathanpeppers requested a review from a team as a code owner May 3, 2023 14:40
@jonathanpeppers jonathanpeppers requested a review from mattleibow May 3, 2023 14:40
@jonathanpeppers jonathanpeppers enabled auto-merge (squash) May 3, 2023 16:58
Copy link
Member

@Eilon Eilon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

@jonathanpeppers jonathanpeppers merged commit 3a8455a into dotnet:main May 3, 2023
@jonathanpeppers jonathanpeppers deleted the DictionaryStringComparer branch May 3, 2023 17:32
rmarinho added a commit that referenced this pull request May 30, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Dec 10, 2023
@Eilon Eilon added the t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf) label May 10, 2024
@samhouts samhouts added the fixed-in-8.0.0-preview.5.8529 Look for this fix in 8.0.0-preview.5.8529! label Aug 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
fixed-in-8.0.0-preview.5.8529 Look for this fix in 8.0.0-preview.5.8529! legacy-area-perf Startup / Runtime performance t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants