[runtime] Change MonoDomain::refobject_hash to use MonoConcGHashTable.
authorRodrigo Kumpera <kumpera@gmail.com>
Mon, 29 May 2017 03:16:29 +0000 (20:16 -0700)
committerRodrigo Kumpera <kumpera@gmail.com>
Mon, 29 May 2017 03:16:29 +0000 (20:16 -0700)
This change massively improves reflection query scalability.

Given this benchmark and my 4 cores laptop:

```
const int T_C = 4;
var list = new List<Thread> ();
bool done = false;
int count = 0;
for (int i = 0; i < T_C; ++i) {
var t = new Thread(() => {
while (!done) {
typeof (Driver)
.GetMethods (
BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Instance | BindingFlags.Static);
Interlocked.Increment (ref count);
}
});
t.Start ();
list.Add (t);
}

Thread.Sleep (5000);
done = true;
foreach (var t in list)
t.Join ();
Console.WriteLine ("Got {0} lists done", count);
```

This change makes us go from 166.725 queries/s to 5.140.821 queries/s. Or 30x faster.

mono/metadata/domain-internals.h
mono/metadata/mono-conc-hash.c
mono/metadata/reflection-cache.h
mono/metadata/reflection.c

index f235f01c01ac8f090d63012133210f13219c95b4..6d8042c07680206f4ed4778cf056266fa67bba2f 100644 (file)
@@ -12,6 +12,7 @@
 #include <mono/metadata/lock-tracer.h>
 #include <mono/utils/mono-codeman.h>
 #include <mono/metadata/mono-hash.h>
+#include <mono/metadata/mono-conc-hash.h>
 #include <mono/utils/mono-compiler.h>
 #include <mono/utils/mono-internal-hash.h>
 #include <mono/metadata/mempool-internals.h>
@@ -339,7 +340,7 @@ struct _MonoDomain {
        MonoGHashTable     *ldstr_table;
        /* hashtables for Reflection handles */
        MonoGHashTable     *type_hash;
-       MonoGHashTable     *refobject_hash;
+       MonoConcGHashTable     *refobject_hash;
        /* maps class -> type initialization exception object */
        MonoGHashTable    *type_init_exception_hash;
        /* maps delegate trampoline addr -> delegate object */
index 1a71aa7a11afcfda68e823042447efdaa4c51b36..c0bdb0219e814caa7146d2a4cc7d85786e4a89fd 100644 (file)
@@ -201,13 +201,14 @@ mono_conc_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func,
        hash->hash_func = hash_func;
        hash->equal_func = key_equal_func;
 
-       hash->table = conc_table_new (hash, INITIAL_SIZE);
        hash->element_count = 0;
        hash->overflow_count = (int)(INITIAL_SIZE * LOAD_FACTOR);
-
        hash->gc_type = type;
        hash->source = source;
        hash->msg = msg;
+
+       hash->table = conc_table_new (hash, INITIAL_SIZE);
+
        if (type > MONO_HASH_KEY_VALUE_GC)
                g_error ("wrong type for gc hashtable");
 
index 5a0e06102b0f13916188cae94c77280996beaa7f..8ba661c7ac8e9ed0f7c3255c3ceb830a79108ee1 100644 (file)
@@ -48,16 +48,17 @@ cache_object (MonoDomain *domain, MonoClass *klass, gpointer item, MonoObject* o
        ReflectedEntry pe;
        pe.item = item;
        pe.refclass = klass;
+
        mono_domain_lock (domain);
        if (!domain->refobject_hash)
-               domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
+               domain->refobject_hash = mono_conc_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
 
-       obj = (MonoObject*) mono_g_hash_table_lookup (domain->refobject_hash, &pe);
+       obj = (MonoObject*) mono_conc_g_hash_table_lookup (domain->refobject_hash, &pe);
        if (obj == NULL) {
                ReflectedEntry *e = ALLOC_REFENTRY;
                e->item = item;
                e->refclass = klass;
-               mono_g_hash_table_insert (domain->refobject_hash, e, o);
+               mono_conc_g_hash_table_insert (domain->refobject_hash, e, o);
                obj = o;
        }
        mono_domain_unlock (domain);
@@ -71,16 +72,17 @@ cache_object_handle (MonoDomain *domain, MonoClass *klass, gpointer item, MonoOb
        ReflectedEntry pe;
        pe.item = item;
        pe.refclass = klass;
+
        mono_domain_lock (domain);
        if (!domain->refobject_hash)
-               domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
+               domain->refobject_hash = mono_conc_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
 
-       MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_g_hash_table_lookup (domain->refobject_hash, &pe));
+       MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_conc_g_hash_table_lookup (domain->refobject_hash, &pe));
        if (MONO_HANDLE_IS_NULL (obj)) {
                ReflectedEntry *e = ALLOC_REFENTRY;
                e->item = item;
                e->refclass = klass;
-               mono_g_hash_table_insert (domain->refobject_hash, e, MONO_HANDLE_RAW (o));
+               mono_conc_g_hash_table_insert (domain->refobject_hash, e, MONO_HANDLE_RAW (o));
                MONO_HANDLE_ASSIGN (obj, o);
        }
        mono_domain_unlock (domain);
@@ -96,11 +98,11 @@ check_object_handle (MonoDomain* domain, MonoClass *klass, gpointer item)
        ReflectedEntry e;
        e.item = item;
        e.refclass = klass;
-       mono_domain_lock (domain);
-       if (!domain->refobject_hash)
-               domain->refobject_hash = mono_g_hash_table_new_type (reflected_hash, reflected_equal, MONO_HASH_VALUE_GC, MONO_ROOT_SOURCE_DOMAIN, "domain reflection objects table");
-       MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_g_hash_table_lookup (domain->refobject_hash, &e));
-       mono_domain_unlock (domain);
+       MonoConcGHashTable *hash = domain->refobject_hash;
+       if (!hash)
+               return MONO_HANDLE_NEW (MonoObject, NULL);
+
+       MonoObjectHandle obj = MONO_HANDLE_NEW (MonoObject, mono_conc_g_hash_table_lookup (hash, &e));
        return obj;
 }
 
index fe80ea7027c03b5533976f925c5f114680c065d8..f7d912d47c80dfac2ef03a35436bcee57fc4e290 100644 (file)
@@ -186,8 +186,9 @@ clear_cached_object (MonoDomain *domain, gpointer o, MonoClass *klass)
 
                pe.item = o;
                pe.refclass = klass;
-               if (mono_g_hash_table_lookup_extended (domain->refobject_hash, &pe, &orig_pe, &orig_value)) {
-                       mono_g_hash_table_remove (domain->refobject_hash, &pe);
+
+               if (mono_conc_g_hash_table_lookup_extended (domain->refobject_hash, &pe, &orig_pe, &orig_value)) {
+                       mono_conc_g_hash_table_remove (domain->refobject_hash, &pe);
                        FREE_REFENTRY (orig_pe);
                }
        }
@@ -208,9 +209,9 @@ mono_reflection_cleanup_domain (MonoDomain *domain)
        if (domain->refobject_hash) {
 /*let's avoid scanning the whole hashtable if not needed*/
 #ifdef REFENTRY_REQUIRES_CLEANUP
-               mono_g_hash_table_foreach (domain->refobject_hash, cleanup_refobject_hash, NULL);
+               mono_conc_g_hash_table_foreach (domain->refobject_hash, cleanup_refobject_hash, NULL);
 #endif
-               mono_g_hash_table_destroy (domain->refobject_hash);
+               mono_conc_g_hash_table_destroy (domain->refobject_hash);
                domain->refobject_hash = NULL;
        }
 }