From eb887a8c74a4b7444154200638fc336d0d0f198f Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Mon, 30 Sep 2019 21:15:42 +0300 Subject: [PATCH] [sgen] Add stats for allocated gchandles (#17074) --- mono/sgen/sgen-gc.c | 4 +++ mono/sgen/sgen-gc.h | 4 +++ mono/sgen/sgen-gchandles.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++ mono/sgen/sgen-internal.c | 1 + 4 files changed, 92 insertions(+) diff --git a/mono/sgen/sgen-gc.c b/mono/sgen/sgen-gc.c index 4697689c2d3..4dcfbee116d 100644 --- a/mono/sgen/sgen-gc.c +++ b/mono/sgen/sgen-gc.c @@ -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=\n"); fprintf (stderr, " binary-protocol=[:]\n"); fprintf (stderr, " nursery-canaries\n"); diff --git a/mono/sgen/sgen-gc.h b/mono/sgen/sgen-gc.h index e1ef721974a..313c28e9535 100644 --- a/mono/sgen/sgen-gc.h +++ b/mono/sgen/sgen-gc.h @@ -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); diff --git a/mono/sgen/sgen-gchandles.c b/mono/sgen/sgen-gchandles.c index 0fb952d124f..1ca10685a8c 100644 --- a/mono/sgen/sgen-gchandles.c +++ b/mono/sgen/sgen-gchandles.c @@ -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 diff --git a/mono/sgen/sgen-internal.c b/mono/sgen/sgen-internal.c index 49ab78651c2..8676f853663 100644 --- a/mono/sgen/sgen-internal.c +++ b/mono/sgen/sgen-internal.c @@ -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"; -- 2.11.4.GIT