diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs index a204195730d0b..9ee421942d509 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs @@ -54,6 +54,8 @@ enum LogEventType { HeapEnd = 1 << 4, HeapObject = 2 << 4, HeapRoots = 3 << 4, + HeapRootRegister = 4 << 4, + HeapRootUnregister = 5 << 4, SampleHit = 0 << 4, SampleUnmanagedSymbol = 1 << 4, @@ -214,4 +216,23 @@ public enum LogHeapshotMode { Milliseconds = 3, Collections = 4, } + + // mono/metadata/mono-gc.h : MonoGCRootSource + public enum LogHeapRootSource { + External = 0, + Stack = 1, + FinalizerQueue = 2, + StaticVariable = 3, + ThreadLocalVariable = 4, + ContextLocalVariable = 5, + GCHandle = 6, + JIT = 7, + Threading = 8, + AppDomain = 9, + Reflection = 10, + Marshal = 11, + ThreadPool = 12, + Debugger = 13, + RuntimeHandle = 14, + } } diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEventVisitor.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEventVisitor.cs index b49416cd2c1fa..61fadf10b0f9e 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEventVisitor.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEventVisitor.cs @@ -94,6 +94,14 @@ public virtual void Visit (HeapRootsEvent ev) { } + public virtual void Visit (HeapRootRegisterEvent ev) + { + } + + public virtual void Visit (HeapRootUnregisterEvent ev) + { + } + public virtual void Visit (GCEvent ev) { } diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEvents.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEvents.cs index 113bf3edc114f..fbfbee2a45991 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEvents.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEvents.cs @@ -257,6 +257,8 @@ public struct HeapRoot { public LogHeapRootAttributes Attributes { get; internal set; } public long ExtraInfo { get; internal set; } + + public long AddressPointer { get; internal set; } } public long MaxGenerationCollectionCount { get; internal set; } @@ -269,6 +271,28 @@ internal override void Accept (LogEventVisitor visitor) } } + public sealed class HeapRootRegisterEvent : LogEvent { + public long Start { get; internal set; } + public long Size { get; internal set; } + public LogHeapRootSource Kind { get; internal set; } + public long Key { get; internal set; } + public string Message { get; internal set; } + + internal override void Accept (LogEventVisitor visitor) + { + visitor.Visit (this); + } + } + + public sealed class HeapRootUnregisterEvent : LogEvent { + public long Start { get; internal set; } + + internal override void Accept (LogEventVisitor visitor) + { + visitor.Visit (this); + } + } + public sealed class GCEvent : LogEvent { public LogGCEvent Type { get; internal set; } diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProcessor.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProcessor.cs index d40897c3a7e60..cce28a1607afe 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProcessor.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogProcessor.cs @@ -392,44 +392,73 @@ LogEvent ReadEvent () ev = new HeapEndEvent (); break; case LogEventType.HeapObject: { - HeapObjectEvent hoe = new HeapObjectEvent { + var refs = Array.Empty (); + ev = new HeapObjectEvent { ObjectPointer = ReadObject (), ClassPointer = ReadPointer (), ObjectSize = (long) _reader.ReadULeb128 (), + References = refs = new HeapObjectEvent.HeapObjectReference [(int) _reader.ReadULeb128 ()], }; - var list = new HeapObjectEvent.HeapObjectReference [(int) _reader.ReadULeb128 ()]; - - for (var i = 0; i < list.Length; i++) { - list [i] = new HeapObjectEvent.HeapObjectReference { + for (var i = 0; i < refs.Length; i++) { + refs [i] = new HeapObjectEvent.HeapObjectReference { Offset = (long) _reader.ReadULeb128 (), ObjectPointer = ReadObject (), }; } - hoe.References = list; - ev = hoe; - break; } case LogEventType.HeapRoots: { - // TODO: This entire event makes no sense. - var hre = new HeapRootsEvent (); - var list = new HeapRootsEvent.HeapRoot [(int) _reader.ReadULeb128 ()]; - - hre.MaxGenerationCollectionCount = (long) _reader.ReadULeb128 (); + var roots = Array.Empty (); + ev = new HeapRootsEvent () { + Roots = roots = new HeapRootsEvent.HeapRoot [(int) _reader.ReadULeb128 ()], + MaxGenerationCollectionCount = StreamHeader.FormatVersion < 15 ? (long) _reader.ReadULeb128 () : -1, + }; - for (var i = 0; i < list.Length; i++) { - list [i] = new HeapRootsEvent.HeapRoot { - ObjectPointer = ReadObject (), - Attributes = StreamHeader.FormatVersion == 13 ? (LogHeapRootAttributes) _reader.ReadByte () : (LogHeapRootAttributes) _reader.ReadULeb128 (), - ExtraInfo = (long) _reader.ReadULeb128 (), - }; + for (var i = 0; i < roots.Length; i++) { + if (StreamHeader.FormatVersion < 13) { + roots [i] = new HeapRootsEvent.HeapRoot { + ObjectPointer = ReadObject (), + Attributes = (LogHeapRootAttributes) _reader.ReadULeb128 (), + ExtraInfo = (long) _reader.ReadULeb128 (), + AddressPointer = -1, + }; + } else if (StreamHeader.FormatVersion < 15) { + roots [i] = new HeapRootsEvent.HeapRoot { + ObjectPointer = ReadObject (), + Attributes = (LogHeapRootAttributes) _reader.ReadByte (), + ExtraInfo = (long) _reader.ReadULeb128 (), + AddressPointer = -1, + }; + } else { + roots [i] = new HeapRootsEvent.HeapRoot { + ObjectPointer = ReadObject (), + Attributes = (LogHeapRootAttributes) 0, + ExtraInfo = 0, + AddressPointer = ReadPointer (), + }; + } } - hre.Roots = list; - ev = hre; + break; + } + case LogEventType.HeapRootRegister: { + ev = new HeapRootRegisterEvent () { + Start = ReadPointer (), + Size = (long) _reader.ReadULeb128 (), + Kind = (LogHeapRootSource) _reader.ReadByte (), + Key = ReadPointer (), + Message = _reader.ReadCString () + }; + + break; + } + case LogEventType.HeapRootUnregister: { + ev = new HeapRootUnregisterEvent () { + Start = ReadPointer () + }; break; } @@ -586,7 +615,7 @@ long ReadPointer () long ReadObject () { - return _reader.ReadSLeb128 () + _bufferHeader.ObjectBase << 3; + return (_reader.ReadSLeb128 () + _bufferHeader.ObjectBase) << 3; } long ReadMethod () diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c index 2bc3052ae690f..4b018e8bb89af 100644 --- a/mono/metadata/boehm-gc.c +++ b/mono/metadata/boehm-gc.c @@ -548,21 +548,21 @@ register_root (gpointer arg) } int -mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg) +mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, void *key, const char *msg) { RootData root_data; root_data.start = start; /* Boehm root processing requires one byte past end of region to be scanned */ root_data.end = start + size + 1; GC_call_with_alloc_lock (register_root, &root_data); - + MONO_PROFILER_RAISE (gc_root_register, ((const mono_byte*)start, size, source, key, msg)); return TRUE; } int -mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg) +mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) { - return mono_gc_register_root (start, size, descr, source, msg); + return mono_gc_register_root (start, size, descr, source, key, msg); } static gpointer @@ -577,6 +577,7 @@ void mono_gc_deregister_root (char* addr) { GC_call_with_alloc_lock (deregister_root, addr); + MONO_PROFILER_RAISE (gc_root_unregister, ((const mono_byte*)addr)); } static void @@ -695,14 +696,17 @@ mono_gc_make_root_descr_all_refs (int numbits) } void* -mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, const char *msg) +mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, void *key, const char *msg) { - return GC_MALLOC_UNCOLLECTABLE (size); + void *start = GC_MALLOC_UNCOLLECTABLE (size); + MONO_PROFILER_RAISE (gc_root_register, (start, size, source, key, msg)); + return start; } void mono_gc_free_fixed (void* addr) { + MONO_PROFILER_RAISE (gc_root_unregister, (addr)); GC_FREE (addr); } @@ -1658,7 +1662,7 @@ handle_data_alloc_entries (HandleData *handles) handles->entries = (void **)g_malloc0 (sizeof (*handles->entries) * handles->size); handles->domain_ids = (guint16 *)g_malloc0 (sizeof (*handles->domain_ids) * handles->size); } else { - handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table"); + handles->entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * handles->size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "gc handles table"); } handles->bitmap = (guint32 *)g_malloc0 (handles->size / CHAR_BIT); } @@ -1725,7 +1729,7 @@ handle_data_grow (HandleData *handles, gboolean track) handles->domain_ids = domain_ids; } else { gpointer *entries; - entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table"); + entries = (void **)mono_gc_alloc_fixed (sizeof (*handles->entries) * new_size, NULL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "gc handles table"); mono_gc_memmove_aligned (entries, handles->entries, sizeof (*handles->entries) * handles->size); mono_gc_free_fixed (handles->entries); handles->entries = entries; diff --git a/mono/metadata/custom-attrs.c b/mono/metadata/custom-attrs.c index 7c160a8486712..eb6a18f237fdf 100644 --- a/mono/metadata/custom-attrs.c +++ b/mono/metadata/custom-attrs.c @@ -761,7 +761,7 @@ create_custom_attr (MonoImage *image, MonoMethod *method, const guchar *data, gu memset (params, 0, sizeof (void*) * sig->param_count); } else { /* Allocate using GC so it gets GC tracking */ - params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, "custom attribute parameters"); + params = (void **)mono_gc_alloc_fixed (sig->param_count * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_REFLECTION, NULL, "custom attribute parameters"); } /* skip prolog */ diff --git a/mono/metadata/domain.c b/mono/metadata/domain.c index c0386177ce545..08e04990a33e7 100644 --- a/mono/metadata/domain.c +++ b/mono/metadata/domain.c @@ -292,6 +292,24 @@ mono_ptrarray_hash (gpointer *s) return hash; } +//g_malloc on sgen and mono_gc_alloc_fixed on boehm +static void* +gc_alloc_fixed_non_heap (size_t size) +{ + if (mono_gc_is_moving ()) + return g_malloc0 (size); + else + return mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, NULL, "Misc AppDomain Memory"); +} + +static void +gc_free_fixed_no_heap (void *ptr) +{ + if (mono_gc_is_moving ()) + return g_free (ptr); + else + return mono_gc_free_fixed (ptr); +} /* * Allocate an id for domain and set domain->domain_id. * LOCKING: must be called while holding appdomains_mutex. @@ -306,7 +324,8 @@ domain_id_alloc (MonoDomain *domain) int id = -1, i; if (!appdomains_list) { appdomain_list_size = 2; - appdomains_list = (MonoDomain **)mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "domains list"); + appdomains_list = (MonoDomain **)gc_alloc_fixed_non_heap (appdomain_list_size * sizeof (void*)); + } for (i = appdomain_next; i < appdomain_list_size; ++i) { if (!appdomains_list [i]) { @@ -328,9 +347,9 @@ domain_id_alloc (MonoDomain *domain) if (new_size >= (1 << 16)) g_assert_not_reached (); id = appdomain_list_size; - new_list = (MonoDomain **)mono_gc_alloc_fixed (new_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "domains list"); + new_list = (MonoDomain **)gc_alloc_fixed_non_heap (new_size * sizeof (void*)); memcpy (new_list, appdomains_list, appdomain_list_size * sizeof (void*)); - mono_gc_free_fixed (appdomains_list); + gc_free_fixed_no_heap (appdomains_list); appdomains_list = new_list; appdomain_list_size = new_size; } @@ -387,10 +406,9 @@ mono_domain_create (void) mono_appdomains_unlock (); if (!mono_gc_is_moving ()) { - domain = (MonoDomain *)mono_gc_alloc_fixed (sizeof (MonoDomain), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "domain object"); + domain = (MonoDomain *)mono_gc_alloc_fixed (sizeof (MonoDomain), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, NULL, "domain object"); } else { - domain = (MonoDomain *)mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc, MONO_ROOT_SOURCE_DOMAIN, "domain object"); - mono_gc_register_root ((char*)&(domain->MONO_DOMAIN_FIRST_GC_TRACKED), G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_LAST_GC_TRACKED) - G_STRUCT_OFFSET (MonoDomain, MONO_DOMAIN_FIRST_GC_TRACKED), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "misc domain fields"); + domain = (MonoDomain *)mono_gc_alloc_fixed (sizeof (MonoDomain), domain_gc_desc, MONO_ROOT_SOURCE_DOMAIN, NULL, "domain object"); } domain->shadow_serial = shadow_serial; domain->domain = NULL; @@ -952,7 +970,7 @@ mono_domain_foreach (MonoDomainFunc func, gpointer user_data) */ mono_appdomains_lock (); size = appdomain_list_size; - copy = (MonoDomain **)mono_gc_alloc_fixed (appdomain_list_size * sizeof (void*), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_DOMAIN, "temporary domains list"); + copy = (MonoDomain **)gc_alloc_fixed_non_heap (appdomain_list_size * sizeof (void*)); memcpy (copy, appdomains_list, appdomain_list_size * sizeof (void*)); mono_appdomains_unlock (); @@ -961,7 +979,7 @@ mono_domain_foreach (MonoDomainFunc func, gpointer user_data) func (copy [i], user_data); } - mono_gc_free_fixed (copy); + gc_free_fixed_no_heap (copy); } /* FIXME: maybe we should integrate this with mono_assembly_open? */ diff --git a/mono/metadata/gc-internals.h b/mono/metadata/gc-internals.h index d87746dee363a..75ba2e525e89c 100644 --- a/mono/metadata/gc-internals.h +++ b/mono/metadata/gc-internals.h @@ -22,7 +22,7 @@ #define mono_domain_finalizers_unlock(domain) mono_os_mutex_unlock (&(domain)->finalizable_objects_hash_lock); /* Register a memory area as a conservatively scanned GC root */ -#define MONO_GC_REGISTER_ROOT_PINNING(x,src,msg) mono_gc_register_root ((char*)&(x), sizeof(x), MONO_GC_DESCRIPTOR_NULL, (src), (msg)) +#define MONO_GC_REGISTER_ROOT_PINNING(x,src,key,msg) mono_gc_register_root ((char*)&(x), sizeof(x), MONO_GC_DESCRIPTOR_NULL, (src), (key), (msg)) #define MONO_GC_UNREGISTER_ROOT(x) mono_gc_deregister_root ((char*)&(x)) @@ -34,18 +34,18 @@ #define MONO_GC_ROOT_DESCR_FOR_FIXED(n) (mono_gc_is_moving () ? mono_gc_make_root_descr_all_refs (0) : MONO_GC_DESCRIPTOR_NULL) /* Register a memory location holding a single object reference as a GC root */ -#define MONO_GC_REGISTER_ROOT_SINGLE(x,src,msg) do { \ +#define MONO_GC_REGISTER_ROOT_SINGLE(x,src,key,msg) do { \ g_assert (sizeof (x) == sizeof (MonoObject*)); \ - mono_gc_register_root ((char*)&(x), sizeof(MonoObject*), mono_gc_make_root_descr_all_refs (1), (src), (msg)); \ + mono_gc_register_root ((char*)&(x), sizeof(MonoObject*), mono_gc_make_root_descr_all_refs (1), (src), (key),(msg)); \ } while (0) /* * This is used for fields which point to objects which are kept alive by other references * when using Boehm. */ -#define MONO_GC_REGISTER_ROOT_IF_MOVING(x,src,msg) do { \ +#define MONO_GC_REGISTER_ROOT_IF_MOVING(x,src,key,msg) do { \ if (mono_gc_is_moving ()) \ - MONO_GC_REGISTER_ROOT_SINGLE(x,src,msg); \ + MONO_GC_REGISTER_ROOT_SINGLE(x,src,key,msg); \ } while (0) #define MONO_GC_UNREGISTER_ROOT_IF_MOVING(x) do { \ @@ -121,7 +121,7 @@ gboolean mono_gc_user_markers_supported (void); * size bytes will be available from the returned address (ie, descr * must not be stored in the returned memory) */ -void* mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg); +void* mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg); void mono_gc_free_fixed (void* addr); /* make sure the gchandle was allocated for an object in domain */ @@ -140,7 +140,7 @@ MonoGCDescriptor mono_gc_make_descr_for_string (gsize *bitmap, int numbits); void mono_gc_register_for_finalization (MonoObject *obj, void *user_data); void mono_gc_add_memory_pressure (gint64 value); -MONO_API int mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg); +MONO_API int mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg); void mono_gc_deregister_root (char* addr); void mono_gc_finalize_domain (MonoDomain *domain); void mono_gc_run_finalize (void *obj, void *data); @@ -159,7 +159,7 @@ void mono_gc_suspend_finalizers (void); * FIXME: Add an API for clearing remset entries if a root with a user defined * mark routine is deleted. */ -int mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg); +int mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg); void mono_gc_wbarrier_set_root (gpointer ptr, MonoObject *value); diff --git a/mono/metadata/marshal.c b/mono/metadata/marshal.c index 0d047053f50bc..357e8a358141d 100644 --- a/mono/metadata/marshal.c +++ b/mono/metadata/marshal.c @@ -4022,7 +4022,7 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, /* to make it work with our special string constructors */ if (!string_dummy) { MonoError error; - MONO_GC_REGISTER_ROOT_SINGLE (string_dummy, MONO_ROOT_SOURCE_MARSHAL, "dummy marshal string"); + MONO_GC_REGISTER_ROOT_SINGLE (string_dummy, MONO_ROOT_SOURCE_MARSHAL, NULL, "dummy marshal string"); string_dummy = mono_string_new_checked (mono_get_root_domain (), "dummy", &error); mono_error_assert_ok (&error); } diff --git a/mono/metadata/mono-conc-hash.c b/mono/metadata/mono-conc-hash.c index f7a50b905cfd9..a7dfdef736772 100644 --- a/mono/metadata/mono-conc-hash.c +++ b/mono/metadata/mono-conc-hash.c @@ -53,9 +53,9 @@ conc_table_new (MonoConcGHashTable *hash, int size) table->gc_type = hash->gc_type; if (hash->gc_type & MONO_HASH_KEY_GC) - mono_gc_register_root_wbarrier ((char*)table->keys, sizeof (MonoObject*) * size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)table->keys, sizeof (MonoObject*) * size, mono_gc_make_vector_descr (), hash->source, NULL, hash->msg); if (hash->gc_type & MONO_HASH_VALUE_GC) - mono_gc_register_root_wbarrier ((char*)table->values, sizeof (MonoObject*) * size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)table->values, sizeof (MonoObject*) * size, mono_gc_make_vector_descr (), hash->source, NULL, hash->msg); return table; } diff --git a/mono/metadata/mono-gc.h b/mono/metadata/mono-gc.h index bd1262a67b8b6..00fb123255071 100644 --- a/mono/metadata/mono-gc.h +++ b/mono/metadata/mono-gc.h @@ -11,7 +11,9 @@ MONO_BEGIN_DECLS typedef int (*MonoGCReferences) (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, MonoObject **refs, uintptr_t *offsets, void *data); - +/* + * This enum is used by the profiler API when reporting root registration. + */ typedef enum { // Roots external to Mono. Embedders may only use this value. MONO_ROOT_SOURCE_EXTERNAL = 0, diff --git a/mono/metadata/mono-hash.c b/mono/metadata/mono-hash.c index 3074e86d37222..720f3d8ed4fab 100644 --- a/mono/metadata/mono-hash.c +++ b/mono/metadata/mono-hash.c @@ -162,9 +162,9 @@ mono_g_hash_table_new_type (GHashFunc hash_func, GEqualFunc key_equal_func, Mono g_error ("wrong type for gc hashtable"); if (hash->gc_type & MONO_HASH_KEY_GC) - mono_gc_register_root_wbarrier ((char*)hash->keys, sizeof (MonoObject*) * hash->table_size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)hash->keys, sizeof (MonoObject*) * hash->table_size, mono_gc_make_vector_descr (), hash->source, NULL, hash->msg); if (hash->gc_type & MONO_HASH_VALUE_GC) - mono_gc_register_root_wbarrier ((char*)hash->values, sizeof (MonoObject*) * hash->table_size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)hash->values, sizeof (MonoObject*) * hash->table_size, mono_gc_make_vector_descr (), hash->source, NULL, hash->msg); return hash; } @@ -221,9 +221,9 @@ rehash (MonoGHashTable *hash) data.values = g_new0 (MonoObject*, data.new_size); if (hash->gc_type & MONO_HASH_KEY_GC) - mono_gc_register_root_wbarrier ((char*)data.keys, sizeof (MonoObject*) * data.new_size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)data.keys, sizeof (MonoObject*) * data.new_size, mono_gc_make_vector_descr (), hash->source, NULL, hash->msg); if (hash->gc_type & MONO_HASH_VALUE_GC) - mono_gc_register_root_wbarrier ((char*)data.values, sizeof (MonoObject*) * data.new_size, mono_gc_make_vector_descr (), hash->source, hash->msg); + mono_gc_register_root_wbarrier ((char*)data.values, sizeof (MonoObject*) * data.new_size, mono_gc_make_vector_descr (), hash->source, NULL, hash->msg); if (!mono_threads_is_coop_enabled ()) { mono_gc_invoke_with_gc_lock (do_rehash, &data); diff --git a/mono/metadata/mono-ptr-array.h b/mono/metadata/mono-ptr-array.h index 61589f3bbbdec..a2ceca61a6199 100644 --- a/mono/metadata/mono-ptr-array.h +++ b/mono/metadata/mono-ptr-array.h @@ -36,7 +36,7 @@ typedef struct { (ARRAY).source = SOURCE; \ (ARRAY).msg = MSG; \ (ARRAY).data = INITIAL_SIZE > MONO_PTR_ARRAY_MAX_ON_STACK \ - ? (void **)mono_gc_alloc_fixed (sizeof (void*) * INITIAL_SIZE, mono_gc_make_root_descr_all_refs (INITIAL_SIZE), SOURCE, MSG) \ + ? (void **)mono_gc_alloc_fixed (sizeof (void*) * INITIAL_SIZE, mono_gc_make_root_descr_all_refs (INITIAL_SIZE), SOURCE, NULL, MSG) \ : g_newa (void*, MONO_PTR_ARRAY_MAX_ON_STACK); \ } while (0) @@ -47,7 +47,7 @@ typedef struct { #define mono_ptr_array_append(ARRAY, VALUE) do { \ if ((ARRAY).size >= (ARRAY).capacity) {\ - void **__tmp = (void **)mono_gc_alloc_fixed (sizeof (void*) * (ARRAY).capacity * 2, mono_gc_make_root_descr_all_refs ((ARRAY).capacity * 2), (ARRAY).source, (ARRAY).msg); \ + void **__tmp = (void **)mono_gc_alloc_fixed (sizeof (void*) * (ARRAY).capacity * 2, mono_gc_make_root_descr_all_refs ((ARRAY).capacity * 2), (ARRAY).source, NULL, (ARRAY).msg); \ mono_gc_memmove_aligned ((void *)__tmp, (ARRAY).data, (ARRAY).capacity * sizeof (void*)); \ if ((ARRAY).capacity > MONO_PTR_ARRAY_MAX_ON_STACK) \ mono_gc_free_fixed ((ARRAY).data); \ diff --git a/mono/metadata/null-gc.c b/mono/metadata/null-gc.c index 1f780b337f524..3aaa89af355ac 100644 --- a/mono/metadata/null-gc.c +++ b/mono/metadata/null-gc.c @@ -110,11 +110,18 @@ mono_object_is_alive (MonoObject* o) } int -mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg) +mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, void *key, const char *msg) { return TRUE; } +int +mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) +{ + return TRUE; +} + + void mono_gc_deregister_root (char* addr) { @@ -157,7 +164,7 @@ mono_gc_make_root_descr_all_refs (int numbits) } void* -mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, const char *msg) +mono_gc_alloc_fixed (size_t size, void *descr, MonoGCRootSource source, void *key, const char *msg) { return g_malloc0 (size); } diff --git a/mono/metadata/object.c b/mono/metadata/object.c index e23a3f9b6e67d..f7faab8324f22 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -215,7 +215,8 @@ mono_thread_set_main (MonoThread *thread) static gboolean registered = FALSE; if (!registered) { - MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, "main thread object"); + void *key = thread->internal_thread ? MONO_UINT_TO_NATIVE_THREAD_ID (thread->internal_thread->tid) : NULL; + MONO_GC_REGISTER_ROOT_SINGLE (main_thread, MONO_ROOT_SOURCE_THREADING, key, "main thread object"); registered = TRUE; } @@ -1955,7 +1956,8 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro bitmap = compute_class_bitmap (klass, default_bitmap, sizeof (default_bitmap) * 8, 0, &max_set, TRUE); /*g_print ("bitmap 0x%x for %s.%s (size: %d)\n", bitmap [0], klass->name_space, klass->name, class_size);*/ statics_gc_descr = mono_gc_make_descr_from_bitmap (bitmap, max_set + 1); - vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, "managed static variables"); + vt->vtable [klass->vtable_size] = mono_gc_alloc_fixed (class_size, statics_gc_descr, MONO_ROOT_SOURCE_STATIC, klass, "managed static variables"); + if (bitmap != default_bitmap) g_free (bitmap); } else { @@ -2082,7 +2084,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro /* This is unregistered in unregister_vtable_reflection_type() in domain.c. */ - MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type"); + MONO_GC_REGISTER_ROOT_IF_MOVING (vt->type, MONO_ROOT_SOURCE_REFLECTION, klass, "vtable reflection type"); } mono_vtable_set_is_remote (vt, mono_class_is_contextbound (klass)); @@ -2141,7 +2143,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro /* This is unregistered in unregister_vtable_reflection_type() in domain.c. */ - MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, "vtable reflection type"); + MONO_GC_REGISTER_ROOT_IF_MOVING(vt->type, MONO_ROOT_SOURCE_REFLECTION, klass, "vtable reflection type"); } mono_domain_unlock (domain); diff --git a/mono/metadata/profiler-events.h b/mono/metadata/profiler-events.h index f0681a6b456f7..8e44ae76619d2 100644 --- a/mono/metadata/profiler-events.h +++ b/mono/metadata/profiler-events.h @@ -75,25 +75,18 @@ MONO_PROFILER_EVENT_0(gc_finalizing, GCFinalizing) MONO_PROFILER_EVENT_0(gc_finalized, GCFinalized) MONO_PROFILER_EVENT_1(gc_finalizing_object, GCFinalizingObject, MonoObject *, object) MONO_PROFILER_EVENT_1(gc_finalized_object, GCFinalizedObject, MonoObject *, object) - -/* - * This callback provides very low quality data and doesn't really match how - * roots are actually handled in the runtime. It will be replaced with a more - * sensible callback in the future. **This will be a breaking change.** - * - * In the meantime, you must define MONO_PROFILER_UNSTABLE_GC_ROOTS to be able - * to use this interface. - */ -#ifdef MONO_PROFILER_UNSTABLE_GC_ROOTS -MONO_PROFILER_EVENT_4(gc_roots, GCRoots, MonoObject *const *, roots, const MonoProfilerGCRootType *, types, const uintptr_t *, extra, uint64_t, count) -#endif +MONO_PROFILER_EVENT_5(gc_root_register, RootRegister, const mono_byte *, start, uintptr_t, size, MonoGCRootSource, kind, const void *, key, const char *, msg) +MONO_PROFILER_EVENT_1(gc_root_unregister, RootUnregister, const mono_byte *, start) +MONO_PROFILER_EVENT_3(gc_roots, GcRoots, uint64_t, count, const mono_byte* const *, addresses, const MonoObject* const *, objects) MONO_PROFILER_EVENT_1(monitor_contention, MonitorContention, MonoObject *, object) MONO_PROFILER_EVENT_1(monitor_failed, MonitorFailed, MonoObject *, object) MONO_PROFILER_EVENT_1(monitor_acquired, MonitorAcquired, MonoObject *, object) MONO_PROFILER_EVENT_1(thread_started, ThreadStarted, uintptr_t, tid) +MONO_PROFILER_EVENT_1(thread_stopping, ThreadStopped, uintptr_t, tid) MONO_PROFILER_EVENT_1(thread_stopped, ThreadStopped, uintptr_t, tid) +MONO_PROFILER_EVENT_1(thread_exited, ThreadUnloaded, uintptr_t, tid) MONO_PROFILER_EVENT_2(thread_name, ThreadName, uintptr_t, tid, const char *, name) MONO_PROFILER_EVENT_2(sample_hit, SampleHit, const mono_byte *, ip, const void *, context) diff --git a/mono/metadata/profiler-private.h b/mono/metadata/profiler-private.h index e8d9a61569a8f..4487b3defdf2b 100644 --- a/mono/metadata/profiler-private.h +++ b/mono/metadata/profiler-private.h @@ -8,7 +8,6 @@ #define __MONO_PROFILER_PRIVATE_H__ #include -#define MONO_PROFILER_UNSTABLE_GC_ROOTS #include #include #include @@ -33,12 +32,15 @@ struct _MonoProfilerDesc { _MONO_PROFILER_EVENT(name) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT }; @@ -78,12 +80,15 @@ typedef struct { _MONO_PROFILER_EVENT(name) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT } MonoProfilerState; @@ -150,12 +155,15 @@ mono_profiler_allocations_enabled (void) _MONO_PROFILER_EVENT(name, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name, arg5_type arg5_name) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT // These are the macros the rest of the runtime should use. diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c index 6917772de4ce6..fccaa91cf4f71 100644 --- a/mono/metadata/profiler.c +++ b/mono/metadata/profiler.c @@ -503,12 +503,15 @@ mono_profiler_cleanup (void) _MONO_PROFILER_EVENT(name) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT } @@ -524,12 +527,15 @@ mono_profiler_cleanup (void) _MONO_PROFILER_EVENT(name, type) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name, type) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT MonoProfilerHandle head = mono_profiler_state.profilers; @@ -606,12 +612,15 @@ update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *co _MONO_PROFILER_EVENT(name, type) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name, type) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT #define _MONO_PROFILER_EVENT(name, type, params, args) \ @@ -634,12 +643,16 @@ update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *co _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name), (h->prof, arg1_name, arg2_name, arg3_name)) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name), (h->prof, arg1_name, arg2_name, arg3_name, arg4_name)) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name, arg5_type arg5_name), (h->prof, arg1_name, arg2_name, arg3_name, arg4_name, arg5_name)) + #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT /* diff --git a/mono/metadata/profiler.h b/mono/metadata/profiler.h index b6e836d3638b6..2100c71e4c450 100644 --- a/mono/metadata/profiler.h +++ b/mono/metadata/profiler.h @@ -334,24 +334,6 @@ MONO_API void *mono_profiler_call_context_get_result (MonoProfilerCallContext *c */ MONO_API void mono_profiler_call_context_free_buffer (void *buffer); -#ifdef MONO_PROFILER_UNSTABLE_GC_ROOTS -typedef enum { - /* Upper 2 bytes. */ - MONO_PROFILER_GC_ROOT_PINNING = 1 << 8, - MONO_PROFILER_GC_ROOT_WEAKREF = 2 << 8, - MONO_PROFILER_GC_ROOT_INTERIOR = 4 << 8, - - /* Lower 2 bytes (flags). */ - MONO_PROFILER_GC_ROOT_STACK = 1 << 0, - MONO_PROFILER_GC_ROOT_FINALIZER = 1 << 1, - MONO_PROFILER_GC_ROOT_HANDLE = 1 << 2, - MONO_PROFILER_GC_ROOT_OTHER = 1 << 3, - MONO_PROFILER_GC_ROOT_MISC = 1 << 4, - - MONO_PROFILER_GC_ROOT_TYPEMASK = 0xff, -} MonoProfilerGCRootType; -#endif - typedef enum { /* data = MonoMethod *method */ MONO_PROFILER_CODE_BUFFER_METHOD = 0, @@ -419,12 +401,15 @@ typedef enum { _MONO_PROFILER_EVENT(type, MonoProfiler *prof, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(type, MonoProfiler *prof, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(type, MonoProfiler *prof, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name, arg5_type arg5_name) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT #define _MONO_PROFILER_EVENT(name, type) \ @@ -439,12 +424,15 @@ typedef enum { _MONO_PROFILER_EVENT(name, type) #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \ + _MONO_PROFILER_EVENT(name, type) #include #undef MONO_PROFILER_EVENT_0 #undef MONO_PROFILER_EVENT_1 #undef MONO_PROFILER_EVENT_2 #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 +#undef MONO_PROFILER_EVENT_5 #undef _MONO_PROFILER_EVENT MONO_END_DECLS diff --git a/mono/metadata/sgen-client-mono.h b/mono/metadata/sgen-client-mono.h index a01890cf339d2..4e83e6c5afc93 100644 --- a/mono/metadata/sgen-client-mono.h +++ b/mono/metadata/sgen-client-mono.h @@ -288,28 +288,11 @@ sgen_client_binary_protocol_collection_requested (int generation, size_t request MONO_GC_REQUESTED (generation, requested_size, force); } -static void G_GNUC_UNUSED -sgen_client_binary_protocol_collection_begin (int minor_gc_count, int generation) -{ - MONO_GC_BEGIN (generation); - - MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_START, generation)); +void +sgen_client_binary_protocol_collection_begin (int minor_gc_count, int generation); -#ifndef DISABLE_PERFCOUNTERS - if (generation == GENERATION_NURSERY) - mono_atomic_inc_i32 (&mono_perfcounters->gc_collections0); - else - mono_atomic_inc_i32 (&mono_perfcounters->gc_collections1); -#endif -} - -static void G_GNUC_UNUSED -sgen_client_binary_protocol_collection_end (int minor_gc_count, int generation, long long num_objects_scanned, long long num_unique_objects_scanned) -{ - MONO_GC_END (generation); - - MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_END, generation)); -} +void +sgen_client_binary_protocol_collection_end (int minor_gc_count, int generation, long long num_objects_scanned, long long num_unique_objects_scanned); static void G_GNUC_UNUSED sgen_client_binary_protocol_concurrent_start (void) @@ -686,6 +669,18 @@ sgen_client_binary_protocol_pin_stats (int objects_pinned_in_nursery, size_t byt { } +static void G_GNUC_UNUSED +sgen_client_root_registered (char *start, size_t size, int source, void *key, const char *msg) +{ + MONO_PROFILER_RAISE (gc_root_register, ((const mono_byte*)start, size, source, key, msg)); +} + +static void G_GNUC_UNUSED +sgen_client_root_deregistered (char *start) +{ + MONO_PROFILER_RAISE (gc_root_unregister, ((const mono_byte*)start)); +} + static void G_GNUC_UNUSED sgen_client_binary_protocol_worker_finish_stats (int worker_index, int generation, gboolean forced, long long major_scan, long long los_scan, long long work_time) { diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index e16f2c869d2fb..4f5a1775b7e9f 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -979,13 +979,13 @@ mono_gc_alloc_mature (MonoVTable *vtable, size_t size) * mono_gc_alloc_fixed: */ void* -mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg) +mono_gc_alloc_fixed (size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) { /* FIXME: do a single allocation */ void *res = g_calloc (1, size); if (!res) return NULL; - if (!mono_gc_register_root ((char *)res, size, descr, source, msg)) { + if (!mono_gc_register_root ((char *)res, size, descr, source, key, msg)) { g_free (res); res = NULL; } @@ -1875,11 +1875,13 @@ mono_gc_set_string_length (MonoString *str, gint32 new_length) */ #define GC_ROOT_NUM 32 +#define SPECIAL_ADDRESS_FIN_QUEUE ((void*)1) +#define SPECIAL_ADDRESS_CRIT_FIN_QUEUE ((void*)2) + typedef struct { int count; /* must be the first field */ + void *addresses [GC_ROOT_NUM]; void *objects [GC_ROOT_NUM]; - int root_types [GC_ROOT_NUM]; - uintptr_t extra_info [GC_ROOT_NUM]; } GCRootReport; static void @@ -1887,63 +1889,34 @@ notify_gc_roots (GCRootReport *report) { if (!report->count) return; - MONO_PROFILER_RAISE (gc_roots, ((MonoObject **) report->objects, (MonoProfilerGCRootType *) report->root_types, report->extra_info, report->count)); + MONO_PROFILER_RAISE (gc_roots, (report->count, (const mono_byte *const *)report->addresses, (const MonoObject *const *)report->objects)); report->count = 0; } static void -add_profile_gc_root (GCRootReport *report, void *object, int rtype, uintptr_t extra_info) +report_gc_root (GCRootReport *report, void *address, void *object) { if (report->count == GC_ROOT_NUM) notify_gc_roots (report); + report->addresses [report->count] = address; report->objects [report->count] = object; - report->root_types [report->count] = rtype; - report->extra_info [report->count++] = (uintptr_t)SGEN_LOAD_VTABLE (object)->klass; -} - -void -sgen_client_nursery_objects_pinned (void **definitely_pinned, int count) -{ - if (MONO_PROFILER_ENABLED (gc_roots)) { - GCRootReport report; - int idx; - report.count = 0; - for (idx = 0; idx < count; ++idx) - add_profile_gc_root (&report, definitely_pinned [idx], MONO_PROFILER_GC_ROOT_PINNING | MONO_PROFILER_GC_ROOT_MISC, 0); - notify_gc_roots (&report); - } -} - -static void -report_finalizer_roots_from_queue (SgenPointerQueue *queue) -{ - GCRootReport report; - size_t i; - - report.count = 0; - for (i = 0; i < queue->next_slot; ++i) { - void *obj = queue->data [i]; - if (!obj) - continue; - add_profile_gc_root (&report, obj, MONO_PROFILER_GC_ROOT_FINALIZER, 0); - } - notify_gc_roots (&report); + report->count++; } static void -report_finalizer_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +single_arg_report_root (MonoObject **obj, void *gc_data) { - report_finalizer_roots_from_queue (fin_ready_queue); - report_finalizer_roots_from_queue (critical_fin_queue); + GCRootReport *report = gc_data; + if (*obj) + report_gc_root (report, obj, *obj); } -static GCRootReport *root_report; - static void -single_arg_report_root (MonoObject **obj, void *gc_data) +two_args_report_root (void *address, MonoObject *obj, void *gc_data) { - if (*obj) - add_profile_gc_root (root_report, *obj, MONO_PROFILER_GC_ROOT_OTHER, 0); + GCRootReport *report = gc_data; + if (obj) + report_gc_root (report, address, obj); } static void @@ -1953,9 +1926,8 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end case ROOT_DESC_BITMAP: desc >>= ROOT_DESC_TYPE_SHIFT; while (desc) { - if ((desc & 1) && *start_root) { - add_profile_gc_root (report, *start_root, MONO_PROFILER_GC_ROOT_OTHER, 0); - } + if ((desc & 1) && *start_root) + report_gc_root (report, start_root, *start_root); desc >>= 1; start_root++; } @@ -1969,9 +1941,8 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end gsize bmap = *bitmap_data++; void **objptr = start_run; while (bmap) { - if ((bmap & 1) && *objptr) { - add_profile_gc_root (report, *objptr, MONO_PROFILER_GC_ROOT_OTHER, 0); - } + if ((bmap & 1) && *objptr) + report_gc_root (report, objptr, *objptr); bmap >>= 1; ++objptr; } @@ -1984,14 +1955,17 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end for (p = start_root; p < end_root; p++) { if (*p) - add_profile_gc_root (report, *p, MONO_PROFILER_GC_ROOT_OTHER, 0); + report_gc_root (report, p, *p); } break; } case ROOT_DESC_USER: { MonoGCRootMarkFunc marker = (MonoGCRootMarkFunc)sgen_get_user_descriptor_func (desc); - root_report = report; - marker ((MonoObject**)start_root, single_arg_report_root, NULL); + + if ((void*)marker == (void*)sgen_mark_normal_gc_handles) + sgen_gc_handles_report_roots (two_args_report_root, report); + else + marker ((MonoObject**)start_root, single_arg_report_root, report); break; } case ROOT_DESC_RUN_LEN: @@ -2002,15 +1976,161 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end } static void -report_registered_roots_by_type (int root_type) +report_pinning_roots (GCRootReport *report, void **start, void **end) +{ + while (start < end) { + mword addr = (mword)*start; + addr &= ~(SGEN_ALLOC_ALIGN - 1); + if (addr) + report_gc_root (report, start, (void*)addr); + + start++; + } +} + +static SgenPointerQueue pinned_objects = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_MOVED_OBJECT); +static mword lower_bound, upper_bound; + +static GCObject* +find_pinned_obj (char *addr) +{ + size_t idx = sgen_pointer_queue_search (&pinned_objects, addr); + + if (idx != pinned_objects.next_slot) { + if (pinned_objects.data [idx] == addr) + return pinned_objects.data [idx]; + if (idx == 0) + return NULL; + } + + GCObject *obj = pinned_objects.data [idx - 1]; + if (addr > (char*)obj && addr < ((char*)obj + sgen_safe_object_get_size (obj))) + return obj; + return NULL; +} + + +/* + * We pass @root_report_address so register are properly accounted towards their thread +*/ +static void +report_conservative_roots (GCRootReport *report, char *root_report_address, void **start, void **end) +{ + while (start < end) { + mword addr = (mword)*start; + addr &= ~(SGEN_ALLOC_ALIGN - 1); + + if (addr < lower_bound || addr > upper_bound) { + ++start; + continue; + } + + GCObject *obj = find_pinned_obj ((char*)addr); + if (obj) + report_gc_root (report, root_report_address, obj); + start++; + } +} + +static void +report_stack_roots (void) +{ + GCRootReport report = {0}; + FOREACH_THREAD (info) { + void *aligned_stack_start; + + if (info->client_info.skip) { + continue; + } else if (info->client_info.gc_disabled) { + continue; + } else if (!mono_thread_info_is_live (info)) { + continue; + } else if (!info->client_info.stack_start) { + continue; + } + + g_assert (info->client_info.stack_start); + g_assert (info->client_info.info.stack_end); + + aligned_stack_start = (void*)(mword) ALIGN_TO ((mword)info->client_info.stack_start, SIZEOF_VOID_P); +#ifdef HOST_WIN32 + /* Windows uses a guard page before the committed stack memory pages to detect when the + stack needs to be grown. If we suspend a thread just after a function prolog has + decremented the stack pointer to point into the guard page but before the thread has + been able to read or write to that page, starting the stack scan at aligned_stack_start + will raise a STATUS_GUARD_PAGE_VIOLATION and the process will crash. This code uses + VirtualQuery() to determine whether stack_start points into the guard page and then + updates aligned_stack_start to point at the next non-guard page. */ + MEMORY_BASIC_INFORMATION mem_info; + SIZE_T result = VirtualQuery (info->client_info.stack_start, &mem_info, sizeof(mem_info)); + g_assert (result != 0); + if (mem_info.Protect & PAGE_GUARD) { + aligned_stack_start = ((char*) mem_info.BaseAddress) + mem_info.RegionSize; + } +#endif + + g_assert (info->client_info.suspend_done); + + //TODO report handle stack + report_conservative_roots (&report, aligned_stack_start, (void **)aligned_stack_start, (void **)info->client_info.info.stack_end); + report_conservative_roots (&report, aligned_stack_start, (void**)&info->client_info.ctx, (void**)(&info->client_info.ctx + 1)); + + } FOREACH_THREAD_END + + notify_gc_roots (&report); +} + +static void +report_pin_queue (void) +{ + lower_bound = SIZE_MAX; + upper_bound = 0; + + //sort the addresses + sgen_pointer_queue_sort_uniq (&pinned_objects); + + for (int i = 0; i < pinned_objects.next_slot; ++i) { + GCObject *obj = pinned_objects.data [i]; + ssize_t size = sgen_safe_object_get_size (obj); + + ssize_t addr = (ssize_t)obj; + lower_bound = MIN (lower_bound, addr); + upper_bound = MAX (upper_bound, addr + size); + } + + report_stack_roots (); + sgen_pointer_queue_clear (&pinned_objects); +} + +static void +report_finalizer_roots_from_queue (SgenPointerQueue *queue, void* queue_address) { GCRootReport report; + size_t i; + + report.count = 0; + for (i = 0; i < queue->next_slot; ++i) { + void *obj = queue->data [i]; + if (!obj) + continue; + report_gc_root (&report, queue_address, obj); + } + notify_gc_roots (&report); +} + +static void +report_registered_roots_by_type (int root_type) +{ + GCRootReport report = { 0 }; void **start_root; RootRecord *root; report.count = 0; SGEN_HASH_TABLE_FOREACH (&roots_hash [root_type], void **, start_root, RootRecord *, root) { - SGEN_LOG (6, "Precise root scan %p-%p (desc: %p)", start_root, root->end_root, (void*)root->root_desc); - precisely_report_roots_from (&report, start_root, (void**)root->end_root, root->root_desc); + SGEN_LOG (6, "Profiler root scan %p-%p (desc: %p)", start_root, root->end_root, (void*)root->root_desc); + if (root_type == ROOT_TYPE_PINNED) + report_pinning_roots (&report, start_root, (void**)root->end_root); + else + precisely_report_roots_from (&report, start_root, (void**)root->end_root, root->root_desc); } SGEN_HASH_TABLE_FOREACH_END; notify_gc_roots (&report); } @@ -2018,52 +2138,83 @@ report_registered_roots_by_type (int root_type) static void report_registered_roots (void) { - report_registered_roots_by_type (ROOT_TYPE_NORMAL); - report_registered_roots_by_type (ROOT_TYPE_WBARRIER); + for (int i = 0; i < ROOT_TYPE_NUM; ++i) + report_registered_roots_by_type (i); +} + +static void +sgen_report_all_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +{ + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; + + report_registered_roots (); + report_pin_queue (); + report_finalizer_roots_from_queue (fin_ready_queue, SPECIAL_ADDRESS_FIN_QUEUE); + report_finalizer_roots_from_queue (critical_fin_queue, SPECIAL_ADDRESS_CRIT_FIN_QUEUE); } void -sgen_client_collecting_minor (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +sgen_client_pinning_start (void) { - if (MONO_PROFILER_ENABLED (gc_roots)) - report_registered_roots (); + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; - if (MONO_PROFILER_ENABLED (gc_roots)) - report_finalizer_roots (fin_ready_queue, critical_fin_queue); + sgen_pointer_queue_clear (&pinned_objects); } -static GCRootReport major_root_report; -static gboolean profile_roots; +void +sgen_client_pinning_end (void) +{ + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; +} void -sgen_client_collecting_major_1 (void) +sgen_client_nursery_objects_pinned (void **definitely_pinned, int count) { - profile_roots = MONO_PROFILER_ENABLED (gc_roots); - memset (&major_root_report, 0, sizeof (GCRootReport)); + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; + + for (int i = 0; i < count; ++i) + sgen_pointer_queue_add (&pinned_objects, definitely_pinned [i]); } void sgen_client_pinned_los_object (GCObject *obj) { - if (profile_roots) - add_profile_gc_root (&major_root_report, (char*)obj, MONO_PROFILER_GC_ROOT_PINNING | MONO_PROFILER_GC_ROOT_MISC, 0); + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; + + sgen_pointer_queue_add (&pinned_objects, obj); +} + +void +sgen_client_pinned_cemented_object (GCObject *obj) +{ + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; } void -sgen_client_collecting_major_2 (void) +sgen_client_pinned_major_heap_object (GCObject *obj) { - if (profile_roots) - notify_gc_roots (&major_root_report); + if (!MONO_PROFILER_ENABLED (gc_roots)) + return; - if (MONO_PROFILER_ENABLED (gc_roots)) - report_registered_roots (); + sgen_pointer_queue_add (&pinned_objects, obj); } void -sgen_client_collecting_major_3 (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +sgen_client_collecting_minor_report_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) { - if (MONO_PROFILER_ENABLED (gc_roots)) - report_finalizer_roots (fin_ready_queue, critical_fin_queue); + sgen_report_all_roots (fin_ready_queue, critical_fin_queue); +} + +void +sgen_client_collecting_major_report_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) +{ + sgen_report_all_roots (fin_ready_queue, critical_fin_queue); } #define MOVED_OBJECTS_NUM 64 @@ -2490,15 +2641,15 @@ mono_gc_set_stack_end (void *stack_end) */ int -mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg) +mono_gc_register_root (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) { - return sgen_register_root (start, size, descr, descr ? ROOT_TYPE_NORMAL : ROOT_TYPE_PINNED, source, msg); + return sgen_register_root (start, size, descr, descr ? ROOT_TYPE_NORMAL : ROOT_TYPE_PINNED, source, key, msg); } int -mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, const char *msg) +mono_gc_register_root_wbarrier (char *start, size_t size, MonoGCDescriptor descr, MonoGCRootSource source, void *key, const char *msg) { - return sgen_register_root (start, size, descr, ROOT_TYPE_WBARRIER, source, msg); + return sgen_register_root (start, size, descr, ROOT_TYPE_WBARRIER, source, key, msg); } void @@ -3095,4 +3246,35 @@ mono_gc_is_null (void) return FALSE; } +void +sgen_client_binary_protocol_collection_begin (int minor_gc_count, int generation) +{ + static gboolean pseudo_roots_registered; + + MONO_GC_BEGIN (generation); + + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_START, generation)); + + if (!pseudo_roots_registered) { + pseudo_roots_registered = TRUE; + MONO_PROFILER_RAISE (gc_root_register, (SPECIAL_ADDRESS_FIN_QUEUE, 1, MONO_ROOT_SOURCE_FINALIZER_QUEUE, NULL, "finalizer queue")); + MONO_PROFILER_RAISE (gc_root_register, (SPECIAL_ADDRESS_CRIT_FIN_QUEUE, 1, MONO_ROOT_SOURCE_FINALIZER_QUEUE, NULL, "critical finalizer queue")); + } + +#ifndef DISABLE_PERFCOUNTERS + if (generation == GENERATION_NURSERY) + mono_atomic_inc_i32 (&mono_perfcounters->gc_collections0); + else + mono_atomic_inc_i32 (&mono_perfcounters->gc_collections1); +#endif +} + +void +sgen_client_binary_protocol_collection_end (int minor_gc_count, int generation, long long num_objects_scanned, long long num_unique_objects_scanned) +{ + MONO_GC_END (generation); + + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_END, generation)); +} + #endif diff --git a/mono/metadata/sre-save.c b/mono/metadata/sre-save.c index 710d9bde53cbb..bcd0be7c10eb4 100644 --- a/mono/metadata/sre-save.c +++ b/mono/metadata/sre-save.c @@ -966,7 +966,7 @@ mono_image_get_generic_param_info (MonoReflectionGenericParam *gparam, guint32 o entry = g_new0 (GenericParamTableEntry, 1); entry->owner = owner; /* FIXME: track where gen_params should be freed and remove the GC root as well */ - MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, "reflection generic parameter"); + MONO_GC_REGISTER_ROOT_IF_MOVING (entry->gparam, MONO_ROOT_SOURCE_REFLECTION, NULL, "reflection generic parameter"); entry->gparam = gparam; g_ptr_array_add (assembly->gen_params, entry); diff --git a/mono/metadata/threadpool-io.c b/mono/metadata/threadpool-io.c index a40ed6de5ea1e..077b47c7c95f6 100644 --- a/mono/metadata/threadpool-io.c +++ b/mono/metadata/threadpool-io.c @@ -541,7 +541,7 @@ initialize (void) mono_coop_mutex_init (&threadpool_io->updates_lock); mono_coop_cond_init (&threadpool_io->updates_cond); - mono_gc_register_root ((char *)&threadpool_io->updates [0], sizeof (threadpool_io->updates), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_THREAD_POOL, "i/o thread pool updates list"); + mono_gc_register_root ((char *)&threadpool_io->updates [0], sizeof (threadpool_io->updates), MONO_GC_DESCRIPTOR_NULL, MONO_ROOT_SOURCE_THREAD_POOL, 0, "i/o thread pool updates list"); threadpool_io->updates_size = 0; diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index dc7f8527964aa..13cfb195a6085 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -561,7 +561,7 @@ create_internal_thread_object (void) thread->managed_id = get_next_managed_thread_id (); if (mono_gc_is_moving ()) { thread->thread_pinning_ref = thread; - MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, "thread pinning reference"); + MONO_GC_REGISTER_ROOT_PINNING (thread->thread_pinning_ref, MONO_ROOT_SOURCE_THREADING, 0, "thread pinning reference"); } thread->priority = MONO_THREAD_PRIORITY_NORMAL; @@ -648,7 +648,7 @@ mono_thread_internal_set_priority (MonoInternalThread *internal, MonoThreadPrior } static void -mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal); +mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, void *alloc_key, gboolean threadlocal); static gboolean mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean force_domain) @@ -716,7 +716,7 @@ mono_thread_attach_internal (MonoThread *thread, gboolean force_attach, gboolean if (thread_static_info.offset || thread_static_info.idx > 0) { /* get the current allocated size */ guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (thread_static_info.idx, thread_static_info.offset, 0); - mono_alloc_static_data (&internal->static_data, offset, TRUE); + mono_alloc_static_data (&internal->static_data, offset, MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), TRUE); } mono_threads_unlock (); @@ -749,6 +749,8 @@ mono_thread_detach_internal (MonoInternalThread *thread) THREAD_DEBUG (g_message ("%s: mono_thread_detach for %p (%"G_GSIZE_FORMAT")", __func__, thread, (gsize)thread->tid)); + MONO_PROFILER_RAISE (thread_stopping, (thread->tid)); + #ifndef HOST_WIN32 mono_w32mutex_abandon (); #endif @@ -845,9 +847,8 @@ mono_thread_detach_internal (MonoInternalThread *thread) mono_release_type_locks (thread); - /* Can happen when we attach the profiler helper thread in order to heapshot. */ - if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread) - MONO_PROFILER_RAISE (thread_stopped, (thread->tid)); + MONO_PROFILER_RAISE (thread_stopped, (thread->tid)); + MONO_PROFILER_RAISE (gc_root_unregister, (((MonoThreadInfo*)thread->thread_info)->stack_start_limit)); mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); @@ -887,6 +888,8 @@ mono_thread_detach_internal (MonoInternalThread *thread) mono_thread_info_unset_internal_thread_gchandle ((MonoThreadInfo*) thread->thread_info); + MONO_PROFILER_RAISE (thread_exited, (thread->tid)); + /* Don't need to close the handle to this thread, even though we took a * reference in mono_thread_attach (), because the GC will do it * when the Thread object is finalised. @@ -905,6 +908,20 @@ typedef struct { MonoCoopSem registered; } StartInfo; +static void +fire_attach_profiler_events (MonoNativeThreadId tid) +{ + MONO_PROFILER_RAISE (thread_started, ((uintptr_t)tid)); + + MonoThreadInfo *info = mono_thread_info_current (); + MONO_PROFILER_RAISE (gc_root_register, ( + info->stack_start_limit, + (char*)info->stack_end - (char*)info->stack_start_limit, + MONO_ROOT_SOURCE_STACK, + (void*)tid, + "thread stack")); +} + static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack_ptr) { MonoError error; @@ -980,7 +997,7 @@ static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack * to lock the thread, and the lock is held by thread_start () which waits for * start_notify. */ - MONO_PROFILER_RAISE (thread_started, (tid)); + fire_attach_profiler_events ((MonoNativeThreadId)tid); /* if the name was set before starting, we didn't invoke the profiler callback */ if (internal->name) { @@ -1276,9 +1293,7 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach) if (mono_thread_attach_cb) mono_thread_attach_cb (MONO_NATIVE_THREAD_ID_TO_UINT (tid), info->stack_end); - /* Can happen when we attach the profiler helper thread in order to heapshot. */ - if (!mono_thread_info_current ()->tools_thread) - MONO_PROFILER_RAISE (thread_started, (MONO_NATIVE_THREAD_ID_TO_UINT (tid))); + fire_attach_profiler_events (tid); return thread; } @@ -4062,7 +4077,7 @@ mark_ctx_slots (void *addr, MonoGCMarkFunc mark_func, void *gc_data) * Allocate memory blocks for storing threads or context static data */ static void -mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean threadlocal) +mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, void *alloc_key, gboolean threadlocal) { guint idx = ACCESS_SPECIAL_STATIC_OFFSET (offset, index); int i; @@ -4082,6 +4097,7 @@ mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean thr static_data = (void **)mono_gc_alloc_fixed (static_data_size [0], threadlocal ? tls_desc : ctx_desc, threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC, + alloc_key, threadlocal ? "managed thread-static variables" : "managed context-static variables"); *static_data_ptr = static_data; static_data [0] = static_data; @@ -4096,6 +4112,7 @@ mono_alloc_static_data (gpointer **static_data_ptr, guint32 offset, gboolean thr else static_data [i] = mono_gc_alloc_fixed (static_data_size [i], MONO_GC_DESCRIPTOR_NULL, threadlocal ? MONO_ROOT_SOURCE_THREAD_STATIC : MONO_ROOT_SOURCE_CONTEXT_STATIC, + alloc_key, threadlocal ? "managed thread-static variables" : "managed context-static variables"); } } @@ -4174,7 +4191,7 @@ context_adjust_static_data (MonoAppContext *ctx) { if (context_static_info.offset || context_static_info.idx > 0) { guint32 offset = MAKE_SPECIAL_STATIC_OFFSET (context_static_info.idx, context_static_info.offset, 0); - mono_alloc_static_data (&ctx->static_data, offset, FALSE); + mono_alloc_static_data (&ctx->static_data, offset, ctx, FALSE); ctx->data->static_data = ctx->static_data; } } @@ -4188,7 +4205,7 @@ alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user) MonoInternalThread *thread = (MonoInternalThread *)value; guint32 offset = GPOINTER_TO_UINT (user); - mono_alloc_static_data (&(thread->static_data), offset, TRUE); + mono_alloc_static_data (&(thread->static_data), offset, MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid), TRUE); } /* @@ -4203,7 +4220,7 @@ alloc_context_static_data_helper (gpointer key, gpointer value, gpointer user) return; guint32 offset = GPOINTER_TO_UINT (user); - mono_alloc_static_data (&ctx->static_data, offset, FALSE); + mono_alloc_static_data (&ctx->static_data, offset, ctx, FALSE); ctx->data->static_data = ctx->static_data; } diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index a5fbec9de5cde..af2f0a9b55dce 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -3899,7 +3899,7 @@ thread_startup (MonoProfiler *prof, uintptr_t tid) g_assert (!tls); // FIXME: Free this somewhere tls = g_new0 (DebuggerTlsData, 1); - MONO_GC_REGISTER_ROOT_SINGLE (tls->thread, MONO_ROOT_SOURCE_DEBUGGER, "debugger thread reference"); + MONO_GC_REGISTER_ROOT_SINGLE (tls->thread, MONO_ROOT_SOURCE_DEBUGGER, NULL, "debugger thread reference"); tls->thread = thread; mono_native_tls_set_value (debugger_tls_id, tls); diff --git a/mono/mini/tasklets.c b/mono/mini/tasklets.c index e767f63125a69..8e50c610bff02 100644 --- a/mono/mini/tasklets.c +++ b/mono/mini/tasklets.c @@ -112,7 +112,7 @@ continuation_store (MonoContinuation *cont, int state, MonoException **e) mono_gc_free_fixed (cont->saved_stack); cont->stack_used_size = num_bytes; cont->stack_alloc_size = num_bytes * 1.1; - cont->saved_stack = mono_gc_alloc_fixed (cont->stack_alloc_size, NULL, MONO_ROOT_SOURCE_THREADING, "saved tasklet stack"); + cont->saved_stack = mono_gc_alloc_fixed (cont->stack_alloc_size, NULL, MONO_ROOT_SOURCE_THREADING, NULL, "saved tasklet stack"); tasklets_unlock (); } memcpy (cont->saved_stack, cont->return_sp, num_bytes); diff --git a/mono/profiler/log.c b/mono/profiler/log.c index b7b9b44a7e115..c823c8f1672ed 100644 --- a/mono/profiler/log.c +++ b/mono/profiler/log.c @@ -166,6 +166,12 @@ typedef struct { int small_id; } MonoProfilerThread; +// Default value in `profiler_tls` for new threads. +#define MONO_PROFILER_THREAD_ZERO ((MonoProfilerThread *) NULL) + +// This is written to `profiler_tls` to indicate that a thread has stopped. +#define MONO_PROFILER_THREAD_DEAD ((MonoProfilerThread *) -1) + // Do not use these TLS macros directly unless you know what you're doing. #ifdef HOST_WIN32 @@ -234,19 +240,19 @@ process_id (void) #define ENTER_LOG(COUNTER, BUFFER, SIZE) \ do { \ MonoProfilerThread *thread__ = get_thread (); \ - if (thread__->attached) \ - buffer_lock (); \ g_assert (!thread__->busy && "Why are we trying to write a new event while already writing one?"); \ thread__->busy = TRUE; \ mono_atomic_inc_i32 ((COUNTER)); \ + if (thread__->attached) \ + buffer_lock (); \ LogBuffer *BUFFER = ensure_logbuf_unsafe (thread__, (SIZE)) #define EXIT_LOG_EXPLICIT(SEND) \ - thread__->busy = FALSE; \ if ((SEND)) \ send_log_unsafe (TRUE); \ if (thread__->attached) \ buffer_unlock (); \ + thread__->busy = FALSE; \ } while (0) // Pass these to EXIT_LOG_EXPLICIT () for easier reading. @@ -512,6 +518,8 @@ init_thread (gboolean add_to_lls) { MonoProfilerThread *thread = PROF_TLS_GET (); + g_assert (thread != MONO_PROFILER_THREAD_DEAD && "Why are we trying to resurrect a stopped thread?"); + /* * Sometimes we may try to initialize a thread twice. One example is the * main thread: We initialize it when setting up the profiler, but we will @@ -523,14 +531,14 @@ init_thread (gboolean add_to_lls) * These cases are harmless anyhow. Just return if we've already done the * initialization work. */ - if (thread) + if (thread != MONO_PROFILER_THREAD_ZERO) return thread; thread = g_malloc (sizeof (MonoProfilerThread)); thread->node.key = thread_id (); thread->attached = add_to_lls; thread->call_depth = 0; - thread->busy = 0; + thread->busy = FALSE; thread->ended = FALSE; init_buffer_state (thread); @@ -543,7 +551,8 @@ init_thread (gboolean add_to_lls) */ if (add_to_lls) { MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); - g_assert (mono_lls_insert (&log_profiler.profiler_thread_list, hp, &thread->node) && "Why can't we insert the thread in the LLS?"); + if (!mono_lls_insert (&log_profiler.profiler_thread_list, hp, &thread->node)) + g_error ("%s: failed to insert thread %p in log_profiler.profiler_thread_list, found = %s", __func__, (gpointer) thread->node.key, mono_lls_find (&log_profiler.profiler_thread_list, hp, thread->node.key) ? "true" : "false"); clear_hazard_pointers (hp); } @@ -559,7 +568,7 @@ deinit_thread (MonoProfilerThread *thread) g_assert (!thread->attached && "Why are we manually freeing an attached thread?"); g_free (thread); - PROF_TLS_SET (NULL); + PROF_TLS_SET (MONO_PROFILER_THREAD_DEAD); } static MonoProfilerThread * @@ -1200,32 +1209,64 @@ gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, } static void -gc_roots (MonoProfiler *prof, MonoObject *const *objects, const MonoProfilerGCRootType *root_types, const uintptr_t *extra_info, uint64_t num) +gc_roots (MonoProfiler *prof, uint64_t num, const mono_byte *const *addresses, const MonoObject* const *objects) { ENTER_LOG (&heap_roots_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* num */ + - LEB128_SIZE /* collections */ + num * ( LEB128_SIZE /* object */ + - LEB128_SIZE /* root type */ + - LEB128_SIZE /* extra info */ + LEB128_SIZE /* address */ ) ); emit_event (logbuffer, TYPE_HEAP_ROOT | TYPE_HEAP); emit_value (logbuffer, num); - emit_value (logbuffer, mono_gc_collection_count (mono_gc_max_generation ())); for (int i = 0; i < num; ++i) { - emit_obj (logbuffer, objects [i]); - emit_value (logbuffer, root_types [i]); - emit_value (logbuffer, extra_info [i]); + emit_obj (logbuffer, (gpointer) objects [i]); + emit_ptr (logbuffer, addresses [i]); } EXIT_LOG; } +static void +gc_root_register (MonoProfiler *prof, const mono_byte *start, size_t size, MonoGCRootSource kind, const void *key, const char *msg) +{ + int msg_len = msg ? strlen (msg) + 1 : 0; + ENTER_LOG (&heap_roots_ctr, logbuffer, + EVENT_SIZE /* event */ + + LEB128_SIZE /* start */ + + LEB128_SIZE /* size */ + + BYTE_SIZE /* kind */ + + LEB128_SIZE /* key */ + + msg_len /*msg */ + ); + + emit_event (logbuffer, TYPE_HEAP_ROOT_REGISTER | TYPE_HEAP); + emit_ptr (logbuffer, start); + emit_uvalue (logbuffer, size); + emit_byte (logbuffer, kind); + emit_ptr (logbuffer, key); + emit_string (logbuffer, msg, msg_len); + + EXIT_LOG; +} + +static void +gc_root_deregister (MonoProfiler *prof, const mono_byte *start) +{ + ENTER_LOG (&heap_roots_ctr, logbuffer, + EVENT_SIZE /* event */ + + LEB128_SIZE /* start */ + ); + + emit_event (logbuffer, TYPE_HEAP_ROOT_UNREGISTER | TYPE_HEAP); + emit_ptr (logbuffer, start); + + EXIT_LOG; +} static void trigger_on_demand_heapshot (void) @@ -2007,7 +2048,7 @@ thread_end (MonoProfiler *prof, uintptr_t tid) thread->ended = TRUE; remove_thread (thread); - PROF_TLS_SET (NULL); + PROF_TLS_SET (MONO_PROFILER_THREAD_DEAD); } static void @@ -4355,10 +4396,15 @@ proflog_icall_SetGCRootEvents (MonoBoolean value) { mono_coop_mutex_lock (&log_profiler.api_mutex); - if (value) + if (value) { ENABLE (PROFLOG_GC_ROOT_EVENTS); - else + mono_profiler_set_gc_root_register_callback (log_profiler.handle, gc_root_register); + mono_profiler_set_gc_root_unregister_callback (log_profiler.handle, gc_root_deregister); + } else { DISABLE (PROFLOG_GC_ROOT_EVENTS); + mono_profiler_set_gc_root_register_callback (log_profiler.handle, NULL); + mono_profiler_set_gc_root_unregister_callback (log_profiler.handle, NULL); + } mono_coop_mutex_unlock (&log_profiler.api_mutex); } @@ -4688,7 +4734,7 @@ mono_profiler_init_log (const char *desc) mono_profiler_set_gc_event_callback (handle, gc_event); mono_profiler_set_thread_started_callback (handle, thread_start); - mono_profiler_set_thread_stopped_callback (handle, thread_end); + mono_profiler_set_thread_exited_callback (handle, thread_end); mono_profiler_set_thread_name_callback (handle, thread_name); mono_profiler_set_domain_loaded_callback (handle, domain_loaded); @@ -4728,6 +4774,11 @@ mono_profiler_init_log (const char *desc) if (ENABLED (PROFLOG_GC_MOVE_EVENTS)) mono_profiler_set_gc_moves_callback (handle, gc_moves); + if (ENABLED (PROFLOG_GC_ROOT_EVENTS)) { + mono_profiler_set_gc_root_register_callback (handle, gc_root_register); + mono_profiler_set_gc_root_unregister_callback (handle, gc_root_deregister); + } + if (ENABLED (PROFLOG_GC_HANDLE_EVENTS)) { mono_profiler_set_gc_handle_created_callback (handle, gc_handle_created); mono_profiler_set_gc_handle_deleted_callback (handle, gc_handle_deleted); diff --git a/mono/profiler/log.h b/mono/profiler/log.h index e381d8975471a..dd5c3532596c0 100644 --- a/mono/profiler/log.h +++ b/mono/profiler/log.h @@ -2,7 +2,6 @@ #define __MONO_PROFLOG_H__ #include -#define MONO_PROFILER_UNSTABLE_GC_ROOTS #include #include @@ -10,13 +9,17 @@ #define LOG_HEADER_ID 0x4D505A01 #define LOG_VERSION_MAJOR 2 #define LOG_VERSION_MINOR 0 -#define LOG_DATA_VERSION 14 +#define LOG_DATA_VERSION 15 /* * Changes in major/minor versions: * version 1.0: removed sysid field from header * added args, arch, os fields to header * + * Version 2.0: Reworked argument parsing, defaults now are a lot more saner + * Events/feature should be explicitly enabled as by default they won't be emited (use legacy option to get closer) + * Heap events (moves, roots, objects) are now all emitted around HEAD_START / HEAD_END events to make it easy to isolate a heapshot + * End-of-GC sync points are now emitted with the world stopped, eliminating the window it races with the mutator. * Changes in data versions: * version 2: added offsets in heap walk * version 3: added GC roots @@ -72,6 +75,8 @@ removed type field from TYPE_SAMPLE_HIT removed MONO_GC_EVENT_{MARK,RECLAIM}_{START,END} reverted the root_type field back to uleb128 + * version 15: GC Roots events now have a different, and saner, format. + added gc root register/unregister events to be used to source gc root information */ /* @@ -250,7 +255,7 @@ * * type heap format * type: TYPE_HEAP - * exinfo: one of TYPE_HEAP_START, TYPE_HEAP_END, TYPE_HEAP_OBJECT, TYPE_HEAP_ROOT + * exinfo: one of TYPE_HEAP_START, TYPE_HEAP_END, TYPE_HEAP_OBJECT, TYPE_HEAP_ROOT, TYPE_HEAP_ROOT_REGISTER, TYPE_HEAP_ROOT_UNREGISTER * if exinfo == TYPE_HEAP_OBJECT * [object: sleb128] the object as a difference from obj_base * [class: sleb128] the object MonoClass* as a difference from ptr_base @@ -265,11 +270,17 @@ * provide additional referenced objects. * if exinfo == TYPE_HEAP_ROOT * [num_roots: uleb128] number of root references - * [num_gc: uleb128] number of major gcs - * [object: sleb128] the object as a difference from obj_base - * [root_type: uleb128] the root_type: MonoProfileGCRootType (profiler.h) - * [extra_info: uleb128] the extra_info value - * object, root_type and extra_info are repeated num_roots times + * num_roots runs of the following: + * [address: sleb128] the root address as a difference from ptr_base + * [object: sleb128] the object address as a difference from obj_base + * if exinfo == TYPE_HEAP_ROOT_REGISTER + * [start:sleb128] start address as a different from ptr_base + * [size:uleb] size of the root region + * [kind:byte] type of the buffer + * [key:sleb] root key, meaning dependent on type, value as a different from ptr_base + * [desc:string] description of the root, as null terminated string + * if exinfo == TYPE_HEAP_ROOT_UNREGISTER + * [start:sleb128] start address as a different from ptr_base * * type sample format * type: TYPE_SAMPLE @@ -376,6 +387,8 @@ enum { TYPE_HEAP_END = 1 << 4, TYPE_HEAP_OBJECT = 2 << 4, TYPE_HEAP_ROOT = 3 << 4, + TYPE_HEAP_ROOT_REGISTER = 4 << 4, + TYPE_HEAP_ROOT_UNREGISTER = 5 << 4, /* extended type for TYPE_METADATA */ TYPE_END_LOAD = 2 << 4, TYPE_END_UNLOAD = 4 << 4, diff --git a/mono/profiler/mprof-report.c b/mono/profiler/mprof-report.c index bc9971ad2320d..f2f7dea5d9d05 100644 --- a/mono/profiler/mprof-report.c +++ b/mono/profiler/mprof-report.c @@ -76,6 +76,23 @@ #define HASH_SIZE 9371 #define SMALL_HASH_SIZE 31 +/* Version < 15 root type enum */ +typedef enum { + /* Upper 2 bytes. */ + MONO_PROFILER_GC_ROOT_PINNING = 1 << 8, + MONO_PROFILER_GC_ROOT_WEAKREF = 2 << 8, + MONO_PROFILER_GC_ROOT_INTERIOR = 4 << 8, + + /* Lower 2 bytes (flags). */ + MONO_PROFILER_GC_ROOT_STACK = 1 << 0, + MONO_PROFILER_GC_ROOT_FINALIZER = 1 << 1, + MONO_PROFILER_GC_ROOT_HANDLE = 1 << 2, + MONO_PROFILER_GC_ROOT_OTHER = 1 << 3, + MONO_PROFILER_GC_ROOT_MISC = 1 << 4, + + MONO_PROFILER_GC_ROOT_TYPEMASK = 0xff, +} MonoProfilerGCRootType; + static int debug = 0; static int collect_traces = 0; static int show_traces = 0; @@ -2691,29 +2708,68 @@ decode_buffer (ProfContext *ctx) fprintf (outfile, "traced object %p, size %llu (%s), refs: %zd\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) size, cd->name, num); } else if (subtype == TYPE_HEAP_ROOT) { uintptr_t num; - if (ctx->data_version > 12) { + if (ctx->data_version > 14) { + int i; uint64_t tdiff = decode_uleb128 (p + 1, &p); LOG_TIME (time_base, tdiff); time_base += tdiff; num = decode_uleb128 (p, &p); - } else - num = decode_uleb128 (p + 1, &p); - uintptr_t gc_num G_GNUC_UNUSED = decode_uleb128 (p, &p); - int i; - for (i = 0; i < num; ++i) { - intptr_t objdiff = decode_sleb128 (p, &p); - int root_type; - if (ctx->data_version == 13) - root_type = *p++; - else - root_type = decode_uleb128 (p, &p); - /* we just discard the extra info for now */ - uintptr_t extra_info = decode_uleb128 (p, &p); - if (debug) - fprintf (outfile, "object %p is a %s root\n", (void*)OBJ_ADDR (objdiff), get_root_name (root_type)); - if (collect_traces) - thread_add_root (thread, OBJ_ADDR (objdiff), root_type, extra_info); + for (i = 0; i < num; ++i) { + intptr_t ptrdiff = decode_sleb128 (p, &p); + intptr_t objdiff = decode_sleb128 (p, &p); + + if (debug) + fprintf (outfile, "object %p at address %zx\n", (void*)OBJ_ADDR (objdiff), ptr_base + ptrdiff); + if (collect_traces) + thread_add_root (thread, OBJ_ADDR (objdiff), MONO_PROFILER_GC_ROOT_MISC, 0); + } + } else { + if (ctx->data_version > 12) { + uint64_t tdiff = decode_uleb128 (p + 1, &p); + LOG_TIME (time_base, tdiff); + time_base += tdiff; + num = decode_uleb128 (p, &p); + } else + num = decode_uleb128 (p + 1, &p); + uintptr_t gc_num G_GNUC_UNUSED = decode_uleb128 (p, &p); + int i; + for (i = 0; i < num; ++i) { + intptr_t objdiff = decode_sleb128 (p, &p); + int root_type; + if (ctx->data_version > 12) + root_type = *p++; + else + root_type = decode_uleb128 (p, &p); + /* we just discard the extra info for now */ + uintptr_t extra_info = decode_uleb128 (p, &p); + if (debug) + fprintf (outfile, "object %p is a %s root\n", (void*)OBJ_ADDR (objdiff), get_root_name (root_type)); + if (collect_traces) + thread_add_root (thread, OBJ_ADDR (objdiff), root_type, extra_info); + } } + } else if (subtype == TYPE_HEAP_ROOT_REGISTER) { + uint64_t tdiff = decode_uleb128 (p + 1, &p); + LOG_TIME (time_base, tdiff); + time_base += tdiff; + + uint64_t ptrdiff = decode_uleb128 (p, &p); + uint64_t size = decode_uleb128 (p, &p); + int type = *p++; + uint64_t keydiff = decode_uleb128 (p, &p); + char *desc = (char*)p; + while (*p++); + + if (debug) + fprintf (outfile, "root register address %llx size %lld type %d key %llx description %s\n", ptr_base + ptrdiff, size, type, ptr_base + keydiff, desc); + } else if (subtype == TYPE_HEAP_ROOT_UNREGISTER) { + uint64_t tdiff = decode_uleb128 (p + 1, &p); + LOG_TIME (time_base, tdiff); + time_base += tdiff; + uint64_t ptrdiff = decode_uleb128 (p, &p); + + if (debug) + fprintf (outfile, "root %llx was unregisted\n", ptr_base + ptrdiff); } else if (subtype == TYPE_HEAP_END) { uint64_t tdiff = decode_uleb128 (p + 1, &p); LOG_TIME (time_base, tdiff); diff --git a/mono/sgen/sgen-client.h b/mono/sgen/sgen-client.h index 4137cacc3c2a9..d79fedb91d9e9 100644 --- a/mono/sgen/sgen-client.h +++ b/mono/sgen/sgen-client.h @@ -107,20 +107,31 @@ void sgen_client_nursery_objects_pinned (void **definitely_pinned, int count); /* * Called at a semi-random point during minor collections. No action is necessary. */ -void sgen_client_collecting_minor (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue); +void sgen_client_collecting_minor_report_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue); /* * Called at semi-random points during major collections. No action is necessary. */ -void sgen_client_collecting_major_1 (void); -void sgen_client_collecting_major_2 (void); -void sgen_client_collecting_major_3 (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue); +void sgen_client_collecting_major_report_roots (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue); /* * Called after a LOS object has been pinned. No action is necessary. */ void sgen_client_pinned_los_object (GCObject *obj); +/* + * Called for each cemented obj + */ +void sgen_client_pinned_cemented_object (GCObject *obj); + +/* + * Called for each major heap obj pinned + */ +void sgen_client_pinned_major_heap_object (GCObject *obj); + +void sgen_client_pinning_start (void); +void sgen_client_pinning_end (void); + /* * Called for every degraded allocation. No action is necessary. */ diff --git a/mono/sgen/sgen-descriptor.h b/mono/sgen/sgen-descriptor.h index 2c7f19b18c46a..f10ebf6a5104a 100644 --- a/mono/sgen/sgen-descriptor.h +++ b/mono/sgen/sgen-descriptor.h @@ -122,6 +122,7 @@ enum { }; typedef void (*SgenUserMarkFunc) (GCObject **addr, void *gc_data); +typedef void (*SgenUserReportRootFunc) (void *addr, GCObject *obj, void *gc_data); typedef void (*SgenUserRootMarkFunc) (void *addr, SgenUserMarkFunc mark_func, void *gc_data); SgenDescriptor sgen_make_user_root_descriptor (SgenUserRootMarkFunc marker); diff --git a/mono/sgen/sgen-gc.c b/mono/sgen/sgen-gc.c index fb3be3507b187..af1432d5e53c8 100644 --- a/mono/sgen/sgen-gc.c +++ b/mono/sgen/sgen-gc.c @@ -673,6 +673,7 @@ pin_objects_from_nursery_pin_queue (gboolean do_scan_objects, ScanCopyContext ct * Finally - pin the object! */ desc = sgen_obj_get_descriptor_safe (obj_to_pin); + if (do_scan_objects) { scan_func (obj_to_pin, desc, queue); } else { @@ -1773,6 +1774,7 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_ time_minor_pinning += TV_ELAPSED (btv, atv); SGEN_LOG (2, "Finding pinned pointers: %zd in %lld usecs", sgen_get_pinned_count (), (long long)TV_ELAPSED (btv, atv)); SGEN_LOG (4, "Start scan with %zd pinned objects", sgen_get_pinned_count ()); + sgen_client_pinning_end (); remset.start_scan_remsets (); @@ -1785,9 +1787,6 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_ sgen_pin_stats_report (); - /* FIXME: Why do we do this at this specific, seemingly random, point? */ - sgen_client_collecting_minor (&fin_ready_queue, &critical_fin_queue); - TV_GETTIME (atv); time_minor_scan_pinned += TV_ELAPSED (btv, atv); @@ -1861,6 +1860,10 @@ collect_nursery (const char *reason, gboolean is_overflow, SgenGrayQueue *unpin_ sgen_debug_dump_heap ("minor", mono_atomic_load_i32 (&gc_stats.minor_gc_count) - 1, NULL); + //This is used by the profiler to report GC roots + //Invanants: heap's finished, no more moves left. Pin queue no longer in use, we can do whatever with it + sgen_client_collecting_minor_report_roots (&fin_ready_queue, &critical_fin_queue); + /* prepare the pin queue for the next collection */ sgen_finish_pinning (); if (sgen_have_pending_finalizers ()) { @@ -1976,8 +1979,6 @@ major_copy_or_mark_from_roots (SgenGrayQueue *gc_thread_gray_queue, size_t *old_ sgen_cement_force_pinned (); } - sgen_client_collecting_major_1 (); - /* * pin_queue now contains all candidate pointers, sorted and * uniqued. We must do two passes now to figure out which @@ -2028,6 +2029,7 @@ major_copy_or_mark_from_roots (SgenGrayQueue *gc_thread_gray_queue, size_t *old_ time_major_pinning += TV_ELAPSED (atv, btv); SGEN_LOG (2, "Finding pinned pointers: %zd in %lld usecs", sgen_get_pinned_count (), (long long)TV_ELAPSED (atv, btv)); SGEN_LOG (4, "Start scan with %zd pinned objects", sgen_get_pinned_count ()); + sgen_client_pinning_end (); if (mode == COPY_OR_MARK_FROM_ROOTS_START_CONCURRENT) sgen_finish_pinning_for_conc (); @@ -2056,13 +2058,9 @@ major_copy_or_mark_from_roots (SgenGrayQueue *gc_thread_gray_queue, size_t *old_ main_gc_thread = mono_native_thread_self (); #endif - sgen_client_collecting_major_2 (); - TV_GETTIME (atv); time_major_scan_pinned += TV_ELAPSED (btv, atv); - sgen_client_collecting_major_3 (&fin_ready_queue, &critical_fin_queue); - enqueue_scan_from_roots_jobs (gc_thread_gray_queue, heap_start, heap_end, object_ops_nopar, FALSE); TV_GETTIME (btv); @@ -2257,6 +2255,8 @@ major_finish_collection (SgenGrayQueue *gc_thread_gray_queue, const char *reason if (do_concurrent_checks && concurrent_collection_in_progress) sgen_debug_check_nursery_is_clean (); + sgen_client_collecting_major_report_roots (&fin_ready_queue, &critical_fin_queue); + /* prepare the pin queue for the next collection */ sgen_finish_pinning (); @@ -2800,10 +2800,13 @@ sgen_have_pending_finalizers (void) * We do not coalesce roots. */ int -sgen_register_root (char *start, size_t size, SgenDescriptor descr, int root_type, int source, const char *msg) +sgen_register_root (char *start, size_t size, SgenDescriptor descr, int root_type, int source, void *key, const char *msg) { RootRecord new_root; int i; + + sgen_client_root_registered (start, size, source, key, msg); + LOCK_GC; for (i = 0; i < ROOT_TYPE_NUM; ++i) { RootRecord *root = (RootRecord *)sgen_hash_table_lookup (&roots_hash [i], start); @@ -2842,6 +2845,8 @@ sgen_deregister_root (char* addr) int root_type; RootRecord root; + sgen_client_root_deregistered (addr); + LOCK_GC; for (root_type = 0; root_type < ROOT_TYPE_NUM; ++root_type) { if (sgen_hash_table_remove (&roots_hash [root_type], addr, &root)) @@ -3722,7 +3727,7 @@ sgen_gc_init (void) sgen_card_table_init (&remset); - sgen_register_root (NULL, 0, sgen_make_user_root_descriptor (sgen_mark_normal_gc_handles), ROOT_TYPE_NORMAL, MONO_ROOT_SOURCE_GC_HANDLE, "normal gc handles"); + sgen_register_root (NULL, 0, sgen_make_user_root_descriptor (sgen_mark_normal_gc_handles), ROOT_TYPE_NORMAL, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "normal gc handles"); gc_initialized = 1; diff --git a/mono/sgen/sgen-gc.h b/mono/sgen/sgen-gc.h index 8cdec588b666d..81c49dc0cce25 100644 --- a/mono/sgen/sgen-gc.h +++ b/mono/sgen/sgen-gc.h @@ -394,7 +394,7 @@ enum { extern SgenHashTable roots_hash [ROOT_TYPE_NUM]; -int sgen_register_root (char *start, size_t size, SgenDescriptor descr, int root_type, int source, const char *msg) +int sgen_register_root (char *start, size_t size, SgenDescriptor descr, int root_type, int source, void *key, const char *msg) MONO_PERMIT (need (sgen_lock_gc)); void sgen_deregister_root (char* addr) MONO_PERMIT (need (sgen_lock_gc)); @@ -997,6 +997,8 @@ void sgen_gchandle_iterate (GCHandleType handle_type, int max_generation, SgenGC void sgen_gchandle_set_target (guint32 gchandle, GCObject *obj); void sgen_mark_normal_gc_handles (void *addr, SgenUserMarkFunc mark_func, void *gc_data) MONO_PERMIT (need (sgen_world_stopped)); +void sgen_gc_handles_report_roots (SgenUserReportRootFunc mark_func, void *gc_data) + MONO_PERMIT (need (sgen_world_stopped)); gpointer sgen_gchandle_get_metadata (guint32 gchandle); GCObject *sgen_gchandle_get_target (guint32 gchandle); void sgen_gchandle_free (guint32 gchandle); diff --git a/mono/sgen/sgen-gchandles.c b/mono/sgen/sgen-gchandles.c index 4a140e53668e0..6a7404d1b3f71 100644 --- a/mono/sgen/sgen-gchandles.c +++ b/mono/sgen/sgen-gchandles.c @@ -94,15 +94,24 @@ static void bucket_alloc_callback (gpointer *bucket, guint32 new_bucket_size, gboolean alloc) { if (alloc) - sgen_register_root ((char *)bucket, new_bucket_size, SGEN_DESCRIPTOR_NULL, ROOT_TYPE_PINNED, MONO_ROOT_SOURCE_GC_HANDLE, "pinned gc handles"); + sgen_register_root ((char *)bucket, new_bucket_size, SGEN_DESCRIPTOR_NULL, ROOT_TYPE_PINNED, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "pinned gc handles"); else sgen_deregister_root ((char *)bucket); } +static void +bucket_alloc_report_root (gpointer *bucket, guint32 new_bucket_size, gboolean alloc) +{ + if (alloc) + sgen_client_root_registered ((char *)bucket, new_bucket_size, MONO_ROOT_SOURCE_GC_HANDLE, NULL, "normal gc handles"); + else + sgen_client_root_deregistered ((char *)bucket); +} + static HandleData gc_handles [] = { { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_WEAK) }, { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_WEAK_TRACK) }, - { SGEN_ARRAY_LIST_INIT (NULL, is_slot_set, try_occupy_slot, -1), (HANDLE_NORMAL) }, + { SGEN_ARRAY_LIST_INIT (bucket_alloc_report_root, is_slot_set, try_occupy_slot, -1), (HANDLE_NORMAL) }, { SGEN_ARRAY_LIST_INIT (bucket_alloc_callback, is_slot_set, try_occupy_slot, -1), (HANDLE_PINNED) } }; @@ -132,6 +141,24 @@ sgen_mark_normal_gc_handles (void *addr, SgenUserMarkFunc mark_func, void *gc_da } SGEN_ARRAY_LIST_END_FOREACH_SLOT; } +void +sgen_gc_handles_report_roots (SgenUserReportRootFunc report_func, void *gc_data) +{ + HandleData *handles = gc_handles_for_type (HANDLE_NORMAL); + 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, FALSE); + + if (MONO_GC_HANDLE_IS_OBJECT_POINTER (hidden)) + report_func ((void*)slot, revealed, gc_data); + } SGEN_ARRAY_LIST_END_FOREACH_SLOT; +} + + static guint32 alloc_handle (HandleData *handles, GCObject *obj, gboolean track) diff --git a/mono/sgen/sgen-marksweep.c b/mono/sgen/sgen-marksweep.c index c17846d9decd5..2624aa7f514bb 100644 --- a/mono/sgen/sgen-marksweep.c +++ b/mono/sgen/sgen-marksweep.c @@ -1410,6 +1410,7 @@ mark_pinned_objects_in_block (MSBlockInfo *block, size_t first_entry, size_t las continue; MS_MARK_OBJECT_AND_ENQUEUE (obj, sgen_obj_get_descriptor (obj), block, queue); sgen_pin_stats_register_object (obj, GENERATION_OLD); + sgen_client_pinned_major_heap_object (obj); last_index = index; } diff --git a/mono/sgen/sgen-pinning.c b/mono/sgen/sgen-pinning.c index 6b43771a93ecf..b23b20b58829d 100644 --- a/mono/sgen/sgen-pinning.c +++ b/mono/sgen/sgen-pinning.c @@ -43,6 +43,7 @@ sgen_init_pinning (void) { memset (pin_hash_filter, 0, sizeof (pin_hash_filter)); pin_queue.mem_type = INTERNAL_MEM_PIN_QUEUE; + sgen_client_pinning_start (); } void @@ -367,6 +368,7 @@ pin_from_hash (CementHashEntry *hash, gboolean has_been_reset) if (has_been_reset) SGEN_ASSERT (5, hash [i].count >= SGEN_CEMENT_THRESHOLD, "Cementing hash inconsistent"); + sgen_client_pinned_cemented_object (hash [i].obj); sgen_pin_stage_ptr (hash [i].obj); binary_protocol_cement_stage (hash [i].obj); /* FIXME: do pin stats if enabled */