From bea9457ca23bbf006d0f24674ce08a49499bfe48 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Wed, 4 Aug 2021 12:02:27 +0200 Subject: [PATCH 1/9] Make EventPipe MonoProfiler provider GC events async safe. EventPipe MonoProfiler provider includes most Mono profiler events, but events currently triggered during GC is not emitted since EventPipe is not async safe. This commit add support to emit the MonoProfiler events triggered during GC (gc resize, gc moves, gc roots and heap dump object references) into a async safe temporary memory buffer that will be emitted into EventPipe once GC completes (and world has been restarted). This opens up the ability to do heapshots using EventPipe running on Mono into nettrace files. Heapshots can be triggered in same way as on CoreCLR, creating an EventPipe session with GCHeapCollectKeyword keyword. Only one heapshot can be triggered at a time, so in order to trigger an additional heapshot, a new EventPipe session is setup (after the previous heapshot has completed). Heapshot events will be included in all session with configured keywords. It is also possible to include all vtable/class references (including class name), into heap dump. This is enabled by a specific keyword and makes the dump self contained (no need to track type load etc). That way runtime can start up without any profiler support, and then it is possible to use custom tool or dotnet-trace to request a heap dump (including all referenced vtable/class references) and once that session is done, it is possible to do a new session and get a new separate heap dump into a new session. Having separate sessions in different files opens up the ability to diff between any heap dump over time. --- src/coreclr/vm/ClrEtwAll.man | 69 +- src/coreclr/vm/ClrEtwAllMeta.lst | 3 +- src/mono/mono/eventpipe/ep-rt-mono.c | 1932 ++++++++++++++++++++++---- 3 files changed, 1683 insertions(+), 321 deletions(-) diff --git a/src/coreclr/vm/ClrEtwAll.man b/src/coreclr/vm/ClrEtwAll.man index 8508666c7e51b1..ac4095205696bd 100644 --- a/src/coreclr/vm/ClrEtwAll.man +++ b/src/coreclr/vm/ClrEtwAll.man @@ -7276,12 +7276,16 @@ message="$(string.MonoProfilerPublisher.GCAllocationKeywordMessage)" symbol="CLR_MONO_PROFILER_GC_ALLOCATION_KEYWORD" /> - + + + + @@ -7737,7 +7742,7 @@ - + @@ -7836,6 +7841,21 @@ + + @@ -8040,77 +8060,77 @@ symbol="MonoProfilerGCEvent" message="$(string.MonoProfilerPublisher.GCEventEventMessage)" /> @@ -8158,6 +8178,11 @@ keywords ="JitKeyword" opcode="JitDoneVerbose" task="MonoProfiler" symbol="MonoProfilerJitDoneVerbose" message="$(string.MonoProfilerPublisher.JitDoneVerboseEventMessage)" /> + + @@ -9186,9 +9211,11 @@ + + + - @@ -9268,6 +9295,8 @@ + + @@ -9362,6 +9391,8 @@ + + diff --git a/src/coreclr/vm/ClrEtwAllMeta.lst b/src/coreclr/vm/ClrEtwAllMeta.lst index 911ca624935061..2fae1ae9af5934 100644 --- a/src/coreclr/vm/ClrEtwAllMeta.lst +++ b/src/coreclr/vm/ClrEtwAllMeta.lst @@ -665,4 +665,5 @@ nostack:MonoProfiler:::MonoProfilerThreadStarted nostack:MonoProfiler:::MonoProfilerThreadStopping nostack:MonoProfiler:::MonoProfilerThreadStopped nostack:MonoProfiler:::MonoProfilerThreadExited -nostack:MonoProfiler:::MonoProfilerThreadName \ No newline at end of file +nostack:MonoProfiler:::MonoProfilerThreadName +nostack:MonoProfiler:::MonoProfilerGCHeapDumpVTableClassReference \ No newline at end of file diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index d8bf2c8023b985..2dbd969536949e 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -57,6 +57,7 @@ static uint32_t _ep_rt_mono_max_sampled_thread_count = 32; static MonoProfilerHandle _ep_rt_default_profiler = NULL; static MonoProfilerHandle _ep_rt_dotnet_runtime_profiler_provider = NULL; static MonoProfilerHandle _ep_rt_dotnet_mono_profiler_provider = NULL; +static MonoProfilerHandle _ep_rt_dotnet_mono_profiler_heap_dump_provider = NULL; static MonoCallSpec _ep_rt_dotnet_mono_profiler_provider_callspec = {0}; // Phantom JIT compile method. @@ -120,7 +121,7 @@ bool const uint32_t domain_index, void *user_data); -typedef struct _EventPipeFireMethodEventsData{ +typedef struct _EventPipeFireMethodEventsData { MonoDomain *domain; uint8_t *buffer; size_t buffer_size; @@ -212,28 +213,65 @@ typedef struct _AssemblyEventData AssemblyEventData; #define CONTENTION_KEYWORD 0x4000 #define EXCEPTION_KEYWORD 0x8000 #define THREADING_KEYWORD 0x10000 +#define GC_HEAP_DUMP_KEYWORD 0x100000 #define GC_ALLOCATION_KEYWORD 0x200000 #define GC_MOVES_KEYWORD 0x400000 -#define GC_ROOT_KEYWORD 0x800000 +#define GC_HEAP_COLLECT_KEYWORD 0x800000 #define GC_FINALIZATION_KEYWORD 0x1000000 #define GC_RESIZE_KEYWORD 0x2000000 +#define GC_ROOT_KEYWORD 0x4000000 +#define GC_HEAP_DUMP_VTABLE_CLASS_REF_KEYWORD 0x8000000 #define METHOD_TRACING_KEYWORD 0x20000000 #define TYPE_DIAGNOSTIC_KEYWORD 0x8000000000 #define TYPE_LOADING_KEYWORD 0x8000000000 #define MONITOR_KEYWORD 0x10000000000 #define METHOD_INSTRUMENTATION_KEYWORD 0x40000000000 -// GC provider types. +// MonoProfiler types. +typedef enum { + MONO_PROFILER_BUFFERED_GC_EVENT = 1, + MONO_PROFILER_BUFFERED_GC_EVENT_RESIZE = 2, + MONO_PROFILER_BUFFERED_GC_EVENT_ROOTS = 3, + MONO_PROFILER_BUFFERED_GC_EVENT_MOVES = 4, + MONO_PROFILER_BUFFERED_GC_EVENT_OBJECT_REF = 5, + MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_REGISTER = 6, + MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_UNREGISTER = 7 +} MonoProfilerBufferedGCEventType; + +typedef struct _MonoProfilerBufferedGCEvent MonoProfilerBufferedGCEvent; +struct _MonoProfilerBufferedGCEvent { + MonoProfilerBufferedGCEventType type; + uint32_t payload_size; +}; + +#define MONO_PROFILER_GC_IN_PROGRESS_STATE_VALUE 0xFFFF +#define MONO_PROFILER_MEM_DEFAULT_BLOCK_SIZE (mono_pagesize() * 16) +#define MONO_PROFILER_MEM_BLOCK_SIZE_INC (mono_pagesize()) + +typedef struct _MonoProfilerMemBlock MonoProfilerMemBlock; +struct _MonoProfilerMemBlock { + MonoProfilerMemBlock *next; + MonoProfilerMemBlock *prev; + uint8_t *start; + uint32_t alloc_size; + uint32_t size; + uint32_t offset; + uint32_t last_used_offset; +}; -typedef struct _GCObjectAddressData { - MonoObject *object; - void *address; -} GCObjectAddressData; +// MonoProfiler GC dump. +static volatile MonoProfilerMemBlock *_ep_rt_mono_profiler_mem_blocks = NULL; +static volatile MonoProfilerMemBlock *_ep_rt_mono_profiler_current_mem_block = NULL; +static volatile uint32_t _ep_rt_mono_profiler_gc_heap_dump_requests = 0; +static volatile uint32_t _ep_rt_mono_profiler_gc_heap_dump_in_progress = 0; +static bool _ep_rt_mono_profiler_gc_can_heap_dump = false; -typedef struct _GCAddressObjectData { - void *address; - MonoObject *object; -} GCAddressObjectData; +// Lightweight atomic "exclusive/shared" lock, prevents new fire events to happend while GC is in progress and gives GC ability to wait until all pending fire events are done +// before progressing. State uint32_t is split into two uint16_t, upper uint16_t represent exclusive lock, taken while GC starts, preventing new fire events to execute and lower +// uint16_t keeps number of fire events in progress, (gc_in_progress << 16) | (fire_event_count & 0xFFFF). Spin lock is only taken on slow path to queue up pending shared requests +// while GC is in progress and should very rarely be needed. +static volatile uint32_t _ep_rt_mono_profiler_gc_state = 0; +static ep_rt_spin_lock_handle_t _ep_rt_mono_profiler_gc_state_lock = {0}; /* * Forward declares of all static functions. @@ -336,6 +374,10 @@ eventpipe_sample_profiler_walk_managed_stack_for_thread_func ( MonoContext *ctx, void *data); +static +void +profiler_eventpipe_runtime_initialized (MonoProfiler *prof); + static void profiler_eventpipe_thread_exited ( @@ -484,6 +526,163 @@ runtime_profiler_jit_code_buffer ( MonoProfilerCodeBufferType type, const void *data); +static +void +mono_profiler_get_class_data ( + MonoClass *klass, + uint64_t *class_id, + uint64_t *module_id, + ep_char8_t **class_name, + uint32_t *class_generic_type_count, + uint8_t **class_generic_types); + +static +void +mono_profiler_fire_event_enter (void); + +static +void +mono_profiler_fire_event_exit (void); + +static +void +mono_profiler_gc_in_progress_start (void); + +static +void +mono_profiler_gc_in_progress_stop (void); + +static +MonoProfilerMemBlock * +mono_profiler_mem_block_alloc (uint32_t req_size); + +static +uint8_t * +mono_profiler_mem_alloc (uint32_t req_size); + +static +void +mono_profiler_mem_block_free_all (void); + +static +void +mono_profiler_mem_block_free_all_but_current (void); + +static +void +mono_profiler_trigger_heap_dump (MonoProfiler *prof); + +static +void +mono_profiler_fire_gc_event_root_register ( + uint8_t *data, + uint32_t payload_size); + +static +void +mono_profiler_fire_buffered_gc_event_root_register ( + MonoProfiler *prof, + const mono_byte *start, + uintptr_t size, + MonoGCRootSource source, + const void * key, + const char * name); + +static +void +mono_profiler_fire_gc_event_root_unregister ( + uint8_t *data, + uint32_t payload_size); + +static +void +mono_profiler_fire_buffered_gc_event_root_unregister ( + MonoProfiler *prof, + const mono_byte *start); + +static +void +mono_profiler_fire_gc_event ( + uint8_t *data, + uint32_t payload_size); + +static +void +mono_profiler_fire_buffered_gc_event ( + uint8_t gc_event_type, + uint32_t generation); + +static +void +mono_profiler_fire_gc_event_resize ( + uint8_t *data, + uint32_t payload_size); + +static +void +mono_profiler_fire_buffered_gc_event_resize ( + MonoProfiler *prof, + uintptr_t size); + +static +void +mono_profiler_fire_gc_event_moves ( + uint8_t *data, + uint32_t payload_size); + +static +void +mono_profiler_fire_buffered_gc_event_moves ( + MonoProfiler *prof, + MonoObject *const* objects, + uint64_t count); + +static +void +mono_profiler_fire_gc_event_roots ( + uint8_t *data, + uint32_t payload_size); + +static +void +mono_profiler_fire_buffered_gc_event_roots ( + MonoProfiler *prof, + uint64_t count, + const mono_byte *const * addresses, + MonoObject *const * objects); + +static +void +mono_profiler_fire_gc_event_heap_dump_object_reference ( + uint8_t *data, + uint32_t payload_size, + GHashTable *cache); + +static +int +mono_profiler_fire_buffered_gc_event_heap_dump_object_reference ( + MonoObject *obj, + MonoClass *klass, + uintptr_t size, + uintptr_t num, + MonoObject **refs, + uintptr_t *offsets, + void *data); + +static +void +mono_profiler_fire_buffered_gc_events ( + MonoProfilerMemBlock *block, + GHashTable *cache); + +static +void +mono_profiler_fire_buffered_gc_events_in_alloc_order (GHashTable *cache); + +static +void +mono_profiler_fire_cached_gc_events (GHashTable *cache); + static void mono_profiler_app_domain_loading ( @@ -573,16 +772,6 @@ mono_profiler_jit_code_buffer ( MonoProfilerCodeBufferType type, const void *data); -static -void -mono_profiler_get_class_data ( - MonoClass *klass, - uint64_t *class_id, - uint64_t *module_id, - ep_char8_t **class_name, - uint32_t *class_generic_type_count, - uint8_t **class_generic_types); - static void mono_profiler_class_loading ( @@ -754,19 +943,6 @@ mono_profiler_gc_allocation ( MonoProfiler *prof, MonoObject *object); -static -void -mono_profiler_gc_moves ( - MonoProfiler *prof, - MonoObject *const* objects, - uint64_t count); - -static -void -mono_profiler_gc_resize ( - MonoProfiler *prof, - uintptr_t size); - static void mono_profiler_gc_handle_created ( @@ -806,14 +982,6 @@ mono_profiler_gc_root_unregister ( MonoProfiler *prof, const mono_byte *start); -static -void -mono_profiler_gc_roots ( - MonoProfiler *prof, - uint64_t count, - const mono_byte *const * addresses, - MonoObject *const * objects); - static void mono_profiler_monitor_contention ( @@ -863,6 +1031,17 @@ mono_profiler_thread_name ( uintptr_t tid, const char *name); +static +void +mono_profiler_ep_provider_callback ( + const uint8_t *source_id, + unsigned long is_enabled, + uint8_t level, + uint64_t match_any_keywords, + uint64_t match_all_keywords, + EventFilterDescriptor *filter_data, + void *callback_data); + /* * Forward declares of all private functions (accessed using extern in ep-rt-mono.h). */ @@ -1596,6 +1775,13 @@ eventpipe_sample_profiler_walk_managed_stack_for_thread_func ( return eventpipe_walk_managed_stack_for_thread (frame, ctx, &sample_data->stack_walk_data); } +static +void +profiler_eventpipe_runtime_initialized (MonoProfiler *prof) +{ + _ep_rt_mono_profiler_gc_can_heap_dump = true; +} + static void profiler_eventpipe_thread_exited ( @@ -1639,6 +1825,7 @@ ep_rt_mono_component_init (void) _ep_rt_default_profiler = mono_profiler_create (NULL); _ep_rt_dotnet_runtime_profiler_provider = mono_profiler_create (NULL); _ep_rt_dotnet_mono_profiler_provider = mono_profiler_create (NULL); + _ep_rt_dotnet_mono_profiler_heap_dump_provider = mono_profiler_create (NULL); char *diag_env = g_getenv("MONO_DIAGNOSTICS"); if (diag_env) { @@ -1701,7 +1888,11 @@ ep_rt_mono_init (void) EP_ASSERT (_ep_rt_default_profiler != NULL); EP_ASSERT (_ep_rt_dotnet_runtime_profiler_provider != NULL); EP_ASSERT (_ep_rt_dotnet_mono_profiler_provider != NULL); + EP_ASSERT (_ep_rt_dotnet_mono_profiler_heap_dump_provider != NULL); + + ep_rt_spin_lock_alloc (&_ep_rt_mono_profiler_gc_state_lock); + mono_profiler_set_runtime_initialized_callback (_ep_rt_default_profiler, profiler_eventpipe_runtime_initialized); mono_profiler_set_thread_stopped_callback (_ep_rt_default_profiler, profiler_eventpipe_thread_exited); MonoMethodSignature *method_signature = mono_metadata_signature_alloc (mono_get_corlib (), 1); @@ -1818,6 +2009,8 @@ ep_rt_mono_fini (void) mono_callspec_cleanup (&_ep_rt_dotnet_mono_profiler_provider_callspec); } + ep_rt_spin_lock_free (&_ep_rt_mono_profiler_gc_state_lock); + _ep_rt_mono_sampled_thread_callstacks = NULL; _ep_rt_mono_rand_provider = NULL; _ep_rt_mono_initialized = FALSE; @@ -3558,13 +3751,13 @@ EventPipeEtwCallbackDotNETRuntime ( } } - if (profiler_callback_is_enabled(match_any_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD | THREADING_KEYWORD)) { - if (!profiler_callback_is_enabled(enabled_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD | THREADING_KEYWORD)) { + if (profiler_callback_is_enabled(match_any_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD) || profiler_callback_is_enabled(match_any_keywords, THREADING_KEYWORD)) { + if (!(profiler_callback_is_enabled(enabled_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD) || profiler_callback_is_enabled(enabled_keywords, THREADING_KEYWORD))) { mono_profiler_set_thread_started_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_thread_started); mono_profiler_set_thread_stopped_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_thread_stopped); } } else { - if (profiler_callback_is_enabled (enabled_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD | THREADING_KEYWORD)) { + if (profiler_callback_is_enabled (enabled_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD) || profiler_callback_is_enabled (enabled_keywords, THREADING_KEYWORD)) { mono_profiler_set_thread_started_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); mono_profiler_set_thread_stopped_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); } @@ -3668,118 +3861,1032 @@ EventPipeEtwCallbackDotNETRuntimeStress ( MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); } + +inline +uint32_t +mono_profiler_atomic_cas_uint32_t (volatile uint32_t *target, uint32_t expected, uint32_t value) +{ + return (uint32_t)(mono_atomic_cas_i32 ((volatile gint32 *)(target), (gint32)(value), (gint32)(expected))); +} + static void -mono_profiler_app_domain_loading ( - MonoProfiler *prof, - MonoDomain *domain) +mono_profiler_fire_event_enter (void) { - if (!EventEnabledMonoProfilerAppDomainLoading ()) - return; + uint32_t old_state = 0; + uint32_t new_state = 0; - uint64_t domain_id = (uint64_t)domain; - FireEtwMonoProfilerAppDomainLoading ( - domain_id, - NULL, - NULL); + // NOTE, mono_profiler_fire_event_start should never be called recursivly. + do { + old_state = ep_rt_volatile_load_uint32_t (&_ep_rt_mono_profiler_gc_state); + if (((uint16_t)(old_state >> 16)) == MONO_PROFILER_GC_IN_PROGRESS_STATE_VALUE) { + // GC in progress and thread tries to fire event (this should be an unlikely scenario). Wait until GC is done. + ep_rt_spin_lock_aquire (&_ep_rt_mono_profiler_gc_state_lock); + ep_rt_spin_lock_release (&_ep_rt_mono_profiler_gc_state_lock); + } + // Increase number of enter calls. + new_state = old_state + 1; + } while (mono_profiler_atomic_cas_uint32_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state); } static void -mono_profiler_app_domain_loaded ( - MonoProfiler *prof, - MonoDomain *domain) +mono_profiler_fire_event_exit (void) { - if (!EventEnabledMonoProfilerAppDomainLoaded ()) - return; + uint32_t old_state = 0; + uint32_t new_state = 0; + uint16_t gc_in_progress = 0; + uint16_t count = 0; - uint64_t domain_id = (uint64_t)domain; - FireEtwMonoProfilerAppDomainLoaded ( - domain_id, - NULL, - NULL); + do { + old_state = ep_rt_volatile_load_uint32_t (&_ep_rt_mono_profiler_gc_state); + count = (uint16_t)old_state; + gc_in_progress = old_state >> 16; + new_state = (uint32_t)(gc_in_progress << 16) | (uint32_t)(--count); + } while (mono_profiler_atomic_cas_uint32_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state); } static void -mono_profiler_app_domain_unloading ( - MonoProfiler *prof, - MonoDomain *domain) +mono_profiler_gc_in_progress_start (void) { - if (!EventEnabledMonoProfilerAppDomainUnloading ()) - return; + uint32_t old_state = 0; + uint32_t new_state = 0; + uint16_t count = 0; - uint64_t domain_id = (uint64_t)domain; - FireEtwMonoProfilerAppDomainUnloading ( - domain_id, - NULL, - NULL); + // Make sure fire event calls will block and wait for GC completion. + ep_rt_spin_lock_aquire (&_ep_rt_mono_profiler_gc_state_lock); + + // Mark gc state in progress bits, preventing new fire event requests. + do { + old_state = ep_rt_volatile_load_uint32_t (&_ep_rt_mono_profiler_gc_state); + count = (uint16_t)old_state; + EP_ASSERT ((old_state >> 16) == 0); + new_state = (uint32_t)(MONO_PROFILER_GC_IN_PROGRESS_STATE_VALUE << 16) | (uint32_t)(count); + } while (mono_profiler_atomic_cas_uint32_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state); + + // Wait for all fire events to complete before progressing with gc. + // NOTE, mono_profiler_fire_event_start should never be called recursivly. + // Default yield count used in SpinLock.cs. + int yield_count = 40; + while (count) { + if (yield_count > 0) { + ep_rt_mono_thread_yield (); + yield_count --; + } else { + ep_rt_thread_sleep (200); + } + count = (uint16_t)ep_rt_volatile_load_uint32_t (&_ep_rt_mono_profiler_gc_state); + } } static void -mono_profiler_app_domain_unloaded ( - MonoProfiler *prof, - MonoDomain *domain) +mono_profiler_gc_in_progress_stop (void) { - if (!EventEnabledMonoProfilerAppDomainUnloaded ()) - return; + uint32_t old_state = 0; - uint64_t domain_id = (uint64_t)domain; - FireEtwMonoProfilerAppDomainUnloaded ( - domain_id, - NULL, - NULL); + // Reset gc in progress bits. + do { + old_state = ep_rt_volatile_load_uint32_t (&_ep_rt_mono_profiler_gc_state); + EP_ASSERT ((old_state >> 16) == MONO_PROFILER_GC_IN_PROGRESS_STATE_VALUE); + EP_ASSERT (((uint16_t)old_state) == 0); + } while (mono_profiler_atomic_cas_uint32_t (&_ep_rt_mono_profiler_gc_state, old_state, 0) != old_state); + + // Make sure fire events can continune to execute. + ep_rt_spin_lock_release (&_ep_rt_mono_profiler_gc_state_lock); } static -void -mono_profiler_app_domain_name ( - MonoProfiler *prof, - MonoDomain *domain, - const char *name) +inline +bool +mono_profiler_gc_in_progress (void) { - if (!EventEnabledMonoProfilerAppDomainName ()) - return; + return ((ep_rt_volatile_load_uint32_t(&_ep_rt_mono_profiler_gc_state) >> 16) == MONO_PROFILER_GC_IN_PROGRESS_STATE_VALUE) != 0 ? true : false; +} - uint64_t domain_id = (uint64_t)domain; - FireEtwMonoProfilerAppDomainName ( - domain_id, - (const ep_char8_t *)(name ? name : ""), - NULL, - NULL); +static +inline +bool +mono_profiler_gc_can_heap_dump (void) +{ + return _ep_rt_mono_profiler_gc_can_heap_dump; } static +inline void -mono_profiler_get_generic_types ( - MonoGenericInst *generic_instance, - uint32_t *generic_type_count, - uint8_t **generic_types) +mono_profiler_gc_heap_dump_requests_inc (void) { - if (generic_instance) { - uint8_t *buffer = g_malloc (generic_instance->type_argc * (sizeof (uint8_t) + sizeof (uint64_t))); - if (buffer) { - *generic_types = buffer; - *generic_type_count = generic_instance->type_argc; - for (uint32_t i = 0; i < generic_instance->type_argc; ++i) { - uint8_t type = generic_instance->type_argv [i]->type; - memcpy (buffer, &type, sizeof (type)); - buffer += sizeof (type); - - uint64_t class_id = (uint64_t)mono_class_from_mono_type_internal (generic_instance->type_argv [i]); - memcpy (buffer, &class_id, sizeof (class_id)); - buffer += sizeof (class_id); - } - } - } + EP_ASSERT (mono_profiler_gc_can_heap_dump ()); + ep_rt_atomic_inc_uint32_t (&_ep_rt_mono_profiler_gc_heap_dump_requests); } static +inline void -mono_profiler_get_jit_data ( - MonoMethod *method, - uint64_t *method_id, +mono_profiler_gc_heap_dump_requests_dec (void) +{ + EP_ASSERT (mono_profiler_gc_can_heap_dump ()); + ep_rt_atomic_dec_uint32_t (&_ep_rt_mono_profiler_gc_heap_dump_requests); +} + +static +inline +bool +mono_profiler_gc_heap_dump_requested (void) +{ + if (!mono_profiler_gc_can_heap_dump ()) + return false; + + return ep_rt_volatile_load_uint32_t(&_ep_rt_mono_profiler_gc_heap_dump_requests) != 0 ? true : false; +} + +static +inline +bool +mono_profiler_gc_heap_dump_in_progress (void) +{ + return ep_rt_volatile_load_uint32_t(&_ep_rt_mono_profiler_gc_heap_dump_in_progress) != 0 ? true : false; +} + +static +inline +void +mono_profiler_gc_heap_dump_in_progress_start (void) +{ + EP_ASSERT (mono_profiler_gc_can_heap_dump ()); + ep_rt_volatile_store_uint32_t(&_ep_rt_mono_profiler_gc_heap_dump_in_progress, 1); +} + +static +inline +void +mono_profiler_gc_heap_dump_in_progress_stop (void) +{ + EP_ASSERT (mono_profiler_gc_can_heap_dump ()); + ep_rt_volatile_store_uint32_t(&_ep_rt_mono_profiler_gc_heap_dump_in_progress, 0); +} + +static +MonoProfilerMemBlock * +mono_profiler_mem_block_alloc (uint32_t req_size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + volatile MonoProfilerMemBlock *prev = NULL; + + uint32_t size = MONO_PROFILER_MEM_DEFAULT_BLOCK_SIZE; + while (size - sizeof(MonoProfilerMemBlock) < req_size) + size += MONO_PROFILER_MEM_BLOCK_SIZE_INC; + + MonoProfilerMemBlock *block = mono_valloc (NULL, size, MONO_MMAP_READ | MONO_MMAP_WRITE | MONO_MMAP_ANON | MONO_MMAP_PRIVATE, MONO_MEM_ACCOUNT_PROFILER); + if (block) { + block->alloc_size = size; + block->start = (uint8_t *)ALIGN_PTR_TO ((uint8_t *)block + sizeof (MonoProfilerMemBlock), 16); + block->size = (uint32_t)(((uint8_t*)block + size) - (uint8_t*)block->start); + block->offset = 0; + block->last_used_offset = 0; + + while (true) { + prev = _ep_rt_mono_profiler_mem_blocks; + if (mono_atomic_cas_ptr ((volatile gpointer*)&_ep_rt_mono_profiler_mem_blocks, block, prev) == prev) + break; + } + + if (prev) + prev->next = block; + block->prev = prev; + } + + return block; +} + +static +uint8_t * +mono_profiler_mem_alloc (uint32_t req_size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + volatile MonoProfilerMemBlock *current_block = _ep_rt_mono_profiler_current_mem_block; + uint8_t *buffer = NULL; + + if (!current_block) { + current_block = mono_profiler_mem_block_alloc (req_size); + if (current_block) { + mono_memory_barrier (); + _ep_rt_mono_profiler_current_mem_block = current_block; + } + } + + if (current_block) { + uint32_t prev_offset = (uint32_t)mono_atomic_fetch_add_i32 ((volatile int32_t *)¤t_block->offset, (int32_t)req_size); + if (prev_offset + req_size > current_block->size) { + if (prev_offset <= current_block->size) + current_block->last_used_offset = prev_offset; + current_block = mono_profiler_mem_block_alloc (req_size); + if (current_block) { + buffer = current_block->start; + current_block->offset += req_size; + mono_memory_barrier (); + _ep_rt_mono_profiler_current_mem_block = current_block; + } + } else { + buffer = (uint8_t*)current_block->start + prev_offset; + } + } + + return buffer; +} + +static +void +mono_profiler_mem_block_free_all (void) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + volatile MonoProfilerMemBlock *current_block = _ep_rt_mono_profiler_current_mem_block; + while (current_block) { + MonoProfilerMemBlock *prev_block = current_block->prev; + mono_vfree ((uint8_t *)current_block, current_block->alloc_size, MONO_MEM_ACCOUNT_MEM_MANAGER); + current_block = prev_block; + } + + _ep_rt_mono_profiler_current_mem_block = NULL; + _ep_rt_mono_profiler_mem_blocks = NULL; +} + +static +void +mono_profiler_mem_block_free_all_but_current (void) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + volatile MonoProfilerMemBlock *current_block = _ep_rt_mono_profiler_current_mem_block; + if (current_block) { + if (current_block->prev) { + current_block = current_block->prev; + while (current_block) { + MonoProfilerMemBlock *prev_block = current_block->prev; + mono_vfree ((uint8_t *)current_block, current_block->alloc_size, MONO_MEM_ACCOUNT_MEM_MANAGER); + current_block = prev_block; + } + } + _ep_rt_mono_profiler_current_mem_block->prev = NULL; + _ep_rt_mono_profiler_current_mem_block->next = NULL; + _ep_rt_mono_profiler_current_mem_block->offset = 0; + _ep_rt_mono_profiler_current_mem_block->last_used_offset = 0; + + } + + _ep_rt_mono_profiler_mem_blocks = _ep_rt_mono_profiler_current_mem_block; +} + +static +inline +uint8_t * +mono_profiler_buffered_gc_event_alloc (uint32_t req_size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + return mono_profiler_mem_alloc (req_size + sizeof (MonoProfilerBufferedGCEvent)); +} + +static +void +mono_profiler_trigger_heap_dump (MonoProfiler *prof) +{ + if (mono_profiler_gc_heap_dump_requested ()) { + mono_gc_collect (mono_gc_max_generation ()); + mono_profiler_gc_heap_dump_requests_dec (); + } +} + +static +void +mono_profiler_fire_gc_event_root_register ( + uint8_t *data, + uint32_t payload_size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uintptr_t root_id; + uintptr_t root_size; + uint8_t root_source; + uintptr_t root_key; + + memcpy (&root_id, data, sizeof (root_id)); + data += sizeof (root_id); + + memcpy (&root_size, data, sizeof (root_size)); + data += sizeof (root_size); + + memcpy (&root_source, data, sizeof (root_source)); + data += sizeof (root_source); + + memcpy (&root_key, data, sizeof (root_key)); + data += sizeof (root_key); + + FireEtwMonoProfilerGCRootRegister ( + (const void *)root_id, + (uint64_t)root_size, + root_source, + (uint64_t)root_key, + (const ep_char8_t *)data, + NULL, + NULL); +} + +static +void +mono_profiler_fire_buffered_gc_event_root_register ( + MonoProfiler *prof, + const mono_byte *start, + uintptr_t size, + MonoGCRootSource source, + const void * key, + const char * name) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uintptr_t root_id = (uintptr_t)start; + uintptr_t root_size = size; + uint8_t root_source = (uint8_t)source; + uintptr_t root_key = (uintptr_t)key; + const char *root_name = (name ? name : ""); + uint32_t root_name_len = strlen (root_name) + 1; + + MonoProfilerBufferedGCEvent gc_event_data; + gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_REGISTER; + gc_event_data.payload_size = + sizeof (root_id) + + sizeof (root_size) + + sizeof (root_source) + + sizeof (root_key) + + root_name_len; + + uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size); + if (buffer) { + // Internal header + memcpy (buffer, &gc_event_data, sizeof (gc_event_data)); + buffer += sizeof (gc_event_data); + + // GCEvent.RootID + memcpy(buffer, &root_id, sizeof (root_id)); + buffer += sizeof (root_id); + + // GCEvent.RootSize + memcpy(buffer, &root_size, sizeof (root_size)); + buffer += sizeof (root_size); + + // GCEvent.RootType + memcpy(buffer, &root_source, sizeof (root_source)); + buffer += sizeof (root_source); + + // GCEvent.RootKeyID + memcpy(buffer, &root_key, sizeof (root_key)); + buffer += sizeof (root_key); + + // GCEvent.RootKeyName + memcpy(buffer, root_name, root_name_len); + } +} + +static +void +mono_profiler_fire_gc_event_root_unregister ( + uint8_t *data, + uint32_t payload_size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uintptr_t root_id; + + memcpy (&root_id, data, sizeof (root_id)); + + FireEtwMonoProfilerGCRootUnregister ( + (const void *)root_id, + NULL, + NULL); +} + +static +void +mono_profiler_fire_buffered_gc_event_root_unregister ( + MonoProfiler *prof, + const mono_byte *start) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uintptr_t root_id = (uintptr_t)start; + + MonoProfilerBufferedGCEvent gc_event_data; + gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_UNREGISTER; + gc_event_data.payload_size = sizeof (root_id); + + uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size); + if (buffer) { + // Internal header + memcpy (buffer, &gc_event_data, sizeof (gc_event_data)); + buffer += sizeof (gc_event_data); + + // GCEvent.RootID + memcpy(buffer, &root_id, sizeof (root_id)); + } +} + +static +void +mono_profiler_fire_gc_event ( + uint8_t *data, + uint32_t payload_size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uint8_t gc_event_type; + uint32_t generation; + + memcpy (&gc_event_type, data, sizeof (gc_event_type)); + data += sizeof (gc_event_type); + + memcpy (&generation, data, sizeof (generation)); + + FireEtwMonoProfilerGCEvent ( + gc_event_type, + generation, + NULL, + NULL); +} + +static +void +mono_profiler_fire_buffered_gc_event ( + uint8_t gc_event_type, + uint32_t generation) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + MonoProfilerBufferedGCEvent gc_event_data; + gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT; + gc_event_data.payload_size = + sizeof (gc_event_type) + + sizeof (generation); + + uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size); + if (buffer) { + // Internal header + memcpy (buffer, &gc_event_data, sizeof (gc_event_data)); + buffer += sizeof (gc_event_data); + + // GCEvent.GCEventType + memcpy(buffer, &gc_event_type, sizeof (gc_event_type)); + buffer += sizeof (gc_event_type); + + // GCEvent.GCGeneration + memcpy(buffer, &generation, sizeof (generation)); + } +} + +static +void +mono_profiler_fire_gc_event_resize ( + uint8_t *data, + uint32_t payload_size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uintptr_t size; + + memcpy (&size, data, sizeof (size)); + + FireEtwMonoProfilerGCResize ( + (uint64_t)size, + NULL, + NULL); +} + +static +void +mono_profiler_fire_buffered_gc_event_resize ( + MonoProfiler *prof, + uintptr_t size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + MonoProfilerBufferedGCEvent gc_event_data; + gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_RESIZE; + gc_event_data.payload_size = sizeof (size); + + uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size); + if (buffer) { + // Internal header + memcpy (buffer, &gc_event_data, sizeof (gc_event_data)); + buffer += sizeof (gc_event_data); + + // GCResize.NewSize + memcpy(buffer, &size, sizeof (size)); + } +} + +static +void +mono_profiler_fire_gc_event_moves ( + uint8_t *data, + uint32_t payload_size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uint64_t count; + + memcpy (&count, data, sizeof (count)); + data += sizeof (count); + + FireEtwMonoProfilerGCMoves ( + (uint32_t)count, + sizeof (uintptr_t) + sizeof (uintptr_t), + data, + NULL, + NULL); +} + +static +void +mono_profiler_fire_buffered_gc_event_moves ( + MonoProfiler *prof, + MonoObject *const* objects, + uint64_t count) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uintptr_t object_id; + uintptr_t address_id; + + // Serialized as object_id/address_id pairs. + count = count / 2; + + MonoProfilerBufferedGCEvent gc_event_data; + gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_MOVES; + gc_event_data.payload_size = + sizeof (count) + + (count * (sizeof (uintptr_t) + sizeof (uintptr_t))); + + uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size); + if (buffer) { + // Internal header + memcpy (buffer, &gc_event_data, sizeof (gc_event_data)); + buffer += sizeof (gc_event_data); + + // GCMoves.Count + memcpy (buffer, &count, sizeof (count)); + buffer += sizeof (count); + + // Serialize directly as memory stream expected by FireEtwMonoProfilerGCMoves. + for (uint64_t i = 0; i < count; i++) { + // GCMoves.Values[].ObjectID. + object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (*objects); + memcpy (buffer, &object_id, sizeof (object_id)); + buffer += sizeof (object_id); + objects++; + + // GCMoves.Values[].AddressID. + address_id = (uintptr_t)*objects; + memcpy (buffer, &address_id, sizeof (address_id)); + buffer += sizeof (address_id); + objects++; + } + } +} + +static +void +mono_profiler_fire_gc_event_roots ( + uint8_t *data, + uint32_t payload_size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uint64_t count; + + memcpy (&count, data, sizeof (count)); + data += sizeof (count); + + FireEtwMonoProfilerGCRoots ( + (uint32_t)count, + sizeof (uintptr_t) + sizeof (uintptr_t), + data, + NULL, + NULL); +} + +static +void +mono_profiler_fire_buffered_gc_event_roots ( + MonoProfiler *prof, + uint64_t count, + const mono_byte *const * addresses, + MonoObject *const * objects) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uintptr_t object_id; + uintptr_t address_id; + + MonoProfilerBufferedGCEvent gc_event_data; + gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_ROOTS; + gc_event_data.payload_size = + sizeof (count) + + (count * (sizeof (uintptr_t) + sizeof (uintptr_t))); + + uint8_t * buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size); + if (buffer) { + // Internal header + memcpy (buffer, &gc_event_data, sizeof (gc_event_data)); + buffer += sizeof (gc_event_data); + + // GCRoots.Count + memcpy (buffer, &count, sizeof (count)); + buffer += sizeof (count); + + // Serialize directly as memory stream expected by FireEtwMonoProfilerGCRoots. + for (uint64_t i = 0; i < count; i++) { + // GCRoots.Values[].ObjectID. + object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (*objects); + memcpy (buffer, &object_id, sizeof (object_id)); + buffer += sizeof (object_id); + objects++; + + // GCRoots.Values[].AddressID. + address_id = (uintptr_t)*objects; + memcpy (buffer, &address_id, sizeof (address_id)); + buffer += sizeof (address_id); + addresses++; + } + } +} + +static +void +mono_profiler_fire_gc_event_heap_dump_object_reference ( + uint8_t *data, + uint32_t payload_size, + GHashTable *cache) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uintptr_t object_id; + uintptr_t vtable_id; + uintptr_t object_size; + uint8_t object_gen; + uintptr_t object_ref_count; + + memcpy (&object_id, data, sizeof (object_id)); + data += sizeof (object_id); + + memcpy (&vtable_id, data, sizeof (vtable_id)); + data += sizeof (vtable_id); + + memcpy (&object_size, data, sizeof (object_size)); + data += sizeof (object_size); + + memcpy (&object_gen, data, sizeof (object_gen)); + data += sizeof (object_gen); + + memcpy (&object_ref_count, data, sizeof (object_ref_count)); + data += sizeof (object_ref_count); + + FireEtwMonoProfilerGCHeapDumpObjectReference ( + (const void *)object_id, + (uint64_t)vtable_id, + (uint64_t)object_size, + object_gen, + (uint32_t)object_ref_count, + sizeof (uint32_t) + sizeof (uintptr_t), + data, + NULL, + NULL); + + if (cache) + g_hash_table_insert (cache, (MonoVTable *)SGEN_POINTER_UNTAG_ALL (vtable_id), NULL); +} + +static +int +mono_profiler_fire_buffered_gc_event_heap_dump_object_reference ( + MonoObject *obj, + MonoClass *klass, + uintptr_t size, + uintptr_t num, + MonoObject **refs, + uintptr_t *offsets, + void *data) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + uintptr_t object_id; + uintptr_t vtable_id; + uint8_t object_gen; + uintptr_t object_size = size; + uintptr_t object_ref_count = num; + uint32_t object_ref_offset; + + /* account for object alignment */ + object_size += 7; + object_size &= ~7; + + MonoProfilerBufferedGCEvent gc_event_data; + gc_event_data.type = MONO_PROFILER_BUFFERED_GC_EVENT_OBJECT_REF; + gc_event_data.payload_size = + sizeof (object_id) + + sizeof (vtable_id) + + sizeof (object_size) + + sizeof (object_gen) + + sizeof (object_ref_count) + + (object_ref_count * (sizeof (uint32_t) + sizeof (uintptr_t))); + + uint8_t *buffer = mono_profiler_buffered_gc_event_alloc (gc_event_data.payload_size); + if (buffer) { + // Internal header + memcpy (buffer, &gc_event_data, sizeof (gc_event_data)); + buffer += sizeof (gc_event_data); + + // GCEvent.ObjectID + object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (obj); + memcpy (buffer, &object_id, sizeof (object_id)); + buffer += sizeof (object_id); + + // GCEvent.VTableID + vtable_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (mono_object_get_vtable_internal (obj)); + memcpy (buffer, &vtable_id, sizeof (vtable_id)); + buffer += sizeof (vtable_id); + + // GCEvent.ObjectSize + memcpy (buffer, &object_size, sizeof (object_size)); + buffer += sizeof (object_size); + + // GCEvent.ObjectGeneration + object_gen = (uint8_t)mono_gc_get_generation (obj); + memcpy (buffer, &object_gen, sizeof (object_gen)); + buffer += sizeof (object_gen); + + // GCEvent.Count + memcpy (buffer, &object_ref_count, sizeof (object_ref_count)); + buffer += sizeof (object_ref_count); + + // Serialize directly as memory stream expected by FireEtwMonoProfilerGCHeapDumpObjectReference. + uintptr_t last_offset = 0; + for (int i = 0; i < object_ref_count; i++) { + // GCEvent.Values[].ReferencesOffset + object_ref_offset = offsets [i] - last_offset; + memcpy (buffer, &object_ref_offset, sizeof (object_ref_offset)); + buffer += sizeof (object_ref_offset); + + // GCEvent.Values[].ObjectID + object_id = (uintptr_t)SGEN_POINTER_UNTAG_ALL (refs[i]); + memcpy (buffer, &object_id, sizeof (object_id)); + buffer += sizeof (object_id); + + last_offset = offsets [i]; + } + } + + return 0; +} + +static +void +mono_profiler_fire_buffered_gc_events ( + MonoProfilerMemBlock *block, + GHashTable *cache) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + if (block) { + uint32_t current_offset = 0; + uint32_t used_size = (block->offset < block->size) ? block->offset : block->last_used_offset; + MonoProfilerBufferedGCEvent gc_event; + while ((current_offset + sizeof (gc_event)) <= used_size) { + uint8_t *data = block->start + current_offset; + memcpy (&gc_event, data, sizeof (gc_event)); + data += sizeof (gc_event); + if ((current_offset + sizeof (gc_event) + gc_event.payload_size) <= used_size) { + switch (gc_event.type) { + case MONO_PROFILER_BUFFERED_GC_EVENT: + mono_profiler_fire_gc_event (data, gc_event.payload_size); + break; + case MONO_PROFILER_BUFFERED_GC_EVENT_RESIZE: + mono_profiler_fire_gc_event_resize (data, gc_event.payload_size); + break; + case MONO_PROFILER_BUFFERED_GC_EVENT_ROOTS: + mono_profiler_fire_gc_event_roots (data, gc_event.payload_size); + break; + case MONO_PROFILER_BUFFERED_GC_EVENT_MOVES: + mono_profiler_fire_gc_event_moves (data, gc_event.payload_size); + break; + case MONO_PROFILER_BUFFERED_GC_EVENT_OBJECT_REF: + mono_profiler_fire_gc_event_heap_dump_object_reference (data, gc_event.payload_size, cache); + break; + case MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_REGISTER: + mono_profiler_fire_gc_event_root_register (data, gc_event.payload_size); + break; + case MONO_PROFILER_BUFFERED_GC_EVENT_ROOT_UNREGISTER: + mono_profiler_fire_gc_event_root_unregister (data, gc_event.payload_size); + break; + default: + EP_ASSERT (!"Unknown buffered GC event type."); + } + + current_offset += sizeof (gc_event) + gc_event.payload_size; + } else { + break; + } + } + } +} + +static +void +mono_profiler_fire_buffered_gc_events_in_alloc_order (GHashTable *cache) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + volatile MonoProfilerMemBlock *first_block = _ep_rt_mono_profiler_current_mem_block; + while (first_block && first_block->prev) + first_block = first_block->prev; + + MonoProfilerMemBlock *current_block = first_block; + while (current_block) { + MonoProfilerMemBlock *next_block = current_block->next; + mono_profiler_fire_buffered_gc_events (current_block, cache); + current_block = next_block; + } + + mono_profiler_mem_block_free_all_but_current (); +} + +static +void +mono_profiler_fire_cached_gc_events (GHashTable *cache) +{ + if (cache) { + GHashTableIter iter; + MonoVTable *object_vtable; + g_hash_table_iter_init (&iter, cache); + while (g_hash_table_iter_next (&iter, (void**)&object_vtable, NULL)) { + if (object_vtable) { + uint64_t vtable_id = (uint64_t)object_vtable; + uint64_t class_id; + uint64_t module_id; + ep_char8_t *class_name; + mono_profiler_get_class_data (object_vtable->klass, &class_id, &module_id, &class_name, NULL, NULL); + FireEtwMonoProfilerGCHeapDumpVTableClassReference ( + vtable_id, + class_id, + module_id, + class_name, + NULL, + NULL); + g_free (class_name); + } + } + } +} + +static +void +mono_profiler_app_domain_loading ( + MonoProfiler *prof, + MonoDomain *domain) +{ + if (!EventEnabledMonoProfilerAppDomainLoading ()) + return; + + uint64_t domain_id = (uint64_t)domain; + + mono_profiler_fire_event_enter (); + + FireEtwMonoProfilerAppDomainLoading ( + domain_id, + NULL, + NULL); + + mono_profiler_fire_event_exit (); +} + +static +void +mono_profiler_app_domain_loaded ( + MonoProfiler *prof, + MonoDomain *domain) +{ + if (!EventEnabledMonoProfilerAppDomainLoaded ()) + return; + + uint64_t domain_id = (uint64_t)domain; + + mono_profiler_fire_event_enter (); + + FireEtwMonoProfilerAppDomainLoaded ( + domain_id, + NULL, + NULL); + + mono_profiler_fire_event_exit (); +} + +static +void +mono_profiler_app_domain_unloading ( + MonoProfiler *prof, + MonoDomain *domain) +{ + if (!EventEnabledMonoProfilerAppDomainUnloading ()) + return; + + uint64_t domain_id = (uint64_t)domain; + + mono_profiler_fire_event_enter (); + + FireEtwMonoProfilerAppDomainUnloading ( + domain_id, + NULL, + NULL); + + mono_profiler_fire_event_exit (); +} + +static +void +mono_profiler_app_domain_unloaded ( + MonoProfiler *prof, + MonoDomain *domain) +{ + if (!EventEnabledMonoProfilerAppDomainUnloaded ()) + return; + + uint64_t domain_id = (uint64_t)domain; + + mono_profiler_fire_event_enter (); + + FireEtwMonoProfilerAppDomainUnloaded ( + domain_id, + NULL, + NULL); + + mono_profiler_fire_event_exit (); +} + +static +void +mono_profiler_app_domain_name ( + MonoProfiler *prof, + MonoDomain *domain, + const char *name) +{ + if (!EventEnabledMonoProfilerAppDomainName ()) + return; + + uint64_t domain_id = (uint64_t)domain; + + mono_profiler_fire_event_enter (); + + FireEtwMonoProfilerAppDomainName ( + domain_id, + (const ep_char8_t *)(name ? name : ""), + NULL, + NULL); + + mono_profiler_fire_event_exit (); +} + +static +void +mono_profiler_get_generic_types ( + MonoGenericInst *generic_instance, + uint32_t *generic_type_count, + uint8_t **generic_types) +{ + if (generic_instance) { + uint8_t *buffer = g_malloc (generic_instance->type_argc * (sizeof (uint8_t) + sizeof (uint64_t))); + if (buffer) { + *generic_types = buffer; + *generic_type_count = generic_instance->type_argc; + for (uint32_t i = 0; i < generic_instance->type_argc; ++i) { + uint8_t type = generic_instance->type_argv [i]->type; + memcpy (buffer, &type, sizeof (type)); + buffer += sizeof (type); + + uint64_t class_id = (uint64_t)mono_class_from_mono_type_internal (generic_instance->type_argv [i]); + memcpy (buffer, &class_id, sizeof (class_id)); + buffer += sizeof (class_id); + } + } + } +} + +static +void +mono_profiler_get_jit_data ( + MonoMethod *method, + uint64_t *method_id, uint64_t *module_id, uint32_t *method_token, uint32_t *method_generic_type_count, @@ -3810,7 +4917,7 @@ mono_profiler_jit_begin ( MonoProfiler *prof, MonoMethod *method) { - if (!EventEnabledMonoProfilerJitBegin()) + if (!EventEnabledMonoProfilerJitBegin ()) return; uint64_t method_id; @@ -3819,12 +4926,16 @@ mono_profiler_jit_begin ( mono_profiler_get_jit_data (method, &method_id, &module_id, &method_token, NULL, NULL); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerJitBegin ( method_id, module_id, method_token, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -3833,7 +4944,7 @@ mono_profiler_jit_failed ( MonoProfiler *prof, MonoMethod *method) { - if (!EventEnabledMonoProfilerJitFailed()) + if (!EventEnabledMonoProfilerJitFailed ()) return; uint64_t method_id; @@ -3842,12 +4953,16 @@ mono_profiler_jit_failed ( mono_profiler_get_jit_data (method, &method_id, &module_id, &method_token, NULL, NULL); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerJitFailed ( method_id, module_id, method_token, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -3869,7 +4984,21 @@ mono_profiler_jit_done ( uint32_t method_generic_type_count = 0; uint8_t *method_generic_types = NULL; - mono_profiler_get_jit_data (method, &method_id, &module_id, &method_token, &method_generic_type_count, &method_generic_types); + char *method_namespace = NULL; + const char *method_name = NULL; + char *method_signature = NULL; + + mono_profiler_get_jit_data (method, &method_id, &module_id, &method_token, &method_generic_type_count, &method_generic_types); + + if (verbose) { + //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. + method_name = method->name; + method_signature = mono_signature_full_name (method->signature); + if (method->klass) + method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL); + } + + mono_profiler_fire_event_enter (); FireEtwMonoProfilerJitDone_V1 ( method_id, @@ -3881,16 +5010,7 @@ mono_profiler_jit_done ( NULL, NULL); - g_free (method_generic_types); - if (verbose) { - //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. - char *method_namespace = NULL; - const char *method_name = method->name; - char *method_signature = mono_signature_full_name (method->signature); - if (method->klass) - method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL); - FireEtwMonoProfilerJitDoneVerbose ( method_id, (const ep_char8_t *)method_namespace, @@ -3898,10 +5018,13 @@ mono_profiler_jit_done ( (const ep_char8_t *)method_signature, NULL, NULL); - - g_free (method_namespace); - g_free (method_signature); } + + mono_profiler_fire_event_exit (); + + g_free (method_namespace); + g_free (method_signature); + g_free (method_generic_types); } static @@ -3911,14 +5034,18 @@ mono_profiler_jit_chunk_created ( const mono_byte *chunk, uintptr_t size) { - if (!EventEnabledMonoProfilerJitChunkCreated()) + if (!EventEnabledMonoProfilerJitChunkCreated ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerJitChunkCreated ( chunk, (uint64_t)size, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -3927,13 +5054,17 @@ mono_profiler_jit_chunk_destroyed ( MonoProfiler *prof, const mono_byte *chunk) { - if (!EventEnabledMonoProfilerJitChunkDestroyed()) + if (!EventEnabledMonoProfilerJitChunkDestroyed ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerJitChunkDestroyed ( chunk, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -3945,15 +5076,19 @@ mono_profiler_jit_code_buffer ( MonoProfilerCodeBufferType type, const void *data) { - if (!EventEnabledMonoProfilerJitCodeBuffer()) + if (!EventEnabledMonoProfilerJitCodeBuffer ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerJitCodeBuffer ( buffer, size, (uint8_t)type, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -3992,7 +5127,7 @@ mono_profiler_class_loading ( MonoProfiler *prof, MonoClass *klass) { - if (!EventEnabledMonoProfilerClassLoading()) + if (!EventEnabledMonoProfilerClassLoading ()) return; uint64_t class_id; @@ -4000,11 +5135,15 @@ mono_profiler_class_loading ( mono_profiler_get_class_data (klass, &class_id, &module_id, NULL, NULL, NULL); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerClassLoading ( class_id, module_id, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4013,7 +5152,7 @@ mono_profiler_class_failed ( MonoProfiler *prof, MonoClass *klass) { - if (!EventEnabledMonoProfilerClassFailed()) + if (!EventEnabledMonoProfilerClassFailed ()) return; uint64_t class_id; @@ -4021,11 +5160,15 @@ mono_profiler_class_failed ( mono_profiler_get_class_data (klass, &class_id, &module_id, NULL, NULL, NULL); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerClassFailed ( class_id, module_id, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4046,6 +5189,8 @@ mono_profiler_class_loaded ( mono_profiler_get_class_data (klass, &class_id, &module_id, &class_name, &class_generic_type_count, &class_generic_types); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerClassLoaded_V1 ( class_id, module_id, @@ -4056,6 +5201,8 @@ mono_profiler_class_loaded ( NULL, NULL); + mono_profiler_fire_event_exit (); + g_free (class_name); g_free (class_generic_types); } @@ -4085,7 +5232,7 @@ mono_profiler_vtable_loading ( MonoProfiler *prof, MonoVTable *vtable) { - if (!EventEnabledMonoProfilerVTableLoading()) + if (!EventEnabledMonoProfilerVTableLoading ()) return; uint64_t vtable_id; @@ -4094,12 +5241,16 @@ mono_profiler_vtable_loading ( get_vtable_data (vtable, &vtable_id, &class_id, &domain_id); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerVTableLoading ( vtable_id, class_id, domain_id, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4108,7 +5259,7 @@ mono_profiler_vtable_failed ( MonoProfiler *prof, MonoVTable *vtable) { - if (!EventEnabledMonoProfilerVTableFailed()) + if (!EventEnabledMonoProfilerVTableFailed ()) return; uint64_t vtable_id; @@ -4116,13 +5267,17 @@ mono_profiler_vtable_failed ( uint64_t domain_id; get_vtable_data (vtable, &vtable_id, &class_id, &domain_id); - + + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerVTableFailed ( vtable_id, class_id, domain_id, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4131,7 +5286,7 @@ mono_profiler_vtable_loaded ( MonoProfiler *prof, MonoVTable *vtable) { - if (!EventEnabledMonoProfilerVTableLoaded()) + if (!EventEnabledMonoProfilerVTableLoaded ()) return; uint64_t vtable_id; @@ -4139,13 +5294,17 @@ mono_profiler_vtable_loaded ( uint64_t domain_id; get_vtable_data (vtable, &vtable_id, &class_id, &domain_id); - + + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerVTableLoaded ( vtable_id, class_id, domain_id, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4157,10 +5316,14 @@ mono_profiler_module_loading ( if (!EventEnabledMonoProfilerModuleLoading ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerModuleLoading ( (uint64_t)image, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4172,10 +5335,14 @@ mono_profiler_module_failed ( if (!EventEnabledMonoProfilerModuleFailed ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerModuleFailed ( (uint64_t)image, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4198,12 +5365,16 @@ mono_profiler_module_loaded ( module_guid = (const ep_char8_t *)mono_image_get_guid (image); } + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerModuleLoaded ( module_id, module_path ? module_path : "", module_guid ? module_guid : "", NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4215,10 +5386,14 @@ mono_profiler_module_unloading ( if (!EventEnabledMonoProfilerModuleUnloading ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerModuleUnloading ( (uint64_t)image, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4241,12 +5416,16 @@ mono_profiler_module_unloaded ( module_guid = (const ep_char8_t *)mono_image_get_guid (image); } + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerModuleUnloaded ( module_id, module_path ? module_path : "", module_guid ? module_guid : "", NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4284,11 +5463,15 @@ mono_profiler_assembly_loading ( get_assembly_data (assembly, &assembly_id, &module_id, NULL); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerAssemblyLoading ( assembly_id, module_id, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4306,6 +5489,8 @@ mono_profiler_assembly_loaded ( get_assembly_data (assembly, &assembly_id, &module_id, &assembly_name); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerAssemblyLoaded ( assembly_id, module_id, @@ -4313,6 +5498,8 @@ mono_profiler_assembly_loaded ( NULL, NULL); + mono_profiler_fire_event_exit (); + g_free (assembly_name); } @@ -4330,11 +5517,15 @@ mono_profiler_assembly_unloading ( get_assembly_data (assembly, &assembly_id, &module_id, NULL); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerAssemblyUnloading ( assembly_id, module_id, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4352,6 +5543,8 @@ mono_profiler_assembly_unloaded ( get_assembly_data (assembly, &assembly_id, &module_id, &assembly_name); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerAssemblyUnloaded ( assembly_id, module_id, @@ -4359,6 +5552,8 @@ mono_profiler_assembly_unloaded ( NULL, NULL); + mono_profiler_fire_event_exit (); + g_free (assembly_name); } @@ -4372,10 +5567,14 @@ mono_profiler_method_enter ( if (!EventEnabledMonoProfilerMethodEnter ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerMethodEnter ( (uint64_t)method, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4388,10 +5587,14 @@ mono_profiler_method_leave ( if (!EventEnabledMonoProfilerMethodLeave ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerMethodLeave ( (uint64_t)method, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4404,10 +5607,14 @@ mono_profiler_method_tail_call ( if (!EventEnabledMonoProfilerMethodTailCall ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerMethodTailCall ( (uint64_t)method, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4420,10 +5627,14 @@ mono_profiler_method_exception_leave ( if (!EventEnabledMonoProfilerMethodExceptionLeave ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerMethodExceptionLeave ( (uint64_t)method, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4435,10 +5646,14 @@ mono_profiler_method_free ( if (!EventEnabledMonoProfilerMethodFree ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerMethodFree ( (uint64_t)method, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4450,10 +5665,14 @@ mono_profiler_method_begin_invoke ( if (!EventEnabledMonoProfilerMethodBeginInvoke ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerMethodBeginInvoke ( (uint64_t)method, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4465,10 +5684,14 @@ mono_profiler_method_end_invoke ( if (!EventEnabledMonoProfilerMethodEndInvoke ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerMethodEndInvoke ( (uint64_t)method, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4500,11 +5723,15 @@ mono_profiler_exception_throw ( if (exc && mono_object_class(exc)) type_id = (uint64_t)m_class_get_byval_arg (mono_object_class(exc)); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerExceptionThrow ( type_id, SGEN_POINTER_UNTAG_ALL (exc), NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4524,6 +5751,8 @@ mono_profiler_exception_clause ( if (exc && mono_object_class(exc)) type_id = (uint64_t)m_class_get_byval_arg (mono_object_class(exc)); + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerExceptionClause ( (uint8_t)clause_type, clause_num, @@ -4532,6 +5761,8 @@ mono_profiler_exception_clause ( SGEN_POINTER_UNTAG_ALL (exc), NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4542,15 +5773,130 @@ mono_profiler_gc_event ( uint32_t generation, mono_bool serial) { - if (!EventEnabledMonoProfilerGCEvent ()) - return; + switch (gc_event) { + case MONO_GC_EVENT_PRE_STOP_WORLD: + case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED: + { + FireEtwMonoProfilerGCEvent ( + (uint8_t)gc_event, + generation, + NULL, + NULL); + break; + } + case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED: + { + FireEtwMonoProfilerGCEvent ( + (uint8_t)gc_event, + generation, + NULL, + NULL); - // TODO: Needs to be async safe. - /*FireEtwMonoProfilerGCEvent ( - (uint8_t)gc_event, - generation, - NULL, - NULL);*/ + mono_profiler_gc_in_progress_start (); + + if (mono_profiler_gc_heap_dump_requested ()) { + mono_profiler_gc_heap_dump_in_progress_start (); + FireEtwMonoProfilerGCHeapDumpStart ( + NULL, + NULL); + } + break; + } + case MONO_GC_EVENT_POST_STOP_WORLD: + { + uint64_t enabled_keywords = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask; + + if (profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) { + mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, mono_profiler_fire_buffered_gc_event_root_register); + mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, mono_profiler_fire_buffered_gc_event_root_unregister); + } + + if (mono_profiler_gc_heap_dump_in_progress ()) { + if (profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) { + mono_profiler_set_gc_roots_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, mono_profiler_fire_buffered_gc_event_roots); + } + + if (profiler_callback_is_enabled (enabled_keywords, GC_MOVES_KEYWORD)) { + mono_profiler_set_gc_moves_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, mono_profiler_fire_buffered_gc_event_moves); + } + + if (profiler_callback_is_enabled (enabled_keywords, GC_RESIZE_KEYWORD)) { + mono_profiler_set_gc_resize_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, mono_profiler_fire_buffered_gc_event_resize); + } + } + + mono_profiler_fire_buffered_gc_event ( + (uint8_t)gc_event, + generation); + break; + } + case MONO_GC_EVENT_START: + case MONO_GC_EVENT_END: + { + mono_profiler_fire_buffered_gc_event ( + (uint8_t)gc_event, + generation); + break; + } + case MONO_GC_EVENT_PRE_START_WORLD: + { + uint64_t enabled_keywords = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask; + + if (mono_profiler_gc_heap_dump_in_progress () && profiler_callback_is_enabled (enabled_keywords, GC_HEAP_DUMP_KEYWORD)) + mono_gc_walk_heap (0, mono_profiler_fire_buffered_gc_event_heap_dump_object_reference, NULL); + + mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, NULL); + mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, NULL); + mono_profiler_set_gc_roots_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, NULL); + mono_profiler_set_gc_moves_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, NULL); + mono_profiler_set_gc_resize_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, NULL); + + if (profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) { + mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_root_register); + mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_root_unregister); + } + + mono_profiler_fire_buffered_gc_event ( + (uint8_t)gc_event, + generation); + + break; + } + case MONO_GC_EVENT_POST_START_WORLD: + { + GHashTable *cache = NULL; + uint64_t enabled_keywords = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask; + + if (mono_profiler_gc_heap_dump_in_progress () && profiler_callback_is_enabled (enabled_keywords, GC_HEAP_DUMP_VTABLE_CLASS_REF_KEYWORD)) + cache = g_hash_table_new_full (NULL, NULL, NULL, NULL); + + mono_profiler_fire_buffered_gc_events_in_alloc_order (cache); + mono_profiler_fire_cached_gc_events (cache); + + if (cache) + g_hash_table_destroy (cache); + + if (mono_profiler_gc_heap_dump_in_progress ()) { + FireEtwMonoProfilerGCHeapDumpStop ( + NULL, + NULL); + mono_profiler_gc_heap_dump_in_progress_stop (); + } + + FireEtwMonoProfilerGCEvent ( + (uint8_t)gc_event, + generation, + NULL, + NULL); + + mono_profiler_gc_in_progress_stop (); + break; + } + default: + break; + } } static @@ -4574,75 +5920,16 @@ mono_profiler_gc_allocation ( object_size &= ~7; } + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerGCAllocation ( vtable_id, SGEN_POINTER_UNTAG_ALL (object), object_size, NULL, NULL); -} - -static -void -mono_profiler_gc_moves ( - MonoProfiler *prof, - MonoObject *const* objects, - uint64_t count) -{ - if (!EventEnabledMonoProfilerGCMoves ()) - return; - - // TODO: Needs to be async safe. - /*uint64_t obj_count = count / 2; - - GCObjectAddressData data [32]; - uint64_t data_chunks = obj_count / G_N_ELEMENTS (data); - uint64_t data_rest = obj_count % G_N_ELEMENTS (data); - uint64_t current_obj = 0; - - for (int chunk = 0; chunk < data_chunks; chunk++) { - for (int i = 0; i < G_N_ELEMENTS (data); i++) { - data [i].object = SGEN_POINTER_UNTAG_ALL (objects [current_obj++]); - data [i].address = objects [current_obj++]; - } - - FireEtwMonoProfilerGCMoves ( - G_N_ELEMENTS (data), - sizeof (GCObjectAddressData), - data, - NULL, - NULL); - } - - if ((data_rest != 0)&& (data_rest % 2 == 0)) { - for (int i = 0; i < data_rest; i++) { - data [i].object = SGEN_POINTER_UNTAG_ALL (objects [current_obj++]); - data [i].address = objects [current_obj++]; - } - - FireEtwMonoProfilerGCMoves ( - data_rest, - sizeof (GCObjectAddressData), - data, - NULL, - NULL); - }*/ -} - -static -void -mono_profiler_gc_resize ( - MonoProfiler *prof, - uintptr_t size) -{ - if (!EventEnabledMonoProfilerGCResize ()) - return; - // TODO: Needs to be async safe. - /*FireEtwMonoProfilerGCResize ( - (uint64_t)size, - NULL, - NULL);*/ + mono_profiler_fire_event_exit (); } static @@ -4656,12 +5943,16 @@ mono_profiler_gc_handle_created ( if (!EventEnabledMonoProfilerGCHandleCreated ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerGCHandleCreated ( handle, (uint8_t)type, SGEN_POINTER_UNTAG_ALL (object), NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4674,11 +5965,15 @@ mono_profiler_gc_handle_deleted ( if (!EventEnabledMonoProfilerGCHandleDeleted ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerGCHandleDeleted ( handle, (uint8_t)type, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4688,9 +5983,13 @@ mono_profiler_gc_finalizing (MonoProfiler *prof) if (!EventEnabledMonoProfilerGCFinalizing ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerGCFinalizing ( NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4700,9 +5999,13 @@ mono_profiler_gc_finalized (MonoProfiler *prof) if (!EventEnabledMonoProfilerGCFinalized ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerGCFinalized ( NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4714,10 +6017,14 @@ mono_profiler_gc_finalizing_object ( if (!EventEnabledMonoProfilerGCFinalizingObject ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerGCFinalizingObject ( SGEN_POINTER_UNTAG_ALL (object), NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4729,10 +6036,14 @@ mono_profiler_gc_finalized_object ( if (!EventEnabledMonoProfilerGCFinalizedObject ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerGCFinalizedObject ( SGEN_POINTER_UNTAG_ALL (object), NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4748,6 +6059,8 @@ mono_profiler_gc_root_register ( if (!EventEnabledMonoProfilerGCRootRegister ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerGCRootRegister ( start, (uint64_t)size, @@ -4756,6 +6069,8 @@ mono_profiler_gc_root_register ( (const ep_char8_t *)(name ? name : ""), NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4767,58 +6082,14 @@ mono_profiler_gc_root_unregister ( if (!EventEnabledMonoProfilerGCRootUnregister ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerGCRootUnregister ( start, NULL, NULL); -} - -static -void -mono_profiler_gc_roots ( - MonoProfiler *prof, - uint64_t count, - const mono_byte *const * addresses, - MonoObject *const * objects) -{ - if (!EventEnabledMonoProfilerGCRoots ()) - return; - // TODO: Needs to be async safe. - /*GCAddressObjectData data [32]; - uint64_t data_chunks = count / G_N_ELEMENTS (data); - uint64_t data_rest = count % G_N_ELEMENTS (data); - uint64_t current_obj = 0; - - for (int chunk = 0; chunk < data_chunks; chunk++) { - for (int i = 0; i < G_N_ELEMENTS (data); i++) { - data [i].address = addresses [current_obj]; - data [i].object = SGEN_POINTER_UNTAG_ALL (objects [current_obj]); - current_obj++; - } - - FireEtwMonoProfilerGCRoots ( - G_N_ELEMENTS (data), - sizeof (GCAddressObjectData), - data, - NULL, - NULL); - } - - if (data_rest != 0) { - for (int i = 0; i < data_rest; i++) { - data [i].address = addresses [current_obj]; - data [i].object = SGEN_POINTER_UNTAG_ALL (objects [current_obj]); - current_obj++; - } - - FireEtwMonoProfilerGCRoots ( - data_rest, - sizeof (GCAddressObjectData), - data, - NULL, - NULL); - }*/ + mono_profiler_fire_event_exit (); } static @@ -4830,10 +6101,14 @@ mono_profiler_monitor_contention ( if (!EventEnabledMonoProfilerMonitorContention ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerMonitorContention ( SGEN_POINTER_UNTAG_ALL (object), NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4845,10 +6120,14 @@ mono_profiler_monitor_failed ( if (!EventEnabledMonoProfilerMonitorFailed ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerMonitorFailed ( SGEN_POINTER_UNTAG_ALL (object), NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4860,10 +6139,14 @@ mono_profiler_monitor_acquired ( if (!EventEnabledMonoProfilerMonitorAcquired ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerMonitorAcquired ( SGEN_POINTER_UNTAG_ALL (object), NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4875,10 +6158,14 @@ mono_profiler_thread_started ( if (!EventEnabledMonoProfilerThreadStarted ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerThreadStarted ( (uint64_t)tid, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4890,10 +6177,14 @@ mono_profiler_thread_stopping ( if (!EventEnabledMonoProfilerThreadStopping ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerThreadStopping ( (uint64_t)tid, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4905,10 +6196,14 @@ mono_profiler_thread_stopped ( if (!EventEnabledMonoProfilerThreadStopped ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerThreadStopped ( (uint64_t)tid, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4920,10 +6215,14 @@ mono_profiler_thread_exited ( if (!EventEnabledMonoProfilerThreadExited ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerThreadExited ( (uint64_t)tid, NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4936,15 +6235,20 @@ mono_profiler_thread_name ( if (!EventEnabledMonoProfilerThreadName ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerThreadName ( (uint64_t)tid, (ep_char8_t *)(name ? name : ""), NULL, NULL); + + mono_profiler_fire_event_exit (); } +static void -EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( +mono_profiler_ep_provider_callback ( const uint8_t *source_id, unsigned long is_enabled, uint8_t level, @@ -4957,6 +6261,7 @@ EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( EP_ASSERT(is_enabled == 0 || is_enabled == 1) ; EP_ASSERT (_ep_rt_dotnet_mono_profiler_provider != NULL); + EP_ASSERT (_ep_rt_dotnet_mono_profiler_heap_dump_provider != NULL); match_any_keywords = (is_enabled == 1) ? match_any_keywords : 0; @@ -5083,57 +6388,37 @@ EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( } } - if (profiler_callback_is_enabled(match_any_keywords, GC_KEYWORD | GC_ALLOCATION_KEYWORD)) { - if (!profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_ALLOCATION_KEYWORD)) { + if (profiler_callback_is_enabled(match_any_keywords, GC_ALLOCATION_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, GC_ALLOCATION_KEYWORD)) { mono_profiler_set_gc_allocation_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_allocation); } } else { - if (profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_ALLOCATION_KEYWORD)) { + if (profiler_callback_is_enabled (enabled_keywords, GC_ALLOCATION_KEYWORD)) { mono_profiler_set_gc_allocation_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); } } - if (profiler_callback_is_enabled(match_any_keywords, GC_KEYWORD | GC_MOVES_KEYWORD)) { - if (!profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_MOVES_KEYWORD)) { - mono_profiler_set_gc_moves_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_moves); - } - } else { - if (profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_MOVES_KEYWORD)) { - mono_profiler_set_gc_moves_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); - } - } - - if (profiler_callback_is_enabled(match_any_keywords, GC_KEYWORD | GC_RESIZE_KEYWORD)) { - if (!profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_RESIZE_KEYWORD)) { - mono_profiler_set_gc_resize_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_resize); - } - } else { - if (profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_RESIZE_KEYWORD)) { - mono_profiler_set_gc_resize_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); - } - } - - if (profiler_callback_is_enabled(match_any_keywords, GC_KEYWORD | GC_HANDLE_KEYWORD)) { - if (!profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_HANDLE_KEYWORD)) { + if (profiler_callback_is_enabled(match_any_keywords, GC_HANDLE_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, GC_HANDLE_KEYWORD)) { mono_profiler_set_gc_handle_created_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_handle_created); mono_profiler_set_gc_handle_deleted_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_handle_deleted); } } else { - if (profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_HANDLE_KEYWORD)) { + if (profiler_callback_is_enabled (enabled_keywords, GC_HANDLE_KEYWORD)) { mono_profiler_set_gc_handle_created_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); mono_profiler_set_gc_handle_deleted_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); } } - if (profiler_callback_is_enabled(match_any_keywords, GC_KEYWORD | GC_FINALIZATION_KEYWORD)) { - if (!profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_FINALIZATION_KEYWORD)) { + if (profiler_callback_is_enabled(match_any_keywords, GC_FINALIZATION_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, GC_FINALIZATION_KEYWORD)) { mono_profiler_set_gc_finalizing_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_finalizing); mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_finalized); mono_profiler_set_gc_finalizing_object_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_finalizing_object); mono_profiler_set_gc_finalized_object_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_finalized_object); } } else { - if (profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_FINALIZATION_KEYWORD)) { + if (profiler_callback_is_enabled (enabled_keywords, GC_FINALIZATION_KEYWORD)) { mono_profiler_set_gc_finalizing_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); mono_profiler_set_gc_finalizing_object_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); @@ -5141,26 +6426,40 @@ EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( } } - if (profiler_callback_is_enabled(match_any_keywords, GC_KEYWORD | GC_ROOT_KEYWORD)) { - if (!profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_ROOT_KEYWORD)) { + if (profiler_callback_is_enabled(match_any_keywords, GC_ROOT_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) { mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_root_register); mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_root_unregister); - mono_profiler_set_gc_roots_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_roots); } } else { - if (profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD | GC_ROOT_KEYWORD)) { + if (profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) { mono_profiler_set_gc_root_register_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); - mono_profiler_set_gc_roots_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); } } - if (profiler_callback_is_enabled(match_any_keywords, MONITOR_KEYWORD | CONTENTION_KEYWORD)) { - if (!profiler_callback_is_enabled (enabled_keywords, MONITOR_KEYWORD | CONTENTION_KEYWORD)) { + if (profiler_callback_is_enabled(match_any_keywords, GC_HEAP_COLLECT_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) { + if (mono_profiler_gc_can_heap_dump ()) { + mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, mono_profiler_trigger_heap_dump); + } + } + if (mono_profiler_gc_can_heap_dump ()) { + mono_profiler_gc_heap_dump_requests_inc (); + mono_gc_finalize_notify (); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) { + mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, NULL); + } + } + + if (profiler_callback_is_enabled(match_any_keywords, MONITOR_KEYWORD) || profiler_callback_is_enabled(match_any_keywords, CONTENTION_KEYWORD)) { + if (!(profiler_callback_is_enabled(enabled_keywords, MONITOR_KEYWORD) || profiler_callback_is_enabled(enabled_keywords, CONTENTION_KEYWORD))) { mono_profiler_set_monitor_contention_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_monitor_contention); } } else { - if (profiler_callback_is_enabled (enabled_keywords, MONITOR_KEYWORD | CONTENTION_KEYWORD)) { + if (profiler_callback_is_enabled(enabled_keywords, MONITOR_KEYWORD) || profiler_callback_is_enabled(enabled_keywords, CONTENTION_KEYWORD)) { mono_profiler_set_monitor_contention_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); } } @@ -5220,6 +6519,37 @@ EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( ep_exit_error_handler (); } +void +EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( + const uint8_t *source_id, + unsigned long is_enabled, + uint8_t level, + uint64_t match_any_keywords, + uint64_t match_all_keywords, + EventFilterDescriptor *filter_data, + void *callback_data) +{ + ep_rt_spin_lock_requires_lock_not_held (&_ep_rt_mono_profiler_gc_state_lock); + + EP_SPIN_LOCK_ENTER (&_ep_rt_mono_profiler_gc_state_lock, section1); + mono_profiler_ep_provider_callback ( + source_id, + is_enabled, + level, + match_any_keywords, + match_all_keywords, + filter_data, + callback_data); + EP_SPIN_LOCK_EXIT (&_ep_rt_mono_profiler_gc_state_lock, section1); + +ep_on_exit: + ep_rt_spin_lock_requires_lock_not_held (&_ep_rt_mono_profiler_gc_state_lock); + return; + +ep_on_error: + ep_exit_error_handler (); +} + #endif /* ENABLE_PERFTRACING */ MONO_EMPTY_SOURCE_FILE(eventpipe_rt_mono); From c62266052797b76e93a08cf68719f868ccf001df Mon Sep 17 00:00:00 2001 From: lateralusX Date: Wed, 4 Aug 2021 12:40:57 +0200 Subject: [PATCH 2/9] Fix build errors. --- src/mono/mono/eventpipe/ep-rt-mono.c | 47 ++++++++++++++++++---------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index 2dbd969536949e..c7e3e2a781fd6f 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -4034,7 +4034,7 @@ mono_profiler_mem_block_alloc (uint32_t req_size) { EP_ASSERT (mono_profiler_gc_in_progress ()); - volatile MonoProfilerMemBlock *prev = NULL; + MonoProfilerMemBlock *prev = NULL; uint32_t size = MONO_PROFILER_MEM_DEFAULT_BLOCK_SIZE; while (size - sizeof(MonoProfilerMemBlock) < req_size) @@ -4049,7 +4049,7 @@ mono_profiler_mem_block_alloc (uint32_t req_size) block->last_used_offset = 0; while (true) { - prev = _ep_rt_mono_profiler_mem_blocks; + prev = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr_without_barrier (&_ep_rt_mono_profiler_mem_blocks); if (mono_atomic_cas_ptr ((volatile gpointer*)&_ep_rt_mono_profiler_mem_blocks, block, prev) == prev) break; } @@ -4068,14 +4068,14 @@ mono_profiler_mem_alloc (uint32_t req_size) { EP_ASSERT (mono_profiler_gc_in_progress ()); - volatile MonoProfilerMemBlock *current_block = _ep_rt_mono_profiler_current_mem_block; + MonoProfilerMemBlock *current_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block); uint8_t *buffer = NULL; if (!current_block) { current_block = mono_profiler_mem_block_alloc (req_size); if (current_block) { mono_memory_barrier (); - _ep_rt_mono_profiler_current_mem_block = current_block; + ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block, current_block); } } @@ -4089,7 +4089,7 @@ mono_profiler_mem_alloc (uint32_t req_size) buffer = current_block->start; current_block->offset += req_size; mono_memory_barrier (); - _ep_rt_mono_profiler_current_mem_block = current_block; + ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block, current_block); } } else { buffer = (uint8_t*)current_block->start + prev_offset; @@ -4105,15 +4105,18 @@ mono_profiler_mem_block_free_all (void) { EP_ASSERT (mono_profiler_gc_in_progress ()); - volatile MonoProfilerMemBlock *current_block = _ep_rt_mono_profiler_current_mem_block; + MonoProfilerMemBlock *current_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr (&_ep_rt_mono_profiler_current_mem_block); + + ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block, NULL); + ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_mem_blocks, NULL); + + mono_memory_barrier (); + while (current_block) { MonoProfilerMemBlock *prev_block = current_block->prev; mono_vfree ((uint8_t *)current_block, current_block->alloc_size, MONO_MEM_ACCOUNT_MEM_MANAGER); current_block = prev_block; } - - _ep_rt_mono_profiler_current_mem_block = NULL; - _ep_rt_mono_profiler_mem_blocks = NULL; } static @@ -4122,7 +4125,14 @@ mono_profiler_mem_block_free_all_but_current (void) { EP_ASSERT (mono_profiler_gc_in_progress ()); - volatile MonoProfilerMemBlock *current_block = _ep_rt_mono_profiler_current_mem_block; + MonoProfilerMemBlock *block_to_keep = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr (&_ep_rt_mono_profiler_current_mem_block); + MonoProfilerMemBlock *current_block = block_to_keep; + + ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block, NULL); + ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_mem_blocks, NULL); + + mono_memory_barrier (); + if (current_block) { if (current_block->prev) { current_block = current_block->prev; @@ -4132,14 +4142,19 @@ mono_profiler_mem_block_free_all_but_current (void) current_block = prev_block; } } - _ep_rt_mono_profiler_current_mem_block->prev = NULL; - _ep_rt_mono_profiler_current_mem_block->next = NULL; - _ep_rt_mono_profiler_current_mem_block->offset = 0; - _ep_rt_mono_profiler_current_mem_block->last_used_offset = 0; + } + if (block_to_keep) { + block_to_keep->prev = NULL; + block_to_keep->next = NULL; + block_to_keep->offset = 0; + block_to_keep->last_used_offset = 0; } - _ep_rt_mono_profiler_mem_blocks = _ep_rt_mono_profiler_current_mem_block; + mono_memory_barrier (); + + ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block, block_to_keep); + ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_mem_blocks, block_to_keep); } static @@ -4708,7 +4723,7 @@ mono_profiler_fire_buffered_gc_events_in_alloc_order (GHashTable *cache) { EP_ASSERT (mono_profiler_gc_in_progress ()); - volatile MonoProfilerMemBlock *first_block = _ep_rt_mono_profiler_current_mem_block; + MonoProfilerMemBlock *first_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr (&_ep_rt_mono_profiler_current_mem_block); while (first_block && first_block->prev) first_block = first_block->prev; From 9a9b93ced9089a9056f4edfb43c58663183c4d6b Mon Sep 17 00:00:00 2001 From: lateralusX Date: Wed, 4 Aug 2021 16:16:43 +0200 Subject: [PATCH 3/9] Review feedback. --- src/mono/mono/eventpipe/ep-rt-mono.c | 109 +++++++++++++++------------ 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index c7e3e2a781fd6f..ff46a73d95e6f5 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -244,7 +244,6 @@ struct _MonoProfilerBufferedGCEvent { uint32_t payload_size; }; -#define MONO_PROFILER_GC_IN_PROGRESS_STATE_VALUE 0xFFFF #define MONO_PROFILER_MEM_DEFAULT_BLOCK_SIZE (mono_pagesize() * 16) #define MONO_PROFILER_MEM_BLOCK_SIZE_INC (mono_pagesize()) @@ -267,10 +266,20 @@ static volatile uint32_t _ep_rt_mono_profiler_gc_heap_dump_in_progress = 0; static bool _ep_rt_mono_profiler_gc_can_heap_dump = false; // Lightweight atomic "exclusive/shared" lock, prevents new fire events to happend while GC is in progress and gives GC ability to wait until all pending fire events are done -// before progressing. State uint32_t is split into two uint16_t, upper uint16_t represent exclusive lock, taken while GC starts, preventing new fire events to execute and lower -// uint16_t keeps number of fire events in progress, (gc_in_progress << 16) | (fire_event_count & 0xFFFF). Spin lock is only taken on slow path to queue up pending shared requests +// before progressing. State uint32_t is split into two uint16_t, upper uint16_t represent gc in progress state, taken when GC starts, preventing new fire events to execute and lower +// uint16_t keeps number of fire events in flight, (gc_in_progress << 16) | (fire_event_count & 0xFFFF). Spin lock is only taken on slow path to queue up pending shared requests // while GC is in progress and should very rarely be needed. -static volatile uint32_t _ep_rt_mono_profiler_gc_state = 0; +typedef uint32_t mono_profiler_gc_state_t; +typedef uint16_t mono_profiler_gc_state_count_t; + +#define MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT(x) ((mono_profiler_gc_state_count_t)((x & 0xFFFF))) +#define MONO_PROFILER_GC_STATE_INC_FIRE_EVENT_COUNT(x) ((mono_profiler_gc_state_t)((mono_profiler_gc_state_t)(x & 0xFFFF0000) | (mono_profiler_gc_state_t)(MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT(x) + 1))) +#define MONO_PROFILER_GC_STATE_DEC_FIRE_EVENT_COUNT(x) ((mono_profiler_gc_state_t)((mono_profiler_gc_state_t)(x & 0xFFFF0000) | (mono_profiler_gc_state_t)(MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT(x) - 1))) +#define MONO_PROFILER_GC_STATE_GC_IN_PROGRESS_START(x) ((mono_profiler_gc_state_t)((mono_profiler_gc_state_t)(0xFFFF << 16) | (mono_profiler_gc_state_t)MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT(x))) +#define MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS(x) (((x >> 16) & 0xFFFF) == 0xFFFF) +#define MONO_PROFILER_GC_STATE_GC_IN_PROGRESS_STOP(x) ((mono_profiler_gc_state_t)((mono_profiler_gc_state_t)MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT(x))) + +static volatile mono_profiler_gc_state_t _ep_rt_mono_profiler_gc_state = 0; static ep_rt_spin_lock_handle_t _ep_rt_mono_profiler_gc_state_lock = {0}; /* @@ -3752,7 +3761,7 @@ EventPipeEtwCallbackDotNETRuntime ( } if (profiler_callback_is_enabled(match_any_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD) || profiler_callback_is_enabled(match_any_keywords, THREADING_KEYWORD)) { - if (!(profiler_callback_is_enabled(enabled_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD) || profiler_callback_is_enabled(enabled_keywords, THREADING_KEYWORD))) { + if (!(profiler_callback_is_enabled(enabled_keywords, APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD) && profiler_callback_is_enabled(enabled_keywords, THREADING_KEYWORD))) { mono_profiler_set_thread_started_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_thread_started); mono_profiler_set_thread_stopped_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_thread_stopped); } @@ -3861,69 +3870,74 @@ EventPipeEtwCallbackDotNETRuntimeStress ( MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); } +static +inline +mono_profiler_gc_state_t +mono_profiler_volatile_load_gc_state_t (const volatile mono_profiler_gc_state_t *ptr) +{ + return ep_rt_volatile_load_uint32_t ((const volatile uint32_t *)ptr); +} +static inline -uint32_t -mono_profiler_atomic_cas_uint32_t (volatile uint32_t *target, uint32_t expected, uint32_t value) +mono_profiler_gc_state_t +mono_profiler_atomic_cas_gc_state_t (volatile mono_profiler_gc_state_t *target, mono_profiler_gc_state_t expected, mono_profiler_gc_state_t value) { - return (uint32_t)(mono_atomic_cas_i32 ((volatile gint32 *)(target), (gint32)(value), (gint32)(expected))); + return (mono_profiler_gc_state_t)(mono_atomic_cas_i32 ((volatile gint32 *)(target), (gint32)(value), (gint32)(expected))); } static void mono_profiler_fire_event_enter (void) { - uint32_t old_state = 0; - uint32_t new_state = 0; + mono_profiler_gc_state_t old_state = 0; + mono_profiler_gc_state_t new_state = 0; // NOTE, mono_profiler_fire_event_start should never be called recursivly. do { - old_state = ep_rt_volatile_load_uint32_t (&_ep_rt_mono_profiler_gc_state); - if (((uint16_t)(old_state >> 16)) == MONO_PROFILER_GC_IN_PROGRESS_STATE_VALUE) { + old_state = mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state); + if (MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (old_state)) { // GC in progress and thread tries to fire event (this should be an unlikely scenario). Wait until GC is done. ep_rt_spin_lock_aquire (&_ep_rt_mono_profiler_gc_state_lock); ep_rt_spin_lock_release (&_ep_rt_mono_profiler_gc_state_lock); + old_state = mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state); } - // Increase number of enter calls. - new_state = old_state + 1; - } while (mono_profiler_atomic_cas_uint32_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state); + // Increase number of fire event calls. + new_state = MONO_PROFILER_GC_STATE_INC_FIRE_EVENT_COUNT (old_state); + } while (mono_profiler_atomic_cas_gc_state_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state); } static void mono_profiler_fire_event_exit (void) { - uint32_t old_state = 0; - uint32_t new_state = 0; - uint16_t gc_in_progress = 0; - uint16_t count = 0; + mono_profiler_gc_state_t old_state = 0; + mono_profiler_gc_state_t new_state = 0; do { - old_state = ep_rt_volatile_load_uint32_t (&_ep_rt_mono_profiler_gc_state); - count = (uint16_t)old_state; - gc_in_progress = old_state >> 16; - new_state = (uint32_t)(gc_in_progress << 16) | (uint32_t)(--count); - } while (mono_profiler_atomic_cas_uint32_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state); + old_state = mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state); + new_state = MONO_PROFILER_GC_STATE_DEC_FIRE_EVENT_COUNT (old_state); + } while (mono_profiler_atomic_cas_gc_state_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state); } static void mono_profiler_gc_in_progress_start (void) { - uint32_t old_state = 0; - uint32_t new_state = 0; - uint16_t count = 0; + mono_profiler_gc_state_t old_state = 0; + mono_profiler_gc_state_t new_state = 0; // Make sure fire event calls will block and wait for GC completion. ep_rt_spin_lock_aquire (&_ep_rt_mono_profiler_gc_state_lock); - // Mark gc state in progress bits, preventing new fire event requests. + // Set gc in progress state, preventing new fire event requests. do { - old_state = ep_rt_volatile_load_uint32_t (&_ep_rt_mono_profiler_gc_state); - count = (uint16_t)old_state; - EP_ASSERT ((old_state >> 16) == 0); - new_state = (uint32_t)(MONO_PROFILER_GC_IN_PROGRESS_STATE_VALUE << 16) | (uint32_t)(count); - } while (mono_profiler_atomic_cas_uint32_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state); + old_state = mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state); + EP_ASSERT (!MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (old_state)); + new_state = MONO_PROFILER_GC_STATE_GC_IN_PROGRESS_START (old_state); + } while (mono_profiler_atomic_cas_gc_state_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state); + + mono_profiler_gc_state_count_t count = MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT (new_state); // Wait for all fire events to complete before progressing with gc. // NOTE, mono_profiler_fire_event_start should never be called recursivly. @@ -3932,11 +3946,11 @@ mono_profiler_gc_in_progress_start (void) while (count) { if (yield_count > 0) { ep_rt_mono_thread_yield (); - yield_count --; + yield_count--; } else { ep_rt_thread_sleep (200); } - count = (uint16_t)ep_rt_volatile_load_uint32_t (&_ep_rt_mono_profiler_gc_state); + count = MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT (mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state)); } } @@ -3944,14 +3958,17 @@ static void mono_profiler_gc_in_progress_stop (void) { - uint32_t old_state = 0; + mono_profiler_gc_state_t old_state = 0; + mono_profiler_gc_state_t new_state = 0; - // Reset gc in progress bits. + // Reset gc in progress state. do { - old_state = ep_rt_volatile_load_uint32_t (&_ep_rt_mono_profiler_gc_state); - EP_ASSERT ((old_state >> 16) == MONO_PROFILER_GC_IN_PROGRESS_STATE_VALUE); - EP_ASSERT (((uint16_t)old_state) == 0); - } while (mono_profiler_atomic_cas_uint32_t (&_ep_rt_mono_profiler_gc_state, old_state, 0) != old_state); + old_state = mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state); + EP_ASSERT (MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (old_state)); + + new_state = MONO_PROFILER_GC_STATE_GC_IN_PROGRESS_STOP (old_state); + EP_ASSERT (!MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (new_state)); + } while (mono_profiler_atomic_cas_gc_state_t (&_ep_rt_mono_profiler_gc_state, old_state, new_state) != old_state); // Make sure fire events can continune to execute. ep_rt_spin_lock_release (&_ep_rt_mono_profiler_gc_state_lock); @@ -3962,7 +3979,7 @@ inline bool mono_profiler_gc_in_progress (void) { - return ((ep_rt_volatile_load_uint32_t(&_ep_rt_mono_profiler_gc_state) >> 16) == MONO_PROFILER_GC_IN_PROGRESS_STATE_VALUE) != 0 ? true : false; + return MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state)); } static @@ -6457,12 +6474,10 @@ mono_profiler_ep_provider_callback ( if (!profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) { if (mono_profiler_gc_can_heap_dump ()) { mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, mono_profiler_trigger_heap_dump); + mono_profiler_gc_heap_dump_requests_inc (); + mono_gc_finalize_notify (); } } - if (mono_profiler_gc_can_heap_dump ()) { - mono_profiler_gc_heap_dump_requests_inc (); - mono_gc_finalize_notify (); - } } else { if (profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) { mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, NULL); @@ -6470,7 +6485,7 @@ mono_profiler_ep_provider_callback ( } if (profiler_callback_is_enabled(match_any_keywords, MONITOR_KEYWORD) || profiler_callback_is_enabled(match_any_keywords, CONTENTION_KEYWORD)) { - if (!(profiler_callback_is_enabled(enabled_keywords, MONITOR_KEYWORD) || profiler_callback_is_enabled(enabled_keywords, CONTENTION_KEYWORD))) { + if (!(profiler_callback_is_enabled(enabled_keywords, MONITOR_KEYWORD) && profiler_callback_is_enabled(enabled_keywords, CONTENTION_KEYWORD))) { mono_profiler_set_monitor_contention_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_monitor_contention); } } else { From 8934709caf1ab9a381505aaef51236e7d788fdb9 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Wed, 4 Aug 2021 16:36:00 +0200 Subject: [PATCH 4/9] Fix build errors. --- src/mono/mono/eventpipe/ep-rt-mono.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index ff46a73d95e6f5..d14ceb60ab5f81 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -4066,7 +4066,7 @@ mono_profiler_mem_block_alloc (uint32_t req_size) block->last_used_offset = 0; while (true) { - prev = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr_without_barrier (&_ep_rt_mono_profiler_mem_blocks); + prev = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_mem_blocks); if (mono_atomic_cas_ptr ((volatile gpointer*)&_ep_rt_mono_profiler_mem_blocks, block, prev) == prev) break; } @@ -4085,14 +4085,14 @@ mono_profiler_mem_alloc (uint32_t req_size) { EP_ASSERT (mono_profiler_gc_in_progress ()); - MonoProfilerMemBlock *current_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block); + MonoProfilerMemBlock *current_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block); uint8_t *buffer = NULL; if (!current_block) { current_block = mono_profiler_mem_block_alloc (req_size); if (current_block) { mono_memory_barrier (); - ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block, current_block); + ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block, current_block); } } @@ -4106,7 +4106,7 @@ mono_profiler_mem_alloc (uint32_t req_size) buffer = current_block->start; current_block->offset += req_size; mono_memory_barrier (); - ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block, current_block); + ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block, current_block); } } else { buffer = (uint8_t*)current_block->start + prev_offset; @@ -4122,10 +4122,10 @@ mono_profiler_mem_block_free_all (void) { EP_ASSERT (mono_profiler_gc_in_progress ()); - MonoProfilerMemBlock *current_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr (&_ep_rt_mono_profiler_current_mem_block); + MonoProfilerMemBlock *current_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr ((volatile void **)&_ep_rt_mono_profiler_current_mem_block); - ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block, NULL); - ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_mem_blocks, NULL); + ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block, NULL); + ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_mem_blocks, NULL); mono_memory_barrier (); @@ -4142,11 +4142,11 @@ mono_profiler_mem_block_free_all_but_current (void) { EP_ASSERT (mono_profiler_gc_in_progress ()); - MonoProfilerMemBlock *block_to_keep = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr (&_ep_rt_mono_profiler_current_mem_block); + MonoProfilerMemBlock *block_to_keep = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr ((volatile void **)&_ep_rt_mono_profiler_current_mem_block); MonoProfilerMemBlock *current_block = block_to_keep; - ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block, NULL); - ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_mem_blocks, NULL); + ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block, NULL); + ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_mem_blocks, NULL); mono_memory_barrier (); @@ -4170,8 +4170,8 @@ mono_profiler_mem_block_free_all_but_current (void) mono_memory_barrier (); - ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_current_mem_block, block_to_keep); - ep_rt_volatile_store_ptr_without_barrier (&_ep_rt_mono_profiler_mem_blocks, block_to_keep); + ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_current_mem_block, block_to_keep); + ep_rt_volatile_store_ptr_without_barrier ((volatile void **)&_ep_rt_mono_profiler_mem_blocks, block_to_keep); } static @@ -4740,7 +4740,7 @@ mono_profiler_fire_buffered_gc_events_in_alloc_order (GHashTable *cache) { EP_ASSERT (mono_profiler_gc_in_progress ()); - MonoProfilerMemBlock *first_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr (&_ep_rt_mono_profiler_current_mem_block); + MonoProfilerMemBlock *first_block = (MonoProfilerMemBlock *)ep_rt_volatile_load_ptr ((volatile void **)&_ep_rt_mono_profiler_current_mem_block); while (first_block && first_block->prev) first_block = first_block->prev; From 1290c55c1d48d9adf8b62ac6127b4f63cf271798 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Fri, 6 Aug 2021 01:09:51 +0200 Subject: [PATCH 5/9] Add MonoProvider heapcollect filter keywords. --- src/mono/mono/eventpipe/ep-rt-mono.c | 156 +++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 11 deletions(-) diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index d14ceb60ab5f81..2b1cf0d6cd032e 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -59,6 +59,7 @@ static MonoProfilerHandle _ep_rt_dotnet_runtime_profiler_provider = NULL; static MonoProfilerHandle _ep_rt_dotnet_mono_profiler_provider = NULL; static MonoProfilerHandle _ep_rt_dotnet_mono_profiler_heap_dump_provider = NULL; static MonoCallSpec _ep_rt_dotnet_mono_profiler_provider_callspec = {0}; +static GSList *_ep_rt_dotnet_mono_profiler_provider_params = NULL; // Phantom JIT compile method. MonoMethod *_ep_rt_mono_runtime_helper_compile_method = NULL; @@ -1040,6 +1041,26 @@ mono_profiler_thread_name ( uintptr_t tid, const char *name); +static +const EventFilterDescriptor * +mono_profiler_add_provider_param ( + GSList **provider_params, + const EventFilterDescriptor *key); + +static +bool +mono_profiler_remove_provider_param ( + GSList **provider_params, + const EventFilterDescriptor *key); + +static +void +mono_profiler_free_provider_params (GSList **provider_params); + +static +bool +mono_profiler_find_heap_collect_ondemand_provider_keyvalue (const EventFilterDescriptor *param); + static void mono_profiler_ep_provider_callback ( @@ -2018,6 +2039,8 @@ ep_rt_mono_fini (void) mono_callspec_cleanup (&_ep_rt_dotnet_mono_profiler_provider_callspec); } + mono_profiler_free_provider_params (&_ep_rt_dotnet_mono_profiler_provider_params); + ep_rt_spin_lock_free (&_ep_rt_mono_profiler_gc_state_lock); _ep_rt_mono_sampled_thread_callstacks = NULL; @@ -4033,7 +4056,7 @@ void mono_profiler_gc_heap_dump_in_progress_start (void) { EP_ASSERT (mono_profiler_gc_can_heap_dump ()); - ep_rt_volatile_store_uint32_t(&_ep_rt_mono_profiler_gc_heap_dump_in_progress, 1); + ep_rt_atomic_inc_uint32_t(&_ep_rt_mono_profiler_gc_heap_dump_in_progress); } static @@ -4042,7 +4065,7 @@ void mono_profiler_gc_heap_dump_in_progress_stop (void) { EP_ASSERT (mono_profiler_gc_can_heap_dump ()); - ep_rt_volatile_store_uint32_t(&_ep_rt_mono_profiler_gc_heap_dump_in_progress, 0); + ep_rt_atomic_dec_uint32_t(&_ep_rt_mono_profiler_gc_heap_dump_in_progress); } static @@ -4188,8 +4211,10 @@ void mono_profiler_trigger_heap_dump (MonoProfiler *prof) { if (mono_profiler_gc_heap_dump_requested ()) { - mono_gc_collect (mono_gc_max_generation ()); mono_profiler_gc_heap_dump_requests_dec (); + mono_profiler_gc_heap_dump_in_progress_start (); + mono_gc_collect (mono_gc_max_generation ()); + mono_profiler_gc_heap_dump_in_progress_stop (); } } @@ -5826,8 +5851,7 @@ mono_profiler_gc_event ( mono_profiler_gc_in_progress_start (); - if (mono_profiler_gc_heap_dump_requested ()) { - mono_profiler_gc_heap_dump_in_progress_start (); + if (mono_profiler_gc_heap_dump_in_progress ()) { FireEtwMonoProfilerGCHeapDumpStart ( NULL, NULL); @@ -5914,7 +5938,6 @@ mono_profiler_gc_event ( FireEtwMonoProfilerGCHeapDumpStop ( NULL, NULL); - mono_profiler_gc_heap_dump_in_progress_stop (); } FireEtwMonoProfilerGCEvent ( @@ -6278,6 +6301,98 @@ mono_profiler_thread_name ( mono_profiler_fire_event_exit (); } +static +const EventFilterDescriptor * +mono_profiler_add_provider_param ( + GSList **provider_params, + const EventFilterDescriptor *key) +{ + EventFilterDescriptor *param = NULL; + if (key && key->ptr && key->size) { + uint64_t param_ptr = (uint64_t)g_malloc (key->size); + if (param_ptr) { + param = ep_event_filter_desc_alloc (param_ptr, key->size, key->type); + if (param) { + memcpy ((uint8_t*)param->ptr,(const uint8_t*)key->ptr, key->size); + *provider_params = g_slist_append (*provider_params, param); + } else { + g_free ((void *)param_ptr); + } + } + } + return param; +} + +static +bool +mono_profiler_remove_provider_param ( + GSList **provider_params, + const EventFilterDescriptor *key) +{ + bool removed = false; + if (*provider_params && key && key->ptr && key->size) { + GSList *list = *provider_params; + EventFilterDescriptor *param = NULL; + while (list) { + param = (const EventFilterDescriptor *)(list->data); + if (param && param->ptr && param->type == key->type && param->size == key->size && + memcmp ((const void *)param->ptr, (const void *)key->ptr, param->size) == 0) { + g_free ((void *)param->ptr); + ep_event_filter_desc_free (param); + *provider_params = g_slist_delete_link (*provider_params, list); + removed = true; + break; + } + list = list->next; + } + } + + return removed; +} + +static +void +mono_profiler_free_provider_params (GSList **provider_params) +{ + for (GSList *list = *provider_params; list; list = list->next) { + const EventFilterDescriptor *param = (const EventFilterDescriptor *)(list->data); + if (param) { + g_free ((void *)param->ptr); + ep_event_filter_desc_free (param); + } + } + g_slist_free (*provider_params); + *provider_params = NULL; +} + +static +bool +mono_profiler_find_heap_collect_ondemand_provider_keyvalue (const EventFilterDescriptor *param) +{ + if (!param || !param->ptr || !param->size) + return false; + + const ep_char8_t *current = (ep_char8_t *)param->ptr; + const ep_char8_t *end = current + param->size; + bool found_heapshot_key = false; + bool found_ondemand_value = false; + + if (!current [param->size - 1]) { + while (current < end) { + if (!stricmp (current, "heapcollect")) + found_heapshot_key = true; + else if (!stricmp (current, "ondemand")) + found_ondemand_value = true; + + if (found_heapshot_key && found_ondemand_value) + break; + current = current + strlen (current) + 1; + } + } + + return found_heapshot_key && found_ondemand_value; +} + static void mono_profiler_ep_provider_callback ( @@ -6472,11 +6587,7 @@ mono_profiler_ep_provider_callback ( if (profiler_callback_is_enabled(match_any_keywords, GC_HEAP_COLLECT_KEYWORD)) { if (!profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) { - if (mono_profiler_gc_can_heap_dump ()) { - mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, mono_profiler_trigger_heap_dump); - mono_profiler_gc_heap_dump_requests_inc (); - mono_gc_finalize_notify (); - } + mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_heap_dump_provider, mono_profiler_trigger_heap_dump); } } else { if (profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) { @@ -6536,6 +6647,29 @@ mono_profiler_ep_provider_callback ( } } + if (match_any_keywords) { + bool request_heap_dump = false; + if (profiler_callback_is_enabled (match_any_keywords, GC_HEAP_COLLECT_KEYWORD)) { + if (mono_profiler_gc_can_heap_dump () && !profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) + request_heap_dump = true; + } + + if (filter_data) { + if (mono_profiler_find_heap_collect_ondemand_provider_keyvalue (filter_data) && !mono_profiler_remove_provider_param (&_ep_rt_dotnet_mono_profiler_provider_params, filter_data)) { + mono_profiler_add_provider_param (&_ep_rt_dotnet_mono_profiler_provider_params, filter_data); + if (mono_profiler_gc_can_heap_dump () && profiler_callback_is_enabled (match_any_keywords, GC_HEAP_COLLECT_KEYWORD)) + request_heap_dump = true; + } + } + + if (request_heap_dump) { + mono_profiler_gc_heap_dump_requests_inc (); + mono_gc_finalize_notify (); + } + } else { + mono_profiler_free_provider_params (&_ep_rt_dotnet_mono_profiler_provider_params); + } + MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.Level = level; MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords; MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); From d41faae2c663935d5e28aad4e90716bf3ea44ce0 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Fri, 6 Aug 2021 01:27:12 +0200 Subject: [PATCH 6/9] Fix build error. --- src/mono/mono/eventpipe/ep-rt-mono.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index 2b1cf0d6cd032e..e4bb108725febb 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -6334,7 +6334,7 @@ mono_profiler_remove_provider_param ( GSList *list = *provider_params; EventFilterDescriptor *param = NULL; while (list) { - param = (const EventFilterDescriptor *)(list->data); + param = (EventFilterDescriptor *)(list->data); if (param && param->ptr && param->type == key->type && param->size == key->size && memcmp ((const void *)param->ptr, (const void *)key->ptr, param->size) == 0) { g_free ((void *)param->ptr); @@ -6379,9 +6379,9 @@ mono_profiler_find_heap_collect_ondemand_provider_keyvalue (const EventFilterDes if (!current [param->size - 1]) { while (current < end) { - if (!stricmp (current, "heapcollect")) + if (!ep_rt_utf8_string_compare_ignore_case (current, "heapcollect")) found_heapshot_key = true; - else if (!stricmp (current, "ondemand")) + else if (!ep_rt_utf8_string_compare_ignore_case (current, "ondemand")) found_ondemand_value = true; if (found_heapshot_key && found_ondemand_value) From 14edfcb1b28c2009389989add745f21bd806fcea Mon Sep 17 00:00:00 2001 From: lateralusX Date: Fri, 6 Aug 2021 01:42:08 +0200 Subject: [PATCH 7/9] Fix build error. --- src/mono/mono/eventpipe/ep-rt-mono.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index e4bb108725febb..eadc48de4a776d 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -6355,7 +6355,7 @@ void mono_profiler_free_provider_params (GSList **provider_params) { for (GSList *list = *provider_params; list; list = list->next) { - const EventFilterDescriptor *param = (const EventFilterDescriptor *)(list->data); + EventFilterDescriptor *param = (EventFilterDescriptor *)(list->data); if (param) { g_free ((void *)param->ptr); ep_event_filter_desc_free (param); From f8b3a5bd5b402522ab0c0a91bf797c7234af9cc8 Mon Sep 17 00:00:00 2001 From: lateralusX Date: Fri, 6 Aug 2021 14:07:00 +0200 Subject: [PATCH 8/9] Add support for session filter param value into DumpHeapStart event. --- src/coreclr/vm/ClrEtwAll.man | 18 +- src/mono/mono/eventpipe/ep-rt-mono.c | 408 ++++++++++++++++++--------- 2 files changed, 284 insertions(+), 142 deletions(-) diff --git a/src/coreclr/vm/ClrEtwAll.man b/src/coreclr/vm/ClrEtwAll.man index ac4095205696bd..3457bca2b01774 100644 --- a/src/coreclr/vm/ClrEtwAll.man +++ b/src/coreclr/vm/ClrEtwAll.man @@ -7738,6 +7738,15 @@ + +