From a9c62517218cfc6dff8a51fde0312cb5c89ae337 Mon Sep 17 00:00:00 2001 From: Jonathan Peppers Date: Thu, 20 Feb 2020 17:09:39 -0600 Subject: [PATCH] [Java.Interop.Tools.Cecil] remove System.Linq in IsSubclassOf Using the Mono profiler, I found: Allocation summary Bytes Count Average Type name 7636736 59662 128 System.Func 3685952 57593 64 Java.Interop.Tools.Cecil.TypeDefinitionRocks.d__3 The stack traces of these are from: 2498944 bytes from: Xamarin.Android.Tasks.GenerateJavaStubs:Run (Java.Interop.Tools.Cecil.DirectoryAssemblyResolver) Xamarin.Android.Tasks.ManifestDocument:Merge (Microsoft.Build.Utilities.TaskLoggingHelper,Java.Interop.Tools.Cecil.TypeDefinitionCache,System.Collections.Generic.List`1,string,bool,string,System.Collections.Generic.IEnumerable`1) Xamarin.Android.Tasks.ManifestDocument:GetGenerator (Mono.Cecil.TypeDefinition,Java.Interop.Tools.Cecil.TypeDefinitionCache) Java.Interop.Tools.Cecil.TypeDefinitionRocks:IsSubclassOf (Mono.Cecil.TypeDefinition,string,Java.Interop.Tools.Cecil.TypeDefinitionCache) (wrapper alloc) object:ProfilerAllocSmall (intptr,intptr) (wrapper managed-to-native) object:__icall_wrapper_mono_profiler_raise_gc_allocation (object) ... 1273344 bytes from: Xamarin.Android.Tasks.ManifestDocument:Merge (Microsoft.Build.Utilities.TaskLoggingHelper,Java.Interop.Tools.Cecil.TypeDefinitionCache,System.Collections.Generic.List`1,string,bool,string,System.Collections.Generic.IEnumerable`1) Xamarin.Android.Tasks.ManifestDocument:GetGenerator (Mono.Cecil.TypeDefinition,Java.Interop.Tools.Cecil.TypeDefinitionCache) Java.Interop.Tools.Cecil.TypeDefinitionRocks:IsSubclassOf (Mono.Cecil.TypeDefinition,string,Java.Interop.Tools.Cecil.TypeDefinitionCache) Java.Interop.Tools.Cecil.TypeDefinitionRocks:GetTypeAndBaseTypes (Mono.Cecil.TypeDefinition,Java.Interop.Tools.Cecil.TypeDefinitionCache) (wrapper alloc) object:ProfilerAllocSmall (intptr,intptr) (wrapper managed-to-native) object:__icall_wrapper_mono_profiler_raise_gc_allocation (object) This `IsSubclassOf` method gets called ~40K times during a build: Method call summary Total(ms) Self(ms) Calls Method name 2431 117 43493 Java.Interop.Tools.Cecil.TypeDefinitionRocks:IsSubclassOf (Mono.Cecil.TypeDefinition,string,Java.Interop.Tools.Cecil.TypeDefinitionCache) Reviewing `IsSubclassOf` we can just remove the System.Linq usage and use a `foreach` loop instead. The results of building the Xamarin.Forms integration project on Windows: Before: 559 ms GenerateJavaStubs 1 calls After: 535 ms GenerateJavaStubs 1 calls A ~24ms savings is pretty good for a small app. I suspect it would have even better improvements on macOS / Mono, due to what I saw in: https://github.com/xamarin/xamarin-android/pull/4260 --- .../Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs index c62cb11f1..690a7fe84 100644 --- a/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs +++ b/src/Java.Interop.Tools.Cecil/Java.Interop.Tools.Cecil/TypeDefinitionRocks.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Mono.Cecil; @@ -74,7 +73,12 @@ public static bool IsSubclassOf (this TypeDefinition type, string typeName) => public static bool IsSubclassOf (this TypeDefinition type, string typeName, TypeDefinitionCache cache) { - return type.GetTypeAndBaseTypes (cache).Any (t => t.FullName == typeName); + foreach (var t in type.GetTypeAndBaseTypes (cache)) { + if (t.FullName == typeName) { + return true; + } + } + return false; } [Obsolete ("Use the TypeDefinitionCache overload for better performance.")]