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

[Windows] Handle focus events using FocusManager (take 2) #24695

Merged

Conversation

MartyIX
Copy link
Contributor

@MartyIX MartyIX commented Sep 10, 2024

Description of Change

This PR is the same as #24355 except that it uses ConditionalWeakTable instead of dependency properties.

Subscribing and unsubscribing focus events for each MAUI view is costly.

This PR attempts to use FocusManager events to achieve the same result.

Performance impact

image

-> ∞ improvement :)

Issues Fixed

Contributes to #21787

cc @albyrock87

@MartyIX MartyIX requested a review from a team as a code owner September 10, 2024 18:12
Copy link
Contributor

Hey there @MartyIX! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@jonathanpeppers
Copy link
Member

/azp run

Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@mattleibow mattleibow added t/a11y Relates to accessibility area-keyboard Keyboard, soft keyboard t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.) platform/windows 🪟 and removed t/a11y Relates to accessibility labels Sep 10, 2024
@MartyIX MartyIX force-pushed the feature/2024-09-10-Windows-Use-FocusManager-take4 branch from ee509b7 to eab2340 Compare September 11, 2024 12:17
@mattleibow
Copy link
Member

/azp run

Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@MartyIX
Copy link
Contributor Author

MartyIX commented Sep 12, 2024

It looks like Windows tests pass.

{
platformView.GotFocus += OnPlatformViewGotFocus;
platformView.LostFocus += OnPlatformViewLostFocus;
FocusManagerMapping.Add(platformView, this);
Copy link
Member

Choose a reason for hiding this comment

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

Is there no perf issues when there is a super complex UI? If we have maybe 1k elements on screen, will not the add and lookup be slow? It may still be faster than what we had before, but I am getting flashbacks when millions of objects would sub and unsub from the theme changed event.

Copy link
Contributor

Choose a reason for hiding this comment

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

when millions of objects would sub and unsub from the theme changed event

Removing an entry from a CWT seems very fast compared to event unsubscription.

https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs#L614

I would rather set an initial capacity of 128 to the CWT to avoid a lot of initial resize operation (which is expensive).

If you're still concerned we have an alternative but much slower implementation:
#24355

Copy link
Contributor Author

@MartyIX MartyIX Sep 12, 2024

Choose a reason for hiding this comment

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

If we have maybe 1k elements on screen, will not the add and lookup be slow?

Adding to CWT is definitely faster because it does not involve interops (perf comparison of ConnectingHandler should be persuasive here). CTW should behave like a dictionary and "insert" operation for dictionaries is O(1) (i.e. so in practice it should be ~<10 nanoseconds1; whereas interops are more like milliseconds). So CWT lookups and inserts should be orders of magnitude faster.

I think that the CWT approach is strictly better for performance right now. What can be done is that I can try to create a huge grid with 1000 elements and measure performance for that scenario.

I would rather set an initial capacity of 128 to the CWT to avoid a lot of initial resize operation (which is expensive).

That's a good idea.

Footnotes

  1. https://startdebugging.net/2023/08/net-8-performance-dictionary-vs-frozendictionary/ just to get a feel what one might expect.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Perhaps @jonathanpeppers can double check my post as he's a performance guru :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I would rather set an initial capacity of 128 to the CWT to avoid a lot of initial resize operation (which is expensive).

That's a good idea.

@albyrock87 Interestingly, the CTW does not support passing capacity as far as I can tell: https://learn.microsoft.com/en-us/dotnet/api/system.runtime.compilerservices.conditionalweaktable-2.-ctor?view=net-8.0 👀

@MartyIX MartyIX force-pushed the feature/2024-09-10-Windows-Use-FocusManager-take4 branch from eab2340 to 4e65db7 Compare September 17, 2024 09:47
@jonathanpeppers
Copy link
Member

/azp run

Copy link

Azure Pipelines successfully started running 3 pipeline(s).

if (e.NewFocusedElement == view)
{
FocusManager.GotFocus -= OnFocused;
focusSource.SetResult();

This comment was marked as resolved.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think that could happen considering the event is being unsubscribed in the line above.

If there was a race condition, raising an exception would be exactly what we want in this device test.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ooh my bad, I didn't see it's a unit test. Reviewing code from mobile is hard 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Btw: are you interested in this PR for performance reasons?

Copy link
Contributor

Choose a reason for hiding this comment

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

@MartyIX yes, and it looks like to have a good gotcha on here, so I'm interested in learning new tricks (;

@MartyIX
Copy link
Contributor Author

MartyIX commented Sep 27, 2024

@rmarinho The mac tests still seem to fail. Is it OK? Or should this PR be rebased?

@rmarinho rmarinho merged commit 0ccf587 into dotnet:main Sep 27, 2024
93 of 97 checks passed
@MartyIX MartyIX deleted the feature/2024-09-10-Windows-Use-FocusManager-take4 branch September 27, 2024 13:17
rmarinho pushed a commit that referenced this pull request Sep 30, 2024
* WIPWIP

* Feedback

* Refactor usage of `FocusManager` to avoid weak table usage

* Use ConditionalWeakTable

---------

Co-authored-by: Alberto Aldegheri <[email protected]>
@samhouts samhouts added fixed-in-net9.0-nightly This may be available in a nightly release! fixed-in-net8.0-nightly This may be available in a nightly release! labels Oct 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-keyboard Keyboard, soft keyboard community ✨ Community Contribution fixed-in-net8.0-nightly This may be available in a nightly release! fixed-in-net9.0-nightly This may be available in a nightly release! platform/windows 🪟 t/perf The issue affects performance (runtime speed, memory usage, startup time, etc.)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants