diff --git a/src/coreclr/vm/ClrEtwAll.man b/src/coreclr/vm/ClrEtwAll.man index 8508666c7e51b1..3457bca2b01774 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" /> - + + + + @@ -7733,11 +7738,20 @@ + + + + @@ -8040,77 +8069,77 @@ symbol="MonoProfilerGCEvent" message="$(string.MonoProfilerPublisher.GCEventEventMessage)" /> + symbol="MonoProfilerGCHeapDumpStart" message="$(string.MonoProfilerPublisher.GCHeapDumpStartEventMessage)" /> + symbol="MonoProfilerGCHeapDumpStop" message="$(string.MonoProfilerPublisher.GCHeapDumpStopEventMessage)" /> @@ -8158,6 +8187,11 @@ keywords ="JitKeyword" opcode="JitDoneVerbose" task="MonoProfiler" symbol="MonoProfilerJitDoneVerbose" message="$(string.MonoProfilerPublisher.JitDoneVerboseEventMessage)" /> + + @@ -9186,9 +9220,11 @@ + + + - @@ -9268,6 +9304,8 @@ + + @@ -9353,7 +9391,8 @@ - + + @@ -9362,6 +9401,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..95b5a72533425b 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_collect_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,77 @@ 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; +}; -typedef struct _GCObjectAddressData { - MonoObject *object; - void *address; -} GCObjectAddressData; +#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 _GCAddressObjectData { - void *address; - MonoObject *object; -} GCAddressObjectData; +// 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_collect_requests = 0; +static volatile uint32_t _ep_rt_mono_profiler_gc_heap_collect_in_progress = 0; +static bool _ep_rt_mono_profiler_gc_can_collect_heap = false; + +static GSList *_ep_rt_mono_profiler_provider_params = NULL; +static GQueue *_ep_rt_mono_profiler_gc_heap_collect_request_params = NULL; + +// 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 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. +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}; /* * Forward declares of all static functions. @@ -336,6 +386,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 +538,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_collect (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 +784,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 +955,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 +994,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 +1043,60 @@ mono_profiler_thread_name ( uintptr_t tid, const char *name); +static +const EventFilterDescriptor * +mono_profiler_add_provider_param (const EventFilterDescriptor *key); + +static +bool +mono_profiler_remove_provider_param (const EventFilterDescriptor *key); + +static +void +mono_profiler_free_provider_params (void); + +static +bool +mono_profiler_provider_params_get_value ( + const EventFilterDescriptor *param, + const ep_char8_t *key, + const ep_char8_t **value); + +static +bool +mono_profiler_provider_param_contains_heap_collect_ondemand (const EventFilterDescriptor *param); + +static +void +mono_profiler_push_gc_heap_collect_param_request_value (const EventFilterDescriptor *param); + +static +void +mono_profiler_pop_gc_heap_collect_param_request_value (void); + +static +void +mono_profiler_pop_gc_heap_collect_param_request_value (void); + +static +const ep_char8_t * +mono_profiler_get_gc_heap_collect_param_request_value (void); + +static +void +mono_profiler_free_gc_heap_collect_param_requests (void); + +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 +1830,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_collect_heap = true; +} + static void profiler_eventpipe_thread_exited ( @@ -1639,6 +1880,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_collect_provider = mono_profiler_create (NULL); char *diag_env = g_getenv("MONO_DIAGNOSTICS"); if (diag_env) { @@ -1701,7 +1943,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_collect_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 +2064,11 @@ ep_rt_mono_fini (void) mono_callspec_cleanup (&_ep_rt_dotnet_mono_profiler_provider_callspec); } + mono_profiler_free_gc_heap_collect_param_requests (); + mono_profiler_free_provider_params (); + + 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 +3809,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); } @@ -3669,92 +3920,1043 @@ EventPipeEtwCallbackDotNETRuntimeStress ( } static -void -mono_profiler_app_domain_loading ( - MonoProfiler *prof, - MonoDomain *domain) +inline +mono_profiler_gc_state_t +mono_profiler_volatile_load_gc_state_t (const volatile mono_profiler_gc_state_t *ptr) { - if (!EventEnabledMonoProfilerAppDomainLoading ()) - return; + return ep_rt_volatile_load_uint32_t ((const volatile uint32_t *)ptr); +} - uint64_t domain_id = (uint64_t)domain; - FireEtwMonoProfilerAppDomainLoading ( - domain_id, - NULL, - NULL); +static +inline +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 (mono_profiler_gc_state_t)(mono_atomic_cas_i32 ((volatile gint32 *)(target), (gint32)(value), (gint32)(expected))); } static void -mono_profiler_app_domain_loaded ( - MonoProfiler *prof, - MonoDomain *domain) +mono_profiler_fire_event_enter (void) { - if (!EventEnabledMonoProfilerAppDomainLoaded ()) - return; + mono_profiler_gc_state_t old_state = 0; + mono_profiler_gc_state_t new_state = 0; - uint64_t domain_id = (uint64_t)domain; - FireEtwMonoProfilerAppDomainLoaded ( - domain_id, - NULL, - NULL); + // NOTE, mono_profiler_fire_event_start should never be called recursivly. + do { + 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 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_app_domain_unloading ( - MonoProfiler *prof, - MonoDomain *domain) +mono_profiler_fire_event_exit (void) { - if (!EventEnabledMonoProfilerAppDomainUnloading ()) - return; + mono_profiler_gc_state_t old_state = 0; + mono_profiler_gc_state_t new_state = 0; - uint64_t domain_id = (uint64_t)domain; - FireEtwMonoProfilerAppDomainUnloading ( - domain_id, - NULL, - NULL); + do { + 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_app_domain_unloaded ( - MonoProfiler *prof, - MonoDomain *domain) +mono_profiler_gc_in_progress_start (void) { - if (!EventEnabledMonoProfilerAppDomainUnloaded ()) - return; + mono_profiler_gc_state_t old_state = 0; + mono_profiler_gc_state_t new_state = 0; - uint64_t domain_id = (uint64_t)domain; - FireEtwMonoProfilerAppDomainUnloaded ( - 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); + + // Set gc in progress state, preventing new fire event requests. + do { + 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. + // 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 = MONO_PROFILER_GC_STATE_GET_FIRE_EVENT_COUNT (mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state)); + } } static void -mono_profiler_app_domain_name ( - MonoProfiler *prof, - MonoDomain *domain, - const char *name) +mono_profiler_gc_in_progress_stop (void) { - if (!EventEnabledMonoProfilerAppDomainName ()) - return; + mono_profiler_gc_state_t old_state = 0; + mono_profiler_gc_state_t new_state = 0; - uint64_t domain_id = (uint64_t)domain; - FireEtwMonoProfilerAppDomainName ( - domain_id, - (const ep_char8_t *)(name ? name : ""), - NULL, - NULL); + // Reset gc in progress state. + do { + 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); } static -void -mono_profiler_get_generic_types ( - MonoGenericInst *generic_instance, - uint32_t *generic_type_count, +inline +bool +mono_profiler_gc_in_progress (void) +{ + return MONO_PROFILER_GC_STATE_IS_GC_IN_PROGRESS (mono_profiler_volatile_load_gc_state_t (&_ep_rt_mono_profiler_gc_state)); +} + +static +inline +bool +mono_profiler_gc_can_collect_heap (void) +{ + return _ep_rt_mono_profiler_gc_can_collect_heap; +} + +static +inline +void +mono_profiler_gc_heap_collect_requests_inc (void) +{ + EP_ASSERT (mono_profiler_gc_can_collect_heap ()); + ep_rt_atomic_inc_uint32_t (&_ep_rt_mono_profiler_gc_heap_collect_requests); +} + +static +inline +void +mono_profiler_gc_heap_collect_requests_dec (void) +{ + EP_ASSERT (mono_profiler_gc_can_collect_heap ()); + ep_rt_atomic_dec_uint32_t (&_ep_rt_mono_profiler_gc_heap_collect_requests); +} + +static +inline +bool +mono_profiler_gc_heap_collect_requested (void) +{ + if (!mono_profiler_gc_can_collect_heap ()) + return false; + + return ep_rt_volatile_load_uint32_t(&_ep_rt_mono_profiler_gc_heap_collect_requests) != 0 ? true : false; +} + +static +inline +bool +mono_profiler_gc_heap_collect_in_progress (void) +{ + ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock); + return ep_rt_volatile_load_uint32_t_without_barrier (&_ep_rt_mono_profiler_gc_heap_collect_in_progress) != 0 ? true : false; +} + +static +inline +void +mono_profiler_gc_heap_collect_in_progress_start (void) +{ + EP_ASSERT (mono_profiler_gc_can_collect_heap ()); + + ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock); + ep_rt_volatile_store_uint32_t_without_barrier (&_ep_rt_mono_profiler_gc_heap_collect_in_progress, 1); +} + +static +inline +void +mono_profiler_gc_heap_collect_in_progress_stop (void) +{ + EP_ASSERT (mono_profiler_gc_can_collect_heap ()); + + ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock); + ep_rt_volatile_store_uint32_t_without_barrier (&_ep_rt_mono_profiler_gc_heap_collect_in_progress, 0); +} + +static +MonoProfilerMemBlock * +mono_profiler_mem_block_alloc (uint32_t req_size) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + 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 = (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; + } + + 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 ()); + + 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 ((volatile void **)&_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_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; + } + } + + return buffer; +} + +static +void +mono_profiler_mem_block_free_all (void) +{ + EP_ASSERT (mono_profiler_gc_in_progress ()); + + 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 ((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 (); + + 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; + } +} + +static +void +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 ((volatile void **)&_ep_rt_mono_profiler_current_mem_block); + MonoProfilerMemBlock *current_block = block_to_keep; + + 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 (); + + 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; + } + } + } + + 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; + } + + mono_memory_barrier (); + + 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 +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_collect (MonoProfiler *prof) +{ + if (mono_profiler_gc_heap_collect_requested ()) { + ep_rt_spin_lock_aquire (&_ep_rt_mono_profiler_gc_state_lock); + mono_profiler_gc_heap_collect_requests_dec (); + mono_profiler_gc_heap_collect_in_progress_start (); + ep_rt_spin_lock_release (&_ep_rt_mono_profiler_gc_state_lock); + + mono_gc_collect (mono_gc_max_generation ()); + + ep_rt_spin_lock_aquire (&_ep_rt_mono_profiler_gc_state_lock); + mono_profiler_pop_gc_heap_collect_param_request_value (); + mono_profiler_gc_heap_collect_in_progress_stop (); + ep_rt_spin_lock_release (&_ep_rt_mono_profiler_gc_state_lock); + } +} + +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 ()); + + 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; + + 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) { @@ -3810,7 +5012,7 @@ mono_profiler_jit_begin ( MonoProfiler *prof, MonoMethod *method) { - if (!EventEnabledMonoProfilerJitBegin()) + if (!EventEnabledMonoProfilerJitBegin ()) return; uint64_t method_id; @@ -3819,12 +5021,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 +5039,7 @@ mono_profiler_jit_failed ( MonoProfiler *prof, MonoMethod *method) { - if (!EventEnabledMonoProfilerJitFailed()) + if (!EventEnabledMonoProfilerJitFailed ()) return; uint64_t method_id; @@ -3842,12 +5048,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,8 +5079,22 @@ mono_profiler_jit_done ( uint32_t method_generic_type_count = 0; uint8_t *method_generic_types = NULL; + 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, module_id, @@ -3881,16 +5105,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 +5113,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 +5129,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 +5149,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 +5171,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 +5222,7 @@ mono_profiler_class_loading ( MonoProfiler *prof, MonoClass *klass) { - if (!EventEnabledMonoProfilerClassLoading()) + if (!EventEnabledMonoProfilerClassLoading ()) return; uint64_t class_id; @@ -4000,11 +5230,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 +5247,7 @@ mono_profiler_class_failed ( MonoProfiler *prof, MonoClass *klass) { - if (!EventEnabledMonoProfilerClassFailed()) + if (!EventEnabledMonoProfilerClassFailed ()) return; uint64_t class_id; @@ -4021,11 +5255,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 +5284,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 +5296,8 @@ mono_profiler_class_loaded ( NULL, NULL); + mono_profiler_fire_event_exit (); + g_free (class_name); g_free (class_generic_types); } @@ -4085,7 +5327,7 @@ mono_profiler_vtable_loading ( MonoProfiler *prof, MonoVTable *vtable) { - if (!EventEnabledMonoProfilerVTableLoading()) + if (!EventEnabledMonoProfilerVTableLoading ()) return; uint64_t vtable_id; @@ -4094,12 +5336,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 +5354,7 @@ mono_profiler_vtable_failed ( MonoProfiler *prof, MonoVTable *vtable) { - if (!EventEnabledMonoProfilerVTableFailed()) + if (!EventEnabledMonoProfilerVTableFailed ()) return; uint64_t vtable_id; @@ -4116,13 +5362,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 +5381,7 @@ mono_profiler_vtable_loaded ( MonoProfiler *prof, MonoVTable *vtable) { - if (!EventEnabledMonoProfilerVTableLoaded()) + if (!EventEnabledMonoProfilerVTableLoaded ()) return; uint64_t vtable_id; @@ -4139,13 +5389,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 +5411,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 +5430,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 +5460,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 +5481,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 +5511,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 +5558,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 +5584,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 +5593,8 @@ mono_profiler_assembly_loaded ( NULL, NULL); + mono_profiler_fire_event_exit (); + g_free (assembly_name); } @@ -4330,11 +5612,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 +5638,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 +5647,8 @@ mono_profiler_assembly_unloaded ( NULL, NULL); + mono_profiler_fire_event_exit (); + g_free (assembly_name); } @@ -4372,10 +5662,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 +5682,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 +5702,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 +5722,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 +5741,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 +5760,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 +5779,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,57 +5818,192 @@ mono_profiler_exception_throw ( if (exc && mono_object_class(exc)) type_id = (uint64_t)m_class_get_byval_arg (mono_object_class(exc)); - FireEtwMonoProfilerExceptionThrow ( - type_id, - SGEN_POINTER_UNTAG_ALL (exc), - NULL, - NULL); -} + mono_profiler_fire_event_enter (); + + FireEtwMonoProfilerExceptionThrow ( + type_id, + SGEN_POINTER_UNTAG_ALL (exc), + NULL, + NULL); + + mono_profiler_fire_event_exit (); +} + +static +void +mono_profiler_exception_clause ( + MonoProfiler *prof, + MonoMethod *method, + uint32_t clause_num, + MonoExceptionEnum clause_type, + MonoObject *exc) +{ + if (!EventEnabledMonoProfilerExceptionClause ()) + return; + + uint64_t type_id = 0; + + 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, + (uint64_t)method, + type_id, + SGEN_POINTER_UNTAG_ALL (exc), + NULL, + NULL); + + mono_profiler_fire_event_exit (); +} + +static +void +mono_profiler_gc_event ( + MonoProfiler *prof, + MonoProfilerGCEvent gc_event, + uint32_t generation, + mono_bool serial) +{ + 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); + + mono_profiler_gc_in_progress_start (); + + if (mono_profiler_gc_heap_collect_in_progress ()) { + FireEtwMonoProfilerGCHeapDumpStart ( + mono_profiler_get_gc_heap_collect_param_request_value (), + NULL, + NULL); + } + + break; + } + case MONO_GC_EVENT_POST_STOP_WORLD: + { + if (mono_profiler_gc_in_progress ()) { + 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_collect_provider, mono_profiler_fire_buffered_gc_event_root_register); + mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, mono_profiler_fire_buffered_gc_event_root_unregister); + } + + if (mono_profiler_gc_heap_collect_in_progress ()) { + if (profiler_callback_is_enabled (enabled_keywords, GC_ROOT_KEYWORD)) { + mono_profiler_set_gc_roots_callback (_ep_rt_dotnet_mono_profiler_heap_collect_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_collect_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_collect_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: + { + if (mono_profiler_gc_in_progress ()) { + mono_profiler_fire_buffered_gc_event ( + (uint8_t)gc_event, + generation); + } + break; + } + case MONO_GC_EVENT_PRE_START_WORLD: + { + if (mono_profiler_gc_in_progress ()) { + uint64_t enabled_keywords = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask; + + if (mono_profiler_gc_heap_collect_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_collect_provider, NULL); + mono_profiler_set_gc_root_unregister_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, NULL); + mono_profiler_set_gc_roots_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, NULL); + mono_profiler_set_gc_moves_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, NULL); + mono_profiler_set_gc_resize_callback (_ep_rt_dotnet_mono_profiler_heap_collect_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: + { + if (mono_profiler_gc_in_progress ()) { + GHashTable *cache = NULL; + uint64_t enabled_keywords = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask; + + if (mono_profiler_gc_heap_collect_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); -static -void -mono_profiler_exception_clause ( - MonoProfiler *prof, - MonoMethod *method, - uint32_t clause_num, - MonoExceptionEnum clause_type, - MonoObject *exc) -{ - if (!EventEnabledMonoProfilerExceptionClause ()) - return; + mono_profiler_fire_buffered_gc_events_in_alloc_order (cache); + mono_profiler_fire_cached_gc_events (cache); - uint64_t type_id = 0; + if (cache) + g_hash_table_destroy (cache); - if (exc && mono_object_class(exc)) - type_id = (uint64_t)m_class_get_byval_arg (mono_object_class(exc)); + if (mono_profiler_gc_heap_collect_in_progress ()) { + FireEtwMonoProfilerGCHeapDumpStop ( + NULL, + NULL); + } - FireEtwMonoProfilerExceptionClause ( - (uint8_t)clause_type, - clause_num, - (uint64_t)method, - type_id, - SGEN_POINTER_UNTAG_ALL (exc), - NULL, - NULL); -} + FireEtwMonoProfilerGCEvent ( + (uint8_t)gc_event, + generation, + NULL, + NULL); -static -void -mono_profiler_gc_event ( - MonoProfiler *prof, - MonoProfilerGCEvent gc_event, - uint32_t generation, - mono_bool serial) -{ - if (!EventEnabledMonoProfilerGCEvent ()) - return; + if (!profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD)) + mono_profiler_set_gc_event_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); - // TODO: Needs to be async safe. - /*FireEtwMonoProfilerGCEvent ( - (uint8_t)gc_event, - generation, - NULL, - NULL);*/ + mono_profiler_gc_heap_collect_in_progress_stop (); + mono_profiler_gc_in_progress_stop (); + } + break; + } + default: + break; + } } static @@ -4574,75 +6027,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 +6050,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 +6072,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 +6090,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 +6106,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 +6124,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 +6143,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 +6166,8 @@ mono_profiler_gc_root_register ( if (!EventEnabledMonoProfilerGCRootRegister ()) return; + mono_profiler_fire_event_enter (); + FireEtwMonoProfilerGCRootRegister ( start, (uint64_t)size, @@ -4756,6 +6176,8 @@ mono_profiler_gc_root_register ( (const ep_char8_t *)(name ? name : ""), NULL, NULL); + + mono_profiler_fire_event_exit (); } static @@ -4767,58 +6189,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 +6208,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 +6227,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 +6246,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 +6265,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 +6284,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 +6303,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 +6322,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 +6342,191 @@ 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 +const EventFilterDescriptor * +mono_profiler_add_provider_param (const EventFilterDescriptor *key) +{ + ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock); + + 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); + _ep_rt_mono_profiler_provider_params = g_slist_append (_ep_rt_mono_profiler_provider_params, param); + } else { + g_free ((void *)param_ptr); + } + } + } + return param; +} + +static +bool +mono_profiler_remove_provider_param (const EventFilterDescriptor *key) +{ + ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock); + + bool removed = false; + if (_ep_rt_mono_profiler_provider_params && key && key->ptr && key->size) { + GSList *list = _ep_rt_mono_profiler_provider_params; + EventFilterDescriptor *param = NULL; + while (list) { + 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); + ep_event_filter_desc_free (param); + _ep_rt_mono_profiler_provider_params = g_slist_delete_link (_ep_rt_mono_profiler_provider_params, list); + removed = true; + break; + } + list = list->next; + } + } + + return removed; } +static void -EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( +mono_profiler_free_provider_params (void) +{ + // Should only be called from ep_rt_mono_fini. + for (GSList *list = _ep_rt_mono_profiler_provider_params; list; list = list->next) { + EventFilterDescriptor *param = (EventFilterDescriptor *)(list->data); + if (param) { + g_free ((void *)param->ptr); + ep_event_filter_desc_free (param); + } + } + g_slist_free (_ep_rt_mono_profiler_provider_params); + _ep_rt_mono_profiler_provider_params = NULL; +} + +static +bool +mono_profiler_provider_params_get_value ( + const EventFilterDescriptor *param, + const ep_char8_t *key, + const ep_char8_t **value) +{ + if (!param || !param->ptr || !param->size || !key) + return false; + + const ep_char8_t *current = (ep_char8_t *)param->ptr; + const ep_char8_t *end = current + param->size; + bool found_key = false; + + if (value) + *value = ""; + + if (!current [param->size - 1]) { + while (current < end) { + if (found_key) { + if (value) + *value = current; + break; + } + + if (!ep_rt_utf8_string_compare_ignore_case (current, key)) { + found_key = true; + } + + current = current + strlen (current) + 1; + } + } + + return found_key; +} + +static +bool +mono_profiler_provider_param_contains_heap_collect_ondemand (const EventFilterDescriptor *param) +{ + const ep_char8_t *value = NULL; + bool found_heap_collect_ondemand_value = false; + + if (mono_profiler_provider_params_get_value (param, "heapcollect", &value)) { + if (strstr (value, "ondemand")) + found_heap_collect_ondemand_value = true; + } + + return found_heap_collect_ondemand_value; +} + +static +void +mono_profiler_push_gc_heap_collect_param_request_value (const EventFilterDescriptor *param) +{ + ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock); + + const ep_char8_t *value = NULL; + if (param) + mono_profiler_provider_params_get_value (param, "heapcollect", &value); + + if (!_ep_rt_mono_profiler_gc_heap_collect_request_params) + _ep_rt_mono_profiler_gc_heap_collect_request_params = g_queue_new (); + if (_ep_rt_mono_profiler_gc_heap_collect_request_params) + g_queue_push_tail (_ep_rt_mono_profiler_gc_heap_collect_request_params, (gpointer)ep_rt_utf8_string_dup (value ? value : "")); +} + +static +void +mono_profiler_pop_gc_heap_collect_param_request_value (void) +{ + ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock); + + ep_char8_t *value = NULL; + if (_ep_rt_mono_profiler_gc_heap_collect_request_params && !g_queue_is_empty (_ep_rt_mono_profiler_gc_heap_collect_request_params)) + value = (ep_char8_t *)g_queue_pop_head (_ep_rt_mono_profiler_gc_heap_collect_request_params); + g_free (value); +} + +static +const ep_char8_t * +mono_profiler_get_gc_heap_collect_param_request_value (void) +{ + ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock); + + ep_char8_t *value = NULL; + if (_ep_rt_mono_profiler_gc_heap_collect_request_params && !g_queue_is_empty (_ep_rt_mono_profiler_gc_heap_collect_request_params)) { + value = (ep_char8_t *)g_queue_pop_head (_ep_rt_mono_profiler_gc_heap_collect_request_params); + g_queue_push_head (_ep_rt_mono_profiler_gc_heap_collect_request_params, (gpointer)value); + } + return value ? value : ""; +} + +static +void +mono_profiler_free_gc_heap_collect_param_requests (void) +{ + // Should only be called from ep_rt_mono_fini. + if (_ep_rt_mono_profiler_gc_heap_collect_request_params) { + while (!g_queue_is_empty (_ep_rt_mono_profiler_gc_heap_collect_request_params)) + g_free (g_queue_pop_head (_ep_rt_mono_profiler_gc_heap_collect_request_params)); + g_queue_free (_ep_rt_mono_profiler_gc_heap_collect_request_params); + _ep_rt_mono_profiler_gc_heap_collect_request_params = NULL; + } +} + +static +void +mono_profiler_ep_provider_callback ( const uint8_t *source_id, unsigned long is_enabled, uint8_t level, @@ -4954,9 +6536,11 @@ EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( void *callback_data) { ep_rt_config_requires_lock_not_held (); + ep_rt_spin_lock_requires_lock_held (&_ep_rt_mono_profiler_gc_state_lock); 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_collect_provider != NULL); match_any_keywords = (is_enabled == 1) ? match_any_keywords : 0; @@ -5078,62 +6662,41 @@ EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( mono_profiler_set_gc_event_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_gc_event); } } else { - if (profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD)) { - mono_profiler_set_gc_event_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); - } + // NOTE, disabled in mono_profiler_gc_event, MONO_GC_EVENT_POST_START_WORLD to make sure all + // callbacks during GC fires. } - 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 +6704,34 @@ 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)) { + mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_heap_collect_provider, mono_profiler_trigger_heap_collect); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) { + mono_profiler_set_gc_finalized_callback (_ep_rt_dotnet_mono_profiler_heap_collect_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); } } @@ -5207,6 +6778,30 @@ EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( } } + if (match_any_keywords) { + bool request_heap_collect = false; + if (profiler_callback_is_enabled (match_any_keywords, GC_HEAP_COLLECT_KEYWORD)) { + if (mono_profiler_gc_can_collect_heap () && !profiler_callback_is_enabled (enabled_keywords, GC_HEAP_COLLECT_KEYWORD)) + request_heap_collect = true; + } + + if (filter_data) { + if (mono_profiler_provider_param_contains_heap_collect_ondemand (filter_data) && !mono_profiler_remove_provider_param (filter_data)) { + mono_profiler_add_provider_param (filter_data); + if (mono_profiler_gc_can_collect_heap () && profiler_callback_is_enabled (match_any_keywords, GC_HEAP_COLLECT_KEYWORD)) + request_heap_collect = true; + } + } + + if (request_heap_collect) { + mono_profiler_push_gc_heap_collect_param_request_value (filter_data); + mono_profiler_gc_heap_collect_requests_inc (); + mono_gc_finalize_notify (); + } + } else { + mono_profiler_free_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); @@ -5220,6 +6815,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);