[sgen] Add stats for allocated gchandles (mono/mono#17074)
authorVlad Brezae <brezaevlad@gmail.com>
Mon, 30 Sep 2019 18:15:42 +0000 (21:15 +0300)
committerGitHub <noreply@github.com>
Mon, 30 Sep 2019 18:15:42 +0000 (21:15 +0300)
Commit migrated from https://github.com/mono/mono/commit/eb887a8c74a4b7444154200638fc336d0d0f198f

src/mono/mono/sgen/sgen-gc.c
src/mono/mono/sgen/sgen-gc.h
src/mono/mono/sgen/sgen-gchandles.c
src/mono/mono/sgen/sgen-internal.c

index 4697689..4dcfbee 100644 (file)
@@ -1786,6 +1786,7 @@ collect_nursery (const char *reason, gboolean is_overflow)
        SGEN_LOG (2, "Old generation scan: %lld usecs", (long long)(TV_ELAPSED (atv, btv) / 10));
 
        sgen_pin_stats_report ();
+       sgen_gchandle_stats_report ();
 
        TV_GETTIME (atv);
        time_minor_scan_pinned += TV_ELAPSED (btv, atv);
@@ -3611,6 +3612,8 @@ sgen_gc_init (void)
                                debug_print_allowance = TRUE;
                        } else if (!strcmp (opt, "print-pinning")) {
                                sgen_pin_stats_enable ();
+                       } else if (!strcmp (opt, "print-gchandles")) {
+                               sgen_gchandle_stats_enable ();
                        } else if (!strcmp (opt, "verify-before-allocs")) {
                                sgen_verify_before_allocs = 1;
                                sgen_has_per_allocation_action = TRUE;
@@ -3719,6 +3722,7 @@ sgen_gc_init (void)
                                fprintf (stderr, "  check-scan-starts\n");
                                fprintf (stderr, "  print-allowance\n");
                                fprintf (stderr, "  print-pinning\n");
+                               fprintf (stderr, "  print-gchandles\n");
                                fprintf (stderr, "  heap-dump=<filename>\n");
                                fprintf (stderr, "  binary-protocol=<filename>[:<file-size-limit>]\n");
                                fprintf (stderr, "  nursery-canaries\n");
index e1ef721..313c28e 100644 (file)
@@ -322,6 +322,7 @@ enum {
        INTERNAL_MEM_STATISTICS,
        INTERNAL_MEM_STAT_PINNED_CLASS,
        INTERNAL_MEM_STAT_REMSET_CLASS,
+       INTERNAL_MEM_STAT_GCHANDLE_CLASS,
        INTERNAL_MEM_GRAY_QUEUE,
        INTERNAL_MEM_MS_TABLES,
        INTERNAL_MEM_MS_BLOCK_INFO,
@@ -470,6 +471,9 @@ void sgen_pin_stats_register_object (GCObject *obj, int generation);
 void sgen_pin_stats_register_global_remset (GCObject *obj);
 void sgen_pin_stats_report (void);
 
+void sgen_gchandle_stats_enable (void);
+void sgen_gchandle_stats_report (void);
+
 void sgen_sort_addresses (void **array, size_t size);
 void sgen_add_to_global_remset (gpointer ptr, GCObject *obj);
 
index 0fb952d..1ca1068 100644 (file)
@@ -20,6 +20,15 @@ static volatile guint32 stat_gc_handles_allocated = 0;
 static volatile guint32 stat_gc_handles_max_allocated = 0;
 #endif
 
+
+typedef struct {
+        size_t num_handles [HANDLE_TYPE_MAX];
+} GCHandleClassEntry;
+
+static gboolean do_gchandle_stats = FALSE;
+
+static SgenHashTable gchandle_class_hash_table = SGEN_HASH_TABLE_INIT (INTERNAL_MEM_STATISTICS, INTERNAL_MEM_STAT_GCHANDLE_CLASS, sizeof (GCHandleClassEntry), g_str_hash, g_str_equal);
+
 /*
  * A table of GC handle data, implementing a simple lock-free bitmap allocator.
  *
@@ -515,6 +524,80 @@ sgen_register_obj_with_weak_fields (GCObject *obj)
 }
 
 void
+sgen_gchandle_stats_enable (void)
+{
+       do_gchandle_stats = TRUE;
+}
+
+static void
+sgen_gchandle_stats_register_vtable (GCVTable vtable, int handle_type)
+{
+       GCHandleClassEntry *entry;
+
+       char *name = g_strdup_printf ("%s.%s", sgen_client_vtable_get_namespace (vtable), sgen_client_vtable_get_name (vtable));
+       entry = (GCHandleClassEntry*) sgen_hash_table_lookup (&gchandle_class_hash_table, name);
+
+       if (entry) {
+               g_free (name);
+       } else {
+               // Create the entry for this class and get the address of it
+               GCHandleClassEntry empty_entry;
+               memset (&empty_entry, 0, sizeof (GCHandleClassEntry));
+               sgen_hash_table_replace (&gchandle_class_hash_table, name, &empty_entry, NULL);
+               entry = (GCHandleClassEntry*) sgen_hash_table_lookup (&gchandle_class_hash_table, name);
+       }
+
+       entry->num_handles [handle_type]++;
+}
+
+static void
+sgen_gchandle_stats_count (void)
+{
+       int i;
+
+       sgen_hash_table_clean (&gchandle_class_hash_table);
+
+       for (i = HANDLE_TYPE_MIN; i < HANDLE_TYPE_MAX; i++) {
+               HandleData *handles = gc_handles_for_type ((GCHandleType)i);
+               SgenArrayList *array = &handles->entries_array;
+               volatile gpointer *slot;
+               gpointer hidden, revealed;
+
+               SGEN_ARRAY_LIST_FOREACH_SLOT (array, slot) {
+                       hidden = *slot;
+                       revealed = MONO_GC_REVEAL_POINTER (hidden, MONO_GC_HANDLE_TYPE_IS_WEAK (i));
+
+                       if (MONO_GC_HANDLE_IS_OBJECT_POINTER (hidden))
+                               sgen_gchandle_stats_register_vtable (SGEN_LOAD_VTABLE (revealed), i);
+               } SGEN_ARRAY_LIST_END_FOREACH_SLOT;
+       }
+}
+
+void
+sgen_gchandle_stats_report (void)
+{
+       char *name;
+       GCHandleClassEntry *gchandle_entry;
+
+       if (!do_gchandle_stats)
+               return;
+
+       sgen_gchandle_stats_count ();
+
+       mono_gc_printf (sgen_gc_debug_file, "\n%-60s  %10s  %10s  %10s\n", "Class", "Normal", "Weak", "Pinned");
+       SGEN_HASH_TABLE_FOREACH (&gchandle_class_hash_table, char *, name, GCHandleClassEntry *, gchandle_entry) {
+               mono_gc_printf (sgen_gc_debug_file, "%-60s", name);
+               mono_gc_printf (sgen_gc_debug_file, "  %10ld", (long)gchandle_entry->num_handles [HANDLE_NORMAL]);
+               size_t weak_handles = gchandle_entry->num_handles [HANDLE_WEAK] +
+                               gchandle_entry->num_handles [HANDLE_WEAK_TRACK] +
+                               gchandle_entry->num_handles [HANDLE_WEAK_FIELDS];
+               mono_gc_printf (sgen_gc_debug_file, "  %10ld", (long)weak_handles);
+               mono_gc_printf (sgen_gc_debug_file, "  %10ld", (long)gchandle_entry->num_handles [HANDLE_PINNED]);
+               mono_gc_printf (sgen_gc_debug_file, "\n");
+       } SGEN_HASH_TABLE_FOREACH_END;
+}
+
+void
 sgen_init_gchandles (void)
 {
 #ifdef HEAVY_STATISTICS
index 49ab786..8676f85 100644 (file)
@@ -138,6 +138,7 @@ description_for_type (int type)
        case INTERNAL_MEM_STATISTICS: return "statistics";
        case INTERNAL_MEM_STAT_PINNED_CLASS: return "pinned-class";
        case INTERNAL_MEM_STAT_REMSET_CLASS: return "remset-class";
+       case INTERNAL_MEM_STAT_GCHANDLE_CLASS: return "gchandle-class";
        case INTERNAL_MEM_GRAY_QUEUE: return "gray-queue";
        case INTERNAL_MEM_MS_TABLES: return "marksweep-tables";
        case INTERNAL_MEM_MS_BLOCK_INFO: return "marksweep-block-info";