Skip to content

Commit

Permalink
[Class] Make looking up a System.Type given a native Class instance f…
Browse files Browse the repository at this point in the history
…aster

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: rolfbjarne/TestApp@004283d

Fix 1 refers to PR xamarin#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 xamarin#4936.
  • Loading branch information
rolfbjarne committed Oct 19, 2018
1 parent 900356c commit ddba7b9
Showing 1 changed file with 14 additions and 4 deletions.
18 changes: 14 additions & 4 deletions src/ObjCRuntime/Class.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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, IntPtr> type_to_class; // accessed from multiple threads, locking required.
static Type[] class_to_type;

internal IntPtr handle;

Expand All @@ -33,12 +34,15 @@ internal unsafe static void Initialize (Runtime.InitializationOptions* options)
{
type_to_class = new Dictionary<Type, IntPtr> (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);
Expand Down Expand Up @@ -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.");
Expand All @@ -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;
}

Expand Down

0 comments on commit ddba7b9

Please sign in to comment.