diff --git a/mono/metadata/sgen-bridge.c b/mono/metadata/sgen-bridge.c index e675f91dd1e26a2e4565da8143dda6eca7dcde3b..9c7920d416659115b30918c8c03c87e7dd5322f9 100644 --- a/mono/metadata/sgen-bridge.c +++ b/mono/metadata/sgen-bridge.c @@ -92,6 +92,11 @@ typedef struct _HashEntry { int scc_index; } HashEntry; +typedef struct { + HashEntry entry; + double weight; +} HashEntryWithAccounting; + typedef struct _SCC { int index; int api_index; @@ -107,6 +112,7 @@ static int current_time; gboolean bridge_processing_in_progress = FALSE; +static gboolean bridge_accounting_enabled = FALSE; /* Core functions */ @@ -401,6 +407,13 @@ mono_gc_wait_for_bridge_processing (void) sgen_gc_unlock (); } +void +sgen_enable_bridge_accounting (void) +{ + bridge_accounting_enabled = TRUE; + hash_table = (SgenHashTable)SGEN_HASH_TABLE_INIT (INTERNAL_MEM_BRIDGE_HASH_TABLE, INTERNAL_MEM_BRIDGE_HASH_TABLE_ENTRY, sizeof (HashEntryWithAccounting), mono_aligned_addr_hash, NULL); +} + void mono_gc_register_bridge_callbacks (MonoGCBridgeCallbacks *callbacks) { @@ -771,6 +784,43 @@ sgen_bridge_processing_finish (int generation) } } + /* + * Compute the weight of each object. The weight of an object is its size plus the size of all + * objects it points do. When the an object is pointed by multiple objects we distribute it's weight + * equally among them. This distribution gives a rough estimate of the real impact of making the object + * go away. + * + * The reasoning for this model is that complex graphs with single roots will have a bridge with very high + * value in comparison to others. + * + * The all_entries array has all objects topologically sorted. To correctly propagate the weights it must be + * done in reverse topological order - so we calculate the weight of the pointed-to objects before processing + * pointer-from objects. + * + * We log those objects in the opposite order for no particular reason. The other constrain is that it should use the same + * direction as the other logging loop that records live/dead information. + */ + if (bridge_accounting_enabled) { + for (i = hash_table.num_entries - 1; i >= 0; --i) { + double w; + HashEntryWithAccounting *entry = (HashEntryWithAccounting*)all_entries [i]; + + entry->weight += (double)sgen_safe_object_get_size (entry->entry.obj); + w = entry->weight / dyn_array_ptr_size (&entry->entry.srcs); + for (j = 0; j < dyn_array_ptr_size (&entry->entry.srcs); ++j) { + HashEntryWithAccounting *other = (HashEntryWithAccounting *)dyn_array_ptr_get (&entry->entry.srcs, j); + other->weight += w; + } + } + for (i = 0; i < hash_table.num_entries; ++i) { + HashEntryWithAccounting *entry = (HashEntryWithAccounting*)all_entries [i]; + if (entry->entry.is_bridge) { + MonoClass *klass = ((MonoVTable*)SGEN_LOAD_VTABLE (entry->entry.obj))->klass; + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, "OBJECT %s::%s (%p) weight %f", klass->name_space, klass->name, entry->entry.obj, entry->weight); + } + } + } + sccs_size = dyn_array_scc_size (&sccs); for (i = 0; i < hash_table.num_entries; ++i) { @@ -897,6 +947,17 @@ sgen_bridge_processing_finish (int generation) sgen_hash_table_clean (&alive_hash); + if (bridge_accounting_enabled) { + for (i = 0; i < num_sccs; ++i) { + for (j = 0; j < api_sccs [i]->num_objs; ++j) + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_GC, + "OBJECT %s (%p) SCC [%d] %s", + sgen_safe_name (api_sccs [i]->objs [j]), api_sccs [i]->objs [j], + i, + api_sccs [i]->is_alive ? "ALIVE" : "DEAD"); + } + } + /* free callback data */ for (i = 0; i < num_sccs; ++i) { diff --git a/mono/metadata/sgen-gc.c b/mono/metadata/sgen-gc.c index 5fe05625497fac22ffd092ac1c74a4360fa7ba96..57ddc6d0797a2628707cceec534b39b8c5413967 100644 --- a/mono/metadata/sgen-gc.c +++ b/mono/metadata/sgen-gc.c @@ -4961,6 +4961,8 @@ mono_gc_base_init (void) } else if (g_str_has_prefix (opt, "binary-protocol=")) { char *filename = strchr (opt, '=') + 1; binary_protocol_init (filename); + } else if (!strcmp (opt, "enable-bridge-accounting")) { + sgen_enable_bridge_accounting (); } else { sgen_env_var_error (MONO_GC_DEBUG_NAME, "Ignoring.", "Unknown option `%s`.", opt); @@ -4989,6 +4991,7 @@ mono_gc_base_init (void) fprintf (stderr, " print-pinning\n"); fprintf (stderr, " heap-dump=\n"); fprintf (stderr, " binary-protocol=\n"); + fprintf (stderr, " enable-bridge-accounting\n"); fprintf (stderr, "\n"); usage_printed = TRUE; diff --git a/mono/metadata/sgen-gc.h b/mono/metadata/sgen-gc.h index 604b9d9897e68141d8a6be750a459b9e93caf31f..506e4d5340665d14a975e7c8980301dd6c394945 100644 --- a/mono/metadata/sgen-gc.h +++ b/mono/metadata/sgen-gc.h @@ -807,6 +807,7 @@ MonoGCBridgeObjectKind sgen_bridge_class_kind (MonoClass *class) MONO_INTERNAL; void sgen_mark_bridge_object (MonoObject *obj) MONO_INTERNAL; void sgen_bridge_register_finalized_object (MonoObject *object) MONO_INTERNAL; void sgen_bridge_describe_pointer (MonoObject *object) MONO_INTERNAL; +void sgen_enable_bridge_accounting (void) MONO_INTERNAL; void sgen_mark_togglerefs (char *start, char *end, ScanCopyContext ctx) MONO_INTERNAL; void sgen_clear_togglerefs (char *start, char *end, ScanCopyContext ctx) MONO_INTERNAL;