From e35e9fbc67323cbd138e15682b9344c207ce3bf9 Mon Sep 17 00:00:00 2001
From: Jonathan Peppers <jonathan.peppers@microsoft.com>
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<JniEnvironmentInfo>     Info    = new ThreadLocal<JniEnvironmentInfo> (() => 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)
