From 8dad36481b7436712604235b93ed4f367fc95057 Mon Sep 17 00:00:00 2001 From: Johan Lorensson Date: Fri, 2 Jul 2021 00:37:24 +0200 Subject: [PATCH] [Mono] Include loaded interpreter methods as EventPipe session rundown method events. (#54953) * Include interpreter methods in EventPipe session rundown events. * Fix build error. --- src/mono/mono/eventpipe/ep-rt-mono.c | 38 +++++++++++++++++------ src/mono/mono/metadata/object-internals.h | 4 +++ src/mono/mono/mini/ee.h | 1 + src/mono/mono/mini/interp-stubs.c | 5 +++ src/mono/mono/mini/interp/interp.c | 33 +++++++++++++++++--- src/mono/mono/mini/mini-runtime.c | 9 +++++- src/mono/mono/utils/mono-internal-hash.c | 4 +-- src/mono/mono/utils/mono-internal-hash.h | 4 +-- 8 files changed, 79 insertions(+), 19 deletions(-) diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index f8b85538db0f0..5ff2183936f52 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -115,6 +115,7 @@ typedef struct _EventPipeSampleProfileData { uintptr_t thread_ip; uint32_t payload_data; bool async_frame; + bool safe_point_frame; } EventPipeSampleProfileData; // Rundown flags. @@ -898,13 +899,15 @@ eventpipe_execute_rundown ( if (root_domain) { uint64_t domain_id = (uint64_t)root_domain; - // Iterate all functions in use (both JIT and AOT). + // Iterate 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; mono_jit_info_table_foreach_internal (eventpipe_fire_method_events_func, &events_data); + if (mono_get_runtime_callbacks ()->is_interpreter_enabled()) + mono_get_runtime_callbacks ()->interp_jit_info_foreach (eventpipe_fire_method_events_func, &events_data); g_free (events_data.buffer); // Iterate all assemblies in domain. @@ -997,21 +1000,32 @@ eventpipe_sample_profiler_walk_managed_stack_for_thread_func ( EP_ASSERT (frame != NULL); EP_ASSERT (data != NULL); - gboolean result = false; EventPipeSampleProfileData *sample_data = (EventPipeSampleProfileData *)data; if (sample_data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR) { - if (frame->type == FRAME_TYPE_MANAGED_TO_NATIVE) + 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; - else + break; + case FRAME_TYPE_INTERP: + if (frame->managed) + sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; + else + sample_data->payload_data = 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; + } } - bool safe_point_frame = false; - result = eventpipe_walk_managed_stack_for_thread (frame, ctx, &sample_data->stack_contents, &sample_data->async_frame, &safe_point_frame); - if (sample_data->payload_data == EP_SAMPLE_PROFILER_SAMPLE_TYPE_EXTERNAL && safe_point_frame) - sample_data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; - return result; + return eventpipe_walk_managed_stack_for_thread (frame, ctx, &sample_data->stack_contents, &sample_data->async_frame, &sample_data->safe_point_frame); } static @@ -1515,8 +1529,12 @@ ep_rt_mono_sample_profiler_write_sampling_event_for_threads ( data->thread_ip = (uintptr_t)MONO_CONTEXT_GET_IP (&thread_state->ctx); data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_ERROR; data->async_frame = FALSE; + data->safe_point_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); + 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->safe_point_frame) + data->payload_data = EP_SAMPLE_PROFILER_SAMPLE_TYPE_MANAGED; + sampled_thread_count++; } } diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 0af9ed940682c..9dfb86c1d9d0d 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -610,6 +610,9 @@ typedef struct { /* Safely access System.Delegate from native code */ TYPED_HANDLE_DECL (MonoDelegate); + +typedef void (*InterpJitInfoFunc) (MonoJitInfo *ji, gpointer user_data); + /* * Callbacks supplied by the runtime and called by the modules in metadata/ * This interface is easier to extend than adding a new function type + @@ -643,6 +646,7 @@ typedef struct { void (*get_exception_stats)(guint32 *exception_count); // Same as compile_method, but returns a MonoFtnDesc in llvmonly mode gpointer (*get_ftnptr)(MonoMethod *method, MonoError *error); + void (*interp_jit_info_foreach)(InterpJitInfoFunc func, gpointer user_data); } MonoRuntimeCallbacks; typedef gboolean (*MonoInternalStackWalk) (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data); diff --git a/src/mono/mono/mini/ee.h b/src/mono/mono/mini/ee.h index ba2796207f091..6f171c85bd718 100644 --- a/src/mono/mono/mini/ee.h +++ b/src/mono/mono/mini/ee.h @@ -59,6 +59,7 @@ typedef gpointer MonoInterpFrameHandle; MONO_EE_CALLBACK (void, invalidate_transformed, (void)) \ MONO_EE_CALLBACK (void, cleanup, (void)) \ MONO_EE_CALLBACK (void, mark_stack, (gpointer thread_info, GcScanFunc func, gpointer gc_data, gboolean precise)) \ + MONO_EE_CALLBACK (void, jit_info_foreach, (InterpJitInfoFunc func, gpointer user_data)) \ typedef struct _MonoEECallbacks { diff --git a/src/mono/mono/mini/interp-stubs.c b/src/mono/mono/mini/interp-stubs.c index 8aa96e0183ccb..81e71c0982793 100644 --- a/src/mono/mono/mini/interp-stubs.c +++ b/src/mono/mono/mini/interp-stubs.c @@ -215,6 +215,11 @@ stub_mark_stack (gpointer thread_data, GcScanFunc func, gpointer gc_data, gboole { } +static void +stub_jit_info_foreach (InterpJitInfoFunc func, gpointer user_data) +{ +} + #undef MONO_EE_CALLBACK #define MONO_EE_CALLBACK(ret, name, sig) stub_ ## name, diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index 1c7468ba3cadc..cc305593c7f26 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -7325,7 +7325,7 @@ static int num_methods; const int opcount_threshold = 100000; static void -interp_add_imethod (gpointer method) +interp_add_imethod (gpointer method, gpointer user_data) { InterpMethod *imethod = (InterpMethod*) method; if (imethod->opcounts > opcount_threshold) @@ -7351,7 +7351,7 @@ interp_print_method_counts (void) jit_mm_lock (jit_mm); imethods = (InterpMethod**) malloc (jit_mm->interp_code_hash.num_entries * sizeof (InterpMethod*)); - mono_internal_hash_table_apply (&jit_mm->interp_code_hash, interp_add_imethod); + mono_internal_hash_table_apply (&jit_mm->interp_code_hash, interp_add_imethod, NULL); jit_mm_unlock (jit_mm); qsort (imethods, num_methods, sizeof (InterpMethod*), imethod_opcount_comparer); @@ -7372,7 +7372,7 @@ interp_set_optimizations (guint32 opts) } static void -invalidate_transform (gpointer imethod_) +invalidate_transform (gpointer imethod_, gpointer user_data) { InterpMethod *imethod = (InterpMethod *) imethod_; imethod->transformed = FALSE; @@ -7451,13 +7451,38 @@ interp_invalidate_transformed (void) MonoJitMemoryManager *jit_mm = get_default_jit_mm (); jit_mm_lock (jit_mm); - mono_internal_hash_table_apply (&jit_mm->interp_code_hash, invalidate_transform); + mono_internal_hash_table_apply (&jit_mm->interp_code_hash, invalidate_transform, NULL); jit_mm_unlock (jit_mm); if (need_stw_restart) mono_restart_world (MONO_THREAD_INFO_FLAGS_NO_GC); } +typedef struct { + InterpJitInfoFunc func; + gpointer user_data; +} InterpJitInfoFuncUserData; + +static void +interp_call_jit_info_func (gpointer imethod, gpointer user_data) +{ + InterpJitInfoFuncUserData *data = (InterpJitInfoFuncUserData *)user_data; + data->func (((InterpMethod *)imethod)->jinfo, data->user_data); +} + +static void +interp_jit_info_foreach (InterpJitInfoFunc func, gpointer user_data) +{ + InterpJitInfoFuncUserData data = {func, user_data}; + + // FIXME: Enumerate all memory managers + MonoJitMemoryManager *jit_mm = get_default_jit_mm (); + + jit_mm_lock (jit_mm); + mono_internal_hash_table_apply (&jit_mm->interp_code_hash, interp_call_jit_info_func, &data); + jit_mm_unlock (jit_mm); +} + static void interp_cleanup (void) { diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index ce8930ff6c82c..c500e946968bd 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -160,6 +160,7 @@ GSList *mono_interp_only_classes; static void register_icalls (void); static void runtime_cleanup (MonoDomain *domain, gpointer user_data); static void mini_invalidate_transformed_interp_methods (MonoAssemblyLoadContext *alc, uint32_t generation); +static void mini_interp_jit_info_foreach(InterpJitInfoFunc func, gpointer user_data); gboolean mono_running_on_valgrind (void) @@ -4357,6 +4358,7 @@ mini_init (const char *filename, const char *runtime_version) callbacks.install_state_summarizer = mini_register_sigterm_handler; #endif callbacks.metadata_update_published = mini_invalidate_transformed_interp_methods; + callbacks.interp_jit_info_foreach = mini_interp_jit_info_foreach; callbacks.init_mem_manager = init_jit_mem_manager; callbacks.free_mem_manager = free_jit_mem_manager; @@ -5139,12 +5141,17 @@ mono_runtime_install_custom_handlers_usage (void) } #endif /* HOST_WIN32 */ -void +static void mini_invalidate_transformed_interp_methods (MonoAssemblyLoadContext *alc G_GNUC_UNUSED, uint32_t generation G_GNUC_UNUSED) { mini_get_interp_callbacks ()->invalidate_transformed (); } +static void +mini_interp_jit_info_foreach(InterpJitInfoFunc func, gpointer user_data) +{ + mini_get_interp_callbacks ()->jit_info_foreach (func, user_data); +} /* * mini_get_default_mem_manager: diff --git a/src/mono/mono/utils/mono-internal-hash.c b/src/mono/mono/utils/mono-internal-hash.c index 92b68d1786100..f19622afe5965 100644 --- a/src/mono/mono/utils/mono-internal-hash.c +++ b/src/mono/mono/utils/mono-internal-hash.c @@ -107,12 +107,12 @@ mono_internal_hash_table_insert (MonoInternalHashTable *table, } void -mono_internal_hash_table_apply (MonoInternalHashTable *table, MonoInternalHashApplyFunc func) +mono_internal_hash_table_apply (MonoInternalHashTable *table, MonoInternalHashApplyFunc func, gpointer user_data) { for (gint i = 0; i < table->size; i++) { gpointer head = table->table [i]; while (head) { - func (head); + func (head, user_data); head = *(table->next_value (head)); } } diff --git a/src/mono/mono/utils/mono-internal-hash.h b/src/mono/mono/utils/mono-internal-hash.h index 8a85f7d10aacb..31acdbf0d2a6e 100644 --- a/src/mono/mono/utils/mono-internal-hash.h +++ b/src/mono/mono/utils/mono-internal-hash.h @@ -37,7 +37,7 @@ typedef struct _MonoInternalHashTable MonoInternalHashTable; typedef gpointer (*MonoInternalHashKeyExtractFunc) (gpointer value); typedef gpointer* (*MonoInternalHashNextValueFunc) (gpointer value); -typedef void (*MonoInternalHashApplyFunc) (gpointer value); +typedef void (*MonoInternalHashApplyFunc) (gpointer value, gpointer user_data); struct _MonoInternalHashTable { @@ -73,7 +73,7 @@ mono_internal_hash_table_insert (MonoInternalHashTable *table, gpointer key, gpointer value); void -mono_internal_hash_table_apply (MonoInternalHashTable *table, MonoInternalHashApplyFunc func); +mono_internal_hash_table_apply (MonoInternalHashTable *table, MonoInternalHashApplyFunc func, gpointer user_data); gboolean mono_internal_hash_table_remove (MonoInternalHashTable *table, gpointer key);