Skip to content

[Windows] Optimize LayoutHandler.Windows.cs (take 2)#26460

Closed
MartyIX wants to merge 13 commits intodotnet:mainfrom
MartyIX:feature/2024-12-08-Optimize-LayoutHandler-for-Windows-2
Closed

[Windows] Optimize LayoutHandler.Windows.cs (take 2)#26460
MartyIX wants to merge 13 commits intodotnet:mainfrom
MartyIX:feature/2024-12-08-Optimize-LayoutHandler-for-Windows-2

Conversation

@MartyIX
Copy link
Contributor

@MartyIX MartyIX commented Dec 8, 2024

Description of Change

I've been scratching my head how to improve performance of LayoutHandler and it seems that storing Children of PlatformView leads to a significant performance gain in my test scenario (#21787). This PR is a replacement for #26161 that implements @mattleibow's suggestion from the previous PR. Interestingly, the suggestion allows to easily use CachedChildren in more places and thus improve performance a bit more.

Explanation from @Sergio0694:

"Do we have an idea what the property [i.e. Panel.Children] does underneath?"

Assuming that's some WinUI Panel control, accessing that property will invoke the get_Children method on the native WinRT object, then marshal the returned IInspectable* pointer to a C# object (ie. it'll go find the existing RCW for it, or create a new one if it doesn't exist already).

Speedscope

image

-> 97% improvement for IPanelMethods.get_Children.

Issues Fixed

Contributes to #21787

@MartyIX MartyIX requested a review from a team as a code owner December 8, 2024 10:05
@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Dec 8, 2024
@MartyIX MartyIX requested review from Foda and mattleibow and removed request for jfversluis and jsuarezruiz December 8, 2024 11:15
Copy link
Member

@mattleibow mattleibow left a comment

Choose a reason for hiding this comment

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

This looks very nice and I do like the fact that you pointed out: we can use the better api in other places.

One thing I think we can do to force usage is to add the old children api to the banned apis file. Then no one can accidentally use it.

{
get
{
_cachedChildren ??= Children;
Copy link
Member

Choose a reason for hiding this comment

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

Can we add the Children api to the banned apis?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Modified.

However, thanks to this change, the PR exploded a bit in size. I tried to split the work in multiple commits so if necessary, it can be split in multiple PRs1.

Footnotes

  1. One variant I like in case the PR is too big: Modify src/Core/src/Handlers/Layout/LayoutHandler.Windows.cs to use CachedChildren. Ban Children and suppress errors. Successive PRs would remove suppressions and use CachedChildren.

@MartyIX MartyIX force-pushed the feature/2024-12-08-Optimize-LayoutHandler-for-Windows-2 branch from 6f2f471 to 7d53052 Compare December 9, 2024 09:44
{
Control.Measure(availableSize);
}
Control?.Measure(availableSize);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Modified because MSVS shows the original if as an error.


public UIElement? GeTPlatformElement() => Control;

UIElementCollection? _cachedChildren;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The parent type VisualElementHandler is in Microsoft.Maui.Controls.Handlers.Compatibility namespace. So I'm not sure if this type is to be touched or not.

}

#pragma warning disable RS0030 // Do not use banned APIs; Panel.Children is banned for performance reasons. MauiPanel might not be used everywhere though.
var oldParentChildren = PlatformView.Parent is MauiPanel mauiPanel
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The thing here is that I don't really believe that PlatformView.Parent is MauiPanel, it appears that MauiPanel is not used everytime.

So we can either

  1. Leave it as is
  2. Just suppress the error here instead of modifying code.
  3. Have a new type CachedPanel that would extend Panel and would have CachedChildren implementation.

I didn't want to add excessive changes.


if (window.VisualDiagnosticsOverlay != null)
window.VisualDiagnosticsOverlay.Initialize();
window.VisualDiagnosticsOverlay?.Initialize();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

MSVS reported an error here

}

_shadowCanvasCachedChildren = null;
_shadowCanvas = null;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It appears that this was missing? I checked WrapperView in Android code and it has that.

public partial class WrapperView : Grid, IDisposable
{
Canvas? _shadowCanvas;
UIElementCollection? _shadowCanvasCachedChildren;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure if this is not "too much".

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 it's too much, if anything it's a simple example of how to use caching

@jfversluis jfversluis added the area-layout StackLayout, GridLayout, ContentView, AbsoluteLayout, FlexLayout, ContentPresenter label Dec 9, 2024
@MartyIX MartyIX added perf/general The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf) platform/windows labels Dec 10, 2024
@MartyIX MartyIX requested a review from mattleibow December 10, 2024 09:47
@Redth
Copy link
Member

Redth commented Dec 10, 2024

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@MartyIX MartyIX force-pushed the feature/2024-12-08-Optimize-LayoutHandler-for-Windows-2 branch from 7d53052 to cfb3772 Compare December 10, 2024 19:57
@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@MartyIX MartyIX force-pushed the feature/2024-12-08-Optimize-LayoutHandler-for-Windows-2 branch from cfb3772 to 3c7c24c Compare December 10, 2024 21:13
@MartyIX
Copy link
Contributor Author

MartyIX commented Dec 10, 2024

CI uncovered a few more places requiring changes. Force-pushed.

@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@MartyIX MartyIX force-pushed the feature/2024-12-08-Optimize-LayoutHandler-for-Windows-2 branch from 3c7c24c to c76d0c5 Compare December 10, 2024 23:03
@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@MartyIX
Copy link
Contributor Author

MartyIX commented Dec 11, 2024

It appears there is no test failure on Windows.

Comment on lines +277 to +280
#pragma warning disable RS0030 // Do not use banned APIs; Panel.Children is banned for performance reasons.
container.Children.Add(image);
container.Children.Add(textBlock);
#pragma warning restore RS0030 // Do not use banned APIs
Copy link
Member

Choose a reason for hiding this comment

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

@mattleibow should we instead just not use BannedApiAnalyzer in src/Compatibility? Maybe we don't care as much about this project going forward?

Comment on lines +59 to +62
#pragma warning disable RS0030 // Do not use banned APIs; Panel.Children is banned for performance reasons. Here we allow it as a part of initialization.
layout.Children.Add(TextBlockMessage);
layout.Children.Add(TextBoxInput);
#pragma warning restore RS0030 // Do not use banned APIs
Copy link
Member

Choose a reason for hiding this comment

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

This one, you could have:

Suggested change
#pragma warning disable RS0030 // Do not use banned APIs; Panel.Children is banned for performance reasons. Here we allow it as a part of initialization.
layout.Children.Add(TextBlockMessage);
layout.Children.Add(TextBoxInput);
#pragma warning restore RS0030 // Do not use banned APIs
#pragma warning disable RS0030 // Do not use banned APIs; Panel.Children is banned for performance reasons. Here we can just cache it.
var children = layout.Children;
#pragma warning restore RS0030 // Do not use banned APIs
children.Add(TextBlockMessage);
children.Add(TextBoxInput);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment on lines +31 to +33
#pragma warning disable RS0030 // Do not use banned APIs; Panel.Children is banned for performance reasons. In tests, we don't mind.
var windowRootViewContainerChildren = windowRootViewContainer.Children;
#pragma warning restore RS0030 // Do not use banned APIs
Copy link
Member

Choose a reason for hiding this comment

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

Wait, do the device tests use BannedApiAnalyzers?!? Seems like tests should not.

Copy link
Member

Choose a reason for hiding this comment

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

This is what controls it:

<Import Condition="'$(SampleProject)' != 'true' and '$(IsTestProject)' != 'true'" Project="eng\BannedApis.targets" />

Seems like $(IsTestProject) should be true for the DeviceTests. Is it?

Copy link
Contributor Author

@MartyIX MartyIX Dec 19, 2024

Choose a reason for hiding this comment

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

I created a new PR #26722 addressing this suggestion1. See commit 1db1088.

Footnotes

  1. It feels good for comparison purposes.

@MartyIX
Copy link
Contributor Author

MartyIX commented Dec 20, 2024

Closing in favor of #26722

@MartyIX MartyIX closed this Dec 20, 2024
@MartyIX MartyIX deleted the feature/2024-12-08-Optimize-LayoutHandler-for-Windows-2 branch December 20, 2024 20:46
@github-actions github-actions bot locked and limited conversation to collaborators Jan 20, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

area-layout StackLayout, GridLayout, ContentView, AbsoluteLayout, FlexLayout, ContentPresenter community ✨ Community Contribution perf/general The issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf) platform/windows

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants