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

[net7.0] [controls] fix performance issue in {AppThemeBinding} #15384

Merged
merged 2 commits into from
Jun 1, 2023

Conversation

github-actions[bot]
Copy link
Contributor

@github-actions github-actions bot commented Jun 1, 2023

Backport of #14625 to net7.0

/cc @hartez @jonathanpeppers

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

Profiling a customer sample app, I noticed a lot of time spent in
`{AppThemeBinding}` and `WeakEventManager` while scrolling:

    2.08s (17%) microsoft.maui.controls!Microsoft.Maui.Controls.AppThemeBinding.Apply(object,Microsoft.Maui.Controls.BindableObject,Micr...
    2.05s (16%) microsoft.maui.controls!Microsoft.Maui.Controls.AppThemeBinding.AttachEvents()
    2.04s (16%) microsoft.maui!Microsoft.Maui.WeakEventManager.RemoveEventHandler(System.EventHandler`1<TEventArgs_REF>,string)

16% is a *lot* to notice while scrolling. Sometimes I've made
improvements where I only shaved off 3% of the total time.

What is going on here is:

* Default `maui` template has lots of `{AppThemeBinding}` in the
  default `Styles.xaml`. This supports Light vs Dark theming.

* `{AppThemeBinding}` subscribes to `Application.RequestedThemeChanged`

* Making every MAUI view subscribe to this event -- potentially
  multiple times.

* Subscribers are a `Dictionary<string, List<Subscriber>>`, where
  there is a dictionary lookup followed by a O(N) search for
  unsubscribe operations.

I spent a little time investigating if we can make a faster
`WeakEventManager`, in general:

dotnet/runtime#61517

I did not immediately see a way to make "weak events" fast, but I did
see a way to make this scenario fast.

Before:
* For any `{AppThemeBinding}`, it calls both:
    * `RequestedThemeChanged -= OnRequestedThemeChanged` O(N) time
    * `RequestedThemeChanged += OnRequestedThemeChanged` constant time
* Where the `-=` is notably slower, due to possibly 100s of subscribers.

After:
* Create an `_attached` boolean, so we know know the "state" if it is
  attached or not.
* New bindings only call `+=`, where `-=` will now only be called by
  `{AppThemeBinding}` in *rare* cases.
* Most .NET MAUI apps do not "unapply" bindings, but `-=` would only
  be used in that case.

After this change, the following method disappeared from `dotnet-trace`
output completely:

    2.05s (16%) microsoft.maui.controls!Microsoft.Maui.Controls.AppThemeBinding.AttachEvents()

Meaning that `AppThemeBinding.AttachEvents()` is now so fast that 0%
(basically no time) is spent inside this method.

I also could notice a difference in general startup time of the sample
app. An average of 10 runs on a Pixel 5:

    Before:
    Average(ms): 967.7
    Std Err(ms): 4.62132737064436
    Std Dev(ms): 14.6139203045133
    After:
    Average(ms): 958.9
    Std Err(ms): 3.22645316098034
    Std Dev(ms): 10.2029407525478

So I could notice a ~10ms improvement to startup in this app, and
scrolling seemed a bit better as well.

Note that I don't think this completely solves #12130, as things still
seem sluggish to me when scrolling. But it is a reasonable improvement
to start with that benefits all .NET MAUI apps on all platforms.
@rmarinho rmarinho merged commit cd646d5 into net7.0 Jun 1, 2023
@rmarinho rmarinho deleted the backport/pr-14625-to-net7.0 branch June 1, 2023 10:18
@github-actions github-actions bot locked and limited conversation to collaborators Dec 10, 2023
@samhouts samhouts added the fixed-in-7.0.92 Look for this fix in 7.0.92! label Aug 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
fixed-in-7.0.92 Look for this fix in 7.0.92! t/housekeeping ♻︎
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants