[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:
Родитель
900356c2e6
Коммит
ac87108152
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче