diff --git a/src/coreclr/scripts/genEventPipe.py b/src/coreclr/scripts/genEventPipe.py index 380710d4a009b2..1076b181e316d5 100644 --- a/src/coreclr/scripts/genEventPipe.py +++ b/src/coreclr/scripts/genEventPipe.py @@ -72,11 +72,19 @@ def generateMethodSignatureWrite(eventName, template, extern, runtimeFlavor): sig_pieces.append(")") return ''.join(sig_pieces) +def includeProvider(providerName, runtimeFlavor): + if runtimeFlavor.coreclr and providerName == "Microsoft-DotNETRuntimeMonoProfiler": + return False + else: + return True + def includeEvent(inclusionList, providerName, eventName): if len(inclusionList) == 0: return True if providerName in inclusionList and eventName in inclusionList[providerName]: return True + elif providerName in inclusionList and "*" in inclusionList[providerName]: + return True elif "*" in inclusionList and eventName in inclusionList["*"]: return True elif "*" in inclusionList and "*" in inclusionList["*"]: @@ -340,6 +348,10 @@ def generateWriteEventBody(template, providerName, eventName, runtimeFlavor): pack_list.append( " success &= write_buffer_double_t(%s, &buffer, &offset, &size, &fixedBuffer);" % (parameter.name,)) + elif parameter.winType == "win:Pointer" and runtimeFlavor.mono: + pack_list.append( + " success &= write_buffer_uintptr_t((uintptr_t)%s, &buffer, &offset, &size, &fixedBuffer);" % + (parameter.name,)) elif runtimeFlavor.mono: pack_list.append( " success &= write_buffer((const uint8_t *)%s, sizeof(%s), &buffer, &offset, &size, &fixedBuffer);" % @@ -669,16 +681,17 @@ def generateEventPipeHelperFile(etwmanifest, eventpipe_directory, target_cpp, ru for providerNode in tree.getElementsByTagName('provider'): providerName = providerNode.getAttribute('name') - providerPrettyName = providerName.replace("Windows-", '') - providerPrettyName = providerPrettyName.replace("Microsoft-", '') - providerPrettyName = providerPrettyName.replace('-', '_') - if extern: helper.write( - 'extern "C" ' - ) - helper.write( - "void Init" + - providerPrettyName + - "(void);\n\n") + if includeProvider(providerName, runtimeFlavor): + providerPrettyName = providerName.replace("Windows-", '') + providerPrettyName = providerPrettyName.replace("Microsoft-", '') + providerPrettyName = providerPrettyName.replace('-', '_') + if extern: helper.write( + 'extern "C" ' + ) + helper.write( + "void Init" + + providerPrettyName + + "(void);\n\n") if extern: helper.write( 'extern "C" ' @@ -687,10 +700,11 @@ def generateEventPipeHelperFile(etwmanifest, eventpipe_directory, target_cpp, ru helper.write("void InitProvidersAndEvents(void)\n{\n") for providerNode in tree.getElementsByTagName('provider'): providerName = providerNode.getAttribute('name') - providerPrettyName = providerName.replace("Windows-", '') - providerPrettyName = providerPrettyName.replace("Microsoft-", '') - providerPrettyName = providerPrettyName.replace('-', '_') - helper.write(" Init" + providerPrettyName + "();\n") + if includeProvider(providerName, runtimeFlavor): + providerPrettyName = providerName.replace("Windows-", '') + providerPrettyName = providerPrettyName.replace("Microsoft-", '') + providerPrettyName = providerPrettyName.replace('-', '_') + helper.write(" Init" + providerPrettyName + "();\n") helper.write("}\n") if runtimeFlavor.coreclr: @@ -892,6 +906,19 @@ def getMonoEventPipeImplFilePrefix(): return write_buffer_int32_t (value, buffer, offset, size, fixed_buffer); } +static +inline +bool +write_buffer_uintptr_t ( + uintptr_t value, + uint8_t **buffer, + size_t *offset, + size_t *size, + bool *fixed_buffer) +{ + return write_buffer ((const uint8_t *)&value, sizeof (uintptr_t), buffer, offset, size, fixed_buffer); +} + static inline EventPipeEvent * @@ -949,6 +976,8 @@ def generateEventPipeImplFiles( for providerNode in tree.getElementsByTagName('provider'): providerName = providerNode.getAttribute('name') + if not includeProvider(providerName, runtimeFlavor): + continue providerPrettyName = providerName.replace("Windows-", '') providerPrettyName = providerPrettyName.replace("Microsoft-", '') diff --git a/src/coreclr/vm/ClrEtwAll.man b/src/coreclr/vm/ClrEtwAll.man index d8a275c6da6295..45895f16fce484 100644 --- a/src/coreclr/vm/ClrEtwAll.man +++ b/src/coreclr/vm/ClrEtwAll.man @@ -7052,6 +7052,930 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -8044,6 +8968,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/coreclr/vm/ClrEtwAllMeta.lst b/src/coreclr/vm/ClrEtwAllMeta.lst index 285e9101c6321d..4ac4fe405d9da4 100644 --- a/src/coreclr/vm/ClrEtwAllMeta.lst +++ b/src/coreclr/vm/ClrEtwAllMeta.lst @@ -633,3 +633,33 @@ nomac:StressLogTask:::StressLogEvent_V1 # StackWalk events ################## nomac:CLRStackStress:::CLRStackWalkStress + +################################# +# Events from the Mono profiler provider +################################# +nostack::MonoProfiler::ExceptionClause +nostack::MonoProfiler::MonoProfilerMethodEnter +nostack::MonoProfiler::MonoProfilerMethodLeave +nostack::MonoProfiler::MonoProfilerMethodTailCall +nostack::MonoProfiler::MonoProfilerMethodExceptionLeave +nostack::MonoProfiler::MonoProfilerMethodFree +nostack::MonoProfiler::MonoProfilerMethodBeginInvoke +nostack::MonoProfiler::MonoProfilerMethodEndInvoke +nostack::MonoProfiler::MonoProfilerGCEvent +nostack::MonoProfiler::MonoProfilerGCMoves +nostack::MonoProfiler::MonoProfilerGCResize +nostack::MonoProfiler::MonoProfilerGCFinalizing +nostack::MonoProfiler::MonoProfilerGCFinalized +nostack::MonoProfiler::MonoProfilerGCFinalizingObject +nostack::MonoProfiler::MonoProfilerGCFinalizedObject +nostack::MonoProfiler::MonoProfilerGCRootRegister +nostack::MonoProfiler::MonoProfilerGCRootUnregister +nostack::MonoProfiler::MonoProfilerGCRoots +nostack::MonoProfiler::MonoProfilerGCHeapDumpStart +nostack::MonoProfiler::MonoProfilerGCHeapDumpStop +nostack::MonoProfiler::MonoProfilerGCHeapDumpObjectReference +nostack::MonoProfiler::MonoProfilerThreadStarted +nostack::MonoProfiler::MonoProfilerThreadStopping +nostack::MonoProfiler::MonoProfilerThreadStopped +nostack::MonoProfiler::MonoProfilerThreadExited +nostack::MonoProfiler::MonoProfilerThreadName \ No newline at end of file diff --git a/src/mono/mono/component/event_pipe.c b/src/mono/mono/component/event_pipe.c index 6ed6171875a03f..24aa0952ce7aa6 100644 --- a/src/mono/mono/component/event_pipe.c +++ b/src/mono/mono/component/event_pipe.c @@ -11,6 +11,8 @@ #include #include +static bool _event_pipe_component_inited = false; + struct _EventPipeProviderConfigurationNative { gunichar2 *provider_name; uint64_t keywords; @@ -284,5 +286,11 @@ event_pipe_thread_ctrl_activity_id ( MonoComponentEventPipe * mono_component_event_pipe_init (void) { + if (!_event_pipe_component_inited) { + extern void ep_rt_mono_component_init (void); + ep_rt_mono_component_init (); + _event_pipe_component_inited = true; + } + return &fn_table; } diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index 9a83d80061bf55..683d94a61bb129 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -16,11 +16,15 @@ #include #include #include +#include #include #include #include #include #include +#include +#include +#include "mono/utils/mono-logger-internals.h" #include #include @@ -49,8 +53,11 @@ char *_ep_rt_mono_managed_cmd_line = NULL; static GArray * _ep_rt_mono_sampled_thread_callstacks = NULL; static uint32_t _ep_rt_mono_max_sampled_thread_count = 32; -// Mono profiler. -static MonoProfilerHandle _ep_rt_mono_profiler = NULL; +// Mono profilers. +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 MonoCallSpec _ep_rt_dotnet_mono_profiler_provider_callspec = {0}; // Phantom JIT compile method. MonoMethod *_ep_rt_mono_runtime_helper_compile_method = NULL; @@ -196,6 +203,38 @@ typedef struct _AssemblyEventData AssemblyEventData; #define EXCEPTION_THROWN_FLAGS_IS_CSE 0x8 #define EXCEPTION_THROWN_FLAGS_IS_CLS_COMPLIANT 0x10 +// Provider keyword flags. +#define GC_KEYWORD 0x1 +#define GC_HANDLE_KEYWORD 0x2 +#define LOADER_KEYWORD 0x8 +#define JIT_KEYWORD 0x10 +#define APP_DOMAIN_RESOURCE_MANAGEMENT_KEYWORD 0x800 +#define CONTENTION_KEYWORD 0x4000 +#define EXCEPTION_KEYWORD 0x8000 +#define THREADING_KEYWORD 0x10000 +#define GC_ALLOCATION_KEYWORD 0x200000 +#define GC_MOVES_KEYWORD 0x400000 +#define GC_ROOT_KEYWORD 0x800000 +#define GC_FINALIZATION_KEYWORD 0x1000000 +#define GC_RESIZE_KEYWORD 0x2000000 +#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. + +typedef struct _GCObjectAddressData { + MonoObject *object; + void *address; +} GCObjectAddressData; + +typedef struct _GCAddressObjectData { + void *address; + MonoObject *object; +} GCAddressObjectData; + /* * Forward declares of all static functions. */ @@ -303,6 +342,10 @@ profiler_eventpipe_thread_exited ( MonoProfiler *prof, uintptr_t tid); +static +bool +parse_mono_profiler_options (const ep_char8_t *option); + static bool get_module_event_data ( @@ -328,86 +371,86 @@ get_exception_ip_func ( static void -profiler_jit_begin ( +runtime_profiler_jit_begin ( MonoProfiler *prof, MonoMethod *method); static void -profiler_jit_failed ( +runtime_profiler_jit_failed ( MonoProfiler *prof, MonoMethod *method); static void -profiler_jit_done ( +runtime_profiler_jit_done ( MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji); static void -profiler_image_loaded ( +runtime_profiler_image_loaded ( MonoProfiler *prof, MonoImage *image); static void -profiler_image_unloaded ( +runtime_profiler_image_unloaded ( MonoProfiler *prof, MonoImage *image); static void -profiler_assembly_loaded ( +runtime_profiler_assembly_loaded ( MonoProfiler *prof, MonoAssembly *assembly); static void -profiler_assembly_unloaded ( +runtime_profiler_assembly_unloaded ( MonoProfiler *prof, MonoAssembly *assembly); static void -profiler_thread_started ( +runtime_profiler_thread_started ( MonoProfiler *prof, uintptr_t tid); static void -profiler_thread_stopped ( +runtime_profiler_thread_stopped ( MonoProfiler *prof, uintptr_t tid); static void -profiler_class_loading ( +runtime_profiler_class_loading ( MonoProfiler *prof, MonoClass *klass); static void -profiler_class_failed ( +runtime_profiler_class_failed ( MonoProfiler *prof, MonoClass *klass); static void -profiler_class_loaded ( +runtime_profiler_class_loaded ( MonoProfiler *prof, MonoClass *klass); static void -profiler_exception_throw ( +runtime_profiler_exception_throw ( MonoProfiler *prof, MonoObject *exception); static void -profiler_exception_clause ( +runtime_profiler_exception_clause ( MonoProfiler *prof, MonoMethod *method, uint32_t clause_num, @@ -416,2571 +459,4443 @@ profiler_exception_clause ( static void -profiler_monitor_contention ( +runtime_profiler_monitor_contention ( MonoProfiler *prof, MonoObject *obj); static void -profiler_monitor_acquired ( +runtime_profiler_monitor_acquired ( MonoProfiler *prof, MonoObject *obj); static void -profiler_monitor_failed ( +runtime_profiler_monitor_failed ( MonoProfiler *prof, MonoObject *obj); static void -profiler_jit_code_buffer ( +runtime_profiler_jit_code_buffer ( MonoProfiler *prof, const mono_byte *buffer, uint64_t size, MonoProfilerCodeBufferType type, const void *data); -/* - * Forward declares of all private functions (accessed using extern in ep-rt-mono.h). - */ +static +void +mono_profiler_app_domain_loading ( + MonoProfiler *prof, + MonoDomain *domain); +static void -ep_rt_mono_init (void); +mono_profiler_app_domain_loaded ( + MonoProfiler *prof, + MonoDomain *domain); +static void -ep_rt_mono_init_finish (void); +mono_profiler_app_domain_unloading ( + MonoProfiler *prof, + MonoDomain *domain); +static void -ep_rt_mono_fini (void); +mono_profiler_app_domain_unloaded ( + MonoProfiler *prof, + MonoDomain *domain); -bool -ep_rt_mono_rand_try_get_bytes ( - uint8_t *buffer, - size_t buffer_size); +static +void +mono_profiler_app_domain_name ( + MonoProfiler *prof, + MonoDomain *domain, + const char *name); -EventPipeThread * -ep_rt_mono_thread_get_or_create (void); +static +void +mono_profiler_jit_begin ( + MonoProfiler *prof, + MonoMethod *method); -void * -ep_rt_mono_thread_attach (bool background_thread); +static +void +mono_profiler_jit_failed ( + MonoProfiler *prof, + MonoMethod *method); -void * -ep_rt_mono_thread_attach_2 (bool background_thread, EventPipeThreadType thread_type); +static +void +mono_profiler_jit_done ( + MonoProfiler *prof, + MonoMethod *method, + MonoJitInfo *ji); +static void -ep_rt_mono_thread_detach (void); +mono_profiler_jit_chunk_created ( + MonoProfiler *prof, + const mono_byte *chunk, + uintptr_t size); +static void -ep_rt_mono_thread_exited (void); +mono_profiler_jit_chunk_destroyed ( + MonoProfiler *prof, + const mono_byte *chunk); -int64_t -ep_rt_mono_perf_counter_query (void); +static +void +mono_profiler_jit_code_buffer ( + MonoProfiler *prof, + const mono_byte *buffer, + uint64_t size, + MonoProfilerCodeBufferType type, + const void *data); -int64_t -ep_rt_mono_perf_frequency_query (void); +static +void +mono_profiler_class_loading ( + MonoProfiler *prof, + MonoClass *klass); +static void -ep_rt_mono_system_time_get (EventPipeSystemTime *system_time); +mono_profiler_class_failed ( + MonoProfiler *prof, + MonoClass *klass); -int64_t -ep_rt_mono_system_timestamp_get (void); +static +void +mono_profiler_class_loaded ( + MonoProfiler *prof, + MonoClass *klass); +static void -ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array); +mono_profiler_vtable_loading ( + MonoProfiler *prof, + MonoVTable *vtable); +static void -ep_rt_mono_init_providers_and_events (void); +mono_profiler_vtable_failed ( + MonoProfiler *prof, + MonoVTable *vtable); +static void -ep_rt_mono_provider_config_init (EventPipeProviderConfiguration *provider_config); +mono_profiler_vtable_loaded ( + MonoProfiler *prof, + MonoVTable *vtable); -bool -ep_rt_mono_providers_validate_all_disabled (void); +static +void +mono_profiler_module_loading ( + MonoProfiler *prof, + MonoImage *image); +static void -ep_rt_mono_fini_providers_and_events (void); +mono_profiler_module_failed ( + MonoProfiler *prof, + MonoImage *image); -bool -ep_rt_mono_sample_profiler_write_sampling_event_for_threads ( - ep_rt_thread_handle_t sampling_thread, - EventPipeEvent *sampling_event); +static +void +mono_profiler_module_loaded ( + MonoProfiler *prof, + MonoImage *image); -bool -ep_rt_mono_walk_managed_stack_for_thread ( - ep_rt_thread_handle_t thread, - EventPipeStackContents *stack_contents); +static +void +mono_profiler_module_unloading ( + MonoProfiler *prof, + MonoImage *image); -bool -ep_rt_mono_method_get_simple_assembly_name ( - ep_rt_method_desc_t *method, - ep_char8_t *name, - size_t name_len); +static +void +mono_profiler_module_unloaded ( + MonoProfiler *prof, + MonoImage *image); -bool -ep_rt_mono_method_get_full_name ( - ep_rt_method_desc_t *method, - ep_char8_t *name, - size_t name_len); +static +void +mono_profiler_assembly_loading ( + MonoProfiler *prof, + MonoAssembly *assembly); +static void -ep_rt_mono_execute_rundown (ep_rt_execution_checkpoint_array_t *execution_checkpoints); +mono_profiler_assembly_loaded ( + MonoProfiler *prof, + MonoAssembly *assembly); static -inline -uint16_t -clr_instance_get_id (void) -{ - // Mono runtime id. - return 9; -} +void +mono_profiler_assembly_unloading ( + MonoProfiler *prof, + MonoAssembly *assembly); static -bool -fire_method_rundown_events_func ( - const uint64_t method_id, - const uint64_t module_id, - const uint64_t method_start_address, - const uint32_t method_size, - const uint32_t method_token, - const uint32_t method_flags, - const ep_char8_t *method_namespace, - const ep_char8_t *method_name, - const ep_char8_t *method_signature, - const uint16_t count_of_map_entries, - const uint32_t *il_offsets, - const uint32_t *native_offsets, - bool aot_method, - bool verbose, - void *user_data) -{ - FireEtwMethodDCEndILToNativeMap ( - method_id, - 0, - 0, - count_of_map_entries, - il_offsets, - native_offsets, - clr_instance_get_id (), - NULL, - NULL); +void +mono_profiler_assembly_unloaded ( + MonoProfiler *prof, + MonoAssembly *assembly); - if (verbose) { - FireEtwMethodDCEndVerbose_V1 ( - method_id, - module_id, - method_start_address, - method_size, - method_token, - method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION, - method_namespace, - method_name, - method_signature, - clr_instance_get_id (), - NULL, - NULL); +static +void +mono_profiler_method_enter ( + MonoProfiler *prof, + MonoMethod *method, + MonoProfilerCallContext *context); - if (aot_method) - FireEtwMethodDCEndVerbose_V1 ( - method_id, - module_id, - method_start_address, - method_size, - method_token, - method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION, - method_namespace, - method_name, - method_signature, - clr_instance_get_id (), - NULL, - NULL); - } else { - FireEtwMethodDCEnd_V1 ( - method_id, - module_id, - method_start_address, - method_size, - method_token, - method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION, - clr_instance_get_id (), - NULL, - NULL); +static +void +mono_profiler_method_leave ( + MonoProfiler *prof, + MonoMethod *method, + MonoProfilerCallContext *context); - if (aot_method) - FireEtwMethodDCEnd_V1 ( - method_id, - module_id, - method_start_address, - method_size, - method_token, - method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION, - clr_instance_get_id (), - NULL, - NULL); - } +static +void +mono_profiler_method_tail_call ( + MonoProfiler *prof, + MonoMethod *method, + MonoMethod *target_method); - return true; -} +static +void +mono_profiler_method_exception_leave ( + MonoProfiler *prof, + MonoMethod *method, + MonoObject *exc); static -bool -fire_assembly_rundown_events_func ( - const uint64_t domain_id, - const uint64_t assembly_id, - const uint32_t assembly_flags, - const uint32_t binding_id, - const ep_char8_t *assembly_name, - const uint64_t module_id, - const uint32_t module_flags, - const uint32_t reserved_flags, - const ep_char8_t *module_il_path, - const ep_char8_t *module_native_path, - const uint8_t *managed_pdb_signature, - const uint32_t managed_pdb_age, - const ep_char8_t *managed_pdb_build_path, - const uint8_t *native_pdb_signature, - const uint32_t native_pdb_age, - const ep_char8_t *native_pdb_build_path, - void *user_data) -{ - FireEtwModuleDCEnd_V2 ( - module_id, - assembly_id, - module_flags, - reserved_flags, - module_il_path, - module_native_path, - clr_instance_get_id (), - managed_pdb_signature, - managed_pdb_age, - managed_pdb_build_path, - native_pdb_signature, - native_pdb_age, - native_pdb_build_path, - NULL, - NULL); +void +mono_profiler_method_free ( + MonoProfiler *prof, + MonoMethod *method); - FireEtwDomainModuleDCEnd_V1 ( - module_id, - assembly_id, - domain_id, - module_flags, - reserved_flags, - module_il_path, - module_native_path, - clr_instance_get_id (), - NULL, - NULL); +static +void +mono_profiler_method_begin_invoke ( + MonoProfiler *prof, + MonoMethod *method); - FireEtwAssemblyDCEnd_V1 ( - assembly_id, - domain_id, - binding_id, - assembly_flags, - assembly_name, - clr_instance_get_id (), - NULL, - NULL); +static +void +mono_profiler_method_end_invoke ( + MonoProfiler *prof, + MonoMethod *method); - return true; -} +static +MonoProfilerCallInstrumentationFlags +mono_profiler_method_instrumentation ( + MonoProfiler *prof, + MonoMethod *method); static -bool -fire_domain_rundown_events_func ( - const uint64_t domain_id, - const uint32_t domain_flags, - const ep_char8_t *domain_name, - const uint32_t domain_index, - void *user_data) -{ - return FireEtwAppDomainDCEnd_V1 ( - domain_id, - domain_flags, - domain_name, - domain_index, - clr_instance_get_id (), - NULL, - NULL); -} +void +mono_profiler_exception_throw ( + MonoProfiler *prof, + MonoObject *exc); static void -eventpipe_fire_method_events ( - MonoJitInfo *ji, +mono_profiler_exception_clause ( + MonoProfiler *prof, MonoMethod *method, - EventPipeFireMethodEventsData *events_data) -{ - EP_ASSERT (ji != NULL); - EP_ASSERT (events_data->domain != NULL); - EP_ASSERT (events_data->method_events_func != NULL); - - uint64_t method_id = 0; - uint64_t module_id = 0; - uint64_t method_code_start = (uint64_t)ji->code_start; - uint32_t method_code_size = (uint32_t)ji->code_size; - uint32_t method_token = 0; - uint32_t method_flags = 0; - uint8_t kind = MONO_CLASS_DEF; - char *method_namespace = NULL; - const char *method_name = NULL; - char *method_signature = NULL; - bool verbose = (MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.Level >= (uint8_t)EP_EVENT_LEVEL_VERBOSE); + uint32_t clause_num, + MonoExceptionEnum clause_type, + MonoObject *exc); - //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. +static +void +mono_profiler_gc_event ( + MonoProfiler *prof, + MonoProfilerGCEvent gc_event, + uint32_t generation, + mono_bool serial); - if (method) { - method_id = (uint64_t)method; - method_token = method->token; +static +void +mono_profiler_gc_allocation ( + MonoProfiler *prof, + MonoObject *object); - if (mono_jit_info_get_generic_sharing_context (ji)) - method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD; +static +void +mono_profiler_gc_moves ( + MonoProfiler *prof, + MonoObject *const* objects, + uint64_t count); - if (method->dynamic) - method_flags |= METHOD_FLAGS_DYNAMIC_METHOD; +static +void +mono_profiler_gc_resize ( + MonoProfiler *prof, + uintptr_t size); - if (!ji->from_aot && !ji->from_llvm) { - method_flags |= METHOD_FLAGS_JITTED_METHOD; - if (method->wrapper_type != MONO_WRAPPER_NONE) - method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD; - } +static +void +mono_profiler_gc_handle_created ( + MonoProfiler *prof, + uint32_t handle, + MonoGCHandleType type, + MonoObject * object); - if (method->is_generic || method->is_inflated) - method_flags |= METHOD_FLAGS_GENERIC_METHOD; +static +void +mono_profiler_gc_handle_deleted ( + MonoProfiler *prof, + uint32_t handle, + MonoGCHandleType type); - if (method->klass) { - module_id = (uint64_t)m_class_get_image (method->klass); - kind = m_class_get_class_kind (method->klass); - if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST) - method_flags |= METHOD_FLAGS_GENERIC_METHOD; - } +static +void +mono_profiler_gc_finalizing (MonoProfiler *prof); - if (verbose) { - 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); - } +static +void +mono_profiler_gc_finalized (MonoProfiler *prof); - } +static +void +mono_profiler_gc_root_register ( + MonoProfiler *prof, + const mono_byte *start, + uintptr_t size, + MonoGCRootSource source, + const void * key, + const char * name); - uint16_t offset_entries = 0; - uint32_t *il_offsets = NULL; - uint32_t *native_offsets = NULL; +static +void +mono_profiler_gc_root_unregister ( + MonoProfiler *prof, + const mono_byte *start); - MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, events_data->domain) : NULL; - if (debug_info) { - offset_entries = debug_info->num_line_numbers; - if (offset_entries != 0) { - size_t needed_size = (offset_entries * sizeof (uint32_t) * 2); - if (!events_data->buffer || needed_size > events_data->buffer_size) { - g_free (events_data->buffer); - events_data->buffer_size = (size_t)(needed_size * 1.5); - events_data->buffer = g_new (uint8_t, events_data->buffer_size); - } +static +void +mono_profiler_gc_roots ( + MonoProfiler *prof, + uint64_t count, + const mono_byte *const * addresses, + MonoObject *const * objects); - if (events_data->buffer) { - il_offsets = (uint32_t*)events_data->buffer; - native_offsets = il_offsets + offset_entries; +static +void +mono_profiler_monitor_contention ( + MonoProfiler *prof, + MonoObject *object); - for (int offset_count = 0; offset_count < offset_entries; ++offset_count) { - il_offsets [offset_count] = debug_info->line_numbers [offset_count].il_offset; - native_offsets [offset_count] = debug_info->line_numbers [offset_count].native_offset; - } - } - } +static +void +mono_profiler_monitor_failed ( + MonoProfiler *prof, + MonoObject *object); - mono_debug_free_method_jit_info (debug_info); - } +static +void +mono_profiler_monitor_acquired ( + MonoProfiler *prof, + MonoObject *object); - if (events_data->buffer && !il_offsets && !native_offsets) { - // No IL offset -> Native offset mapping available. Put all code on IL offset 0. - EP_ASSERT (events_data->buffer_size >= sizeof (uint32_t) * 2); - offset_entries = 1; - il_offsets = (uint32_t*)events_data->buffer; - native_offsets = il_offsets + offset_entries; - il_offsets [0] = 0; - native_offsets [0] = (uint32_t)ji->code_size; - } +static +void +mono_profiler_thread_started ( + MonoProfiler *prof, + uintptr_t tid); - events_data->method_events_func ( - method_id, - module_id, - method_code_start, - method_code_size, - method_token, - method_flags, - (ep_char8_t *)method_namespace, - (ep_char8_t *)method_name, - (ep_char8_t *)method_signature, - offset_entries, - il_offsets, - native_offsets, - (ji->from_aot || ji->from_llvm), - verbose, - NULL); +static +void +mono_profiler_thread_stopping ( + MonoProfiler *prof, + uintptr_t tid); - g_free (method_namespace); - g_free (method_signature); -} +static +void +mono_profiler_thread_stopped ( + MonoProfiler *prof, + uintptr_t tid); static -inline -bool -include_method (MonoMethod *method) -{ - if (!method) { - return false; - } else if (!m_method_is_wrapper (method)) { - return true; - } else { - WrapperInfo *wrapper = mono_marshal_get_wrapper_info (method); - return (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_PINVOKE) ? true : false; - } -} +void +mono_profiler_thread_exited ( + MonoProfiler *prof, + uintptr_t tid); static void -eventpipe_fire_method_events_func ( - MonoJitInfo *ji, - void *user_data) -{ - EventPipeFireMethodEventsData *events_data = (EventPipeFireMethodEventsData *)user_data; - EP_ASSERT (events_data != NULL); +mono_profiler_thread_name ( + MonoProfiler *prof, + uintptr_t tid, + const char *name); - if (ji && !ji->is_trampoline && !ji->async) { - MonoMethod *method = jinfo_get_method (ji); - if (include_method (method)) - eventpipe_fire_method_events (ji, method, events_data); - } -} +/* + * Forward declares of all private functions (accessed using extern in ep-rt-mono.h). + */ -static void -eventpipe_fire_assembly_events ( - MonoDomain *domain, - MonoAssembly *assembly, - ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func) -{ - EP_ASSERT (domain != NULL); - EP_ASSERT (assembly != NULL); - EP_ASSERT (assembly_events_func != NULL); - - uint64_t domain_id = (uint64_t)domain; - uint64_t module_id = (uint64_t)assembly->image; - uint64_t assembly_id = (uint64_t)assembly; - - // TODO: Extract all module IL/Native paths and pdb metadata when available. - const char *module_il_path = ""; - const char *module_il_pdb_path = ""; - const char *module_native_path = ""; - const char *module_native_pdb_path = ""; - uint8_t signature [EP_GUID_SIZE] = { 0 }; - uint32_t module_il_pdb_age = 0; - uint32_t module_native_pdb_age = 0; +ep_rt_mono_component_init (void); - uint32_t reserved_flags = 0; - uint64_t binding_id = 0; +void +ep_rt_mono_init (void); - // Native methods are part of JIT table and already emitted. - // TODO: FireEtwMethodDCEndVerbose_V1_or_V2 for all native methods in module as well? +void +ep_rt_mono_init_finish (void); - // Netcore has a 1:1 between assemblies and modules, so its always a manifest module. - uint32_t module_flags = MODULE_FLAGS_MANIFEST_MODULE; - if (assembly->image) { - if (assembly->image->dynamic) - module_flags |= MODULE_FLAGS_DYNAMIC_MODULE; - if (assembly->image->aot_module) - module_flags |= MODULE_FLAGS_NATIVE_MODULE; +void +ep_rt_mono_fini (void); - module_il_path = assembly->image->filename ? assembly->image->filename : ""; - } +bool +ep_rt_mono_rand_try_get_bytes ( + uint8_t *buffer, + size_t buffer_size); - uint32_t assembly_flags = 0; - if (assembly->dynamic) - assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; +EventPipeThread * +ep_rt_mono_thread_get_or_create (void); - if (assembly->image && assembly->image->aot_module) { - assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; - } +void * +ep_rt_mono_thread_attach (bool background_thread); - char *assembly_name = mono_stringify_assembly_name (&assembly->aname); +void * +ep_rt_mono_thread_attach_2 (bool background_thread, EventPipeThreadType thread_type); - assembly_events_func ( - domain_id, - assembly_id, - assembly_flags, - binding_id, - (const ep_char8_t*)assembly_name, - module_id, - module_flags, - reserved_flags, - (const ep_char8_t *)module_il_path, - (const ep_char8_t *)module_native_path, - signature, - module_il_pdb_age, - (const ep_char8_t *)module_il_pdb_path, - signature, - module_native_pdb_age, - (const ep_char8_t *)module_native_pdb_path, - NULL); +void +ep_rt_mono_thread_detach (void); - g_free (assembly_name); -} +void +ep_rt_mono_thread_exited (void); -static -gboolean -eventpipe_execute_rundown ( - ep_rt_mono_fire_domain_rundown_events_func domain_events_func, - ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func, - ep_rt_mono_fire_method_rundown_events_func method_events_func) -{ - EP_ASSERT (domain_events_func != NULL); - EP_ASSERT (assembly_events_func != NULL); - EP_ASSERT (method_events_func != NULL); +int64_t +ep_rt_mono_perf_counter_query (void); - // Under netcore we only have root domain. - MonoDomain *root_domain = mono_get_root_domain (); - if (root_domain) { - uint64_t domain_id = (uint64_t)root_domain; +int64_t +ep_rt_mono_perf_frequency_query (void); - // Emit all functions in use (JIT, AOT and Interpreter). - EventPipeFireMethodEventsData events_data; - events_data.domain = root_domain; - events_data.buffer_size = 1024 * sizeof(uint32_t); - events_data.buffer = g_new (uint8_t, events_data.buffer_size); - events_data.method_events_func = method_events_func; +void +ep_rt_mono_system_time_get (EventPipeSystemTime *system_time); - // All called JIT/AOT methods should be included in jit info table. - mono_jit_info_table_foreach_internal (eventpipe_fire_method_events_func, &events_data); +int64_t +ep_rt_mono_system_timestamp_get (void); - // All called interpreted methods should be included in interpreter jit info table. - if (mono_get_runtime_callbacks ()->is_interpreter_enabled()) - mono_get_runtime_callbacks ()->interp_jit_info_foreach (eventpipe_fire_method_events_func, &events_data); +void +ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array); - // Phantom methods injected in callstacks representing runtime functions. - if (_ep_rt_mono_runtime_helper_compile_method_jitinfo && _ep_rt_mono_runtime_helper_compile_method) - eventpipe_fire_method_events (_ep_rt_mono_runtime_helper_compile_method_jitinfo, _ep_rt_mono_runtime_helper_compile_method, &events_data); - if (_ep_rt_mono_monitor_enter_method_jitinfo && _ep_rt_mono_monitor_enter_method) - eventpipe_fire_method_events (_ep_rt_mono_monitor_enter_method_jitinfo, _ep_rt_mono_monitor_enter_method, &events_data); - if (_ep_rt_mono_monitor_enter_v4_method_jitinfo && _ep_rt_mono_monitor_enter_v4_method) - eventpipe_fire_method_events (_ep_rt_mono_monitor_enter_v4_method_jitinfo, _ep_rt_mono_monitor_enter_v4_method, &events_data); +void +ep_rt_mono_init_providers_and_events (void); - g_free (events_data.buffer); +void +ep_rt_mono_provider_config_init (EventPipeProviderConfiguration *provider_config); - // Iterate all assemblies in domain. - GPtrArray *assemblies = mono_alc_get_all_loaded_assemblies (); - if (assemblies) { - for (int i = 0; i < assemblies->len; ++i) { - MonoAssembly *assembly = (MonoAssembly *)g_ptr_array_index (assemblies, i); - if (assembly) - eventpipe_fire_assembly_events (root_domain, assembly, assembly_events_func); - } - g_ptr_array_free (assemblies, TRUE); - } +bool +ep_rt_mono_providers_validate_all_disabled (void); - uint32_t domain_flags = DOMAIN_FLAGS_DEFAULT_DOMAIN | DOMAIN_FLAGS_EXECUTABLE_DOMAIN; - const char *domain_name = root_domain->friendly_name ? root_domain->friendly_name : ""; - uint32_t domain_index = 1; +void +ep_rt_mono_fini_providers_and_events (void); - domain_events_func ( - domain_id, - domain_flags, - (const ep_char8_t *)domain_name, - domain_index, - NULL); - } +bool +ep_rt_mono_sample_profiler_write_sampling_event_for_threads ( + ep_rt_thread_handle_t sampling_thread, + EventPipeEvent *sampling_event); - return TRUE; -} +bool +ep_rt_mono_walk_managed_stack_for_thread ( + ep_rt_thread_handle_t thread, + EventPipeStackContents *stack_contents); -inline -static bool -in_safe_point_frame (EventPipeStackContents *stack_content, WrapperInfo *wrapper) -{ - EP_ASSERT (stack_content != NULL); +ep_rt_mono_method_get_simple_assembly_name ( + ep_rt_method_desc_t *method, + ep_char8_t *name, + size_t name_len); - // If top of stack is a managed->native icall wrapper for one of the below subtypes, we are at a safe point frame. - if (wrapper && ep_stack_contents_get_length (stack_content) == 0 && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER && - (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_state_poll || - wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_enter_gc_safe_region_unbalanced || - wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_exit_gc_safe_region_unbalanced || - wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_enter_gc_unsafe_region_unbalanced || - wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_exit_gc_unsafe_region_unbalanced)) - return true; +bool +ep_rt_mono_method_get_full_name ( + ep_rt_method_desc_t *method, + ep_char8_t *name, + size_t name_len); - return false; -} +void +ep_rt_mono_execute_rundown (ep_rt_execution_checkpoint_array_t *execution_checkpoints); -inline static +inline bool -in_runtime_invoke_frame (EventPipeStackContents *stack_content, WrapperInfo *wrapper) +profiler_callback_is_enabled (uint64_t enabled_keywords, uint64_t keyword) { - EP_ASSERT (stack_content != NULL); - - // If top of stack is a managed->native runtime invoke wrapper, we are at a managed frame. - if (wrapper && ep_stack_contents_get_length (stack_content) == 0 && - (wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL || - wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT || - wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC || - wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL)) - return true; - - return false; + return (enabled_keywords & keyword) == keyword; } -inline static -bool -in_monitor_enter_frame (WrapperInfo *wrapper) +inline +uint16_t +clr_instance_get_id (void) { - if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER && - (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_fast || - wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_internal)) - return true; - - return false; + // Mono runtime id. + return 9; } -inline static bool -in_monitor_enter_v4_frame (WrapperInfo *wrapper) +fire_method_rundown_events_func ( + const uint64_t method_id, + const uint64_t module_id, + const uint64_t method_start_address, + const uint32_t method_size, + const uint32_t method_token, + const uint32_t method_flags, + const ep_char8_t *method_namespace, + const ep_char8_t *method_name, + const ep_char8_t *method_signature, + const uint16_t count_of_map_entries, + const uint32_t *il_offsets, + const uint32_t *native_offsets, + bool aot_method, + bool verbose, + void *user_data) { - if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER && - (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_v4_fast || - wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_v4_internal)) - return true; - - return false; -} - -static + FireEtwMethodDCEndILToNativeMap ( + method_id, + 0, + 0, + count_of_map_entries, + il_offsets, + native_offsets, + clr_instance_get_id (), + NULL, + NULL); + + if (verbose) { + FireEtwMethodDCEndVerbose_V1 ( + method_id, + module_id, + method_start_address, + method_size, + method_token, + method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION, + method_namespace, + method_name, + method_signature, + clr_instance_get_id (), + NULL, + NULL); + + if (aot_method) + FireEtwMethodDCEndVerbose_V1 ( + method_id, + module_id, + method_start_address, + method_size, + method_token, + method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION, + method_namespace, + method_name, + method_signature, + clr_instance_get_id (), + NULL, + NULL); + } else { + FireEtwMethodDCEnd_V1 ( + method_id, + module_id, + method_start_address, + method_size, + method_token, + method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION, + clr_instance_get_id (), + NULL, + NULL); + + if (aot_method) + FireEtwMethodDCEnd_V1 ( + method_id, + module_id, + method_start_address, + method_size, + method_token, + method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION, + clr_instance_get_id (), + NULL, + NULL); + } + + return true; +} + +static +bool +fire_assembly_rundown_events_func ( + const uint64_t domain_id, + const uint64_t assembly_id, + const uint32_t assembly_flags, + const uint32_t binding_id, + const ep_char8_t *assembly_name, + const uint64_t module_id, + const uint32_t module_flags, + const uint32_t reserved_flags, + const ep_char8_t *module_il_path, + const ep_char8_t *module_native_path, + const uint8_t *managed_pdb_signature, + const uint32_t managed_pdb_age, + const ep_char8_t *managed_pdb_build_path, + const uint8_t *native_pdb_signature, + const uint32_t native_pdb_age, + const ep_char8_t *native_pdb_build_path, + void *user_data) +{ + FireEtwModuleDCEnd_V2 ( + module_id, + assembly_id, + module_flags, + reserved_flags, + module_il_path, + module_native_path, + clr_instance_get_id (), + managed_pdb_signature, + managed_pdb_age, + managed_pdb_build_path, + native_pdb_signature, + native_pdb_age, + native_pdb_build_path, + NULL, + NULL); + + FireEtwDomainModuleDCEnd_V1 ( + module_id, + assembly_id, + domain_id, + module_flags, + reserved_flags, + module_il_path, + module_native_path, + clr_instance_get_id (), + NULL, + NULL); + + FireEtwAssemblyDCEnd_V1 ( + assembly_id, + domain_id, + binding_id, + assembly_flags, + assembly_name, + clr_instance_get_id (), + NULL, + NULL); + + return true; +} + +static +bool +fire_domain_rundown_events_func ( + const uint64_t domain_id, + const uint32_t domain_flags, + const ep_char8_t *domain_name, + const uint32_t domain_index, + void *user_data) +{ + return FireEtwAppDomainDCEnd_V1 ( + domain_id, + domain_flags, + domain_name, + domain_index, + clr_instance_get_id (), + NULL, + NULL); +} + +static +void +eventpipe_fire_method_events ( + MonoJitInfo *ji, + MonoMethod *method, + EventPipeFireMethodEventsData *events_data) +{ + EP_ASSERT (ji != NULL); + EP_ASSERT (events_data->domain != NULL); + EP_ASSERT (events_data->method_events_func != NULL); + + uint64_t method_id = 0; + uint64_t module_id = 0; + uint64_t method_code_start = (uint64_t)ji->code_start; + uint32_t method_code_size = (uint32_t)ji->code_size; + uint32_t method_token = 0; + uint32_t method_flags = 0; + uint8_t kind = MONO_CLASS_DEF; + char *method_namespace = NULL; + const char *method_name = NULL; + char *method_signature = NULL; + bool verbose = (MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.Level >= (uint8_t)EP_EVENT_LEVEL_VERBOSE); + + //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. + + if (method) { + method_id = (uint64_t)method; + method_token = method->token; + + if (mono_jit_info_get_generic_sharing_context (ji)) + method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD; + + if (method->dynamic) + method_flags |= METHOD_FLAGS_DYNAMIC_METHOD; + + if (!ji->from_aot && !ji->from_llvm) { + method_flags |= METHOD_FLAGS_JITTED_METHOD; + if (method->wrapper_type != MONO_WRAPPER_NONE) + method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD; + } + + if (method->is_generic || method->is_inflated) + method_flags |= METHOD_FLAGS_GENERIC_METHOD; + + if (method->klass) { + module_id = (uint64_t)m_class_get_image (method->klass); + kind = m_class_get_class_kind (method->klass); + if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST) + method_flags |= METHOD_FLAGS_GENERIC_METHOD; + } + + if (verbose) { + 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); + } + + } + + uint16_t offset_entries = 0; + uint32_t *il_offsets = NULL; + uint32_t *native_offsets = NULL; + + MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, events_data->domain) : NULL; + if (debug_info) { + offset_entries = debug_info->num_line_numbers; + if (offset_entries != 0) { + size_t needed_size = (offset_entries * sizeof (uint32_t) * 2); + if (!events_data->buffer || needed_size > events_data->buffer_size) { + g_free (events_data->buffer); + events_data->buffer_size = (size_t)(needed_size * 1.5); + events_data->buffer = g_new (uint8_t, events_data->buffer_size); + } + + if (events_data->buffer) { + il_offsets = (uint32_t*)events_data->buffer; + native_offsets = il_offsets + offset_entries; + + for (int offset_count = 0; offset_count < offset_entries; ++offset_count) { + il_offsets [offset_count] = debug_info->line_numbers [offset_count].il_offset; + native_offsets [offset_count] = debug_info->line_numbers [offset_count].native_offset; + } + } + } + + mono_debug_free_method_jit_info (debug_info); + } + + if (events_data->buffer && !il_offsets && !native_offsets) { + // No IL offset -> Native offset mapping available. Put all code on IL offset 0. + EP_ASSERT (events_data->buffer_size >= sizeof (uint32_t) * 2); + offset_entries = 1; + il_offsets = (uint32_t*)events_data->buffer; + native_offsets = il_offsets + offset_entries; + il_offsets [0] = 0; + native_offsets [0] = (uint32_t)ji->code_size; + } + + events_data->method_events_func ( + method_id, + module_id, + method_code_start, + method_code_size, + method_token, + method_flags, + (ep_char8_t *)method_namespace, + (ep_char8_t *)method_name, + (ep_char8_t *)method_signature, + offset_entries, + il_offsets, + native_offsets, + (ji->from_aot || ji->from_llvm), + verbose, + NULL); + + g_free (method_namespace); + g_free (method_signature); +} + +static +inline +bool +include_method (MonoMethod *method) +{ + if (!method) { + return false; + } else if (!m_method_is_wrapper (method)) { + return true; + } else { + WrapperInfo *wrapper = mono_marshal_get_wrapper_info (method); + return (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_PINVOKE) ? true : false; + } +} + +static +void +eventpipe_fire_method_events_func ( + MonoJitInfo *ji, + void *user_data) +{ + EventPipeFireMethodEventsData *events_data = (EventPipeFireMethodEventsData *)user_data; + EP_ASSERT (events_data != NULL); + + if (ji && !ji->is_trampoline && !ji->async) { + MonoMethod *method = jinfo_get_method (ji); + if (include_method (method)) + eventpipe_fire_method_events (ji, method, events_data); + } +} + +static +void +eventpipe_fire_assembly_events ( + MonoDomain *domain, + MonoAssembly *assembly, + ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func) +{ + EP_ASSERT (domain != NULL); + EP_ASSERT (assembly != NULL); + EP_ASSERT (assembly_events_func != NULL); + + uint64_t domain_id = (uint64_t)domain; + uint64_t module_id = (uint64_t)assembly->image; + uint64_t assembly_id = (uint64_t)assembly; + + // TODO: Extract all module IL/Native paths and pdb metadata when available. + const char *module_il_path = ""; + const char *module_il_pdb_path = ""; + const char *module_native_path = ""; + const char *module_native_pdb_path = ""; + uint8_t signature [EP_GUID_SIZE] = { 0 }; + uint32_t module_il_pdb_age = 0; + uint32_t module_native_pdb_age = 0; + + uint32_t reserved_flags = 0; + uint64_t binding_id = 0; + + // Native methods are part of JIT table and already emitted. + // TODO: FireEtwMethodDCEndVerbose_V1_or_V2 for all native methods in module as well? + + // Netcore has a 1:1 between assemblies and modules, so its always a manifest module. + uint32_t module_flags = MODULE_FLAGS_MANIFEST_MODULE; + if (assembly->image) { + if (assembly->image->dynamic) + module_flags |= MODULE_FLAGS_DYNAMIC_MODULE; + if (assembly->image->aot_module) + module_flags |= MODULE_FLAGS_NATIVE_MODULE; + + module_il_path = assembly->image->filename ? assembly->image->filename : ""; + } + + uint32_t assembly_flags = 0; + if (assembly->dynamic) + assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; + + if (assembly->image && assembly->image->aot_module) { + assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; + } + + char *assembly_name = mono_stringify_assembly_name (&assembly->aname); + + assembly_events_func ( + domain_id, + assembly_id, + assembly_flags, + binding_id, + (const ep_char8_t*)assembly_name, + module_id, + module_flags, + reserved_flags, + (const ep_char8_t *)module_il_path, + (const ep_char8_t *)module_native_path, + signature, + module_il_pdb_age, + (const ep_char8_t *)module_il_pdb_path, + signature, + module_native_pdb_age, + (const ep_char8_t *)module_native_pdb_path, + NULL); + + g_free (assembly_name); +} + +static +gboolean +eventpipe_execute_rundown ( + ep_rt_mono_fire_domain_rundown_events_func domain_events_func, + ep_rt_mono_fire_assembly_rundown_events_func assembly_events_func, + ep_rt_mono_fire_method_rundown_events_func method_events_func) +{ + EP_ASSERT (domain_events_func != NULL); + EP_ASSERT (assembly_events_func != NULL); + EP_ASSERT (method_events_func != NULL); + + // Under netcore we only have root domain. + MonoDomain *root_domain = mono_get_root_domain (); + if (root_domain) { + uint64_t domain_id = (uint64_t)root_domain; + + // Emit all functions in use (JIT, AOT and Interpreter). + EventPipeFireMethodEventsData events_data; + events_data.domain = root_domain; + events_data.buffer_size = 1024 * sizeof(uint32_t); + events_data.buffer = g_new (uint8_t, events_data.buffer_size); + events_data.method_events_func = method_events_func; + + // All called JIT/AOT methods should be included in jit info table. + mono_jit_info_table_foreach_internal (eventpipe_fire_method_events_func, &events_data); + + // All called interpreted methods should be included in interpreter jit info table. + if (mono_get_runtime_callbacks ()->is_interpreter_enabled()) + mono_get_runtime_callbacks ()->interp_jit_info_foreach (eventpipe_fire_method_events_func, &events_data); + + // Phantom methods injected in callstacks representing runtime functions. + if (_ep_rt_mono_runtime_helper_compile_method_jitinfo && _ep_rt_mono_runtime_helper_compile_method) + eventpipe_fire_method_events (_ep_rt_mono_runtime_helper_compile_method_jitinfo, _ep_rt_mono_runtime_helper_compile_method, &events_data); + if (_ep_rt_mono_monitor_enter_method_jitinfo && _ep_rt_mono_monitor_enter_method) + eventpipe_fire_method_events (_ep_rt_mono_monitor_enter_method_jitinfo, _ep_rt_mono_monitor_enter_method, &events_data); + if (_ep_rt_mono_monitor_enter_v4_method_jitinfo && _ep_rt_mono_monitor_enter_v4_method) + eventpipe_fire_method_events (_ep_rt_mono_monitor_enter_v4_method_jitinfo, _ep_rt_mono_monitor_enter_v4_method, &events_data); + + g_free (events_data.buffer); + + // Iterate all assemblies in domain. + GPtrArray *assemblies = mono_alc_get_all_loaded_assemblies (); + if (assemblies) { + for (int i = 0; i < assemblies->len; ++i) { + MonoAssembly *assembly = (MonoAssembly *)g_ptr_array_index (assemblies, i); + if (assembly) + eventpipe_fire_assembly_events (root_domain, assembly, assembly_events_func); + } + g_ptr_array_free (assemblies, TRUE); + } + + uint32_t domain_flags = DOMAIN_FLAGS_DEFAULT_DOMAIN | DOMAIN_FLAGS_EXECUTABLE_DOMAIN; + const char *domain_name = root_domain->friendly_name ? root_domain->friendly_name : ""; + uint32_t domain_index = 1; + + domain_events_func ( + domain_id, + domain_flags, + (const ep_char8_t *)domain_name, + domain_index, + NULL); + } + + return TRUE; +} + +inline +static +bool +in_safe_point_frame (EventPipeStackContents *stack_content, WrapperInfo *wrapper) +{ + EP_ASSERT (stack_content != NULL); + + // If top of stack is a managed->native icall wrapper for one of the below subtypes, we are at a safe point frame. + if (wrapper && ep_stack_contents_get_length (stack_content) == 0 && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER && + (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_state_poll || + wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_enter_gc_safe_region_unbalanced || + wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_exit_gc_safe_region_unbalanced || + wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_enter_gc_unsafe_region_unbalanced || + wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_threads_exit_gc_unsafe_region_unbalanced)) + return true; + + return false; +} + +inline +static +bool +in_runtime_invoke_frame (EventPipeStackContents *stack_content, WrapperInfo *wrapper) +{ + EP_ASSERT (stack_content != NULL); + + // If top of stack is a managed->native runtime invoke wrapper, we are at a managed frame. + if (wrapper && ep_stack_contents_get_length (stack_content) == 0 && + (wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_NORMAL || + wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DIRECT || + wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_DYNAMIC || + wrapper->subtype == WRAPPER_SUBTYPE_RUNTIME_INVOKE_VIRTUAL)) + return true; + + return false; +} + +inline +static +bool +in_monitor_enter_frame (WrapperInfo *wrapper) +{ + if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER && + (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_fast || + wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_internal)) + return true; + + return false; +} + +inline +static +bool +in_monitor_enter_v4_frame (WrapperInfo *wrapper) +{ + if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_ICALL_WRAPPER && + (wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_v4_fast || + wrapper->d.icall.jit_icall_id == MONO_JIT_ICALL_mono_monitor_enter_v4_internal)) + return true; + + return false; +} + +static gboolean eventpipe_walk_managed_stack_for_thread ( MonoStackFrameInfo *frame, MonoContext *ctx, EventPipeStackWalkData *stack_walk_data) { - EP_ASSERT (frame != NULL); - EP_ASSERT (stack_walk_data != NULL); + EP_ASSERT (frame != NULL); + EP_ASSERT (stack_walk_data != NULL); + + switch (frame->type) { + case FRAME_TYPE_DEBUGGER_INVOKE: + case FRAME_TYPE_MANAGED_TO_NATIVE: + case FRAME_TYPE_TRAMPOLINE: + case FRAME_TYPE_INTERP_TO_MANAGED: + case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX: + case FRAME_TYPE_INTERP_ENTRY: + stack_walk_data->top_frame = false; + return FALSE; + case FRAME_TYPE_JIT_ENTRY: + // Frame in JIT compiler at top of callstack, add phantom frame representing call into JIT compiler. + // Makes it possible to detect stacks waiting on JIT compiler. + if (_ep_rt_mono_runtime_helper_compile_method && stack_walk_data->top_frame) + ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_ep_rt_mono_runtime_helper_compile_method), _ep_rt_mono_runtime_helper_compile_method); + stack_walk_data->top_frame = false; + return FALSE; + case FRAME_TYPE_MANAGED: + case FRAME_TYPE_INTERP: + if (frame->ji) { + stack_walk_data->async_frame |= frame->ji->async; + MonoMethod *method = frame->ji->async ? NULL : frame->actual_method; + if (method && m_method_is_wrapper (method)) { + WrapperInfo *wrapper = mono_marshal_get_wrapper_info (method); + if (in_safe_point_frame (stack_walk_data->stack_contents, wrapper)) { + stack_walk_data->safe_point_frame = true; + }else if (in_runtime_invoke_frame (stack_walk_data->stack_contents, wrapper)) { + stack_walk_data->runtime_invoke_frame = true; + } else if (_ep_rt_mono_monitor_enter_method && in_monitor_enter_frame (wrapper)) { + ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_ep_rt_mono_monitor_enter_method), _ep_rt_mono_monitor_enter_method); + } else if (_ep_rt_mono_monitor_enter_v4_method && in_monitor_enter_v4_frame (wrapper)) { + ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_ep_rt_mono_monitor_enter_v4_method), _ep_rt_mono_monitor_enter_v4_method); + } else if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_PINVOKE) { + ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start + frame->native_offset), method); + } + } else if (method && !m_method_is_wrapper (method)) { + ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start + frame->native_offset), method); + } else if (!method && frame->ji->async && !frame->ji->is_trampoline) { + ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start), method); + } + } + stack_walk_data->top_frame = false; + return ep_stack_contents_get_length (stack_walk_data->stack_contents) >= EP_MAX_STACK_DEPTH; + default: + EP_UNREACHABLE ("eventpipe_walk_managed_stack_for_thread"); + return FALSE; + } +} + +static +gboolean +eventpipe_walk_managed_stack_for_thread_func ( + MonoStackFrameInfo *frame, + MonoContext *ctx, + void *data) +{ + return eventpipe_walk_managed_stack_for_thread (frame, ctx, (EventPipeStackWalkData *)data); +} + +static +gboolean +eventpipe_sample_profiler_walk_managed_stack_for_thread_func ( + MonoStackFrameInfo *frame, + MonoContext *ctx, + void *data) +{ + EP_ASSERT (frame != NULL); + EP_ASSERT (data != NULL); + + EventPipeSampleProfileStackWalkData *sample_data = (EventPipeSampleProfileStackWalkData *)data; + + if (sample_data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR) { + switch (frame->type) { + case FRAME_TYPE_MANAGED: + sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; + break; + case FRAME_TYPE_MANAGED_TO_NATIVE: + case FRAME_TYPE_TRAMPOLINE: + sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL; + break; + case FRAME_TYPE_JIT_ENTRY: + sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL; + break; + case FRAME_TYPE_INTERP: + sample_data->payload_data = frame->managed ? EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED : EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL; + break; + case FRAME_TYPE_INTERP_TO_MANAGED: + case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX: + break; + default: + sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; + } + } + + return eventpipe_walk_managed_stack_for_thread (frame, ctx, &sample_data->stack_walk_data); +} + +static +void +profiler_eventpipe_thread_exited ( + MonoProfiler *prof, + uintptr_t tid) +{ + void ep_rt_mono_thread_exited (void); + ep_rt_mono_thread_exited (); +} + +static bool +parse_mono_profiler_options (const ep_char8_t *option) +{ + do { + if (!*option) + return false; + + if (!strncmp (option, "alloc", 5)) { + mono_profiler_enable_allocations (); + option += 5; + } else if (!strncmp (option, "exception", 9)) { + mono_profiler_enable_clauses (); + option += 9; + /*} else if (!strncmp (option, "sample", 6)) { + mono_profiler_enable_sampling (_ep_rt_dotnet_mono_profiler_provider); + option += 6;*/ + } else { + return false; + } + + if (*option == ',') + option++; + } while (*option); + + return true; +} + +void +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); + + char *diag_env = g_getenv("MONO_DIAGNOSTICS"); + if (diag_env) { + int diag_argc = 1; + char **diag_argv = g_new (char *, 1); + if (diag_argv) { + diag_argv [0] = NULL; + if (!mono_parse_options_from (diag_env, &diag_argc, &diag_argv)) { + for (int i = 0; i < diag_argc; ++i) { + if (diag_argv [i]) { + if (strncmp (diag_argv [i], "--diagnostic-mono-profiler=", 27) == 0) { + if (!parse_mono_profiler_options (diag_argv [i] + 27)) + mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing MONO_DIAGNOSTICS environment variable option: %s", diag_argv [i]); + } else if (strncmp (diag_argv [i], "--diagnostic-mono-profiler-callspec=", 36) == 0) { + char *errstr = NULL; + if (!mono_callspec_parse (diag_argv [i] + 36, &_ep_rt_dotnet_mono_profiler_provider_callspec, &errstr)) { + mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing '%s': %s", diag_argv [i], errstr); + g_free (errstr); + mono_callspec_cleanup (&_ep_rt_dotnet_mono_profiler_provider_callspec); + } else { + mono_profiler_set_call_instrumentation_filter_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_instrumentation); + } + } else if (strncmp (diag_argv [i], "--diagnostic-ports=", 19) == 0) { + char *diag_ports_env = g_getenv("DOTNET_DiagnosticPorts"); + if (diag_ports_env) + mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_DIAGNOSTICS, "DOTNET_DiagnosticPorts environment variable already set, ignoring --diagnostic-ports used in MONO_DIAGNOSTICS environment variable"); + else + g_setenv ("DOTNET_DiagnosticPorts", diag_argv [i] + 19, TRUE); + g_free (diag_ports_env); + + } else { + mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing MONO_DIAGNOSTICS environment variable, unknown option: %s", diag_argv [i]); + } + + g_free (diag_argv [i]); + diag_argv [i] = NULL; + } + } + + g_free (diag_argv); + } else { + mono_trace (G_LOG_LEVEL_ERROR, MONO_TRACE_DIAGNOSTICS, "Failed parsing MONO_DIAGNOSTICS environment variable"); + } + } + } + g_free (diag_env); +} + +void +ep_rt_mono_init (void) +{ + mono_native_tls_alloc (&_ep_rt_mono_thread_holder_tls_id, NULL); + + mono_100ns_ticks (); + mono_rand_open (); + _ep_rt_mono_rand_provider = mono_rand_init (NULL, 0); + + _ep_rt_mono_initialized = TRUE; + + 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); + + 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); + if (method_signature) { + method_signature->params[0] = m_class_get_byval_arg (mono_get_object_class()); + method_signature->ret = m_class_get_byval_arg (mono_get_void_class()); + + ERROR_DECL (error); + MonoClass *runtime_helpers = mono_class_from_name_checked (mono_get_corlib (), "System.Runtime.CompilerServices", "RuntimeHelpers", error); + if (is_ok (error) && runtime_helpers) { + MonoMethodBuilder *method_builder = mono_mb_new (runtime_helpers, "CompileMethod", MONO_WRAPPER_RUNTIME_INVOKE); + if (method_builder) { + _ep_rt_mono_runtime_helper_compile_method = mono_mb_create_method (method_builder, method_signature, 1); + mono_mb_free (method_builder); + } + } + mono_error_cleanup (error); + mono_metadata_free_method_signature (method_signature); + + if (_ep_rt_mono_runtime_helper_compile_method) { + _ep_rt_mono_runtime_helper_compile_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1); + if (_ep_rt_mono_runtime_helper_compile_method) { + _ep_rt_mono_runtime_helper_compile_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_ep_rt_mono_runtime_helper_compile_method); + _ep_rt_mono_runtime_helper_compile_method_jitinfo->code_size = 20; + _ep_rt_mono_runtime_helper_compile_method_jitinfo->d.method = _ep_rt_mono_runtime_helper_compile_method; + } + } + } + + { + ERROR_DECL (error); + MonoMethodDesc *desc = NULL; + MonoClass *monitor = mono_class_from_name_checked (mono_get_corlib (), "System.Threading", "Monitor", error); + if (is_ok (error) && monitor) { + desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE); + if (desc) { + _ep_rt_mono_monitor_enter_v4_method = mono_method_desc_search_in_class (desc, monitor); + mono_method_desc_free (desc); + + if (_ep_rt_mono_monitor_enter_v4_method) { + _ep_rt_mono_monitor_enter_v4_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1); + if (_ep_rt_mono_monitor_enter_v4_method_jitinfo) { + _ep_rt_mono_monitor_enter_v4_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_ep_rt_mono_monitor_enter_v4_method); + _ep_rt_mono_monitor_enter_v4_method_jitinfo->code_size = 20; + _ep_rt_mono_monitor_enter_v4_method_jitinfo->d.method = _ep_rt_mono_monitor_enter_v4_method; + } + } + } + + desc = mono_method_desc_new ("Monitor:Enter(object)", FALSE); + if (desc) { + _ep_rt_mono_monitor_enter_method = mono_method_desc_search_in_class (desc, monitor); + mono_method_desc_free (desc); + + if (_ep_rt_mono_monitor_enter_method ) { + _ep_rt_mono_monitor_enter_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1); + if (_ep_rt_mono_monitor_enter_method_jitinfo) { + _ep_rt_mono_monitor_enter_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_ep_rt_mono_monitor_enter_method); + _ep_rt_mono_monitor_enter_method_jitinfo->code_size = 20; + _ep_rt_mono_monitor_enter_method_jitinfo->d.method = _ep_rt_mono_monitor_enter_method; + } + } + } + } + mono_error_cleanup (error); + } +} + +void +ep_rt_mono_init_finish (void) +{ + if (mono_runtime_get_no_exec ()) + return; + + // Managed init of diagnostics classes, like registration of RuntimeEventSource (if available). + ERROR_DECL (error); + + MonoClass *runtime_event_source = mono_class_from_name_checked (mono_get_corlib (), "System.Diagnostics.Tracing", "RuntimeEventSource", error); + if (is_ok (error) && runtime_event_source) { + MonoMethod *init = mono_class_get_method_from_name_checked (runtime_event_source, "Initialize", -1, 0, error); + if (is_ok (error) && init) { + mono_runtime_try_invoke_handle (init, NULL_HANDLE, NULL, error); + } + } + + mono_error_cleanup (error); +} + +void +ep_rt_mono_fini (void) +{ + if (_ep_rt_mono_sampled_thread_callstacks) + g_array_free (_ep_rt_mono_sampled_thread_callstacks, TRUE); + + if (_ep_rt_mono_initialized) + mono_rand_close (_ep_rt_mono_rand_provider); + + g_free (_ep_rt_mono_runtime_helper_compile_method_jitinfo); + _ep_rt_mono_runtime_helper_compile_method_jitinfo = NULL; + + mono_free_method (_ep_rt_mono_runtime_helper_compile_method); + _ep_rt_mono_runtime_helper_compile_method = NULL; + + g_free (_ep_rt_mono_monitor_enter_method_jitinfo); + _ep_rt_mono_monitor_enter_method_jitinfo = NULL; + _ep_rt_mono_monitor_enter_method = NULL; + + g_free (_ep_rt_mono_monitor_enter_v4_method_jitinfo); + _ep_rt_mono_monitor_enter_v4_method_jitinfo = NULL; + _ep_rt_mono_monitor_enter_v4_method = NULL; + + if (_ep_rt_dotnet_mono_profiler_provider_callspec.enabled) { + mono_profiler_set_call_instrumentation_filter_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_callspec_cleanup (&_ep_rt_dotnet_mono_profiler_provider_callspec); + } + + _ep_rt_mono_sampled_thread_callstacks = NULL; + _ep_rt_mono_rand_provider = NULL; + _ep_rt_mono_initialized = FALSE; +} + +bool +ep_rt_mono_rand_try_get_bytes ( + uint8_t *buffer, + size_t buffer_size) +{ + EP_ASSERT (_ep_rt_mono_rand_provider != NULL); + + ERROR_DECL (error); + return mono_rand_try_get_bytes (&_ep_rt_mono_rand_provider, (guchar *)buffer, (gssize)buffer_size, error); +} + +EventPipeThread * +ep_rt_mono_thread_get_or_create (void) +{ + EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id); + if (!thread_holder) { + thread_holder = thread_holder_alloc_func (); + mono_native_tls_set_value (_ep_rt_mono_thread_holder_tls_id, thread_holder); + } + return ep_thread_holder_get_thread (thread_holder); +} + +void * +ep_rt_mono_thread_attach (bool background_thread) +{ + MonoThread *thread = NULL; + + // NOTE, under netcore, only root domain exists. + if (!mono_thread_current ()) { + thread = mono_thread_internal_attach (mono_get_root_domain ()); + if (background_thread && thread) { + mono_thread_set_state (thread, ThreadState_Background); + mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_SAMPLE); + } + } + + return thread; +} + +void * +ep_rt_mono_thread_attach_2 (bool background_thread, EventPipeThreadType thread_type) +{ + void *result = ep_rt_mono_thread_attach (background_thread); + if (result && thread_type == EP_THREAD_TYPE_SAMPLING) { + // Increase sampling thread priority, accepting failures. +#ifdef HOST_WIN32 + SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST); +#elif _POSIX_PRIORITY_SCHEDULING + int policy; + int priority; + struct sched_param param; + int schedparam_result = pthread_getschedparam (pthread_self (), &policy, ¶m); + if (schedparam_result == 0) { + // Attempt to switch the thread to real time scheduling. This will not + // necessarily work on all OSs; for example, most Linux systems will give + // us EPERM here unless configured to allow this. + priority = param.sched_priority; + param.sched_priority = sched_get_priority_max (SCHED_RR); + if (param.sched_priority != -1) { + schedparam_result = pthread_setschedparam (pthread_self (), SCHED_RR, ¶m); + if (schedparam_result != 0) { + // Fallback, attempt to increase to max priority using current policy. + param.sched_priority = sched_get_priority_max (policy); + if (param.sched_priority != -1 && param.sched_priority != priority) + pthread_setschedparam (pthread_self (), policy, ¶m); + } + } + } +#endif + } + + return result; +} + +void +ep_rt_mono_thread_detach (void) +{ + MonoThread *current_thread = mono_thread_current (); + if (current_thread) + mono_thread_internal_detach (current_thread); +} + +void +ep_rt_mono_thread_exited (void) +{ + if (_ep_rt_mono_initialized) { + EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id); + if (thread_holder) + thread_holder_free_func (thread_holder); + mono_native_tls_set_value (_ep_rt_mono_thread_holder_tls_id, NULL); + } +} + +#ifdef HOST_WIN32 +int64_t +ep_rt_mono_perf_counter_query (void) +{ + LARGE_INTEGER value; + if (QueryPerformanceCounter (&value)) + return (int64_t)value.QuadPart; + else + return 0; +} + +int64_t +ep_rt_mono_perf_frequency_query (void) +{ + LARGE_INTEGER value; + if (QueryPerformanceFrequency (&value)) + return (int64_t)value.QuadPart; + else + return 0; +} + +void +ep_rt_mono_system_time_get (EventPipeSystemTime *system_time) +{ + SYSTEMTIME value; + GetSystemTime (&value); + + EP_ASSERT (system_time != NULL); + ep_system_time_set ( + system_time, + value.wYear, + value.wMonth, + value.wDayOfWeek, + value.wDay, + value.wHour, + value.wMinute, + value.wSecond, + value.wMilliseconds); +} + +int64_t +ep_rt_mono_system_timestamp_get (void) +{ + FILETIME value; + GetSystemTimeAsFileTime (&value); + return (int64_t)((((uint64_t)value.dwHighDateTime) << 32) | (uint64_t)value.dwLowDateTime); +} +#else +#include +#include +#include +#include + +#if HAVE_SYS_TIME_H +#include +#endif // HAVE_SYS_TIME_H + +#if HAVE_MACH_ABSOLUTE_TIME +#include +static mono_lazy_init_t _ep_rt_mono_time_base_info_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; +static mach_timebase_info_data_t _ep_rt_mono_time_base_info = {0}; +#endif + +#ifdef HAVE_LOCALTIME_R +#define HAVE_GMTIME_R 1 +#endif + +static const int64_t SECS_BETWEEN_1601_AND_1970_EPOCHS = 11644473600LL; +static const int64_t SECS_TO_100NS = 10000000; +static const int64_t SECS_TO_NS = 1000000000; +static const int64_t MSECS_TO_MIS = 1000; + +/* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */ +#if defined (HAVE_CLOCK_MONOTONIC) && (defined(TARGET_IOS) || defined(TARGET_OSX) || defined(TARGET_WATCHOS) || defined(TARGET_TVOS)) +#undef HAVE_CLOCK_MONOTONIC +#endif + +#ifndef HAVE_CLOCK_MONOTONIC +static const int64_t MISECS_TO_NS = 1000; +#endif + +static +void +time_base_info_lazy_init (void); + +static +int64_t +system_time_to_int64 ( + time_t sec, + long nsec); + +#if HAVE_MACH_ABSOLUTE_TIME +static +void +time_base_info_lazy_init (void) +{ + kern_return_t result = mach_timebase_info (&_ep_rt_mono_time_base_info); + if (result != KERN_SUCCESS) + memset (&_ep_rt_mono_time_base_info, 0, sizeof (_ep_rt_mono_time_base_info)); +} +#endif + +int64_t +ep_rt_mono_perf_counter_query (void) +{ +#if HAVE_MACH_ABSOLUTE_TIME + return (int64_t)mach_absolute_time (); +#elif HAVE_CLOCK_MONOTONIC + struct timespec ts; + int result = clock_gettime (CLOCK_MONOTONIC, &ts); + if (result == 0) + return ((int64_t)(ts.tv_sec) * (int64_t)(SECS_TO_NS)) + (int64_t)(ts.tv_nsec); +#else + #error "ep_rt_mono_perf_counter_get requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported." +#endif + return 0; +} + +int64_t +ep_rt_mono_perf_frequency_query (void) +{ +#if HAVE_MACH_ABSOLUTE_TIME + // (numer / denom) gives you the nanoseconds per tick, so the below code + // computes the number of ticks per second. We explicitly do the multiplication + // first in order to help minimize the error that is produced by integer division. + mono_lazy_initialize (&_ep_rt_mono_time_base_info_init, time_base_info_lazy_init); + if (_ep_rt_mono_time_base_info.denom == 0 || _ep_rt_mono_time_base_info.numer == 0) + return 0; + return ((int64_t)(SECS_TO_NS) * (int64_t)(_ep_rt_mono_time_base_info.denom)) / (int64_t)(_ep_rt_mono_time_base_info.numer); +#elif HAVE_CLOCK_MONOTONIC + // clock_gettime () returns a result in terms of nanoseconds rather than a count. This + // means that we need to either always scale the result by the actual resolution (to + // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer + // the latter since it allows the highest throughput and should minimize error propagated + // to the user. + return (int64_t)(SECS_TO_NS); +#else + #error "ep_rt_mono_perf_frequency_query requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported." +#endif + return 0; +} + +void +ep_rt_mono_system_time_get (EventPipeSystemTime *system_time) +{ + time_t tt; +#if HAVE_GMTIME_R + struct tm ut; +#endif /* HAVE_GMTIME_R */ + struct tm *ut_ptr; + struct timeval time_val; + int timeofday_retval; + + EP_ASSERT (system_time != NULL); + + tt = time (NULL); + + /* We can't get millisecond resolution from time (), so we get it from gettimeofday () */ + timeofday_retval = gettimeofday (&time_val, NULL); + +#if HAVE_GMTIME_R + ut_ptr = &ut; + if (gmtime_r (&tt, ut_ptr) == NULL) +#else /* HAVE_GMTIME_R */ + if ((ut_ptr = gmtime (&tt)) == NULL) +#endif /* HAVE_GMTIME_R */ + EP_UNREACHABLE (); + + uint16_t milliseconds = 0; + if (timeofday_retval != -1) { + int old_seconds; + int new_seconds; + + milliseconds = time_val.tv_usec / MSECS_TO_MIS; + + old_seconds = ut_ptr->tm_sec; + new_seconds = time_val.tv_sec % 60; + + /* just in case we reached the next second in the interval between time () and gettimeofday () */ + if (old_seconds != new_seconds) + milliseconds = 999; + } + + ep_system_time_set ( + system_time, + 1900 + ut_ptr->tm_year, + ut_ptr->tm_mon + 1, + ut_ptr->tm_wday, + ut_ptr->tm_mday, + ut_ptr->tm_hour, + ut_ptr->tm_min, + ut_ptr->tm_sec, + milliseconds); +} + +static +inline +int64_t +system_time_to_int64 ( + time_t sec, + long nsec) +{ + return ((int64_t)sec + SECS_BETWEEN_1601_AND_1970_EPOCHS) * SECS_TO_100NS + (nsec / 100); +} + +int64_t +ep_rt_mono_system_timestamp_get (void) +{ +#if HAVE_CLOCK_MONOTONIC + struct timespec time; + if (clock_gettime (CLOCK_REALTIME, &time) == 0) + return system_time_to_int64 (time.tv_sec, time.tv_nsec); +#else + struct timeval time; + if (gettimeofday (&time, NULL) == 0) + return system_time_to_int64 (time.tv_sec, time.tv_usec * MISECS_TO_NS); +#endif + else + return system_time_to_int64 (0, 0); +} +#endif + +#ifndef HOST_WIN32 +#if defined(__APPLE__) +#if defined (TARGET_OSX) +G_BEGIN_DECLS +gchar ***_NSGetEnviron(void); +G_END_DECLS +#define environ (*_NSGetEnviron()) +#else +static char *_ep_rt_mono_environ[1] = { NULL }; +#define environ _ep_rt_mono_environ +#endif /* defined (TARGET_OSX) */ +#else +G_BEGIN_DECLS +extern char **environ; +G_END_DECLS +#endif /* defined (__APPLE__) */ +#endif /* !defined (HOST_WIN32) */ + +void +ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array) +{ + EP_ASSERT (env_array != NULL); +#ifdef HOST_WIN32 + LPWSTR envs = GetEnvironmentStringsW (); + if (envs) { + LPWSTR next = envs; + while (*next) { + ep_rt_env_array_utf16_append (env_array, ep_rt_utf16_string_dup (next)); + next += ep_rt_utf16_string_len (next) + 1; + } + FreeEnvironmentStringsW (envs); + } +#else + gchar **next = NULL; + for (next = environ; *next != NULL; ++next) + ep_rt_env_array_utf16_append (env_array, ep_rt_utf8_to_utf16_string (*next, -1)); +#endif +} + +void +ep_rt_mono_init_providers_and_events (void) +{ + extern void InitProvidersAndEvents (void); + InitProvidersAndEvents (); +} + +void +ep_rt_mono_provider_config_init (EventPipeProviderConfiguration *provider_config) +{ + if (!ep_rt_utf8_string_compare (ep_config_get_rundown_provider_name_utf8 (), ep_provider_config_get_provider_name (provider_config))) { + MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.Level = ep_provider_config_get_logging_level (provider_config); + MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = ep_provider_config_get_keywords (provider_config); + MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.IsEnabled = true; + } +} + +bool +ep_rt_mono_providers_validate_all_disabled (void) +{ + return (!MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.IsEnabled && + !MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.IsEnabled && + !MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.IsEnabled && + !MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.IsEnabled); +} + +void +ep_rt_mono_fini_providers_and_events (void) +{ + // dotnet/runtime: issue 12775: EventPipe shutdown race conditions + // Deallocating providers/events here might cause AV if a WriteEvent + // was to occur. Thus, we are not doing this cleanup. +} + +bool +ep_rt_mono_walk_managed_stack_for_thread ( + ep_rt_thread_handle_t thread, + EventPipeStackContents *stack_contents) +{ + EP_ASSERT (thread != NULL && stack_contents != NULL); + + EventPipeStackWalkData stack_walk_data; + stack_walk_data.stack_contents = stack_contents; + stack_walk_data.top_frame = true; + stack_walk_data.async_frame = false; + stack_walk_data.safe_point_frame = false; + stack_walk_data.runtime_invoke_frame = false; + + if (thread == ep_rt_thread_get_handle () && mono_get_eh_callbacks ()->mono_walk_stack_with_ctx) + mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (eventpipe_walk_managed_stack_for_thread_func, NULL, MONO_UNWIND_SIGNAL_SAFE, &stack_walk_data); + else if (mono_get_eh_callbacks ()->mono_walk_stack_with_state) + mono_get_eh_callbacks ()->mono_walk_stack_with_state (eventpipe_walk_managed_stack_for_thread_func, mono_thread_info_get_suspend_state (thread), MONO_UNWIND_SIGNAL_SAFE, &stack_walk_data); + + return true; +} + +bool +ep_rt_mono_method_get_simple_assembly_name ( + ep_rt_method_desc_t *method, + ep_char8_t *name, + size_t name_len) +{ + EP_ASSERT (method != NULL); + EP_ASSERT (name != NULL); + + MonoClass *method_class = mono_method_get_class (method); + MonoImage *method_image = method_class ? mono_class_get_image (method_class) : NULL; + const ep_char8_t *assembly_name = method_image ? mono_image_get_name (method_image) : NULL; + + if (!assembly_name) + return false; + + g_strlcpy (name, assembly_name, name_len); + return true; +} + +bool +ep_rt_mono_method_get_full_name ( + ep_rt_method_desc_t *method, + ep_char8_t *name, + size_t name_len) +{ + EP_ASSERT (method != NULL); + EP_ASSERT (name != NULL); + + char *full_method_name = mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL); + if (!full_method_name) + return false; + + g_strlcpy (name, full_method_name, name_len); + + g_free (full_method_name); + return true; +} + +bool +ep_rt_mono_sample_profiler_write_sampling_event_for_threads ( + ep_rt_thread_handle_t sampling_thread, + EventPipeEvent *sampling_event) +{ + // Follows CoreClr implementation of sample profiler. Generic invasive/expensive way to do CPU sample profiling relying on STW and stackwalks. + // TODO: Investigate alternatives on platforms supporting Signals/SuspendThread (see Mono profiler) or CPU PMU's (see ETW/perf_event_open). + + // Sample profiler only runs on one thread, no need to synchorinize. + if (!_ep_rt_mono_sampled_thread_callstacks) + _ep_rt_mono_sampled_thread_callstacks = g_array_sized_new (FALSE, FALSE, sizeof (EventPipeSampleProfileStackWalkData), _ep_rt_mono_max_sampled_thread_count); + + // Make sure there is room based on previous max number of sampled threads. + // NOTE, there is a chance there are more threads than max, if that's the case we will + // miss those threads in this sample, but will be included in next when max has been adjusted. + g_array_set_size (_ep_rt_mono_sampled_thread_callstacks, _ep_rt_mono_max_sampled_thread_count); + + uint32_t filtered_thread_count = 0; + uint32_t sampled_thread_count = 0; + + mono_stop_world (MONO_THREAD_INFO_FLAGS_NO_GC); + + gboolean async_context = mono_thread_info_is_async_context (); + mono_thread_info_set_is_async_context (TRUE); + + // Record all info needed in sample events while runtime is suspended, must be async safe. + FOREACH_THREAD_SAFE_EXCLUDE (thread_info, MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE) { + if (!mono_thread_info_is_running (thread_info)) { + MonoThreadUnwindState *thread_state = mono_thread_info_get_suspend_state (thread_info); + if (thread_state->valid) { + if (sampled_thread_count < _ep_rt_mono_max_sampled_thread_count) { + EventPipeSampleProfileStackWalkData *data = &g_array_index (_ep_rt_mono_sampled_thread_callstacks, EventPipeSampleProfileStackWalkData, sampled_thread_count); + data->thread_id = ep_rt_thread_id_t_to_uint64_t (mono_thread_info_get_tid (thread_info)); + data->thread_ip = (uintptr_t)MONO_CONTEXT_GET_IP (&thread_state->ctx); + data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR; + data->stack_walk_data.stack_contents = &data->stack_contents; + data->stack_walk_data.top_frame = true; + data->stack_walk_data.async_frame = false; + data->stack_walk_data.safe_point_frame = false; + data->stack_walk_data.runtime_invoke_frame = false; + ep_stack_contents_reset (&data->stack_contents); + mono_get_eh_callbacks ()->mono_walk_stack_with_state (eventpipe_sample_profiler_walk_managed_stack_for_thread_func, thread_state, MONO_UNWIND_SIGNAL_SAFE, data); + if (data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL && (data->stack_walk_data.safe_point_frame || data->stack_walk_data.runtime_invoke_frame)) { + // If classified as external code (managed->native frame on top of stack), but have a safe point or runtime invoke frame + // as second, re-classify current callstack to be executing managed code. + data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; + } + + sampled_thread_count++; + } + } + } + filtered_thread_count++; + } FOREACH_THREAD_SAFE_END + + mono_thread_info_set_is_async_context (async_context); + mono_restart_world (MONO_THREAD_INFO_FLAGS_NO_GC); + + // Fire sample event for threads. Must be done after runtime is resumed since it's not async safe. + // Since we can't keep thread info around after runtime as been suspended, use an empty + // adapter instance and only set recorded tid as parameter inside adapter. + THREAD_INFO_TYPE adapter = { { 0 } }; + for (uint32_t i = 0; i < sampled_thread_count; ++i) { + EventPipeSampleProfileStackWalkData *data = &g_array_index (_ep_rt_mono_sampled_thread_callstacks, EventPipeSampleProfileStackWalkData, i); + if (data->payload_data != EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR && ep_stack_contents_get_length(&data->stack_contents) > 0) { + // Check if we have an async frame, if so we will need to make sure all frames are registered in regular jit info table. + // TODO: An async frame can contain wrapper methods (no way to check during stackwalk), we could skip writing profile event + // for this specific stackwalk or we could cleanup stack_frames before writing profile event. + if (data->stack_walk_data.async_frame) { + for (int i = 0; i < data->stack_contents.next_available_frame; ++i) + mono_jit_info_table_find_internal ((gpointer)data->stack_contents.stack_frames [i], TRUE, FALSE); + } + mono_thread_info_set_tid (&adapter, ep_rt_uint64_t_to_thread_id_t (data->thread_id)); + ep_write_sample_profile_event (sampling_thread, sampling_event, &adapter, &data->stack_contents, (uint8_t *)&data->payload_data, sizeof (data->payload_data)); + } + } + + // Current thread count will be our next maximum sampled threads. + _ep_rt_mono_max_sampled_thread_count = filtered_thread_count; + + return true; +} + +void +ep_rt_mono_execute_rundown (ep_rt_execution_checkpoint_array_t *execution_checkpoints) +{ + ep_char8_t runtime_module_path [256]; + const uint8_t object_guid [EP_GUID_SIZE] = { 0 }; + const uint16_t runtime_product_qfe_version = 0; + const uint32_t startup_flags = 0; + const uint8_t startup_mode = 0; + const ep_char8_t *command_line = ""; + + if (!g_module_address ((void *)mono_init, runtime_module_path, sizeof (runtime_module_path), NULL, NULL, 0, NULL)) + runtime_module_path [0] = '\0'; + + FireEtwRuntimeInformationDCStart ( + clr_instance_get_id (), + RUNTIME_SKU_CORECLR, + RuntimeProductMajorVersion, + RuntimeProductMinorVersion, + RuntimeProductPatchVersion, + runtime_product_qfe_version, + RuntimeFileMajorVersion, + RuntimeFileMajorVersion, + RuntimeFileBuildVersion, + RuntimeFileRevisionVersion, + startup_mode, + startup_flags, + command_line, + object_guid, + runtime_module_path, + NULL, + NULL); + + if (execution_checkpoints) { + ep_rt_execution_checkpoint_array_iterator_t execution_checkpoints_iterator = ep_rt_execution_checkpoint_array_iterator_begin (execution_checkpoints); + while (!ep_rt_execution_checkpoint_array_iterator_end (execution_checkpoints, &execution_checkpoints_iterator)) { + EventPipeExecutionCheckpoint *checkpoint = ep_rt_execution_checkpoint_array_iterator_value (&execution_checkpoints_iterator); + FireEtwExecutionCheckpointDCEnd ( + clr_instance_get_id (), + checkpoint->name, + checkpoint->timestamp, + NULL, + NULL); + ep_rt_execution_checkpoint_array_iterator_next (&execution_checkpoints_iterator); + } + } + + FireEtwDCEndInit_V1 ( + clr_instance_get_id (), + NULL, + NULL); + + eventpipe_execute_rundown ( + fire_domain_rundown_events_func, + fire_assembly_rundown_events_func, + fire_method_rundown_events_func); + + FireEtwDCEndComplete_V1 ( + clr_instance_get_id (), + NULL, + NULL); +} + +bool +ep_rt_mono_write_event_ee_startup_start (void) +{ + return FireEtwEEStartupStart_V1 ( + clr_instance_get_id (), + NULL, + NULL); +} + +bool +ep_rt_mono_write_event_jit_start (MonoMethod *method) +{ + if (!EventEnabledMethodJittingStarted_V1 ()) + return true; + + //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. + if (method) { + uint64_t method_id = 0; + uint64_t module_id = 0; + uint32_t code_size = 0; + uint32_t method_token = 0; + char *method_namespace = NULL; + const char *method_name = NULL; + char *method_signature = NULL; + + //TODO: SendMethodDetailsEvent + + method_id = (uint64_t)method; + + if (!method->dynamic) + method_token = method->token; + + if (!mono_method_has_no_body (method)) { + ERROR_DECL (error); + MonoMethodHeader *header = mono_method_get_header_internal (method, error); + if (header) + code_size = header->code_size; + } + + method_name = method->name; + method_signature = mono_signature_full_name (method->signature); + + if (method->klass) { + module_id = (uint64_t)m_class_get_image (method->klass); + method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL); + } + + FireEtwMethodJittingStarted_V1 ( + method_id, + module_id, + method_token, + code_size, + method_namespace, + method_name, + method_signature, + clr_instance_get_id (), + NULL, + NULL); + + g_free (method_namespace); + g_free (method_signature); + } + + return true; +} + +bool +ep_rt_mono_write_event_method_il_to_native_map ( + MonoMethod *method, + MonoJitInfo *ji) +{ + if (!EventEnabledMethodILToNativeMap ()) + return true; + + if (method) { + // Under netcore we only have root domain. + MonoDomain *root_domain = mono_get_root_domain (); + + uint64_t method_id = (uint64_t)method; + uint32_t fixed_buffer [64]; + uint8_t *buffer = NULL; + + uint16_t offset_entries = 0; + uint32_t *il_offsets = NULL; + uint32_t *native_offsets = NULL; + + MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, root_domain) : NULL; + if (debug_info) { + if (offset_entries != 0) { + offset_entries = debug_info->num_line_numbers; + size_t needed_size = (offset_entries * sizeof (uint32_t) * 2); + if (needed_size > sizeof (fixed_buffer)) { + buffer = g_new (uint8_t, needed_size); + il_offsets = (uint32_t*)buffer; + } else { + il_offsets = fixed_buffer; + } + if (il_offsets) { + native_offsets = il_offsets + offset_entries; + for (int offset_count = 0; offset_count < offset_entries; ++offset_count) { + il_offsets [offset_count] = debug_info->line_numbers [offset_count].il_offset; + native_offsets [offset_count] = debug_info->line_numbers [offset_count].native_offset; + } + } + } + + mono_debug_free_method_jit_info (debug_info); + } + + if (!il_offsets && !native_offsets) { + // No IL offset -> Native offset mapping available. Put all code on IL offset 0. + EP_ASSERT (sizeof (fixed_buffer) >= sizeof (uint32_t) * 2); + offset_entries = 1; + il_offsets = fixed_buffer; + native_offsets = il_offsets + offset_entries; + il_offsets [0] = 0; + native_offsets [0] = ji ? (uint32_t)ji->code_size : 0; + } + + FireEtwMethodILToNativeMap ( + method_id, + 0, + 0, + offset_entries, + il_offsets, + native_offsets, + clr_instance_get_id (), + NULL, + NULL); + + g_free (buffer); + } + + return true; +} + +bool +ep_rt_mono_write_event_method_load ( + MonoMethod *method, + MonoJitInfo *ji) +{ + if (!EventEnabledMethodLoad_V1 () && !EventEnabledMethodLoadVerbose_V1()) + return true; + + //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. + if (method) { + uint64_t method_id = 0; + uint64_t module_id = 0; + uint64_t method_code_start = ji ? (uint64_t)ji->code_start : 0; + uint32_t method_code_size = ji ? (uint32_t)ji->code_size : 0; + uint32_t method_token = 0; + uint32_t method_flags = 0; + uint8_t kind = MONO_CLASS_DEF; + char *method_namespace = NULL; + const char *method_name = NULL; + char *method_signature = NULL; + bool verbose = (MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.Level >= (uint8_t)EP_EVENT_LEVEL_VERBOSE); + + method_id = (uint64_t)method; + + if (!method->dynamic) + method_token = method->token; + + if (ji && mono_jit_info_get_generic_sharing_context (ji)) { + method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD; + verbose = true; + } + + if (method->dynamic) { + method_flags |= METHOD_FLAGS_DYNAMIC_METHOD; + verbose = true; + } + + if (ji && !ji->from_aot && !ji->from_llvm) { + method_flags |= METHOD_FLAGS_JITTED_METHOD; + if (method->wrapper_type != MONO_WRAPPER_NONE) + method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD; + } + + if (method->is_generic || method->is_inflated) { + method_flags |= METHOD_FLAGS_GENERIC_METHOD; + verbose = true; + } + + if (method->klass) { + module_id = (uint64_t)m_class_get_image (method->klass); + kind = m_class_get_class_kind (method->klass); + if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST) + method_flags |= METHOD_FLAGS_GENERIC_METHOD; + } + + //TODO: SendMethodDetailsEvent + + if (verbose) { + 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); + + FireEtwMethodLoadVerbose_V1 ( + method_id, + module_id, + method_code_start, + method_code_size, + method_token, + method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION, + method_namespace, + method_name, + method_signature, + clr_instance_get_id (), + NULL, + NULL); + + if (ji && (ji->from_aot || ji->from_llvm)) + FireEtwMethodLoadVerbose_V1 ( + method_id, + module_id, + method_code_start, + method_code_size, + method_token, + method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION, + method_namespace, + method_name, + method_signature, + clr_instance_get_id (), + NULL, + NULL); + } else { + FireEtwMethodLoad_V1 ( + method_id, + module_id, + method_code_start, + method_code_size, + method_token, + method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION, + clr_instance_get_id (), + NULL, + NULL); + + if (ji && (ji->from_aot || ji->from_llvm)) + FireEtwMethodLoad_V1 ( + method_id, + module_id, + method_code_start, + method_code_size, + method_token, + method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION, + clr_instance_get_id (), + NULL, + NULL); + } + + g_free (method_namespace); + g_free (method_signature); + } + + return true; +} + +static +bool +get_module_event_data ( + MonoImage *image, + ModuleEventData *module_data) +{ + if (image && module_data) { + memset (module_data->signature, 0, EP_GUID_SIZE); + + // Under netcore we only have root domain. + MonoDomain *root_domain = mono_get_root_domain (); + + module_data->domain_id = (uint64_t)root_domain; + module_data->module_id = (uint64_t)image; + module_data->assembly_id = (uint64_t)image->assembly; + + // TODO: Extract all module IL/Native paths and pdb metadata when available. + module_data->module_il_path = ""; + module_data->module_il_pdb_path = ""; + module_data->module_native_path = ""; + module_data->module_native_pdb_path = ""; + + module_data->module_il_pdb_age = 0; + module_data->module_native_pdb_age = 0; + + module_data->reserved_flags = 0; + + // Netcore has a 1:1 between assemblies and modules, so its always a manifest module. + module_data->module_flags = MODULE_FLAGS_MANIFEST_MODULE; + if (image->dynamic) + module_data->module_flags |= MODULE_FLAGS_DYNAMIC_MODULE; + if (image->aot_module) + module_data->module_flags |= MODULE_FLAGS_NATIVE_MODULE; + + module_data->module_il_path = image->filename ? image->filename : ""; + } + + return true; +} + +bool +ep_rt_mono_write_event_module_load (MonoImage *image) +{ + if (!EventEnabledModuleLoad_V2 () && !EventEnabledDomainModuleLoad_V1()) + return true; - switch (frame->type) { - case FRAME_TYPE_DEBUGGER_INVOKE: - case FRAME_TYPE_MANAGED_TO_NATIVE: - case FRAME_TYPE_TRAMPOLINE: - case FRAME_TYPE_INTERP_TO_MANAGED: - case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX: - case FRAME_TYPE_INTERP_ENTRY: - stack_walk_data->top_frame = false; - return FALSE; - case FRAME_TYPE_JIT_ENTRY: - // Frame in JIT compiler at top of callstack, add phantom frame representing call into JIT compiler. - // Makes it possible to detect stacks waiting on JIT compiler. - if (_ep_rt_mono_runtime_helper_compile_method && stack_walk_data->top_frame) - ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_ep_rt_mono_runtime_helper_compile_method), _ep_rt_mono_runtime_helper_compile_method); - stack_walk_data->top_frame = false; - return FALSE; - case FRAME_TYPE_MANAGED: - case FRAME_TYPE_INTERP: - if (frame->ji) { - stack_walk_data->async_frame |= frame->ji->async; - MonoMethod *method = frame->ji->async ? NULL : frame->actual_method; - if (method && m_method_is_wrapper (method)) { - WrapperInfo *wrapper = mono_marshal_get_wrapper_info (method); - if (in_safe_point_frame (stack_walk_data->stack_contents, wrapper)) { - stack_walk_data->safe_point_frame = true; - }else if (in_runtime_invoke_frame (stack_walk_data->stack_contents, wrapper)) { - stack_walk_data->runtime_invoke_frame = true; - } else if (_ep_rt_mono_monitor_enter_method && in_monitor_enter_frame (wrapper)) { - ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_ep_rt_mono_monitor_enter_method), _ep_rt_mono_monitor_enter_method); - } else if (_ep_rt_mono_monitor_enter_v4_method && in_monitor_enter_v4_frame (wrapper)) { - ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)_ep_rt_mono_monitor_enter_v4_method), _ep_rt_mono_monitor_enter_v4_method); - } else if (wrapper && wrapper->subtype == WRAPPER_SUBTYPE_PINVOKE) { - ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start + frame->native_offset), method); - } - } else if (method && !m_method_is_wrapper (method)) { - ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start + frame->native_offset), method); - } else if (!method && frame->ji->async && !frame->ji->is_trampoline) { - ep_stack_contents_append (stack_walk_data->stack_contents, (uintptr_t)((uint8_t*)frame->ji->code_start), method); - } + if (image) { + ModuleEventData module_data; + if (get_module_event_data (image, &module_data)) { + FireEtwModuleLoad_V2 ( + module_data.module_id, + module_data.assembly_id, + module_data.module_flags, + module_data.reserved_flags, + module_data.module_il_path, + module_data.module_native_path, + clr_instance_get_id (), + module_data.signature, + module_data.module_il_pdb_age, + module_data.module_il_pdb_path, + module_data.signature, + module_data.module_native_pdb_age, + module_data.module_native_pdb_path, + NULL, + NULL); + + FireEtwDomainModuleLoad_V1 ( + module_data.module_id, + module_data.assembly_id, + module_data.domain_id, + module_data.module_flags, + module_data.reserved_flags, + module_data.module_il_path, + module_data.module_native_path, + clr_instance_get_id (), + NULL, + NULL); } - stack_walk_data->top_frame = false; - return ep_stack_contents_get_length (stack_walk_data->stack_contents) >= EP_MAX_STACK_DEPTH; - default: - EP_UNREACHABLE ("eventpipe_walk_managed_stack_for_thread"); - return FALSE; } + + return true; +} + +bool +ep_rt_mono_write_event_module_unload (MonoImage *image) +{ + if (!EventEnabledModuleUnload_V2()) + return true; + + if (image) { + ModuleEventData module_data; + if (get_module_event_data (image, &module_data)) { + FireEtwModuleUnload_V2 ( + module_data.module_id, + module_data.assembly_id, + module_data.module_flags, + module_data.reserved_flags, + module_data.module_il_path, + module_data.module_native_path, + clr_instance_get_id (), + module_data.signature, + module_data.module_il_pdb_age, + module_data.module_il_pdb_path, + module_data.signature, + module_data.module_native_pdb_age, + module_data.module_native_pdb_path, + NULL, + NULL); + } + } + + return true; +} + +static +bool +get_assembly_event_data ( + MonoAssembly *assembly, + AssemblyEventData *assembly_data) +{ + if (assembly && assembly_data) { + // Under netcore we only have root domain. + MonoDomain *root_domain = mono_get_root_domain (); + + assembly_data->domain_id = (uint64_t)root_domain; + assembly_data->assembly_id = (uint64_t)assembly; + assembly_data->binding_id = 0; + + assembly_data->assembly_flags = 0; + if (assembly->dynamic) + assembly_data->assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; + + if (assembly->image && assembly->image->aot_module) + assembly_data->assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; + + assembly_data->assembly_name = mono_stringify_assembly_name (&assembly->aname); + } + + return true; +} + +bool +ep_rt_mono_write_event_assembly_load (MonoAssembly *assembly) +{ + if (!EventEnabledAssemblyLoad_V1 ()) + return true; + + if (assembly) { + AssemblyEventData assembly_data; + if (get_assembly_event_data (assembly, &assembly_data)) { + FireEtwAssemblyLoad_V1 ( + assembly_data.assembly_id, + assembly_data.domain_id, + assembly_data.binding_id, + assembly_data.assembly_flags, + assembly_data.assembly_name, + clr_instance_get_id (), + NULL, + NULL); + + g_free (assembly_data.assembly_name); + } + } + + return true; +} + +bool +ep_rt_mono_write_event_assembly_unload (MonoAssembly *assembly) +{ + if (!EventEnabledAssemblyUnload_V1 ()) + return true; + + if (assembly) { + AssemblyEventData assembly_data; + if (get_assembly_event_data (assembly, &assembly_data)) { + FireEtwAssemblyUnload_V1 ( + assembly_data.assembly_id, + assembly_data.domain_id, + assembly_data.binding_id, + assembly_data.assembly_flags, + assembly_data.assembly_name, + clr_instance_get_id (), + NULL, + NULL); + + g_free (assembly_data.assembly_name); + } + } + + return true; +} + +bool +ep_rt_mono_write_event_thread_created (ep_rt_thread_id_t tid) +{ + if (!EventEnabledThreadCreated ()) + return true; + + uint64_t managed_thread = 0; + uint64_t native_thread_id = ep_rt_thread_id_t_to_uint64_t (tid); + uint64_t managed_thread_id = 0; + uint32_t flags = 0; + + MonoThread *thread = mono_thread_current (); + if (thread && mono_thread_info_get_tid (thread->thread_info) == tid) { + managed_thread_id = (uint64_t)mono_thread_get_managed_id (thread); + managed_thread = (uint64_t)thread; + + switch (mono_thread_info_get_flags (thread->thread_info)) { + case MONO_THREAD_INFO_FLAGS_NO_GC: + case MONO_THREAD_INFO_FLAGS_NO_SAMPLE: + flags |= THREAD_FLAGS_GC_SPECIAL; + } + + if (mono_gc_is_finalizer_thread (thread)) + flags |= THREAD_FLAGS_FINALIZER; + + if (thread->threadpool_thread) + flags |= THREAD_FLAGS_THREADPOOL_WORKER; + } + + FireEtwThreadCreated ( + managed_thread, + (uint64_t)mono_get_root_domain (), + flags, + managed_thread_id, + native_thread_id, + clr_instance_get_id (), + NULL, + NULL); + + return true; } -static -gboolean -eventpipe_walk_managed_stack_for_thread_func ( - MonoStackFrameInfo *frame, - MonoContext *ctx, - void *data) +bool +ep_rt_mono_write_event_thread_terminated (ep_rt_thread_id_t tid) { - return eventpipe_walk_managed_stack_for_thread (frame, ctx, (EventPipeStackWalkData *)data); + if (!EventEnabledThreadTerminated ()) + return true; + + uint64_t managed_thread = 0; + MonoThread *thread = mono_thread_current (); + if (thread && mono_thread_info_get_tid (thread->thread_info) == tid) + managed_thread = (uint64_t)thread; + + FireEtwThreadTerminated ( + managed_thread, + (uint64_t)mono_get_root_domain (), + clr_instance_get_id (), + NULL, + NULL); + + return true; } static -gboolean -eventpipe_sample_profiler_walk_managed_stack_for_thread_func ( - MonoStackFrameInfo *frame, - MonoContext *ctx, - void *data) +uint32_t +get_type_start_id (MonoType *type) { - EP_ASSERT (frame != NULL); - EP_ASSERT (data != NULL); + uint32_t start_id = (uint32_t)(uintptr_t)type; - EventPipeSampleProfileStackWalkData *sample_data = (EventPipeSampleProfileStackWalkData *)data; + start_id = (((start_id * 215497) >> 16) ^ ((start_id * 1823231) + start_id)); - if (sample_data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR) { - switch (frame->type) { - case FRAME_TYPE_MANAGED: - sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; - break; - case FRAME_TYPE_MANAGED_TO_NATIVE: - case FRAME_TYPE_TRAMPOLINE: - sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL; - break; - case FRAME_TYPE_JIT_ENTRY: - sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL; - break; - case FRAME_TYPE_INTERP: - sample_data->payload_data = frame->managed ? EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED : EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL; - break; - case FRAME_TYPE_INTERP_TO_MANAGED: - case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX: - break; - default: - sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; - } - } + // Mix in highest bits on 64-bit systems only + if (sizeof (type) > 4) + start_id = start_id ^ (((uint64_t)type >> 31) >> 1); - return eventpipe_walk_managed_stack_for_thread (frame, ctx, &sample_data->stack_walk_data); + return start_id; } -static -void -profiler_eventpipe_thread_exited ( - MonoProfiler *prof, - uintptr_t tid) +bool +ep_rt_mono_write_event_type_load_start (MonoType *type) { - void ep_rt_mono_thread_exited (void); - ep_rt_mono_thread_exited (); + if (!EventEnabledTypeLoadStart ()) + return true; + + FireEtwTypeLoadStart ( + get_type_start_id (type), + clr_instance_get_id (), + NULL, + NULL); + + return true; } -void -ep_rt_mono_init (void) +bool +ep_rt_mono_write_event_type_load_stop (MonoType *type) { - mono_native_tls_alloc (&_ep_rt_mono_thread_holder_tls_id, NULL); + if (!EventEnabledTypeLoadStop ()) + return true; - mono_100ns_ticks (); - mono_rand_open (); - _ep_rt_mono_rand_provider = mono_rand_init (NULL, 0); + char *type_name = NULL; + if (type) + type_name = mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL); - _ep_rt_mono_initialized = TRUE; + FireEtwTypeLoadStop ( + get_type_start_id (type), + clr_instance_get_id (), + 6 /* CLASS_LOADED */, + (uint64_t)type, + type_name, + NULL, + NULL); - _ep_rt_mono_profiler = mono_profiler_create (NULL); - mono_profiler_set_thread_stopped_callback (_ep_rt_mono_profiler, profiler_eventpipe_thread_exited); + g_free (type_name); - MonoMethodSignature *method_signature = mono_metadata_signature_alloc (mono_get_corlib (), 1); - if (method_signature) { - method_signature->params[0] = m_class_get_byval_arg (mono_get_object_class()); - method_signature->ret = m_class_get_byval_arg (mono_get_void_class()); + return true; +} + +static +gboolean +get_exception_ip_func ( + MonoStackFrameInfo *frame, + MonoContext *ctx, + void *data) +{ + *(uintptr_t *)data = (uintptr_t)MONO_CONTEXT_GET_IP (ctx); + return TRUE; +} + +bool +ep_rt_mono_write_event_exception_thrown (MonoObject *obj) +{ + if (!EventEnabledExceptionThrown_V1 ()) + return true; + if (obj) { ERROR_DECL (error); - MonoClass *runtime_helpers = mono_class_from_name_checked (mono_get_corlib (), "System.Runtime.CompilerServices", "RuntimeHelpers", error); - if (is_ok (error) && runtime_helpers) { - MonoMethodBuilder *method_builder = mono_mb_new (runtime_helpers, "CompileMethod", MONO_WRAPPER_RUNTIME_INVOKE); - if (method_builder) { - _ep_rt_mono_runtime_helper_compile_method = mono_mb_create_method (method_builder, method_signature, 1); - mono_mb_free (method_builder); - } - } - mono_error_cleanup (error); - mono_metadata_free_method_signature (method_signature); + char *type_name = NULL; + char *exception_message = NULL; + uint16_t flags = 0; + uint32_t hresult = 0; + uintptr_t ip = 0; - _ep_rt_mono_runtime_helper_compile_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1); - if (_ep_rt_mono_runtime_helper_compile_method) { - _ep_rt_mono_runtime_helper_compile_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_ep_rt_mono_runtime_helper_compile_method); - _ep_rt_mono_runtime_helper_compile_method_jitinfo->code_size = 20; - _ep_rt_mono_runtime_helper_compile_method_jitinfo->d.method = _ep_rt_mono_runtime_helper_compile_method; + if (mono_object_isinst_checked ((MonoObject *) obj, mono_get_exception_class (), error)) { + MonoException *exception = (MonoException *)obj; + flags |= EXCEPTION_THROWN_FLAGS_IS_CLS_COMPLIANT; + if (exception->inner_ex) + flags |= EXCEPTION_THROWN_FLAGS_HAS_INNER; + exception_message = ep_rt_utf16_to_utf8_string (mono_string_chars_internal (exception->message), mono_string_length_internal (exception->message)); + hresult = exception->hresult; } - } - { - ERROR_DECL (error); - MonoMethodDesc *desc = NULL; - MonoClass *monitor = mono_class_from_name_checked (mono_get_corlib (), "System.Threading", "Monitor", error); - if (is_ok (error) && monitor) { - desc = mono_method_desc_new ("Monitor:Enter(object,bool&)", FALSE); - if (desc) { - _ep_rt_mono_monitor_enter_v4_method = mono_method_desc_search_in_class (desc, monitor); - mono_method_desc_free (desc); + if (mono_get_eh_callbacks ()->mono_walk_stack_with_ctx) + mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (get_exception_ip_func, NULL, MONO_UNWIND_SIGNAL_SAFE, (void *)&ip); - _ep_rt_mono_monitor_enter_v4_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1); - if (_ep_rt_mono_monitor_enter_v4_method_jitinfo) { - _ep_rt_mono_monitor_enter_v4_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_ep_rt_mono_monitor_enter_v4_method); - _ep_rt_mono_monitor_enter_v4_method_jitinfo->code_size = 20; - _ep_rt_mono_monitor_enter_v4_method_jitinfo->d.method = _ep_rt_mono_monitor_enter_v4_method; - } - } + type_name = mono_type_get_name_full (m_class_get_byval_arg (mono_object_class (obj)), MONO_TYPE_NAME_FORMAT_IL); - desc = mono_method_desc_new ("Monitor:Enter(object)", FALSE); - if (desc) { - _ep_rt_mono_monitor_enter_method = mono_method_desc_search_in_class (desc, monitor); - mono_method_desc_free (desc); + FireEtwExceptionThrown_V1 ( + type_name, + exception_message, + (void *)&ip, + hresult, + flags, + clr_instance_get_id (), + NULL, + NULL); - _ep_rt_mono_monitor_enter_method_jitinfo = (MonoJitInfo *)g_new0 (MonoJitInfo, 1); - if (_ep_rt_mono_monitor_enter_method_jitinfo) { - _ep_rt_mono_monitor_enter_method_jitinfo->code_start = MINI_FTNPTR_TO_ADDR (_ep_rt_mono_monitor_enter_method); - _ep_rt_mono_monitor_enter_method_jitinfo->code_size = 20; - _ep_rt_mono_monitor_enter_method_jitinfo->d.method = _ep_rt_mono_monitor_enter_method; - } - } + if (!mono_component_profiler_clauses_enabled ()) { + FireEtwExceptionThrownStop ( + NULL, + NULL); } - mono_error_cleanup (error); - } -} - -void -ep_rt_mono_init_finish (void) -{ - if (mono_runtime_get_no_exec ()) - return; - // Managed init of diagnostics classes, like registration of RuntimeEventSource (if available). - ERROR_DECL (error); + g_free (exception_message); + g_free (type_name); - MonoClass *runtime_event_source = mono_class_from_name_checked (mono_get_corlib (), "System.Diagnostics.Tracing", "RuntimeEventSource", error); - if (is_ok (error) && runtime_event_source) { - MonoMethod *init = mono_class_get_method_from_name_checked (runtime_event_source, "Initialize", -1, 0, error); - if (is_ok (error) && init) { - mono_runtime_try_invoke_handle (init, NULL_HANDLE, NULL, error); - } + mono_error_cleanup (error); } - mono_error_cleanup (error); + return true; } -void -ep_rt_mono_fini (void) +bool +ep_rt_mono_write_event_exception_clause ( + MonoMethod *method, + uint32_t clause_num, + MonoExceptionEnum clause_type, + MonoObject *obj) { - if (_ep_rt_mono_sampled_thread_callstacks) - g_array_free (_ep_rt_mono_sampled_thread_callstacks, TRUE); - - if (_ep_rt_mono_initialized) - mono_rand_close (_ep_rt_mono_rand_provider); + if (!mono_component_profiler_clauses_enabled ()) + return true; - g_free (_ep_rt_mono_runtime_helper_compile_method_jitinfo); - _ep_rt_mono_runtime_helper_compile_method_jitinfo = NULL; + if ((clause_type == MONO_EXCEPTION_CLAUSE_FAULT || clause_type == MONO_EXCEPTION_CLAUSE_NONE) && (!EventEnabledExceptionCatchStart() || !EventEnabledExceptionCatchStop())) + return true; - mono_free_method (_ep_rt_mono_runtime_helper_compile_method); - _ep_rt_mono_runtime_helper_compile_method = NULL; + if (clause_type == MONO_EXCEPTION_CLAUSE_FILTER && (!EventEnabledExceptionFilterStart() || !EventEnabledExceptionFilterStop())) + return true; - g_free (_ep_rt_mono_monitor_enter_method_jitinfo); - _ep_rt_mono_monitor_enter_method_jitinfo = NULL; - _ep_rt_mono_monitor_enter_method = NULL; + if (clause_type == MONO_EXCEPTION_CLAUSE_FINALLY && (!EventEnabledExceptionFinallyStart() || !EventEnabledExceptionFinallyStop())) + return true; - g_free (_ep_rt_mono_monitor_enter_v4_method_jitinfo); - _ep_rt_mono_monitor_enter_v4_method_jitinfo = NULL; - _ep_rt_mono_monitor_enter_v4_method = NULL; + uintptr_t ip = 0; //TODO: Have profiler pass along IP of handler block. + uint64_t method_id = (uint64_t)method; + char *method_name = NULL; - _ep_rt_mono_sampled_thread_callstacks = NULL; - _ep_rt_mono_rand_provider = NULL; - _ep_rt_mono_initialized = FALSE; -} + method_name = mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL); -bool -ep_rt_mono_rand_try_get_bytes ( - uint8_t *buffer, - size_t buffer_size) -{ - EP_ASSERT (_ep_rt_mono_rand_provider != NULL); + if ((clause_type == MONO_EXCEPTION_CLAUSE_FAULT || clause_type == MONO_EXCEPTION_CLAUSE_NONE)) { + FireEtwExceptionCatchStart ( + (uint64_t)ip, + method_id, + (const ep_char8_t *)method_name, + clr_instance_get_id (), + NULL, + NULL); - ERROR_DECL (error); - return mono_rand_try_get_bytes (&_ep_rt_mono_rand_provider, (guchar *)buffer, (gssize)buffer_size, error); -} + FireEtwExceptionCatchStop ( + NULL, + NULL); -EventPipeThread * -ep_rt_mono_thread_get_or_create (void) -{ - EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id); - if (!thread_holder) { - thread_holder = thread_holder_alloc_func (); - mono_native_tls_set_value (_ep_rt_mono_thread_holder_tls_id, thread_holder); + FireEtwExceptionThrownStop ( + NULL, + NULL); } - return ep_thread_holder_get_thread (thread_holder); -} -void * -ep_rt_mono_thread_attach (bool background_thread) -{ - MonoThread *thread = NULL; + if (clause_type == MONO_EXCEPTION_CLAUSE_FILTER) { + FireEtwExceptionFilterStart ( + (uint64_t)ip, + method_id, + (const ep_char8_t *)method_name, + clr_instance_get_id (), + NULL, + NULL); - // NOTE, under netcore, only root domain exists. - if (!mono_thread_current ()) { - thread = mono_thread_internal_attach (mono_get_root_domain ()); - if (background_thread && thread) { - mono_thread_set_state (thread, ThreadState_Background); - mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_SAMPLE); - } + FireEtwExceptionFilterStop ( + NULL, + NULL); } - return thread; -} + if (clause_type == MONO_EXCEPTION_CLAUSE_FINALLY) { + FireEtwExceptionFinallyStart ( + (uint64_t)ip, + method_id, + (const ep_char8_t *)method_name, + clr_instance_get_id (), + NULL, + NULL); -void * -ep_rt_mono_thread_attach_2 (bool background_thread, EventPipeThreadType thread_type) -{ - void *result = ep_rt_mono_thread_attach (background_thread); - if (result && thread_type == EP_THREAD_TYPE_SAMPLING) { - // Increase sampling thread priority, accepting failures. -#ifdef HOST_WIN32 - SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST); -#elif _POSIX_PRIORITY_SCHEDULING - int policy; - int priority; - struct sched_param param; - int schedparam_result = pthread_getschedparam (pthread_self (), &policy, ¶m); - if (schedparam_result == 0) { - // Attempt to switch the thread to real time scheduling. This will not - // necessarily work on all OSs; for example, most Linux systems will give - // us EPERM here unless configured to allow this. - priority = param.sched_priority; - param.sched_priority = sched_get_priority_max (SCHED_RR); - if (param.sched_priority != -1) { - schedparam_result = pthread_setschedparam (pthread_self (), SCHED_RR, ¶m); - if (schedparam_result != 0) { - // Fallback, attempt to increase to max priority using current policy. - param.sched_priority = sched_get_priority_max (policy); - if (param.sched_priority != -1 && param.sched_priority != priority) - pthread_setschedparam (pthread_self (), policy, ¶m); - } - } - } -#endif + FireEtwExceptionFinallyStop ( + NULL, + NULL); } - return result; + g_free (method_name); + return true; } -void -ep_rt_mono_thread_detach (void) +bool +ep_rt_mono_write_event_monitor_contention_start (MonoObject *obj) { - MonoThread *current_thread = mono_thread_current (); - if (current_thread) - mono_thread_internal_detach (current_thread); -} + if (!EventEnabledContentionStart_V1 ()) + return true; -void -ep_rt_mono_thread_exited (void) -{ - if (_ep_rt_mono_initialized) { - EventPipeThreadHolder *thread_holder = (EventPipeThreadHolder *)mono_native_tls_get_value (_ep_rt_mono_thread_holder_tls_id); - if (thread_holder) - thread_holder_free_func (thread_holder); - mono_native_tls_set_value (_ep_rt_mono_thread_holder_tls_id, NULL); - } -} + FireEtwContentionStart_V1 ( + 0 /* ManagedContention */, + clr_instance_get_id (), + NULL, + NULL); -#ifdef HOST_WIN32 -int64_t -ep_rt_mono_perf_counter_query (void) -{ - LARGE_INTEGER value; - if (QueryPerformanceCounter (&value)) - return (int64_t)value.QuadPart; - else - return 0; + return true; } -int64_t -ep_rt_mono_perf_frequency_query (void) +bool +ep_rt_mono_write_event_monitor_contention_stop (MonoObject *obj) { - LARGE_INTEGER value; - if (QueryPerformanceFrequency (&value)) - return (int64_t)value.QuadPart; - else - return 0; -} + if (!EventEnabledContentionStop ()) + return true; -void -ep_rt_mono_system_time_get (EventPipeSystemTime *system_time) -{ - SYSTEMTIME value; - GetSystemTime (&value); + FireEtwContentionStop ( + 0 /* ManagedContention */, + clr_instance_get_id (), + NULL, + NULL); - EP_ASSERT (system_time != NULL); - ep_system_time_set ( - system_time, - value.wYear, - value.wMonth, - value.wDayOfWeek, - value.wDay, - value.wHour, - value.wMinute, - value.wSecond, - value.wMilliseconds); + return true; } -int64_t -ep_rt_mono_system_timestamp_get (void) +bool +ep_rt_mono_write_event_method_jit_memory_allocated_for_code ( + const uint8_t *buffer, + uint64_t size, + MonoProfilerCodeBufferType type, + const void *data) { - FILETIME value; - GetSystemTimeAsFileTime (&value); - return (int64_t)((((uint64_t)value.dwHighDateTime) << 32) | (uint64_t)value.dwLowDateTime); -} -#else -#include -#include -#include -#include - -#if HAVE_SYS_TIME_H -#include -#endif // HAVE_SYS_TIME_H - -#if HAVE_MACH_ABSOLUTE_TIME -#include -static mono_lazy_init_t _ep_rt_mono_time_base_info_init = MONO_LAZY_INIT_STATUS_NOT_INITIALIZED; -static mach_timebase_info_data_t _ep_rt_mono_time_base_info = {0}; -#endif + if (!EventEnabledMethodJitMemoryAllocatedForCode ()) + return true; -#ifdef HAVE_LOCALTIME_R -#define HAVE_GMTIME_R 1 -#endif + if (type != MONO_PROFILER_CODE_BUFFER_METHOD) + return true; -static const int64_t SECS_BETWEEN_1601_AND_1970_EPOCHS = 11644473600LL; -static const int64_t SECS_TO_100NS = 10000000; -static const int64_t SECS_TO_NS = 1000000000; -static const int64_t MSECS_TO_MIS = 1000; + uint64_t method_id = 0; + uint64_t module_id = 0; -/* clock_gettime () is found by configure on Apple builds, but its only present from ios 10, macos 10.12, tvos 10 and watchos 3 */ -#if defined (HAVE_CLOCK_MONOTONIC) && (defined(TARGET_IOS) || defined(TARGET_OSX) || defined(TARGET_WATCHOS) || defined(TARGET_TVOS)) -#undef HAVE_CLOCK_MONOTONIC -#endif + if (data) { + MonoMethod *method; + method = (MonoMethod *)data; + method_id = (uint64_t)method; + if (method->klass) + module_id = (uint64_t)(uint64_t)m_class_get_image (method->klass); + } -#ifndef HAVE_CLOCK_MONOTONIC -static const int64_t MISECS_TO_NS = 1000; -#endif + FireEtwMethodJitMemoryAllocatedForCode ( + method_id, + module_id, + size, + 0, + size, + 0 /* CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN */, + clr_instance_get_id (), + NULL, + NULL); -static -void -time_base_info_lazy_init (void); + return true; +} -static -int64_t -system_time_to_int64 ( - time_t sec, - long nsec); +bool +ep_rt_write_event_threadpool_worker_thread_start ( + uint32_t active_thread_count, + uint32_t retired_worker_thread_count, + uint16_t clr_instance_id) +{ + return FireEtwThreadPoolWorkerThreadStart ( + active_thread_count, + retired_worker_thread_count, + clr_instance_id, + NULL, + NULL) == 0 ? true : false; +} -#if HAVE_MACH_ABSOLUTE_TIME -static -void -time_base_info_lazy_init (void) +bool +ep_rt_write_event_threadpool_worker_thread_stop ( + uint32_t active_thread_count, + uint32_t retired_worker_thread_count, + uint16_t clr_instance_id) { - kern_return_t result = mach_timebase_info (&_ep_rt_mono_time_base_info); - if (result != KERN_SUCCESS) - memset (&_ep_rt_mono_time_base_info, 0, sizeof (_ep_rt_mono_time_base_info)); + return FireEtwThreadPoolWorkerThreadStop ( + active_thread_count, + retired_worker_thread_count, + clr_instance_id, + NULL, + NULL) == 0 ? true : false; } -#endif -int64_t -ep_rt_mono_perf_counter_query (void) +bool +ep_rt_write_event_threadpool_worker_thread_wait ( + uint32_t active_thread_count, + uint32_t retired_worker_thread_count, + uint16_t clr_instance_id) { -#if HAVE_MACH_ABSOLUTE_TIME - return (int64_t)mach_absolute_time (); -#elif HAVE_CLOCK_MONOTONIC - struct timespec ts; - int result = clock_gettime (CLOCK_MONOTONIC, &ts); - if (result == 0) - return ((int64_t)(ts.tv_sec) * (int64_t)(SECS_TO_NS)) + (int64_t)(ts.tv_nsec); -#else - #error "ep_rt_mono_perf_counter_get requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported." -#endif - return 0; + return FireEtwThreadPoolWorkerThreadWait ( + active_thread_count, + retired_worker_thread_count, + clr_instance_id, + NULL, + NULL) == 0 ? true : false; } -int64_t -ep_rt_mono_perf_frequency_query (void) +bool +ep_rt_write_event_threadpool_worker_thread_adjustment_sample ( + double throughput, + uint16_t clr_instance_id) { -#if HAVE_MACH_ABSOLUTE_TIME - // (numer / denom) gives you the nanoseconds per tick, so the below code - // computes the number of ticks per second. We explicitly do the multiplication - // first in order to help minimize the error that is produced by integer division. - mono_lazy_initialize (&_ep_rt_mono_time_base_info_init, time_base_info_lazy_init); - if (_ep_rt_mono_time_base_info.denom == 0 || _ep_rt_mono_time_base_info.numer == 0) - return 0; - return ((int64_t)(SECS_TO_NS) * (int64_t)(_ep_rt_mono_time_base_info.denom)) / (int64_t)(_ep_rt_mono_time_base_info.numer); -#elif HAVE_CLOCK_MONOTONIC - // clock_gettime () returns a result in terms of nanoseconds rather than a count. This - // means that we need to either always scale the result by the actual resolution (to - // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer - // the latter since it allows the highest throughput and should minimize error propagated - // to the user. - return (int64_t)(SECS_TO_NS); -#else - #error "ep_rt_mono_perf_frequency_query requires either mach_absolute_time () or clock_gettime (CLOCK_MONOTONIC) to be supported." -#endif - return 0; + return FireEtwThreadPoolWorkerThreadAdjustmentSample ( + throughput, + clr_instance_id, + NULL, + NULL) == 0 ? true : false; } -void -ep_rt_mono_system_time_get (EventPipeSystemTime *system_time) +bool +ep_rt_write_event_threadpool_worker_thread_adjustment_adjustment ( + double average_throughput, + uint32_t networker_thread_count, + /*NativeRuntimeEventSource.ThreadAdjustmentReasonMap*/ int32_t reason, + uint16_t clr_instance_id) { - time_t tt; -#if HAVE_GMTIME_R - struct tm ut; -#endif /* HAVE_GMTIME_R */ - struct tm *ut_ptr; - struct timeval time_val; - int timeofday_retval; - - EP_ASSERT (system_time != NULL); - - tt = time (NULL); - - /* We can't get millisecond resolution from time (), so we get it from gettimeofday () */ - timeofday_retval = gettimeofday (&time_val, NULL); - -#if HAVE_GMTIME_R - ut_ptr = &ut; - if (gmtime_r (&tt, ut_ptr) == NULL) -#else /* HAVE_GMTIME_R */ - if ((ut_ptr = gmtime (&tt)) == NULL) -#endif /* HAVE_GMTIME_R */ - EP_UNREACHABLE (); - - uint16_t milliseconds = 0; - if (timeofday_retval != -1) { - int old_seconds; - int new_seconds; - - milliseconds = time_val.tv_usec / MSECS_TO_MIS; - - old_seconds = ut_ptr->tm_sec; - new_seconds = time_val.tv_sec % 60; - - /* just in case we reached the next second in the interval between time () and gettimeofday () */ - if (old_seconds != new_seconds) - milliseconds = 999; - } + return FireEtwThreadPoolWorkerThreadAdjustmentAdjustment ( + average_throughput, + networker_thread_count, + reason, + clr_instance_id, + NULL, + NULL) == 0 ? true : false; +} - ep_system_time_set ( - system_time, - 1900 + ut_ptr->tm_year, - ut_ptr->tm_mon + 1, - ut_ptr->tm_wday, - ut_ptr->tm_mday, - ut_ptr->tm_hour, - ut_ptr->tm_min, - ut_ptr->tm_sec, - milliseconds); +bool +ep_rt_write_event_threadpool_worker_thread_adjustment_stats ( + double duration, + double throughput, + double threadpool_worker_thread_wait, + double throughput_wave, + double throughput_error_estimate, + double average_throughput_error_estimate, + double throughput_ratio, + double confidence, + double new_control_setting, + uint16_t new_thread_wave_magnitude, + uint16_t clr_instance_id) +{ + return FireEtwThreadPoolWorkerThreadAdjustmentStats ( + duration, + throughput, + threadpool_worker_thread_wait, + throughput_wave, + throughput_error_estimate, + average_throughput_error_estimate, + throughput_ratio, + confidence, + new_control_setting, + new_thread_wave_magnitude, + clr_instance_id, + NULL, + NULL) == 0 ? true : false; } -static -inline -int64_t -system_time_to_int64 ( - time_t sec, - long nsec) +bool +ep_rt_write_event_threadpool_io_enqueue ( + intptr_t native_overlapped, + intptr_t overlapped, + bool multi_dequeues, + uint16_t clr_instance_id) { - return ((int64_t)sec + SECS_BETWEEN_1601_AND_1970_EPOCHS) * SECS_TO_100NS + (nsec / 100); + return FireEtwThreadPoolIOEnqueue ( + (const void *)native_overlapped, + (const void *)overlapped, + multi_dequeues, + clr_instance_id, + NULL, + NULL) == 0 ? true : false; } -int64_t -ep_rt_mono_system_timestamp_get (void) +bool +ep_rt_write_event_threadpool_io_dequeue ( + intptr_t native_overlapped, + intptr_t overlapped, + uint16_t clr_instance_id) { -#if HAVE_CLOCK_MONOTONIC - struct timespec time; - if (clock_gettime (CLOCK_REALTIME, &time) == 0) - return system_time_to_int64 (time.tv_sec, time.tv_nsec); -#else - struct timeval time; - if (gettimeofday (&time, NULL) == 0) - return system_time_to_int64 (time.tv_sec, time.tv_usec * MISECS_TO_NS); -#endif - else - return system_time_to_int64 (0, 0); + return FireEtwThreadPoolIODequeue ( + (const void *)native_overlapped, + (const void *)overlapped, + clr_instance_id, + NULL, + NULL) == 0 ? true : false; } -#endif -#ifndef HOST_WIN32 -#if defined(__APPLE__) -#if defined (TARGET_OSX) -G_BEGIN_DECLS -gchar ***_NSGetEnviron(void); -G_END_DECLS -#define environ (*_NSGetEnviron()) -#else -static char *_ep_rt_mono_environ[1] = { NULL }; -#define environ _ep_rt_mono_environ -#endif /* defined (TARGET_OSX) */ -#else -G_BEGIN_DECLS -extern char **environ; -G_END_DECLS -#endif /* defined (__APPLE__) */ -#endif /* !defined (HOST_WIN32) */ +bool +ep_rt_write_event_threadpool_working_thread_count ( + uint16_t count, + uint16_t clr_instance_id) +{ + return FireEtwThreadPoolWorkingThreadCount ( + count, + clr_instance_id, + NULL, + NULL) == 0 ? true : false; +} +static void -ep_rt_mono_os_environment_get_utf16 (ep_rt_env_array_utf16_t *env_array) +runtime_profiler_jit_begin ( + MonoProfiler *prof, + MonoMethod *method) { - EP_ASSERT (env_array != NULL); -#ifdef HOST_WIN32 - LPWSTR envs = GetEnvironmentStringsW (); - if (envs) { - LPWSTR next = envs; - while (*next) { - ep_rt_env_array_utf16_append (env_array, ep_rt_utf16_string_dup (next)); - next += ep_rt_utf16_string_len (next) + 1; - } - FreeEnvironmentStringsW (envs); - } -#else - gchar **next = NULL; - for (next = environ; *next != NULL; ++next) - ep_rt_env_array_utf16_append (env_array, ep_rt_utf8_to_utf16_string (*next, -1)); -#endif + ep_rt_mono_write_event_jit_start (method); +} + +static +void +runtime_profiler_jit_failed ( + MonoProfiler *prof, + MonoMethod *method) +{ + //TODO: CoreCLR doesn't have this case, so no failure event currently exists. } +static void -ep_rt_mono_init_providers_and_events (void) +runtime_profiler_jit_done ( + MonoProfiler *prof, + MonoMethod *method, + MonoJitInfo *ji) { - extern void InitProvidersAndEvents (void); - InitProvidersAndEvents (); + ep_rt_mono_write_event_method_load (method, ji); + ep_rt_mono_write_event_method_il_to_native_map (method, ji); } +static void -ep_rt_mono_provider_config_init (EventPipeProviderConfiguration *provider_config) +runtime_profiler_image_loaded ( + MonoProfiler *prof, + MonoImage *image) { - if (!ep_rt_utf8_string_compare (ep_config_get_rundown_provider_name_utf8 (), ep_provider_config_get_provider_name (provider_config))) { - MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.Level = ep_provider_config_get_logging_level (provider_config); - MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = ep_provider_config_get_keywords (provider_config); - MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.IsEnabled = true; - } + if (image && image->heap_pdb.size == 0) + ep_rt_mono_write_event_module_load (image); } -bool -ep_rt_mono_providers_validate_all_disabled (void) +static +void +runtime_profiler_image_unloaded ( + MonoProfiler *prof, + MonoImage *image) { - return (!MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.IsEnabled && - !MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.IsEnabled && - !MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.IsEnabled); + if (image && image->heap_pdb.size == 0) + ep_rt_mono_write_event_module_unload (image); } +static void -ep_rt_mono_fini_providers_and_events (void) +runtime_profiler_assembly_loaded ( + MonoProfiler *prof, + MonoAssembly *assembly) { - // dotnet/runtime: issue 12775: EventPipe shutdown race conditions - // Deallocating providers/events here might cause AV if a WriteEvent - // was to occur. Thus, we are not doing this cleanup. + ep_rt_mono_write_event_assembly_load (assembly); } -bool -ep_rt_mono_walk_managed_stack_for_thread ( - ep_rt_thread_handle_t thread, - EventPipeStackContents *stack_contents) +static +void +runtime_profiler_assembly_unloaded ( + MonoProfiler *prof, + MonoAssembly *assembly) { - EP_ASSERT (thread != NULL && stack_contents != NULL); - - EventPipeStackWalkData stack_walk_data; - stack_walk_data.stack_contents = stack_contents; - stack_walk_data.top_frame = true; - stack_walk_data.async_frame = false; - stack_walk_data.safe_point_frame = false; - stack_walk_data.runtime_invoke_frame = false; - - if (thread == ep_rt_thread_get_handle () && mono_get_eh_callbacks ()->mono_walk_stack_with_ctx) - mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (eventpipe_walk_managed_stack_for_thread_func, NULL, MONO_UNWIND_SIGNAL_SAFE, &stack_walk_data); - else if (mono_get_eh_callbacks ()->mono_walk_stack_with_state) - mono_get_eh_callbacks ()->mono_walk_stack_with_state (eventpipe_walk_managed_stack_for_thread_func, mono_thread_info_get_suspend_state (thread), MONO_UNWIND_SIGNAL_SAFE, &stack_walk_data); - - return true; + ep_rt_mono_write_event_assembly_unload (assembly); } -bool -ep_rt_mono_method_get_simple_assembly_name ( - ep_rt_method_desc_t *method, - ep_char8_t *name, - size_t name_len) +static +void +runtime_profiler_thread_started ( + MonoProfiler *prof, + uintptr_t tid) { - EP_ASSERT (method != NULL); - EP_ASSERT (name != NULL); - - MonoClass *method_class = mono_method_get_class (method); - MonoImage *method_image = method_class ? mono_class_get_image (method_class) : NULL; - const ep_char8_t *assembly_name = method_image ? mono_image_get_name (method_image) : NULL; - - if (!assembly_name) - return false; - - g_strlcpy (name, assembly_name, name_len); - return true; + ep_rt_mono_write_event_thread_created (ep_rt_uint64_t_to_thread_id_t (tid)); } -bool -ep_rt_mono_method_get_full_name ( - ep_rt_method_desc_t *method, - ep_char8_t *name, - size_t name_len) +static +void +runtime_profiler_thread_stopped ( + MonoProfiler *prof, + uintptr_t tid) { - EP_ASSERT (method != NULL); - EP_ASSERT (name != NULL); - - char *full_method_name = mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL); - if (!full_method_name) - return false; - - g_strlcpy (name, full_method_name, name_len); - - g_free (full_method_name); - return true; + ep_rt_mono_write_event_thread_terminated (ep_rt_uint64_t_to_thread_id_t (tid)); } -bool -ep_rt_mono_sample_profiler_write_sampling_event_for_threads ( - ep_rt_thread_handle_t sampling_thread, - EventPipeEvent *sampling_event) +static +void +runtime_profiler_class_loading ( + MonoProfiler *prof, + MonoClass *klass) { - // Follows CoreClr implementation of sample profiler. Generic invasive/expensive way to do CPU sample profiling relying on STW and stackwalks. - // TODO: Investigate alternatives on platforms supporting Signals/SuspendThread (see Mono profiler) or CPU PMU's (see ETW/perf_event_open). - - // Sample profiler only runs on one thread, no need to synchorinize. - if (!_ep_rt_mono_sampled_thread_callstacks) - _ep_rt_mono_sampled_thread_callstacks = g_array_sized_new (FALSE, FALSE, sizeof (EventPipeSampleProfileStackWalkData), _ep_rt_mono_max_sampled_thread_count); - - // Make sure there is room based on previous max number of sampled threads. - // NOTE, there is a chance there are more threads than max, if that's the case we will - // miss those threads in this sample, but will be included in next when max has been adjusted. - g_array_set_size (_ep_rt_mono_sampled_thread_callstacks, _ep_rt_mono_max_sampled_thread_count); - - uint32_t filtered_thread_count = 0; - uint32_t sampled_thread_count = 0; - - mono_stop_world (MONO_THREAD_INFO_FLAGS_NO_GC); - - gboolean async_context = mono_thread_info_is_async_context (); - mono_thread_info_set_is_async_context (TRUE); - - // Record all info needed in sample events while runtime is suspended, must be async safe. - FOREACH_THREAD_SAFE_EXCLUDE (thread_info, MONO_THREAD_INFO_FLAGS_NO_GC | MONO_THREAD_INFO_FLAGS_NO_SAMPLE) { - if (!mono_thread_info_is_running (thread_info)) { - MonoThreadUnwindState *thread_state = mono_thread_info_get_suspend_state (thread_info); - if (thread_state->valid) { - if (sampled_thread_count < _ep_rt_mono_max_sampled_thread_count) { - EventPipeSampleProfileStackWalkData *data = &g_array_index (_ep_rt_mono_sampled_thread_callstacks, EventPipeSampleProfileStackWalkData, sampled_thread_count); - data->thread_id = ep_rt_thread_id_t_to_uint64_t (mono_thread_info_get_tid (thread_info)); - data->thread_ip = (uintptr_t)MONO_CONTEXT_GET_IP (&thread_state->ctx); - data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR; - data->stack_walk_data.stack_contents = &data->stack_contents; - data->stack_walk_data.top_frame = true; - data->stack_walk_data.async_frame = false; - data->stack_walk_data.safe_point_frame = false; - data->stack_walk_data.runtime_invoke_frame = false; - ep_stack_contents_reset (&data->stack_contents); - mono_get_eh_callbacks ()->mono_walk_stack_with_state (eventpipe_sample_profiler_walk_managed_stack_for_thread_func, thread_state, MONO_UNWIND_SIGNAL_SAFE, data); - if (data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL && (data->stack_walk_data.safe_point_frame || data->stack_walk_data.runtime_invoke_frame)) { - // If classified as external code (managed->native frame on top of stack), but have a safe point or runtime invoke frame - // as second, re-classify current callstack to be executing managed code. - data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; - } - - sampled_thread_count++; - } - } - } - filtered_thread_count++; - } FOREACH_THREAD_SAFE_END - - mono_thread_info_set_is_async_context (async_context); - mono_restart_world (MONO_THREAD_INFO_FLAGS_NO_GC); - - // Fire sample event for threads. Must be done after runtime is resumed since it's not async safe. - // Since we can't keep thread info around after runtime as been suspended, use an empty - // adapter instance and only set recorded tid as parameter inside adapter. - THREAD_INFO_TYPE adapter = { { 0 } }; - for (uint32_t i = 0; i < sampled_thread_count; ++i) { - EventPipeSampleProfileStackWalkData *data = &g_array_index (_ep_rt_mono_sampled_thread_callstacks, EventPipeSampleProfileStackWalkData, i); - if (data->payload_data != EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR && ep_stack_contents_get_length(&data->stack_contents) > 0) { - // Check if we have an async frame, if so we will need to make sure all frames are registered in regular jit info table. - // TODO: An async frame can contain wrapper methods (no way to check during stackwalk), we could skip writing profile event - // for this specific stackwalk or we could cleanup stack_frames before writing profile event. - if (data->stack_walk_data.async_frame) { - for (int i = 0; i < data->stack_contents.next_available_frame; ++i) - mono_jit_info_table_find_internal ((gpointer)data->stack_contents.stack_frames [i], TRUE, FALSE); - } - mono_thread_info_set_tid (&adapter, ep_rt_uint64_t_to_thread_id_t (data->thread_id)); - ep_write_sample_profile_event (sampling_thread, sampling_event, &adapter, &data->stack_contents, (uint8_t *)&data->payload_data, sizeof (data->payload_data)); - } - } - - // Current thread count will be our next maximum sampled threads. - _ep_rt_mono_max_sampled_thread_count = filtered_thread_count; - - return true; + ep_rt_mono_write_event_type_load_start (m_class_get_byval_arg (klass)); } +static void -ep_rt_mono_execute_rundown (ep_rt_execution_checkpoint_array_t *execution_checkpoints) +runtime_profiler_class_failed ( + MonoProfiler *prof, + MonoClass *klass) { - ep_char8_t runtime_module_path [256]; - const uint8_t object_guid [EP_GUID_SIZE] = { 0 }; - const uint16_t runtime_product_qfe_version = 0; - const uint32_t startup_flags = 0; - const uint8_t startup_mode = 0; - const ep_char8_t *command_line = ""; + ep_rt_mono_write_event_type_load_stop (m_class_get_byval_arg (klass)); +} - if (!g_module_address ((void *)mono_init, runtime_module_path, sizeof (runtime_module_path), NULL, NULL, 0, NULL)) - runtime_module_path [0] = '\0'; +static +void +runtime_profiler_class_loaded ( + MonoProfiler *prof, + MonoClass *klass) +{ + ep_rt_mono_write_event_type_load_stop (m_class_get_byval_arg (klass)); +} - FireEtwRuntimeInformationDCStart ( - clr_instance_get_id (), - RUNTIME_SKU_CORECLR, - RuntimeProductMajorVersion, - RuntimeProductMinorVersion, - RuntimeProductPatchVersion, - runtime_product_qfe_version, - RuntimeFileMajorVersion, - RuntimeFileMajorVersion, - RuntimeFileBuildVersion, - RuntimeFileRevisionVersion, - startup_mode, - startup_flags, - command_line, - object_guid, - runtime_module_path, - NULL, - NULL); +static +void +runtime_profiler_exception_throw ( + MonoProfiler *prof, + MonoObject *exc) +{ + ep_rt_mono_write_event_exception_thrown (exc); +} - if (execution_checkpoints) { - ep_rt_execution_checkpoint_array_iterator_t execution_checkpoints_iterator = ep_rt_execution_checkpoint_array_iterator_begin (execution_checkpoints); - while (!ep_rt_execution_checkpoint_array_iterator_end (execution_checkpoints, &execution_checkpoints_iterator)) { - EventPipeExecutionCheckpoint *checkpoint = ep_rt_execution_checkpoint_array_iterator_value (&execution_checkpoints_iterator); - FireEtwExecutionCheckpointDCEnd ( - clr_instance_get_id (), - checkpoint->name, - checkpoint->timestamp, - NULL, - NULL); - ep_rt_execution_checkpoint_array_iterator_next (&execution_checkpoints_iterator); - } - } +static +void +runtime_profiler_exception_clause ( + MonoProfiler *prof, + MonoMethod *method, + uint32_t clause_num, + MonoExceptionEnum clause_type, + MonoObject *exc) +{ + ep_rt_mono_write_event_exception_clause (method, clause_num, clause_type, exc); +} - FireEtwDCEndInit_V1 ( - clr_instance_get_id (), - NULL, - NULL); +static +void +runtime_profiler_monitor_contention ( + MonoProfiler *prof, + MonoObject *obj) +{ + ep_rt_mono_write_event_monitor_contention_start (obj); +} - eventpipe_execute_rundown ( - fire_domain_rundown_events_func, - fire_assembly_rundown_events_func, - fire_method_rundown_events_func); +static +void +runtime_profiler_monitor_acquired ( + MonoProfiler *prof, + MonoObject *obj) +{ + ep_rt_mono_write_event_monitor_contention_stop (obj); +} - FireEtwDCEndComplete_V1 ( - clr_instance_get_id (), - NULL, - NULL); +static +void +runtime_profiler_monitor_failed ( + MonoProfiler *prof, + MonoObject *obj) +{ + ep_rt_mono_write_event_monitor_contention_stop (obj); } -bool -ep_rt_mono_write_event_ee_startup_start (void) +static +void +runtime_profiler_jit_code_buffer ( + MonoProfiler *prof, + const mono_byte *buffer, + uint64_t size, + MonoProfilerCodeBufferType type, + const void *data) { - return FireEtwEEStartupStart_V1 ( - clr_instance_get_id (), - NULL, - NULL); + ep_rt_mono_write_event_method_jit_memory_allocated_for_code ((const uint8_t *)buffer, size, type, data); } -bool -ep_rt_mono_write_event_jit_start (MonoMethod *method) +void +EventPipeEtwCallbackDotNETRuntime ( + 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) { - if (!EventEnabledMethodJittingStarted_V1 ()) - return true; + ep_rt_config_requires_lock_not_held (); - //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. - if (method) { - uint64_t method_id = 0; - uint64_t module_id = 0; - uint32_t code_size = 0; - uint32_t method_token = 0; - char *method_namespace = NULL; - const char *method_name = NULL; - char *method_signature = NULL; + EP_ASSERT(is_enabled == 0 || is_enabled == 1) ; + EP_ASSERT (_ep_rt_dotnet_runtime_profiler_provider != NULL); - //TODO: SendMethodDetailsEvent + match_any_keywords = (is_enabled == 1) ? match_any_keywords : 0; - method_id = (uint64_t)method; + EP_LOCK_ENTER (section1) + uint64_t enabled_keywords = MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask; - if (!method->dynamic) - method_token = method->token; + if (profiler_callback_is_enabled(match_any_keywords, JIT_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, JIT_KEYWORD)) { + mono_profiler_set_jit_begin_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_jit_begin); + mono_profiler_set_jit_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_jit_failed); + mono_profiler_set_jit_done_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_jit_done); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, JIT_KEYWORD)) { + mono_profiler_set_jit_begin_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + mono_profiler_set_jit_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + mono_profiler_set_jit_done_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + } + } - if (!mono_method_has_no_body (method)) { - ERROR_DECL (error); - MonoMethodHeader *header = mono_method_get_header_internal (method, error); - if (header) - code_size = header->code_size; + if (profiler_callback_is_enabled(match_any_keywords, LOADER_KEYWORD)) { + if (!profiler_callback_is_enabled(enabled_keywords, LOADER_KEYWORD)) { + mono_profiler_set_image_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_image_loaded); + mono_profiler_set_image_unloaded_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_image_unloaded); + mono_profiler_set_assembly_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_assembly_loaded); + mono_profiler_set_assembly_unloaded_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_assembly_unloaded); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, LOADER_KEYWORD)) { + mono_profiler_set_image_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + mono_profiler_set_image_unloaded_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + mono_profiler_set_assembly_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + mono_profiler_set_assembly_unloaded_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + } } - method_name = method->name; - method_signature = mono_signature_full_name (method->signature); + 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)) { + 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)) { + 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); + } + } - if (method->klass) { - module_id = (uint64_t)m_class_get_image (method->klass); - method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL); + if (profiler_callback_is_enabled(match_any_keywords, TYPE_DIAGNOSTIC_KEYWORD)) { + if (!profiler_callback_is_enabled(enabled_keywords, TYPE_DIAGNOSTIC_KEYWORD)) { + mono_profiler_set_class_loading_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_class_loading); + mono_profiler_set_class_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_class_failed); + mono_profiler_set_class_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_class_loaded); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, TYPE_DIAGNOSTIC_KEYWORD)) { + mono_profiler_set_class_loading_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + mono_profiler_set_class_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + mono_profiler_set_class_loaded_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + } } - FireEtwMethodJittingStarted_V1 ( - method_id, - module_id, - method_token, - code_size, - method_namespace, - method_name, - method_signature, - clr_instance_get_id (), - NULL, - NULL); + if (profiler_callback_is_enabled(match_any_keywords, EXCEPTION_KEYWORD)) { + if (!profiler_callback_is_enabled(enabled_keywords, EXCEPTION_KEYWORD)) { + mono_profiler_set_exception_throw_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_exception_throw); + mono_profiler_set_exception_clause_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_exception_clause); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, EXCEPTION_KEYWORD)) { + mono_profiler_set_exception_throw_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + mono_profiler_set_exception_clause_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + } + } - g_free (method_namespace); - g_free (method_signature); - } + if (profiler_callback_is_enabled(match_any_keywords, CONTENTION_KEYWORD)) { + if (!profiler_callback_is_enabled(enabled_keywords, CONTENTION_KEYWORD)) { + mono_profiler_set_monitor_contention_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_monitor_contention); + mono_profiler_set_monitor_acquired_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_monitor_acquired); + mono_profiler_set_monitor_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, runtime_profiler_monitor_failed); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, CONTENTION_KEYWORD)) { + mono_profiler_set_monitor_contention_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + mono_profiler_set_monitor_acquired_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + mono_profiler_set_monitor_failed_callback (_ep_rt_dotnet_runtime_profiler_provider, NULL); + } + } - return true; + MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.Level = level; + MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords; + MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); + EP_LOCK_EXIT (section1) + +ep_on_exit: + ep_rt_config_requires_lock_not_held (); + return; + +ep_on_error: + ep_exit_error_handler (); } -bool -ep_rt_mono_write_event_method_il_to_native_map ( - MonoMethod *method, - MonoJitInfo *ji) +void +EventPipeEtwCallbackDotNETRuntimeRundown ( + 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) { - if (!EventEnabledMethodILToNativeMap ()) - return true; + MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.Level = level; + MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords; + MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); +} - if (method) { - // Under netcore we only have root domain. - MonoDomain *root_domain = mono_get_root_domain (); +void +EventPipeEtwCallbackDotNETRuntimePrivate ( + 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) +{ + MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.Level = level; + MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords; + MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); +} - uint64_t method_id = (uint64_t)method; - uint32_t fixed_buffer [64]; - uint8_t *buffer = NULL; +void +EventPipeEtwCallbackDotNETRuntimeStress ( + 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) +{ + MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.Level = level; + MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords; + MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); +} - uint16_t offset_entries = 0; - uint32_t *il_offsets = NULL; - uint32_t *native_offsets = NULL; +static +void +mono_profiler_app_domain_loading ( + MonoProfiler *prof, + MonoDomain *domain) +{ + if (!EventEnabledMonoProfilerAppDomainLoading ()) + return; - MonoDebugMethodJitInfo *debug_info = method ? mono_debug_find_method (method, root_domain) : NULL; - if (debug_info) { - if (offset_entries != 0) { - offset_entries = debug_info->num_line_numbers; - size_t needed_size = (offset_entries * sizeof (uint32_t) * 2); - if (needed_size > sizeof (fixed_buffer)) { - buffer = g_new (uint8_t, needed_size); - il_offsets = (uint32_t*)buffer; - } else { - il_offsets = fixed_buffer; - } - if (il_offsets) { - native_offsets = il_offsets + offset_entries; - for (int offset_count = 0; offset_count < offset_entries; ++offset_count) { - il_offsets [offset_count] = debug_info->line_numbers [offset_count].il_offset; - native_offsets [offset_count] = debug_info->line_numbers [offset_count].native_offset; - } - } - } + uint64_t domain_id = (uint64_t)domain; + FireEtwMonoProfilerAppDomainLoading ( + clr_instance_get_id (), + domain_id, + NULL, + NULL); +} - mono_debug_free_method_jit_info (debug_info); - } +static +void +mono_profiler_app_domain_loaded ( + MonoProfiler *prof, + MonoDomain *domain) +{ + if (!EventEnabledMonoProfilerAppDomainLoaded ()) + return; - if (!il_offsets && !native_offsets) { - // No IL offset -> Native offset mapping available. Put all code on IL offset 0. - EP_ASSERT (sizeof (fixed_buffer) >= sizeof (uint32_t) * 2); - offset_entries = 1; - il_offsets = fixed_buffer; - native_offsets = il_offsets + offset_entries; - il_offsets [0] = 0; - native_offsets [0] = ji ? (uint32_t)ji->code_size : 0; - } + uint64_t domain_id = (uint64_t)domain; + FireEtwMonoProfilerAppDomainLoaded ( + clr_instance_get_id (), + domain_id, + NULL, + NULL); +} + +static +void +mono_profiler_app_domain_unloading ( + MonoProfiler *prof, + MonoDomain *domain) +{ + if (!EventEnabledMonoProfilerAppDomainUnloading ()) + return; + + uint64_t domain_id = (uint64_t)domain; + FireEtwMonoProfilerAppDomainUnloading ( + clr_instance_get_id (), + domain_id, + NULL, + NULL); +} - FireEtwMethodILToNativeMap ( - method_id, - 0, - 0, - offset_entries, - il_offsets, - native_offsets, - clr_instance_get_id (), - NULL, - NULL); +static +void +mono_profiler_app_domain_unloaded ( + MonoProfiler *prof, + MonoDomain *domain) +{ + if (!EventEnabledMonoProfilerAppDomainUnloaded ()) + return; - g_free (buffer); - } + uint64_t domain_id = (uint64_t)domain; + FireEtwMonoProfilerAppDomainUnloaded ( + clr_instance_get_id (), + domain_id, + NULL, + NULL); +} - return true; +static +void +mono_profiler_app_domain_name ( + MonoProfiler *prof, + MonoDomain *domain, + const char *name) +{ + if (!EventEnabledMonoProfilerAppDomainName ()) + return; + + uint64_t domain_id = (uint64_t)domain; + FireEtwMonoProfilerAppDomainName ( + clr_instance_get_id (), + domain_id, + (const ep_char8_t *)(name ? name : ""), + NULL, + NULL); } -bool -ep_rt_mono_write_event_method_load ( +static +inline +void +get_jit_data ( MonoMethod *method, - MonoJitInfo *ji) + uint64_t *method_id, + uint64_t *module_id, + uint32_t *method_token) { - if (!EventEnabledMethodLoad_V1 () && !EventEnabledMethodLoadVerbose_V1()) - return true; + *method_id = (uint64_t)method; + *module_id = 0; + *method_token = 0; - //TODO: Optimize string formatting into functions accepting GString to reduce heap alloc. if (method) { - uint64_t method_id = 0; - uint64_t module_id = 0; - uint64_t method_code_start = ji ? (uint64_t)ji->code_start : 0; - uint32_t method_code_size = ji ? (uint32_t)ji->code_size : 0; - uint32_t method_token = 0; - uint32_t method_flags = 0; - uint8_t kind = MONO_CLASS_DEF; - char *method_namespace = NULL; - const char *method_name = NULL; - char *method_signature = NULL; - bool verbose = (MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.Level >= (uint8_t)EP_EVENT_LEVEL_VERBOSE); - - method_id = (uint64_t)method; + *method_token = method->token; + if (method->klass) + *module_id = (uint64_t)m_class_get_image (method->klass); + } +} - if (!method->dynamic) - method_token = method->token; +static +void +mono_profiler_jit_begin ( + MonoProfiler *prof, + MonoMethod *method) +{ + if (!EventEnabledMonoProfilerJitBegin()) + return; - if (ji && mono_jit_info_get_generic_sharing_context (ji)) { - method_flags |= METHOD_FLAGS_SHARED_GENERIC_METHOD; - verbose = true; - } + uint64_t method_id; + uint64_t module_id; + uint32_t method_token; - if (method->dynamic) { - method_flags |= METHOD_FLAGS_DYNAMIC_METHOD; - verbose = true; - } + get_jit_data (method, &method_id, &module_id, &method_token); - if (ji && !ji->from_aot && !ji->from_llvm) { - method_flags |= METHOD_FLAGS_JITTED_METHOD; - if (method->wrapper_type != MONO_WRAPPER_NONE) - method_flags |= METHOD_FLAGS_JITTED_HELPER_METHOD; - } + FireEtwMonoProfilerJitBegin ( + clr_instance_get_id (), + method_id, + module_id, + method_token, + NULL, + NULL); +} - if (method->is_generic || method->is_inflated) { - method_flags |= METHOD_FLAGS_GENERIC_METHOD; - verbose = true; - } +static +void +mono_profiler_jit_failed ( + MonoProfiler *prof, + MonoMethod *method) +{ + if (!EventEnabledMonoProfilerJitFailed()) + return; - if (method->klass) { - module_id = (uint64_t)m_class_get_image (method->klass); - kind = m_class_get_class_kind (method->klass); - if (kind == MONO_CLASS_GTD || kind == MONO_CLASS_GINST) - method_flags |= METHOD_FLAGS_GENERIC_METHOD; - } + uint64_t method_id; + uint64_t module_id; + uint32_t method_token; - //TODO: SendMethodDetailsEvent + get_jit_data (method, &method_id, &module_id, &method_token); - if (verbose) { - method_name = method->name; - method_signature = mono_signature_full_name (method->signature); + FireEtwMonoProfilerJitFailed ( + clr_instance_get_id (), + method_id, + module_id, + method_token, + NULL, + NULL); +} - if (method->klass) - method_namespace = mono_type_get_name_full (m_class_get_byval_arg (method->klass), MONO_TYPE_NAME_FORMAT_IL); +static +void +mono_profiler_jit_done ( + MonoProfiler *prof, + MonoMethod *method, + MonoJitInfo *ji) +{ + if (!EventEnabledMonoProfilerJitDone()) + return; - FireEtwMethodLoadVerbose_V1 ( - method_id, - module_id, - method_code_start, - method_code_size, - method_token, - method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION, - method_namespace, - method_name, - method_signature, - clr_instance_get_id (), - NULL, - NULL); + uint64_t method_id; + uint64_t module_id; + uint32_t method_token; - if (ji && (ji->from_aot || ji->from_llvm)) - FireEtwMethodLoadVerbose_V1 ( - method_id, - module_id, - method_code_start, - method_code_size, - method_token, - method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION, - method_namespace, - method_name, - method_signature, - clr_instance_get_id (), - NULL, - NULL); - } else { - FireEtwMethodLoad_V1 ( - method_id, - module_id, - method_code_start, - method_code_size, - method_token, - method_flags | METHOD_FLAGS_EXTENT_HOT_SECTION, - clr_instance_get_id (), - NULL, - NULL); + get_jit_data (method, &method_id, &module_id, &method_token); - if (ji && (ji->from_aot || ji->from_llvm)) - FireEtwMethodLoad_V1 ( - method_id, - module_id, - method_code_start, - method_code_size, - method_token, - method_flags | METHOD_FLAGS_EXTENT_COLD_SECTION, - clr_instance_get_id (), - NULL, - NULL); - } + FireEtwMonoProfilerJitDone ( + clr_instance_get_id (), + method_id, + module_id, + method_token, + NULL, + NULL); +} - g_free (method_namespace); - g_free (method_signature); - } +static +void +mono_profiler_jit_chunk_created ( + MonoProfiler *prof, + const mono_byte *chunk, + uintptr_t size) +{ + if (!EventEnabledMonoProfilerJitChunkCreated()) + return; - return true; + FireEtwMonoProfilerJitChunkCreated ( + clr_instance_get_id (), + chunk, + (uint64_t)size, + NULL, + NULL); } static -bool -get_module_event_data ( - MonoImage *image, - ModuleEventData *module_data) +void +mono_profiler_jit_chunk_destroyed ( + MonoProfiler *prof, + const mono_byte *chunk) { - if (image && module_data) { - memset (module_data->signature, 0, EP_GUID_SIZE); + if (!EventEnabledMonoProfilerJitChunkDestroyed()) + return; - // Under netcore we only have root domain. - MonoDomain *root_domain = mono_get_root_domain (); + FireEtwMonoProfilerJitChunkDestroyed ( + clr_instance_get_id (), + chunk, + NULL, + NULL); +} - module_data->domain_id = (uint64_t)root_domain; - module_data->module_id = (uint64_t)image; - module_data->assembly_id = (uint64_t)image->assembly; +static +void +mono_profiler_jit_code_buffer ( + MonoProfiler *prof, + const mono_byte *buffer, + uint64_t size, + MonoProfilerCodeBufferType type, + const void *data) +{ + if (!EventEnabledMonoProfilerJitCodeBuffer()) + return; - // TODO: Extract all module IL/Native paths and pdb metadata when available. - module_data->module_il_path = ""; - module_data->module_il_pdb_path = ""; - module_data->module_native_path = ""; - module_data->module_native_pdb_path = ""; + FireEtwMonoProfilerJitCodeBuffer ( + clr_instance_get_id (), + buffer, + size, + (uint8_t)type, + NULL, + NULL); +} - module_data->module_il_pdb_age = 0; - module_data->module_native_pdb_age = 0; +static +inline +void +get_class_data ( + MonoClass *klass, + uint64_t *class_id, + uint64_t *module_id, + ep_char8_t **class_name) +{ + *class_id = (uint64_t)klass; + *module_id = 0; - module_data->reserved_flags = 0; + if (klass) + *module_id = (uint64_t)m_class_get_image (klass); - // Netcore has a 1:1 between assemblies and modules, so its always a manifest module. - module_data->module_flags = MODULE_FLAGS_MANIFEST_MODULE; - if (image->dynamic) - module_data->module_flags |= MODULE_FLAGS_DYNAMIC_MODULE; - if (image->aot_module) - module_data->module_flags |= MODULE_FLAGS_NATIVE_MODULE; + if (klass && class_name) + *class_name = (ep_char8_t *)mono_type_get_name_full (m_class_get_byval_arg (klass), MONO_TYPE_NAME_FORMAT_IL); + else if (class_name) + *class_name = NULL; +} - module_data->module_il_path = image->filename ? image->filename : ""; - } +static +void +mono_profiler_class_loading ( + MonoProfiler *prof, + MonoClass *klass) +{ + if (!EventEnabledMonoProfilerClassLoading()) + return; - return true; + uint64_t class_id; + uint64_t module_id; + + get_class_data (klass, &class_id, &module_id, NULL); + + FireEtwMonoProfilerClassLoading ( + clr_instance_get_id (), + class_id, + module_id, + NULL, + NULL); } -bool -ep_rt_mono_write_event_module_load (MonoImage *image) +static +void +mono_profiler_class_failed ( + MonoProfiler *prof, + MonoClass *klass) { - if (!EventEnabledModuleLoad_V2 () && !EventEnabledDomainModuleLoad_V1()) - return true; + if (!EventEnabledMonoProfilerClassFailed()) + return; - if (image) { - ModuleEventData module_data; - if (get_module_event_data (image, &module_data)) { - FireEtwModuleLoad_V2 ( - module_data.module_id, - module_data.assembly_id, - module_data.module_flags, - module_data.reserved_flags, - module_data.module_il_path, - module_data.module_native_path, - clr_instance_get_id (), - module_data.signature, - module_data.module_il_pdb_age, - module_data.module_il_pdb_path, - module_data.signature, - module_data.module_native_pdb_age, - module_data.module_native_pdb_path, - NULL, - NULL); + uint64_t class_id; + uint64_t module_id; - FireEtwDomainModuleLoad_V1 ( - module_data.module_id, - module_data.assembly_id, - module_data.domain_id, - module_data.module_flags, - module_data.reserved_flags, - module_data.module_il_path, - module_data.module_native_path, - clr_instance_get_id (), - NULL, - NULL); - } - } + get_class_data (klass, &class_id, &module_id, NULL); - return true; + FireEtwMonoProfilerClassFailed ( + clr_instance_get_id (), + class_id, + module_id, + NULL, + NULL); } -bool -ep_rt_mono_write_event_module_unload (MonoImage *image) +static +void +mono_profiler_class_loaded ( + MonoProfiler *prof, + MonoClass *klass) { - if (!EventEnabledModuleUnload_V2()) - return true; + if (!EventEnabledMonoProfilerClassLoaded()) + return; - if (image) { - ModuleEventData module_data; - if (get_module_event_data (image, &module_data)) { - FireEtwModuleUnload_V2 ( - module_data.module_id, - module_data.assembly_id, - module_data.module_flags, - module_data.reserved_flags, - module_data.module_il_path, - module_data.module_native_path, - clr_instance_get_id (), - module_data.signature, - module_data.module_il_pdb_age, - module_data.module_il_pdb_path, - module_data.signature, - module_data.module_native_pdb_age, - module_data.module_native_pdb_path, - NULL, - NULL); - } - } + uint64_t class_id; + uint64_t module_id; + ep_char8_t *class_name; - return true; + get_class_data (klass, &class_id, &module_id, &class_name); + + FireEtwMonoProfilerClassLoaded ( + clr_instance_get_id (), + class_id, + module_id, + class_name ? class_name : "", + NULL, + NULL); + + g_free (class_name); } static -bool -get_assembly_event_data ( - MonoAssembly *assembly, - AssemblyEventData *assembly_data) +inline +void +get_vtable_data ( + MonoVTable *vtable, + uint64_t *vtable_id, + uint64_t *class_id, + uint64_t *domain_id) { - if (assembly && assembly_data) { - // Under netcore we only have root domain. - MonoDomain *root_domain = mono_get_root_domain (); + *vtable_id = (uint64_t)vtable; + *class_id = 0; + *domain_id = 0; - assembly_data->domain_id = (uint64_t)root_domain; - assembly_data->assembly_id = (uint64_t)assembly; - assembly_data->binding_id = 0; + if (vtable) { + *class_id = (uint64_t)mono_vtable_class_internal (vtable); + *domain_id = (uint64_t)mono_vtable_domain_internal (vtable); + } +} - assembly_data->assembly_flags = 0; - if (assembly->dynamic) - assembly_data->assembly_flags |= ASSEMBLY_FLAGS_DYNAMIC_ASSEMBLY; +static +void +mono_profiler_vtable_loading ( + MonoProfiler *prof, + MonoVTable *vtable) +{ + if (!EventEnabledMonoProfilerVTableLoading()) + return; - if (assembly->image && assembly->image->aot_module) - assembly_data->assembly_flags |= ASSEMBLY_FLAGS_NATIVE_ASSEMBLY; + uint64_t vtable_id; + uint64_t class_id; + uint64_t domain_id; - assembly_data->assembly_name = mono_stringify_assembly_name (&assembly->aname); - } + get_vtable_data (vtable, &vtable_id, &class_id, &domain_id); - return true; + FireEtwMonoProfilerVTableLoading ( + clr_instance_get_id (), + vtable_id, + class_id, + domain_id, + NULL, + NULL); } -bool -ep_rt_mono_write_event_assembly_load (MonoAssembly *assembly) +static +void +mono_profiler_vtable_failed ( + MonoProfiler *prof, + MonoVTable *vtable) { - if (!EventEnabledAssemblyLoad_V1 ()) - return true; - - if (assembly) { - AssemblyEventData assembly_data; - if (get_assembly_event_data (assembly, &assembly_data)) { - FireEtwAssemblyLoad_V1 ( - assembly_data.assembly_id, - assembly_data.domain_id, - assembly_data.binding_id, - assembly_data.assembly_flags, - assembly_data.assembly_name, - clr_instance_get_id (), - NULL, - NULL); + if (!EventEnabledMonoProfilerVTableFailed()) + return; - g_free (assembly_data.assembly_name); - } - } + uint64_t vtable_id; + uint64_t class_id; + uint64_t domain_id; - return true; + get_vtable_data (vtable, &vtable_id, &class_id, &domain_id); + + FireEtwMonoProfilerVTableFailed ( + clr_instance_get_id (), + vtable_id, + class_id, + domain_id, + NULL, + NULL); } -bool -ep_rt_mono_write_event_assembly_unload (MonoAssembly *assembly) +static +void +mono_profiler_vtable_loaded ( + MonoProfiler *prof, + MonoVTable *vtable) { - if (!EventEnabledAssemblyUnload_V1 ()) - return true; - - if (assembly) { - AssemblyEventData assembly_data; - if (get_assembly_event_data (assembly, &assembly_data)) { - FireEtwAssemblyUnload_V1 ( - assembly_data.assembly_id, - assembly_data.domain_id, - assembly_data.binding_id, - assembly_data.assembly_flags, - assembly_data.assembly_name, - clr_instance_get_id (), - NULL, - NULL); + if (!EventEnabledMonoProfilerVTableLoaded()) + return; - g_free (assembly_data.assembly_name); - } - } + uint64_t vtable_id; + uint64_t class_id; + uint64_t domain_id; - return true; + get_vtable_data (vtable, &vtable_id, &class_id, &domain_id); + + FireEtwMonoProfilerVTableLoaded ( + clr_instance_get_id (), + vtable_id, + class_id, + domain_id, + NULL, + NULL); } -bool -ep_rt_mono_write_event_thread_created (ep_rt_thread_id_t tid) +static +void +mono_profiler_module_loading ( + MonoProfiler *prof, + MonoImage *image) { - if (!EventEnabledThreadCreated ()) - return true; - - uint64_t managed_thread = 0; - uint64_t native_thread_id = ep_rt_thread_id_t_to_uint64_t (tid); - uint64_t managed_thread_id = 0; - uint32_t flags = 0; + if (!EventEnabledMonoProfilerModuleLoading ()) + return; + + FireEtwMonoProfilerModuleLoading ( + clr_instance_get_id (), + (uint64_t)image, + NULL, + NULL); +} - MonoThread *thread = mono_thread_current (); - if (thread && mono_thread_info_get_tid (thread->thread_info) == tid) { - managed_thread_id = (uint64_t)mono_thread_get_managed_id (thread); - managed_thread = (uint64_t)thread; +static +void +mono_profiler_module_failed ( + MonoProfiler *prof, + MonoImage *image) +{ + if (!EventEnabledMonoProfilerModuleFailed ()) + return; - switch (mono_thread_info_get_flags (thread->thread_info)) { - case MONO_THREAD_INFO_FLAGS_NO_GC: - case MONO_THREAD_INFO_FLAGS_NO_SAMPLE: - flags |= THREAD_FLAGS_GC_SPECIAL; - } + FireEtwMonoProfilerModuleFailed ( + clr_instance_get_id (), + (uint64_t)image, + NULL, + NULL); +} - if (mono_gc_is_finalizer_thread (thread)) - flags |= THREAD_FLAGS_FINALIZER; +static +void +mono_profiler_module_loaded ( + MonoProfiler *prof, + MonoImage *image) +{ + if (!EventEnabledMonoProfilerModuleLoaded ()) + return; + + uint64_t module_id = (uint64_t)image; + const ep_char8_t *module_path = NULL; + const ep_char8_t *module_guid = NULL; - if (thread->threadpool_thread) - flags |= THREAD_FLAGS_THREADPOOL_WORKER; + if (image) { + ModuleEventData module_data; + if (get_module_event_data (image, &module_data)) + module_path = (const ep_char8_t *)module_data.module_il_path; + module_guid = (const ep_char8_t *)mono_image_get_guid (image); } - FireEtwThreadCreated ( - managed_thread, - (uint64_t)mono_get_root_domain (), - flags, - managed_thread_id, - native_thread_id, + FireEtwMonoProfilerModuleLoaded ( clr_instance_get_id (), + module_id, + module_path ? module_path : "", + module_guid ? module_guid : "", NULL, NULL); +} - return true; +static +void +mono_profiler_module_unloading ( + MonoProfiler *prof, + MonoImage *image) +{ + if (!EventEnabledMonoProfilerModuleUnloading ()) + return; + + FireEtwMonoProfilerModuleUnloading ( + clr_instance_get_id (), + (uint64_t)image, + NULL, + NULL); } -bool -ep_rt_mono_write_event_thread_terminated (ep_rt_thread_id_t tid) +static +void +mono_profiler_module_unloaded ( + MonoProfiler *prof, + MonoImage *image) { - if (!EventEnabledThreadTerminated ()) - return true; + if (!EventEnabledMonoProfilerModuleUnloaded ()) + return; + + uint64_t module_id = (uint64_t)image; + const ep_char8_t *module_path = NULL; + const ep_char8_t *module_guid = NULL; - uint64_t managed_thread = 0; - MonoThread *thread = mono_thread_current (); - if (thread && mono_thread_info_get_tid (thread->thread_info) == tid) - managed_thread = (uint64_t)thread; + if (image) { + ModuleEventData module_data; + if (get_module_event_data (image, &module_data)) + module_path = (const ep_char8_t *)module_data.module_il_path; + module_guid = (const ep_char8_t *)mono_image_get_guid (image); + } - FireEtwThreadTerminated ( - managed_thread, - (uint64_t)mono_get_root_domain (), + FireEtwMonoProfilerModuleUnloaded ( clr_instance_get_id (), + module_id, + module_path ? module_path : "", + module_guid ? module_guid : "", NULL, NULL); - - return true; } static -uint32_t -get_type_start_id (MonoType *type) +inline +void +get_assembly_data ( + MonoAssembly *assembly, + uint64_t *assembly_id, + uint64_t *module_id, + ep_char8_t **assembly_name) { - uint32_t start_id = (uint32_t)(uintptr_t)type; + *assembly_id = (uint64_t)assembly; + *module_id = 0; - start_id = (((start_id * 215497) >> 16) ^ ((start_id * 1823231) + start_id)); - - // Mix in highest bits on 64-bit systems only - if (sizeof (type) > 4) - start_id = start_id ^ (((uint64_t)type >> 31) >> 1); + if (assembly) + *module_id = (uint64_t)mono_assembly_get_image_internal (assembly); - return start_id; + if (assembly && assembly_name) + *assembly_name = (ep_char8_t *)mono_stringify_assembly_name (&assembly->aname); + else if (assembly_name) + *assembly_name = NULL; } -bool -ep_rt_mono_write_event_type_load_start (MonoType *type) +static +void +mono_profiler_assembly_loading ( + MonoProfiler *prof, + MonoAssembly *assembly) { - if (!EventEnabledTypeLoadStart ()) - return true; + if (!EventEnabledMonoProfilerAssemblyLoading ()) + return; + + uint64_t assembly_id; + uint64_t module_id; - FireEtwTypeLoadStart ( - get_type_start_id (type), + get_assembly_data (assembly, &assembly_id, &module_id, NULL); + + FireEtwMonoProfilerAssemblyLoading ( clr_instance_get_id (), + assembly_id, + module_id, NULL, NULL); - - return true; } -bool -ep_rt_mono_write_event_type_load_stop (MonoType *type) +static +void +mono_profiler_assembly_loaded ( + MonoProfiler *prof, + MonoAssembly *assembly) { - if (!EventEnabledTypeLoadStop ()) - return true; + if (!EventEnabledMonoProfilerAssemblyLoaded ()) + return; - char *type_name = NULL; - if (type) - type_name = mono_type_get_name_full (type, MONO_TYPE_NAME_FORMAT_IL); + uint64_t assembly_id; + uint64_t module_id; + ep_char8_t *assembly_name; - FireEtwTypeLoadStop ( - get_type_start_id (type), + get_assembly_data (assembly, &assembly_id, &module_id, &assembly_name); + + FireEtwMonoProfilerAssemblyLoaded ( clr_instance_get_id (), - 6 /* CLASS_LOADED */, - (uint64_t)type, - type_name, + assembly_id, + module_id, + assembly_name ? assembly_name : "", NULL, NULL); - g_free (type_name); - - return true; + g_free (assembly_name); } static -gboolean -get_exception_ip_func ( - MonoStackFrameInfo *frame, - MonoContext *ctx, - void *data) -{ - *(uintptr_t *)data = (uintptr_t)MONO_CONTEXT_GET_IP (ctx); - return TRUE; -} - -bool -ep_rt_mono_write_event_exception_thrown (MonoObject *obj) +void +mono_profiler_assembly_unloading ( + MonoProfiler *prof, + MonoAssembly *assembly) { - if (!EventEnabledExceptionThrown_V1 ()) - return true; - - if (obj) { - ERROR_DECL (error); - char *type_name = NULL; - char *exception_message = NULL; - uint16_t flags = 0; - uint32_t hresult = 0; - uintptr_t ip = 0; - - if (mono_object_isinst_checked ((MonoObject *) obj, mono_get_exception_class (), error)) { - MonoException *exception = (MonoException *)obj; - flags |= EXCEPTION_THROWN_FLAGS_IS_CLS_COMPLIANT; - if (exception->inner_ex) - flags |= EXCEPTION_THROWN_FLAGS_HAS_INNER; - exception_message = ep_rt_utf16_to_utf8_string (mono_string_chars_internal (exception->message), mono_string_length_internal (exception->message)); - hresult = exception->hresult; - } + if (!EventEnabledMonoProfilerAssemblyUnloading ()) + return; + + uint64_t assembly_id; + uint64_t module_id; - if (mono_get_eh_callbacks ()->mono_walk_stack_with_ctx) - mono_get_eh_callbacks ()->mono_walk_stack_with_ctx (get_exception_ip_func, NULL, MONO_UNWIND_SIGNAL_SAFE, (void *)&ip); + get_assembly_data (assembly, &assembly_id, &module_id, NULL); - type_name = mono_type_get_name_full (m_class_get_byval_arg (mono_object_class (obj)), MONO_TYPE_NAME_FORMAT_IL); + FireEtwMonoProfilerAssemblyUnloading ( + clr_instance_get_id (), + assembly_id, + module_id, + NULL, + NULL); +} - FireEtwExceptionThrown_V1 ( - type_name, - exception_message, - (void *)&ip, - hresult, - flags, - clr_instance_get_id (), - NULL, - NULL); +static +void +mono_profiler_assembly_unloaded ( + MonoProfiler *prof, + MonoAssembly *assembly) +{ + if (!EventEnabledMonoProfilerAssemblyUnloaded ()) + return; - if (!mono_component_profiler_clauses_enabled ()) { - FireEtwExceptionThrownStop ( - NULL, - NULL); - } + uint64_t assembly_id; + uint64_t module_id; + ep_char8_t *assembly_name; - g_free (exception_message); - g_free (type_name); + get_assembly_data (assembly, &assembly_id, &module_id, &assembly_name); - mono_error_cleanup (error); - } + FireEtwMonoProfilerAssemblyUnloaded ( + clr_instance_get_id (), + assembly_id, + module_id, + assembly_name ? assembly_name : "", + NULL, + NULL); - return true; + g_free (assembly_name); } -bool -ep_rt_mono_write_event_exception_clause ( +static +void +mono_profiler_method_enter ( + MonoProfiler *prof, MonoMethod *method, - uint32_t clause_num, - MonoExceptionEnum clause_type, - MonoObject *obj) + MonoProfilerCallContext *context) { - if (!mono_component_profiler_clauses_enabled ()) - return true; - - if ((clause_type == MONO_EXCEPTION_CLAUSE_FAULT || clause_type == MONO_EXCEPTION_CLAUSE_NONE) && (!EventEnabledExceptionCatchStart() || !EventEnabledExceptionCatchStop())) - return true; - - if (clause_type == MONO_EXCEPTION_CLAUSE_FILTER && (!EventEnabledExceptionFilterStart() || !EventEnabledExceptionFilterStop())) - return true; - - if (clause_type == MONO_EXCEPTION_CLAUSE_FINALLY && (!EventEnabledExceptionFinallyStart() || !EventEnabledExceptionFinallyStop())) - return true; - - uintptr_t ip = 0; //TODO: Have profiler pass along IP of handler block. - uint64_t method_id = (uint64_t)method; - char *method_name = NULL; - - method_name = mono_method_get_name_full (method, TRUE, TRUE, MONO_TYPE_NAME_FORMAT_IL); - - if ((clause_type == MONO_EXCEPTION_CLAUSE_FAULT || clause_type == MONO_EXCEPTION_CLAUSE_NONE)) { - FireEtwExceptionCatchStart ( - (uint64_t)ip, - method_id, - (const ep_char8_t *)method_name, - clr_instance_get_id (), - NULL, - NULL); - - FireEtwExceptionCatchStop ( - NULL, - NULL); - - FireEtwExceptionThrownStop ( - NULL, - NULL); - } + if (!EventEnabledMonoProfilerMethodEnter ()) + return; - if (clause_type == MONO_EXCEPTION_CLAUSE_FILTER) { - FireEtwExceptionFilterStart ( - (uint64_t)ip, - method_id, - (const ep_char8_t *)method_name, - clr_instance_get_id (), - NULL, - NULL); + FireEtwMonoProfilerMethodEnter ( + clr_instance_get_id (), + (uint64_t)method, + NULL, + NULL); +} - FireEtwExceptionFilterStop ( - NULL, - NULL); - } +static +void +mono_profiler_method_leave ( + MonoProfiler *prof, + MonoMethod *method, + MonoProfilerCallContext *context) +{ + if (!EventEnabledMonoProfilerMethodLeave ()) + return; - if (clause_type == MONO_EXCEPTION_CLAUSE_FINALLY) { - FireEtwExceptionFinallyStart ( - (uint64_t)ip, - method_id, - (const ep_char8_t *)method_name, - clr_instance_get_id (), - NULL, - NULL); + FireEtwMonoProfilerMethodLeave ( + clr_instance_get_id (), + (uint64_t)method, + NULL, + NULL); +} - FireEtwExceptionFinallyStop ( - NULL, - NULL); - } +static +void +mono_profiler_method_tail_call ( + MonoProfiler *prof, + MonoMethod *method, + MonoMethod *target_method) +{ + if (!EventEnabledMonoProfilerMethodTailCall ()) + return; - g_free (method_name); - return true; + FireEtwMonoProfilerMethodTailCall ( + clr_instance_get_id (), + (uint64_t)method, + NULL, + NULL); } -bool -ep_rt_mono_write_event_monitor_contention_start (MonoObject *obj) +static +void +mono_profiler_method_exception_leave ( + MonoProfiler *prof, + MonoMethod *method, + MonoObject *exc) { - if (!EventEnabledContentionStart_V1 ()) - return true; + if (!EventEnabledMonoProfilerMethodExceptionLeave ()) + return; - FireEtwContentionStart_V1 ( - 0 /* ManagedContention */, + FireEtwMonoProfilerMethodExceptionLeave ( clr_instance_get_id (), + (uint64_t)method, NULL, NULL); - - return true; } -bool -ep_rt_mono_write_event_monitor_contention_stop (MonoObject *obj) +static +void +mono_profiler_method_free ( + MonoProfiler *prof, + MonoMethod *method) { - if (!EventEnabledContentionStop ()) - return true; + if (!EventEnabledMonoProfilerMethodFree ()) + return; - FireEtwContentionStop ( - 0 /* ManagedContention */, + FireEtwMonoProfilerMethodFree ( clr_instance_get_id (), + (uint64_t)method, NULL, NULL); - - return true; } -bool -ep_rt_mono_write_event_method_jit_memory_allocated_for_code ( - const uint8_t *buffer, - uint64_t size, - MonoProfilerCodeBufferType type, - const void *data) +static +void +mono_profiler_method_begin_invoke ( + MonoProfiler *prof, + MonoMethod *method) { - if (!EventEnabledMethodJitMemoryAllocatedForCode ()) - return true; - - if (type != MONO_PROFILER_CODE_BUFFER_METHOD) - return true; - - uint64_t method_id = 0; - uint64_t module_id = 0; - - if (data) { - MonoMethod *method; - method = (MonoMethod *)data; - method_id = (uint64_t)method; - if (method->klass) - module_id = (uint64_t)(uint64_t)m_class_get_image (method->klass); - } + if (!EventEnabledMonoProfilerMethodBeginInvoke ()) + return; - FireEtwMethodJitMemoryAllocatedForCode ( - method_id, - module_id, - size, - 0, - size, - 0 /* CORJIT_ALLOCMEM_DEFAULT_CODE_ALIGN */, + FireEtwMonoProfilerMethodBeginInvoke ( clr_instance_get_id (), + (uint64_t)method, NULL, NULL); - - return true; } -bool -ep_rt_write_event_threadpool_worker_thread_start ( - uint32_t active_thread_count, - uint32_t retired_worker_thread_count, - uint16_t clr_instance_id) +static +void +mono_profiler_method_end_invoke ( + MonoProfiler *prof, + MonoMethod *method) { - return FireEtwThreadPoolWorkerThreadStart ( - active_thread_count, - retired_worker_thread_count, - clr_instance_id, - NULL, - NULL) == 0 ? true : false; -} + if (!EventEnabledMonoProfilerMethodEndInvoke ()) + return; -bool -ep_rt_write_event_threadpool_worker_thread_stop ( - uint32_t active_thread_count, - uint32_t retired_worker_thread_count, - uint16_t clr_instance_id) -{ - return FireEtwThreadPoolWorkerThreadStop ( - active_thread_count, - retired_worker_thread_count, - clr_instance_id, + FireEtwMonoProfilerMethodEndInvoke ( + clr_instance_get_id (), + (uint64_t)method, NULL, - NULL) == 0 ? true : false; + NULL); } -bool -ep_rt_write_event_threadpool_worker_thread_wait ( - uint32_t active_thread_count, - uint32_t retired_worker_thread_count, - uint16_t clr_instance_id) +static +MonoProfilerCallInstrumentationFlags +mono_profiler_method_instrumentation ( + MonoProfiler *prof, + MonoMethod *method) { - return FireEtwThreadPoolWorkerThreadWait ( - active_thread_count, - retired_worker_thread_count, - clr_instance_id, - NULL, - NULL) == 0 ? true : false; -} + if (_ep_rt_dotnet_mono_profiler_provider_callspec.len > 0 && !mono_callspec_eval (method, &_ep_rt_dotnet_mono_profiler_provider_callspec)) + return MONO_PROFILER_CALL_INSTRUMENTATION_NONE; -bool -ep_rt_write_event_threadpool_worker_thread_adjustment_sample ( - double throughput, - uint16_t clr_instance_id) -{ - return FireEtwThreadPoolWorkerThreadAdjustmentSample ( - throughput, - clr_instance_id, - NULL, - NULL) == 0 ? true : false; + return MONO_PROFILER_CALL_INSTRUMENTATION_ENTER | + MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE | + MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL | + MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE; } -bool -ep_rt_write_event_threadpool_worker_thread_adjustment_adjustment ( - double average_throughput, - uint32_t networker_thread_count, - /*NativeRuntimeEventSource.ThreadAdjustmentReasonMap*/ int32_t reason, - uint16_t clr_instance_id) +static +void +mono_profiler_exception_throw ( + MonoProfiler *prof, + MonoObject *exc) { - return FireEtwThreadPoolWorkerThreadAdjustmentAdjustment ( - average_throughput, - networker_thread_count, - reason, - clr_instance_id, + if (!EventEnabledMonoProfilerExceptionThrow ()) + 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)); + + FireEtwMonoProfilerExceptionThrow ( + clr_instance_get_id (), + type_id, + SGEN_POINTER_UNTAG_ALL (exc), NULL, - NULL) == 0 ? true : false; + NULL); } -bool -ep_rt_write_event_threadpool_worker_thread_adjustment_stats ( - double duration, - double throughput, - double threadpool_worker_thread_wait, - double throughput_wave, - double throughput_error_estimate, - double average_throughput_error_estimate, - double throughput_ratio, - double confidence, - double new_control_setting, - uint16_t new_thread_wave_magnitude, - uint16_t clr_instance_id) +static +void +mono_profiler_exception_clause ( + MonoProfiler *prof, + MonoMethod *method, + uint32_t clause_num, + MonoExceptionEnum clause_type, + MonoObject *exc) { - return FireEtwThreadPoolWorkerThreadAdjustmentStats ( - duration, - throughput, - threadpool_worker_thread_wait, - throughput_wave, - throughput_error_estimate, - average_throughput_error_estimate, - throughput_ratio, - confidence, - new_control_setting, - new_thread_wave_magnitude, - clr_instance_id, + 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)); + + FireEtwMonoProfilerExceptionClause ( + clr_instance_get_id (), + (uint8_t)clause_type, + clause_num, + (uint64_t)method, + type_id, + SGEN_POINTER_UNTAG_ALL (exc), NULL, - NULL) == 0 ? true : false; + NULL); } -bool -ep_rt_write_event_threadpool_io_enqueue ( - intptr_t native_overlapped, - intptr_t overlapped, - bool multi_dequeues, - uint16_t clr_instance_id) +static +void +mono_profiler_gc_event ( + MonoProfiler *prof, + MonoProfilerGCEvent gc_event, + uint32_t generation, + mono_bool serial) { - return FireEtwThreadPoolIOEnqueue ( - (const void *)native_overlapped, - (const void *)overlapped, - multi_dequeues, - clr_instance_id, + if (!EventEnabledMonoProfilerGCEvent ()) + return; + + // TODO: Needs to be async safe. + /*FireEtwMonoProfilerGCEvent ( + clr_instance_get_id (), + (uint8_t)gc_event, + generation, NULL, - NULL) == 0 ? true : false; + NULL);*/ } -bool -ep_rt_write_event_threadpool_io_dequeue ( - intptr_t native_overlapped, - intptr_t overlapped, - uint16_t clr_instance_id) +static +void +mono_profiler_gc_allocation ( + MonoProfiler *prof, + MonoObject *object) { - return FireEtwThreadPoolIODequeue ( - (const void *)native_overlapped, - (const void *)overlapped, - clr_instance_id, + if (!EventEnabledMonoProfilerGCAllocation ()) + return; + + uint64_t vtable_id = 0; + uint64_t object_size = 0; + + if (object) { + vtable_id = (uint64_t)mono_object_get_vtable_internal (object); + object_size = (uint64_t)mono_object_get_size_internal (object); + + /* account for object alignment */ + object_size += 7; + object_size &= ~7; + } + + FireEtwMonoProfilerGCAllocation ( + clr_instance_get_id (), + vtable_id, + SGEN_POINTER_UNTAG_ALL (object), + object_size, NULL, - NULL) == 0 ? true : false; + NULL); } -bool -ep_rt_write_event_threadpool_working_thread_count ( - uint16_t count, - uint16_t clr_instance_id) +static +void +mono_profiler_gc_moves ( + MonoProfiler *prof, + MonoObject *const* objects, + uint64_t count) { - return FireEtwThreadPoolWorkingThreadCount ( - count, - clr_instance_id, - NULL, - NULL) == 0 ? true : false; + 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 ( + clr_instance_get_id (), + 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 ( + clr_instance_get_id (), + data_rest, + sizeof (GCObjectAddressData), + data, + NULL, + NULL); + }*/ } static void -profiler_jit_begin ( +mono_profiler_gc_resize ( MonoProfiler *prof, - MonoMethod *method) + uintptr_t size) { - ep_rt_mono_write_event_jit_start (method); + if (!EventEnabledMonoProfilerGCResize ()) + return; + + // TODO: Needs to be async safe. + /*FireEtwMonoProfilerGCResize ( + clr_instance_get_id (), + (uint64_t)size, + NULL, + NULL);*/ } static void -profiler_jit_failed ( +mono_profiler_gc_handle_created ( MonoProfiler *prof, - MonoMethod *method) + uint32_t handle, + MonoGCHandleType type, + MonoObject *object) { - //TODO: CoreCLR doesn't have this case, so no failure event currently exists. + if (!EventEnabledMonoProfilerGCHandleCreated ()) + return; + + FireEtwMonoProfilerGCHandleCreated ( + clr_instance_get_id (), + handle, + (uint8_t)type, + SGEN_POINTER_UNTAG_ALL (object), + NULL, + NULL); } static void -profiler_jit_done ( +mono_profiler_gc_handle_deleted ( MonoProfiler *prof, - MonoMethod *method, - MonoJitInfo *ji) + uint32_t handle, + MonoGCHandleType type) { - ep_rt_mono_write_event_method_load (method, ji); - ep_rt_mono_write_event_method_il_to_native_map (method, ji); + if (!EventEnabledMonoProfilerGCHandleDeleted ()) + return; + + FireEtwMonoProfilerGCHandleDeleted ( + clr_instance_get_id (), + handle, + (uint8_t)type, + NULL, + NULL); } static void -profiler_image_loaded ( - MonoProfiler *prof, - MonoImage *image) +mono_profiler_gc_finalizing (MonoProfiler *prof) { - if (image && image->heap_pdb.size == 0) - ep_rt_mono_write_event_module_load (image); + if (!EventEnabledMonoProfilerGCFinalizing ()) + return; + + FireEtwMonoProfilerGCFinalizing ( + clr_instance_get_id (), + NULL, + NULL); } static void -profiler_image_unloaded ( - MonoProfiler *prof, - MonoImage *image) +mono_profiler_gc_finalized (MonoProfiler *prof) { - if (image && image->heap_pdb.size == 0) - ep_rt_mono_write_event_module_unload (image); + if (!EventEnabledMonoProfilerGCFinalized ()) + return; + + FireEtwMonoProfilerGCFinalized ( + clr_instance_get_id (), + NULL, + NULL); } static void -profiler_assembly_loaded ( +mono_profiler_gc_finalizing_object ( MonoProfiler *prof, - MonoAssembly *assembly) + MonoObject *object) { - ep_rt_mono_write_event_assembly_load (assembly); + if (!EventEnabledMonoProfilerGCFinalizingObject ()) + return; + + FireEtwMonoProfilerGCFinalizingObject ( + clr_instance_get_id (), + SGEN_POINTER_UNTAG_ALL (object), + NULL, + NULL); } static void -profiler_assembly_unloaded ( +mono_profiler_gc_finalized_object ( MonoProfiler *prof, - MonoAssembly *assembly) + MonoObject * object) { - ep_rt_mono_write_event_assembly_unload (assembly); + if (!EventEnabledMonoProfilerGCFinalizedObject ()) + return; + + FireEtwMonoProfilerGCFinalizedObject ( + clr_instance_get_id (), + SGEN_POINTER_UNTAG_ALL (object), + NULL, + NULL); } static void -profiler_thread_started ( +mono_profiler_gc_root_register ( MonoProfiler *prof, - uintptr_t tid) + const mono_byte *start, + uintptr_t size, + MonoGCRootSource source, + const void * key, + const char * name) { - ep_rt_mono_write_event_thread_created (ep_rt_uint64_t_to_thread_id_t (tid)); + if (!EventEnabledMonoProfilerGCRootRegister ()) + return; + + FireEtwMonoProfilerGCRootRegister ( + clr_instance_get_id (), + start, + (uint64_t)size, + (uint8_t) source, + (uint64_t)key, + (const ep_char8_t *)(name ? name : ""), + NULL, + NULL); } static void -profiler_thread_stopped ( +mono_profiler_gc_root_unregister ( MonoProfiler *prof, - uintptr_t tid) + const mono_byte *start) { - ep_rt_mono_write_event_thread_terminated (ep_rt_uint64_t_to_thread_id_t (tid)); + if (!EventEnabledMonoProfilerGCRootUnregister ()) + return; + + FireEtwMonoProfilerGCRootUnregister ( + clr_instance_get_id (), + start, + NULL, + NULL); } static void -profiler_class_loading ( +mono_profiler_gc_roots ( MonoProfiler *prof, - MonoClass *klass) + uint64_t count, + const mono_byte *const * addresses, + MonoObject *const * objects) { - ep_rt_mono_write_event_type_load_start (m_class_get_byval_arg (klass)); + 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 ( + clr_instance_get_id (), + 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 ( + clr_instance_get_id (), + data_rest, + sizeof (GCAddressObjectData), + data, + NULL, + NULL); + }*/ } static void -profiler_class_failed ( +mono_profiler_monitor_contention ( MonoProfiler *prof, - MonoClass *klass) + MonoObject *object) { - ep_rt_mono_write_event_type_load_stop (m_class_get_byval_arg (klass)); + if (!EventEnabledMonoProfilerMonitorContention ()) + return; + + FireEtwMonoProfilerMonitorContention ( + clr_instance_get_id (), + SGEN_POINTER_UNTAG_ALL (object), + NULL, + NULL); } static void -profiler_class_loaded ( +mono_profiler_monitor_failed ( MonoProfiler *prof, - MonoClass *klass) + MonoObject *object) { - ep_rt_mono_write_event_type_load_stop (m_class_get_byval_arg (klass)); + if (!EventEnabledMonoProfilerMonitorFailed ()) + return; + + FireEtwMonoProfilerMonitorFailed ( + clr_instance_get_id (), + SGEN_POINTER_UNTAG_ALL (object), + NULL, + NULL); } static void -profiler_exception_throw ( +mono_profiler_monitor_acquired ( MonoProfiler *prof, - MonoObject *exc) + MonoObject *object) { - ep_rt_mono_write_event_exception_thrown (exc); + if (!EventEnabledMonoProfilerMonitorAcquired ()) + return; + + FireEtwMonoProfilerMonitorAcquired ( + clr_instance_get_id (), + SGEN_POINTER_UNTAG_ALL (object), + NULL, + NULL); } static void -profiler_exception_clause ( +mono_profiler_thread_started ( MonoProfiler *prof, - MonoMethod *method, - uint32_t clause_num, - MonoExceptionEnum clause_type, - MonoObject *exc) + uintptr_t tid) { - ep_rt_mono_write_event_exception_clause (method, clause_num, clause_type, exc); + if (!EventEnabledMonoProfilerThreadStarted ()) + return; + + FireEtwMonoProfilerThreadStarted ( + clr_instance_get_id (), + (uint64_t)tid, + NULL, + NULL); } static void -profiler_monitor_contention ( +mono_profiler_thread_stopping ( MonoProfiler *prof, - MonoObject *obj) + uintptr_t tid) { - ep_rt_mono_write_event_monitor_contention_start (obj); + if (!EventEnabledMonoProfilerThreadStopping ()) + return; + + FireEtwMonoProfilerThreadStopping ( + clr_instance_get_id (), + (uint64_t)tid, + NULL, + NULL); } static void -profiler_monitor_acquired ( +mono_profiler_thread_stopped ( MonoProfiler *prof, - MonoObject *obj) + uintptr_t tid) { - ep_rt_mono_write_event_monitor_contention_stop (obj); + if (!EventEnabledMonoProfilerThreadStopped ()) + return; + + FireEtwMonoProfilerThreadStopped ( + clr_instance_get_id (), + (uint64_t)tid, + NULL, + NULL); } static void -profiler_monitor_failed ( +mono_profiler_thread_exited ( MonoProfiler *prof, - MonoObject *obj) + uintptr_t tid) { - ep_rt_mono_write_event_monitor_contention_stop (obj); + if (!EventEnabledMonoProfilerThreadExited ()) + return; + + FireEtwMonoProfilerThreadExited ( + clr_instance_get_id (), + (uint64_t)tid, + NULL, + NULL); } static void -profiler_jit_code_buffer ( +mono_profiler_thread_name ( MonoProfiler *prof, - const mono_byte *buffer, - uint64_t size, - MonoProfilerCodeBufferType type, - const void *data) + uintptr_t tid, + const char *name) { - ep_rt_mono_write_event_method_jit_memory_allocated_for_code ((const uint8_t *)buffer, size, type, data); + if (!EventEnabledMonoProfilerThreadName ()) + return; + + FireEtwMonoProfilerThreadName ( + clr_instance_get_id (), + (uint64_t)tid, + (ep_char8_t *)(name ? name : ""), + NULL, + NULL); } void -EventPipeEtwCallbackDotNETRuntime ( +EventPipeEtwCallbackDotNETRuntimeMonoProfiler ( const uint8_t *source_id, unsigned long is_enabled, uint8_t level, @@ -2992,55 +4907,261 @@ EventPipeEtwCallbackDotNETRuntime ( ep_rt_config_requires_lock_not_held (); EP_ASSERT(is_enabled == 0 || is_enabled == 1) ; - EP_ASSERT (_ep_rt_mono_profiler != NULL); + EP_ASSERT (_ep_rt_dotnet_mono_profiler_provider != NULL); + + match_any_keywords = (is_enabled == 1) ? match_any_keywords : 0; EP_LOCK_ENTER (section1) - if (is_enabled == 1 && !MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.IsEnabled) { - // Add profiler callbacks for DotNETRuntime provider events. - mono_profiler_set_jit_begin_callback (_ep_rt_mono_profiler, profiler_jit_begin); - mono_profiler_set_jit_failed_callback (_ep_rt_mono_profiler, profiler_jit_failed); - mono_profiler_set_jit_done_callback (_ep_rt_mono_profiler, profiler_jit_done); - mono_profiler_set_image_loaded_callback (_ep_rt_mono_profiler, profiler_image_loaded); - mono_profiler_set_image_unloaded_callback (_ep_rt_mono_profiler, profiler_image_unloaded); - mono_profiler_set_assembly_loaded_callback (_ep_rt_mono_profiler, profiler_assembly_loaded); - mono_profiler_set_assembly_unloaded_callback (_ep_rt_mono_profiler, profiler_assembly_unloaded); - mono_profiler_set_thread_started_callback (_ep_rt_mono_profiler, profiler_thread_started); - mono_profiler_set_thread_stopped_callback (_ep_rt_mono_profiler, profiler_thread_stopped); - mono_profiler_set_class_loading_callback (_ep_rt_mono_profiler, profiler_class_loading); - mono_profiler_set_class_failed_callback (_ep_rt_mono_profiler, profiler_class_failed); - mono_profiler_set_class_loaded_callback (_ep_rt_mono_profiler, profiler_class_loaded); - mono_profiler_set_exception_throw_callback (_ep_rt_mono_profiler, profiler_exception_throw); - mono_profiler_set_exception_clause_callback (_ep_rt_mono_profiler, profiler_exception_clause); - mono_profiler_set_monitor_contention_callback (_ep_rt_mono_profiler, profiler_monitor_contention); - mono_profiler_set_monitor_acquired_callback (_ep_rt_mono_profiler, profiler_monitor_acquired); - mono_profiler_set_monitor_failed_callback (_ep_rt_mono_profiler, profiler_monitor_failed); - mono_profiler_set_jit_code_buffer_callback (_ep_rt_mono_profiler, profiler_jit_code_buffer); - } else if (is_enabled == 0 && MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.IsEnabled) { - // Remove profiler callbacks for DotNETRuntime provider events. - mono_profiler_set_jit_code_buffer_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_monitor_failed_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_monitor_acquired_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_monitor_contention_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_exception_clause_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_exception_throw_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_class_loaded_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_class_failed_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_class_loading_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_thread_started_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_thread_started_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_assembly_unloaded_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_assembly_loaded_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_image_unloaded_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_image_loaded_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_jit_done_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_jit_failed_callback (_ep_rt_mono_profiler, NULL); - mono_profiler_set_jit_begin_callback (_ep_rt_mono_profiler, NULL); + uint64_t enabled_keywords = MICROSOFT_DOTNETRUNTIME_MONO_PROFILER_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask; + + if (profiler_callback_is_enabled(match_any_keywords, LOADER_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, LOADER_KEYWORD)) { + mono_profiler_set_domain_loading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_app_domain_loading); + mono_profiler_set_domain_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_app_domain_loaded); + mono_profiler_set_domain_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_app_domain_unloading); + mono_profiler_set_domain_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_app_domain_unloaded); + mono_profiler_set_domain_name_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_app_domain_name); + mono_profiler_set_image_loading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_module_loading); + mono_profiler_set_image_failed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_module_failed); + mono_profiler_set_image_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_module_loaded); + mono_profiler_set_image_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_module_unloading); + mono_profiler_set_image_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_module_unloaded); + mono_profiler_set_assembly_loading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_assembly_loading); + mono_profiler_set_assembly_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_assembly_loaded); + mono_profiler_set_assembly_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_assembly_unloading); + mono_profiler_set_assembly_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_assembly_unloaded); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, LOADER_KEYWORD)) { + mono_profiler_set_domain_loading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_domain_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_domain_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_domain_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_domain_name_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_image_loading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_image_failed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_image_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_image_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_image_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_assembly_loading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_assembly_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_assembly_unloading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_assembly_unloaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + } + } + + if (profiler_callback_is_enabled(match_any_keywords, JIT_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, JIT_KEYWORD)) { + mono_profiler_set_jit_begin_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_begin); + mono_profiler_set_jit_failed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_failed); + mono_profiler_set_jit_done_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_done); + mono_profiler_set_jit_chunk_created_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_chunk_created); + mono_profiler_set_jit_chunk_destroyed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_chunk_destroyed); + mono_profiler_set_jit_code_buffer_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_jit_code_buffer); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, JIT_KEYWORD)) { + mono_profiler_set_jit_begin_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_jit_failed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_jit_done_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_jit_chunk_created_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_jit_chunk_destroyed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_jit_code_buffer_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + } + } + + if (profiler_callback_is_enabled(match_any_keywords, TYPE_LOADING_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, TYPE_LOADING_KEYWORD)) { + mono_profiler_set_class_loading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_class_loading); + mono_profiler_set_class_failed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_class_failed); + mono_profiler_set_class_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_class_loaded); + mono_profiler_set_vtable_loading_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_vtable_loading); + mono_profiler_set_vtable_failed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_vtable_failed); + mono_profiler_set_vtable_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_vtable_loaded); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, TYPE_LOADING_KEYWORD)) { + mono_profiler_set_class_loading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_class_failed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_class_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_vtable_loading_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_vtable_failed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_vtable_loaded_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + } + } + + if (profiler_callback_is_enabled(match_any_keywords, METHOD_TRACING_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, METHOD_TRACING_KEYWORD)) { + mono_profiler_set_method_enter_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_enter); + mono_profiler_set_method_leave_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_leave); + mono_profiler_set_method_tail_call_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_tail_call); + mono_profiler_set_method_exception_leave_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_exception_leave); + mono_profiler_set_method_free_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_free); + mono_profiler_set_method_begin_invoke_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_begin_invoke); + mono_profiler_set_method_end_invoke_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_end_invoke); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, METHOD_TRACING_KEYWORD)) { + mono_profiler_set_method_enter_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_method_leave_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_method_tail_call_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_method_exception_leave_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_method_free_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_method_begin_invoke_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_method_end_invoke_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + } + } + + if (profiler_callback_is_enabled(match_any_keywords, EXCEPTION_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, EXCEPTION_KEYWORD)) { + mono_profiler_set_exception_throw_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_exception_throw); + mono_profiler_set_exception_clause_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_exception_clause); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, EXCEPTION_KEYWORD)) { + mono_profiler_set_exception_throw_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_exception_clause_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + } + } + + if (profiler_callback_is_enabled(match_any_keywords, GC_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, GC_KEYWORD)) { + 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); + } + } + + 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)) { + 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)) { + 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)) { + 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)) { + 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)) { + 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)) { + 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); + mono_profiler_set_gc_finalized_object_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + } + } + + 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)) { + 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)) { + 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)) { + 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)) { + mono_profiler_set_monitor_contention_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + } + } + + if (profiler_callback_is_enabled(match_any_keywords, MONITOR_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, MONITOR_KEYWORD)) { + mono_profiler_set_monitor_failed_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_monitor_failed); + mono_profiler_set_monitor_acquired_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_monitor_acquired); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, MONITOR_KEYWORD)) { + mono_profiler_set_monitor_failed_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_monitor_acquired_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + } + } + + if (profiler_callback_is_enabled(match_any_keywords, THREADING_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, THREADING_KEYWORD)) { + mono_profiler_set_thread_started_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_thread_started); + mono_profiler_set_thread_stopping_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_thread_stopping); + mono_profiler_set_thread_stopped_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_thread_stopped); + mono_profiler_set_thread_exited_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_thread_exited); + mono_profiler_set_thread_name_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_thread_name); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, THREADING_KEYWORD)) { + mono_profiler_set_thread_started_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_thread_stopping_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_thread_stopped_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_thread_exited_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + mono_profiler_set_thread_name_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + } + } + + if (!_ep_rt_dotnet_mono_profiler_provider_callspec.enabled) { + if (profiler_callback_is_enabled(match_any_keywords, METHOD_INSTRUMENTATION_KEYWORD)) { + if (!profiler_callback_is_enabled (enabled_keywords, METHOD_INSTRUMENTATION_KEYWORD)) { + mono_profiler_set_call_instrumentation_filter_callback (_ep_rt_dotnet_mono_profiler_provider, mono_profiler_method_instrumentation); + } + } else { + if (profiler_callback_is_enabled (enabled_keywords, METHOD_INSTRUMENTATION_KEYWORD)) { + mono_profiler_set_call_instrumentation_filter_callback (_ep_rt_dotnet_mono_profiler_provider, NULL); + } + } } - EP_LOCK_EXIT (section1) - MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.Level = level; - MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords; - MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); + 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); + EP_LOCK_EXIT (section1) ep_on_exit: ep_rt_config_requires_lock_not_held (); @@ -3050,51 +5171,6 @@ EventPipeEtwCallbackDotNETRuntime ( ep_exit_error_handler (); } -void -EventPipeEtwCallbackDotNETRuntimeRundown ( - 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) -{ - MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.Level = level; - MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords; - MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); -} - -void -EventPipeEtwCallbackDotNETRuntimePrivate ( - 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) -{ - MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.Level = level; - MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords; - MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); -} - -void -EventPipeEtwCallbackDotNETRuntimeStress ( - 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) -{ - MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.Level = level; - MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.EnabledKeywordsBitmask = match_any_keywords; - MICROSOFT_WINDOWS_DOTNETRUNTIME_STRESS_PROVIDER_EVENTPIPE_Context.IsEnabled = (is_enabled == 1 ? true : false); -} - #endif /* ENABLE_PERFTRACING */ MONO_EMPTY_SOURCE_FILE(eventpipe_rt_mono); diff --git a/src/mono/mono/eventpipe/ep-rt-mono.h b/src/mono/mono/eventpipe/ep-rt-mono.h index 2c3a5f7e36d707..49b6456cdb9df8 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-mono.h @@ -2344,6 +2344,16 @@ EventPipeEtwCallbackDotNETRuntimeStress ( EventFilterDescriptor *filter_data, void *callback_data); +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); + #endif /* ENABLE_PERFTRACING */ #endif /* __EVENTPIPE_RT_MONO_H__ */ diff --git a/src/mono/mono/eventpipe/gen-eventing-event-inc.lst b/src/mono/mono/eventpipe/gen-eventing-event-inc.lst index f74d476889e65d..ad52dd9f8c8ebb 100644 --- a/src/mono/mono/eventpipe/gen-eventing-event-inc.lst +++ b/src/mono/mono/eventpipe/gen-eventing-event-inc.lst @@ -45,3 +45,4 @@ ThreadPoolWorkingThreadCount ThreadTerminated TypeLoadStart TypeLoadStop +Microsoft-DotNETRuntimeMonoProfiler:* \ No newline at end of file