From ddba7b9917060bbed9531cf4809b78bbd2d7914b Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Wed, 17 Oct 2018 11:44:05 +0200 Subject: [PATCH] [Class] Make looking up a System.Type given a native Class instance faster Cache the Class -> System.Type lookup in an array. I could also have used a dictionary, but there are a couple of disadvantages compared to the array approach: * A dictionary would require a lock every time it's read/written to. The array is created at launch, and after that we don't have to care about thread safety because it's safe to do the slow lookup multiple times. * Its memory requirements would be higher with more elements (in particular since we'd not only need to store the Type instance, but also a boolean determining whether it's a user type or not). * It's ~1% slower (probably due to the lock). Numbers ======= Test case: https://github.com/rolfbjarne/TestApp/commit/004283d7b628a29fcf711d98d8842bfd4ef4393b Fix 1 refers to PR #5009. Fix 2 is this fix. iPad Air 2 ---------- | Configuration | Before | After fix 1 | After fix 2 | Improvement from fix 1 to fix 2 | Cumulative improvement | | ------------------- | ------ | ----------: | -----------: | ------------------------------: | ---------------------: | | Release (link all) | 477 ms | 481 ms | 224 ms | 257 ms (53%) | 253 ms (53%) | | Release (dont link) | 738 ms | 656 ms | 377 ms | 279 ms (43%) | 459 ms (62%) | iPhone X -------- | Configuration | Before | After fix 1 | After fix 2 | Improvement from fix 1 to fix 2 | Cumulative improvement | | ------------------- | ------ | ----------: | -----------: | ------------------------------: | ---------------------: | | Release (link all) | 98 ms | 99 ms | 42 ms | 57 ms (58%) | 56 ms (57%) | | Release (dont link) | 197 ms | 153 ms | 91 ms | 62 ms (41%) | 106 ms (54%) | When linking all assemblies, the type map has 24 entries, and when not linking at all it has 2993 entries. This is part 2 of multiple fixes for #4936. --- src/ObjCRuntime/Class.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/ObjCRuntime/Class.cs b/src/ObjCRuntime/Class.cs index 200819b31f24..d348b57f167e 100644 --- a/src/ObjCRuntime/Class.cs +++ b/src/ObjCRuntime/Class.cs @@ -25,6 +25,7 @@ public partial class Class : INativeObject // We use the last significant bit of the IntPtr to store if this is a custom class or not. static Dictionary type_to_class; // accessed from multiple threads, locking required. + static Type[] class_to_type; internal IntPtr handle; @@ -33,12 +34,15 @@ internal unsafe static void Initialize (Runtime.InitializationOptions* options) { type_to_class = new Dictionary (Runtime.TypeEqualityComparer); - if (!Runtime.DynamicRegistrationSupported) - return; // Only the dynamic registrar needs the list of registered assemblies. - var map = options->RegistrationMap; if (map == null) return; + + class_to_type = new Type [map->map_count]; + + if (!Runtime.DynamicRegistrationSupported) + return; // Only the dynamic registrar needs the list of registered assemblies. + for (int i = 0; i < map->assembly_count; i++) { var ptr = Marshal.ReadIntPtr (map->assembly, i * IntPtr.Size); @@ -340,10 +344,14 @@ internal unsafe static Type FindType (IntPtr @class, out bool is_custom_type) return null; } + Type type = class_to_type [mapIndex]; + if (type != null) + return type; + // Resolve the map entry we found to a managed type var type_reference = map->map [mapIndex].type_reference; var member = ResolveTokenReference (type_reference, 0x02000000); - var type = member as Type; + type = member as Type; if (type == null && member != null) throw ErrorHelper.CreateError (8022, $"Expected the token reference 0x{type_reference:X} to be a type, but it's a {member.GetType ().Name}. Please file a bug report at https://github.com/xamarin/xamarin-macios/issues/new."); @@ -352,6 +360,8 @@ internal unsafe static Type FindType (IntPtr @class, out bool is_custom_type) Console.WriteLine ($"FindType (0x{@class:X} = {Marshal.PtrToStringAuto (class_getName (@class))}) => {type.FullName}; is custom: {is_custom_type} (token reference: 0x{type_reference:X})."); #endif + class_to_type [mapIndex] = type; + return type; }