[Mono] Include loaded interpreter methods as EventPipe session rundown method events...
authorJohan Lorensson <lateralusx.github@gmail.com>
Thu, 1 Jul 2021 22:37:24 +0000 (00:37 +0200)
committerGitHub <noreply@github.com>
Thu, 1 Jul 2021 22:37:24 +0000 (17:37 -0500)
* Include interpreter methods in EventPipe session rundown events.

* Fix build error.

src/mono/mono/eventpipe/ep-rt-mono.c
src/mono/mono/metadata/object-internals.h
src/mono/mono/mini/ee.h
src/mono/mono/mini/interp-stubs.c
src/mono/mono/mini/interp/interp.c
src/mono/mono/mini/mini-runtime.c
src/mono/mono/utils/mono-internal-hash.c
src/mono/mono/utils/mono-internal-hash.h

index f8b8553..5ff2183 100644 (file)
@@ -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++;
                                }
                        }
index 0af9ed9..9dfb86c 100644 (file)
@@ -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);
index ba27962..6f171c8 100644 (file)
@@ -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 {
 
index 8aa96e0..81e71c0 100644 (file)
@@ -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,
 
index 1c7468b..cc30559 100644 (file)
@@ -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)
 {
index ce8930f..c500e94 100644 (file)
@@ -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:
index 92b68d1..f19622a 100644 (file)
@@ -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));
                }
        }
index 8a85f7d..31acdbf 100644 (file)
@@ -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);