Skip to content

Commit f4e559a

Browse files
jonathanpeppersrmarinho
authored andcommitted
[android] reduce JNI calls during layout measurement (#8034)
Context: https://github.com/unoplatform/performance/tree/master/src/dopes/DopeTestMaui Building upon #7996, #8001, and #8033, I noticed while profiling the sample app putting N Label on the screen: 783.92ms (6.2%) microsoft.maui!Microsoft.Maui.ViewHandlerExtensions.GetDesiredSizeFromHandler(Microsoft.Maui.IViewHandler,double,double) So around %6 of the time spend just measuring. Looking through the call stack, I can see 3 JNI calls happening: 932.51ms (7.4%) mono.android!Android.Views.View.Measure(int,int) 115.53ms (0.91%) mono.android!Android.Views.View.get_MeasuredWidth() 96.97ms (0.77%) mono.android!Android.Views.View.get_MeasuredHeight() So, we could write a Java method that calls all three of these and somehow returns the `MeasuredWidth` and `MeasuredHeight`. After a little research, it seemed the best approach here was to "pack" two integers into a `long`. If we tried to return some Java object instead, then we'd have the same number of JNI calls to get the integers out. I found a couple links describing how to "pack" an `int` into a `long`: * Java: https://stackoverflow.com/a/12772968 * C#: https://stackoverflow.com/a/827267 Which after some testing, arrives at: public static long measureAndGetWidthAndHeight(View view, int widthMeasureSpec, int heightMeasureSpec) { view.measure(widthMeasureSpec, heightMeasureSpec); int width = view.getMeasuredWidth(); int height = view.getMeasuredHeight(); return ((long)width << 32) | (height & 0xffffffffL); } Unpacked in C# such as: var packed = PlatformInterop.MeasureAndGetWidthAndHeight(platformView, widthSpec, heightSpec); var measuredWidth = (int)(packed >> 32); var measuredHeight = (int)(packed & 0xffffffffL); Reducing 3 JNI calls in every `View`'s layout to 1. ~~ Results ~~ A `Release` build on a Pixel 5 device, I was getting: Before: 91.94 Dopes/s After: 102.45 Dopes/s After profiling again, it drops the % time spent in `GetDesiredSizeFromHandler`: 528.96ms (4.5%) microsoft.maui!Microsoft.Maui.ViewHandlerExtensions.GetDesiredSizeFromHandler So the added math is negligible compared to reduced JNI calls.
1 parent f3371ba commit f4e559a

File tree

3 files changed

+11
-3
lines changed

3 files changed

+11
-3
lines changed

src/Core/AndroidNative/maui/src/main/java/com/microsoft/maui/PlatformInterop.java

+7
Original file line numberDiff line numberDiff line change
@@ -318,4 +318,11 @@ public static ColorStateList getColorStateListForToolbarStyleableAttribute(Conte
318318
styledAttributes.recycle();
319319
}
320320
}
321+
322+
public static long measureAndGetWidthAndHeight(View view, int widthMeasureSpec, int heightMeasureSpec) {
323+
view.measure(widthMeasureSpec, heightMeasureSpec);
324+
int width = view.getMeasuredWidth();
325+
int height = view.getMeasuredHeight();
326+
return ((long)width << 32) | (height & 0xffffffffL);
327+
}
321328
}

src/Core/src/Handlers/ViewHandlerExtensions.Android.cs

+4-3
Original file line numberDiff line numberDiff line change
@@ -88,11 +88,12 @@ internal static Size GetDesiredSizeFromHandler(this IViewHandler viewHandler, do
8888
var widthSpec = Context.CreateMeasureSpec(widthConstraint, virtualView.Width, virtualView.MaximumWidth);
8989
var heightSpec = Context.CreateMeasureSpec(heightConstraint, virtualView.Height, virtualView.MaximumHeight);
9090

91-
platformView.Measure(widthSpec, heightSpec);
91+
var packed = PlatformInterop.MeasureAndGetWidthAndHeight(platformView, widthSpec, heightSpec);
92+
var measuredWidth = (int)(packed >> 32);
93+
var measuredHeight = (int)(packed & 0xffffffffL);
9294

9395
// Convert back to xplat sizes for the return value
94-
return Context.FromPixels(platformView.MeasuredWidth, platformView.MeasuredHeight);
95-
96+
return Context.FromPixels(measuredWidth, measuredHeight);
9697
}
9798

9899
internal static void PlatformArrangeHandler(this IViewHandler viewHandler, Rect frame)

src/Core/src/maui.aar

195 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)