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
Improves performance of GetLayoutHandlerIndex #18499
Conversation
Hey there @albyrock87! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Otherwise, the changes do look straightforward here: a single for-loop O(N) should be better than OrderBy(...).IndexOf(...)
which is probably O(N^2). 👍
/azp run |
Azure Pipelines successfully started running 3 pipeline(s). |
aa12496
5a1e88b
to
bb7a186
Compare
/azp run |
Azure Pipelines successfully started running 2 pipeline(s), but failed to run 1 pipeline(s). |
{ | ||
case 0: | ||
return -1; | ||
case 1: | ||
return view == layout[0] ? 0 : -1; | ||
default: | ||
return layout.OrderByZIndex().IndexOf(view); | ||
var found = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A suggestion to improve code readability and optimum performance is to use MemoryExtensions.Sort and MemoryExtensions.BinarySearch - with a custom comparer to sort by ZIndex. If one can't sort layout in place one could stackalloc a buffer array to avoid using the heap.
Another idea would be for the layout itself to keep a sorted list of the children.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In this case any kind of sort is still less performant than O(N).
A SortedList though would be beneficial for both methods in this class, but the problem is that both zIndex and childIndex might change in time (i.e. adding or removing children).
I'm thinking about a more general solution for the long term, but I felt this was a low hanging fruit for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's true that the total thing would be O(N log N) which really isn't much more than O(N) for the low numbers found in layout children. My guess it's probably the allocations of the original code that makes it slower. The sorting itself could in fact be negligible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do think your code is optimal, I was mainly commenting on readability.
/azp run MAUI-UITests-public |
Azure Pipelines successfully started running 1 pipeline(s). |
Description of Change
While examining Lols Benchmark results by @jonathanpeppers I've noticed that 6.4% of the total time is consumed by
LayoutExtensions.GetLayoutHandlerIndex
.This function is being called every time a layout child is added while the layout is already attached to an handler.
The function uses
OrderBy
which internally creates aSortedMap
, this has a cost in terms of memory (array allocation and resize/copy) and CPU (may vary depending on the sorting algorithm used there).This PR replaces that
OrderBy
+IndexOf
with a simple O(N) algorithm which counts views with a lower zIndex.That count matches the actual zIndex of the view.
I've added a benchmark to test the internal method performance change.
Unit test of this method already exist.
Before
After