Skip to content

Commit

Permalink
[android] reduce JNI calls during layout measurement (#8034)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jonathanpeppers authored and rmarinho committed Jun 23, 2022
1 parent f3371ba commit f4e559a
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,11 @@ public static ColorStateList getColorStateListForToolbarStyleableAttribute(Conte
styledAttributes.recycle();
}
}

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);
}
}
7 changes: 4 additions & 3 deletions src/Core/src/Handlers/ViewHandlerExtensions.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,12 @@ internal static Size GetDesiredSizeFromHandler(this IViewHandler viewHandler, do
var widthSpec = Context.CreateMeasureSpec(widthConstraint, virtualView.Width, virtualView.MaximumWidth);
var heightSpec = Context.CreateMeasureSpec(heightConstraint, virtualView.Height, virtualView.MaximumHeight);

platformView.Measure(widthSpec, heightSpec);
var packed = PlatformInterop.MeasureAndGetWidthAndHeight(platformView, widthSpec, heightSpec);
var measuredWidth = (int)(packed >> 32);
var measuredHeight = (int)(packed & 0xffffffffL);

// Convert back to xplat sizes for the return value
return Context.FromPixels(platformView.MeasuredWidth, platformView.MeasuredHeight);

return Context.FromPixels(measuredWidth, measuredHeight);
}

internal static void PlatformArrangeHandler(this IViewHandler viewHandler, Rect frame)
Expand Down
Binary file modified src/Core/src/maui.aar
Binary file not shown.

0 comments on commit f4e559a

Please sign in to comment.