From e35e9fbc67323cbd138e15682b9344c207ce3bf9 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Mon, 16 Dec 2019 10:26:28 -0600 Subject: [PATCH] [Java.Interop] apply AggressiveInlining where profiler shows calls Context: https://github.com/xamarin/xamarin-android/blob/master/Documentation/guides/profiling.md#profiling-managed-code I noticed the following when profiling startup in the Blank Xamarin.Forms app template: Method call summary Total(ms) Self(ms) Calls Method name 2 2 6470 Java.Interop.JniObjectReference:get_Handle () 6 4 4043 Java.Interop.JniObjectReference:get_IsValid () 1 1 3881 Java.Interop.JniEnvironmentInfo:get_Runtime () 12 3 3084 Java.Interop.JniEnvironment:get_CurrentInfo () 5 3 3084 Java.Interop.JniEnvironmentInfo:get_IsValid () 9 1 1634 Java.Interop.JniEnvironment:get_EnvironmentPointer () 4 0 797 Java.Interop.JniEnvironment:get_Runtime () 2 0 672 Java.Interop.JniType:AssertValid () None of these calls seem to be slow in themselves, but Xamarin.Forms tends to make *many* managed-to-java transitions throughout its startup. I found I could just sprinkle: [MethodImpl (MethodImplOptions.AggressiveInlining)] and I was able to see a performance improvement! A `Debug` build of the app: Before: 12-16 10:23:08.289 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +919ms 12-16 10:23:12.126 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +802ms 12-16 10:23:16.087 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +805ms 12-16 10:23:20.053 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +806ms 12-16 10:23:24.019 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +811ms 12-16 10:23:27.985 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +815ms 12-16 10:23:31.934 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +803ms 12-16 10:23:35.901 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +816ms 12-16 10:23:39.865 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +807ms 12-16 10:23:43.797 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +806ms Average(ms): 819 Std Err(ms): 11.2111056051082 Std Dev(ms): 35.4526288008222 After: 12-16 10:25:11.825 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +816ms 12-16 10:25:15.758 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +808ms 12-16 10:25:19.692 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +805ms 12-16 10:25:23.656 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +805ms 12-16 10:25:27.605 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +797ms 12-16 10:25:31.574 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +803ms 12-16 10:25:35.555 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +806ms 12-16 10:25:39.490 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +802ms 12-16 10:25:43.437 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +808ms 12-16 10:25:47.383 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +813ms Average(ms): 806.3 Std Err(ms): 1.71302202100395 Std Dev(ms): 5.41705126839727 A `Release` build of the app: Before (Release): 12-16 10:21:23.643 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +574ms 12-16 10:21:27.576 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +557ms 12-16 10:21:31.558 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +567ms 12-16 10:21:35.557 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +557ms 12-16 10:21:39.522 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +572ms 12-16 10:21:43.471 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +555ms 12-16 10:21:47.452 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +558ms 12-16 10:21:51.388 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +553ms 12-16 10:21:55.335 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +560ms 12-16 10:21:59.267 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +554ms Average(ms): 560.7 Std Err(ms): 2.39467000742157 Std Dev(ms): 7.57261146794449 After: 12-16 10:26:52.042 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +551ms 12-16 10:26:56.023 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +547ms 12-16 10:27:00.038 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +550ms 12-16 10:27:04.004 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +533ms 12-16 10:27:07.953 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +540ms 12-16 10:27:11.917 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +552ms 12-16 10:27:15.869 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +540ms 12-16 10:27:19.832 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +534ms 12-16 10:27:23.815 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +543ms 12-16 10:27:27.765 1490 1517 I ActivityTaskManager: Displayed com.xamarin.forms.helloforms/crc6450e568c951913723.MainActivity: +538ms Average(ms): 542.8 Std Err(ms): 2.19494368442058 Std Dev(ms): 6.94102137857086 I would say this is a ~17ms improvement to a Xamarin.Forms app's startup? These numbers were taken running on a Pixel 3 XL, a Blank Xamarin.Forms app template using Xamarin.Forms/master. The project and script used is in this PR: https://github.com/xamarin/Xamarin.Forms/pull/8867 --- src/Java.Interop/Java.Interop/JniEnvironment.cs | 7 +++++++ src/Java.Interop/Java.Interop/JniObjectReference.cs | 9 ++++++++- src/Java.Interop/Java.Interop/JniType.cs | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Java.Interop/Java.Interop/JniEnvironment.cs b/src/Java.Interop/Java.Interop/JniEnvironment.cs index ac9f8397c..88b9c6b18 100644 --- a/src/Java.Interop/Java.Interop/JniEnvironment.cs +++ b/src/Java.Interop/Java.Interop/JniEnvironment.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; @@ -12,6 +13,7 @@ public static partial class JniEnvironment { internal static readonly ThreadLocal Info = new ThreadLocal (() => new JniEnvironmentInfo (), trackAllValues: true); internal static JniEnvironmentInfo CurrentInfo { + [MethodImpl (MethodImplOptions.AggressiveInlining)] get { var e = Info.Value; if (!e.IsValid) @@ -21,22 +23,27 @@ internal static JniEnvironmentInfo CurrentInfo { } public static JniRuntime Runtime { + [MethodImpl (MethodImplOptions.AggressiveInlining)] get {return CurrentInfo.Runtime;} } public static IntPtr EnvironmentPointer { + [MethodImpl (MethodImplOptions.AggressiveInlining)] get {return CurrentInfo.EnvironmentPointer;} } public static JniVersion JniVersion { + [MethodImpl (MethodImplOptions.AggressiveInlining)] get {return (JniVersion) Versions.GetVersion ();} } public static int LocalReferenceCount { + [MethodImpl (MethodImplOptions.AggressiveInlining)] get {return CurrentInfo.LocalReferenceCount;} } public static bool WithinNewObjectScope { + [MethodImpl (MethodImplOptions.AggressiveInlining)] get {return CurrentInfo.WithinNewObjectScope;} internal set {CurrentInfo.WithinNewObjectScope = value;} } diff --git a/src/Java.Interop/Java.Interop/JniObjectReference.cs b/src/Java.Interop/Java.Interop/JniObjectReference.cs index faf7fccd6..e72659371 100644 --- a/src/Java.Interop/Java.Interop/JniObjectReference.cs +++ b/src/Java.Interop/Java.Interop/JniObjectReference.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; #if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES && FEATURE_JNIOBJECTREFERENCE_INTPTRS @@ -24,6 +25,7 @@ internal JniReferenceSafeHandle SafeHandle { get {return gcHandle.IsAllocated ? ((JniReferenceSafeHandle) gcHandle.Target) : JniReferenceSafeHandle.Null;} } public IntPtr Handle { + [MethodImpl (MethodImplOptions.AggressiveInlining)] get { var h = SafeHandle; return h == null @@ -32,7 +34,11 @@ public IntPtr Handle { } } #elif FEATURE_JNIOBJECTREFERENCE_INTPTRS - public IntPtr Handle {get; private set;} + public IntPtr Handle { + [MethodImpl (MethodImplOptions.AggressiveInlining)] + get; + private set; + } #endif uint referenceInfo; @@ -47,6 +53,7 @@ internal JniObjectReferenceFlags Flags { } public bool IsValid { + [MethodImpl (MethodImplOptions.AggressiveInlining)] get { #if FEATURE_JNIOBJECTREFERENCE_SAFEHANDLES return SafeHandle != null && !SafeHandle.IsInvalid && !SafeHandle.IsClosed; diff --git a/src/Java.Interop/Java.Interop/JniType.cs b/src/Java.Interop/Java.Interop/JniType.cs index 83837d10f..18c8afc51 100644 --- a/src/Java.Interop/Java.Interop/JniType.cs +++ b/src/Java.Interop/Java.Interop/JniType.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading; using Java.Interop; @@ -78,6 +79,7 @@ void RegisterWithRuntime () registered = true; } + [MethodImpl (MethodImplOptions.AggressiveInlining)] void AssertValid () { if (!PeerReference.IsValid)