[Class] Make looking up a System.Type given a native Class instance faster (#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: 004283d7b6

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.
This commit is contained in:
Rolf Bjarne Kvinge 2018-10-19 16:04:36 +02:00 коммит произвёл GitHub
Родитель 900356c2e6
Коммит ac87108152
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 14 добавлений и 4 удалений

Просмотреть файл

@ -25,6 +25,7 @@ namespace ObjCRuntime {
// 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;
@ -33,12 +34,15 @@ namespace ObjCRuntime {
{
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);
@ -340,10 +344,14 @@ namespace ObjCRuntime {
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 @@ namespace ObjCRuntime {
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;
}