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 (#5013)

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 #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.
  • Loading branch information
rolfbjarne authored Oct 19, 2018
1 parent 900356c commit ac87108
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

1 comment on commit ac87108

@xamarin-release-manager
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Jenkins job (on internal Jenkins) succeeded

Build succeeded
API Diff (from stable)
ℹ️ API Diff (from PR only) (please review changes)
Generator Diff (no change)
Test run succeeded

Please sign in to comment.