Merge pull request #5317 from alexrp/master
authorAlex Rønne Petersen <alex@alexrp.com>
Tue, 8 Aug 2017 06:55:11 +0000 (08:55 +0200)
committerGitHub <noreply@github.com>
Tue, 8 Aug 2017 06:55:11 +0000 (08:55 +0200)
[profiler] Some profiler API improvements.

15 files changed:
mono/metadata/class-internals.h
mono/metadata/object-offsets.h
mono/metadata/profiler-events.h
mono/metadata/profiler-private.h
mono/metadata/profiler.c
mono/metadata/profiler.h
mono/mini/interp/interp.c
mono/mini/interp/transform.c
mono/mini/method-to-ir.c
mono/mini/mini-exceptions.c
mono/mini/mini-profiler.c
mono/mini/mini-runtime.c
mono/mini/mini.h
mono/profiler/log.c
samples/profiler/sample.c

index ef8127e14a4ab94e43f545d5eea84ef80f660039..3ff6e77cbb990f3d2b15b3252b2cb22628ebe4ac 100644 (file)
@@ -37,8 +37,10 @@ typedef struct _MonoMethodPInvoke MonoMethodPInvoke;
 
 #ifdef ENABLE_ICALL_EXPORT
 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
+#define ICALL_DECL_EXPORT MONO_API
 #define ICALL_EXPORT MONO_API
 #else
+#define ICALL_DECL_EXPORT
 #define ICALL_EXPORT static
 #endif
 
index a939ca88bf9eb681aa9b634c887ec11d73d77ced..dcf37e0015cf646f710a3c277e705980b25b6793 100644 (file)
@@ -142,6 +142,7 @@ DECL_OFFSET(MonoThreadsSync, status)
 DECL_OFFSET(MonoThreadsSync, nest)
 
 DECL_OFFSET(MonoProfilerCallContext, method)
+DECL_OFFSET(MonoProfilerCallContext, return_value)
 
 #ifdef HAVE_SGEN_GC
 DECL_OFFSET(SgenClientThreadInfo, in_critical_region)
index 1a7e0b25ef9e3cb2178565ca4e84b5cb4bf36318..f0681a6b456f78bc91c020de3254381d0bb68485 100644 (file)
@@ -56,6 +56,7 @@ MONO_PROFILER_EVENT_1(assembly_unloaded, AssemblyLUnloaded, MonoAssembly *, asse
 
 MONO_PROFILER_EVENT_2(method_enter, MethodEnter, MonoMethod *, method, MonoProfilerCallContext *, context)
 MONO_PROFILER_EVENT_2(method_leave, MethodLeave, MonoMethod *, method, MonoProfilerCallContext *, context)
+MONO_PROFILER_EVENT_2(method_tail_call, MethodTailCall, MonoMethod *, method, MonoMethod *, target)
 MONO_PROFILER_EVENT_2(method_exception_leave, MethodExceptionLeave, MonoMethod *, method, MonoObject *, exception)
 MONO_PROFILER_EVENT_1(method_free, MethodFree, MonoMethod *, method)
 MONO_PROFILER_EVENT_1(method_begin_invoke, MethodBeginInvoke, MonoMethod *, method)
index 293c2bd05e974436c41b8987c85a7c585485a11b..e8d9a61569a8fbcae6d821cc1b4b3edfa70bd029 100644 (file)
@@ -7,16 +7,17 @@
 #ifndef __MONO_PROFILER_PRIVATE_H__
 #define __MONO_PROFILER_PRIVATE_H__
 
+#include <mono/metadata/class-internals.h>
 #define MONO_PROFILER_UNSTABLE_GC_ROOTS
 #include <mono/metadata/profiler.h>
 #include <mono/utils/mono-context.h>
-#include <mono/utils/mono-lazy-init.h>
 #include <mono/utils/mono-os-mutex.h>
 #include <mono/utils/mono-os-semaphore.h>
 
 struct _MonoProfilerDesc {
        MonoProfilerHandle next;
        MonoProfiler *prof;
+       volatile gpointer cleanup_callback;
        volatile gpointer coverage_filter;
        volatile gpointer call_instrumentation_filter;
 
@@ -46,7 +47,7 @@ typedef struct {
 
        MonoProfilerHandle profilers;
 
-       mono_lazy_init_t coverage_status;
+       gboolean code_coverage;
        mono_mutex_t coverage_mutex;
        GHashTable *coverage_hash;
 
@@ -106,7 +107,6 @@ mono_profiler_installed (void)
 }
 
 MonoProfilerCoverageInfo *mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries);
-void mono_profiler_coverage_free (MonoMethod *method);
 
 struct _MonoProfilerCallContext {
        /*
@@ -139,7 +139,7 @@ mono_profiler_allocations_enabled (void)
 }
 
 #define _MONO_PROFILER_EVENT(name, ...) \
-       void mono_profiler_raise_ ## name (__VA_ARGS__);
+       ICALL_DECL_EXPORT void mono_profiler_raise_ ## name (__VA_ARGS__);
 #define MONO_PROFILER_EVENT_0(name, type) \
        _MONO_PROFILER_EVENT(name, void)
 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
index fa3f4eec9d1a6dfff683034165b8f94baaaba0b8..23f65469c81d412832909bd5b1f3d080072a1d74 100644 (file)
@@ -157,23 +157,31 @@ mono_profiler_create (MonoProfiler *prof)
        return handle;
 }
 
+void
+mono_profiler_set_cleanup_callback (MonoProfilerHandle handle, MonoProfilerCleanupCallback cb)
+{
+       InterlockedWritePointer (&handle->cleanup_callback, (gpointer) cb);
+}
+
 void
 mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfilerCoverageFilterCallback cb)
 {
        InterlockedWritePointer (&handle->coverage_filter, (gpointer) cb);
 }
 
-static void
-initialize_coverage (void)
+mono_bool
+mono_profiler_enable_coverage (void)
 {
+       if (mono_profiler_state.startup_done)
+               return FALSE;
+
        mono_os_mutex_init (&mono_profiler_state.coverage_mutex);
        mono_profiler_state.coverage_hash = g_hash_table_new (NULL, NULL);
-}
 
-static void
-lazy_initialize_coverage (void)
-{
-       mono_lazy_initialize (&mono_profiler_state.coverage_status, initialize_coverage);
+       if (!mono_debug_enabled ())
+               mono_debug_init (MONO_DEBUG_FORMAT_MONO);
+
+       return TRUE;
 }
 
 static void
@@ -188,10 +196,11 @@ coverage_unlock (void)
        mono_os_mutex_unlock (&mono_profiler_state.coverage_mutex);
 }
 
-void
+mono_bool
 mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb)
 {
-       lazy_initialize_coverage ();
+       if (!mono_profiler_state.code_coverage)
+               return FALSE;
 
        coverage_lock ();
 
@@ -200,7 +209,7 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
        coverage_unlock ();
 
        if (!info)
-               return;
+               return FALSE;
 
        MonoError error;
        MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
@@ -245,12 +254,15 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method,
        }
 
        mono_metadata_free_mh (header);
+
+       return TRUE;
 }
 
 MonoProfilerCoverageInfo *
 mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
 {
-       lazy_initialize_coverage ();
+       if (!mono_profiler_state.code_coverage)
+               return FALSE;
 
        gboolean cover = FALSE;
 
@@ -277,23 +289,6 @@ mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
        return info;
 }
 
-void
-mono_profiler_coverage_free (MonoMethod *method)
-{
-       lazy_initialize_coverage ();
-
-       coverage_lock ();
-
-       MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method);
-
-       if (info) {
-               g_hash_table_remove (mono_profiler_state.coverage_hash, method);
-               g_free (info);
-       }
-
-       coverage_unlock ();
-}
-
 mono_bool
 mono_profiler_enable_sampling (MonoProfilerHandle handle)
 {
@@ -489,6 +484,38 @@ mono_profiler_cleanup (void)
 #undef MONO_PROFILER_EVENT_3
 #undef MONO_PROFILER_EVENT_4
 #undef _MONO_PROFILER_EVENT
+
+       MonoProfilerHandle head = mono_profiler_state.profilers;
+
+       while (head) {
+               MonoProfilerCleanupCallback cb = head->cleanup_callback;
+
+               if (cb)
+                       cb (head->prof);
+
+               MonoProfilerHandle cur = head;
+               head = head->next;
+
+               g_free (cur);
+       }
+
+       if (mono_profiler_state.code_coverage) {
+               mono_os_mutex_destroy (&mono_profiler_state.coverage_mutex);
+
+               GHashTableIter iter;
+
+               g_hash_table_iter_init (&iter, mono_profiler_state.coverage_hash);
+
+               MonoProfilerCoverageInfo *info;
+
+               while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info))
+                       g_free (info);
+
+               g_hash_table_destroy (mono_profiler_state.coverage_hash);
+       }
+
+       if (mono_profiler_state.sampling_owner)
+               mono_os_sem_destroy (&mono_profiler_state.sampling_semaphore);
 }
 
 static void
index 133fec753d9d1be212209078c420a629e80fca10..b6e836d3638b6d0912666f3fec8a33adf2788671 100644 (file)
@@ -42,7 +42,9 @@ typedef struct _MonoProfilerDesc *MonoProfilerHandle;
 
 /*
  * Installs a profiler and returns a handle for it. The handle is used with the
- * other functions in the profiler API (e.g. for setting up callbacks).
+ * other functions in the profiler API (e.g. for setting up callbacks). The
+ * given structure pointer will be passed to all callbacks from the profiler
+ * API. It can be NULL.
  *
  * This function may only be called from your profiler's init function.
  *
@@ -61,6 +63,31 @@ typedef struct _MonoProfilerDesc *MonoProfilerHandle;
  */
 MONO_API MonoProfilerHandle mono_profiler_create (MonoProfiler *prof);
 
+typedef void (*MonoProfilerCleanupCallback) (MonoProfiler *prof);
+
+/*
+ * Sets a profiler cleanup function. This function will be invoked at shutdown
+ * when the profiler API is cleaning up its internal structures. It's mainly
+ * intended for a profiler to free the structure pointer that was passed to
+ * mono_profiler_create, if necessary.
+ *
+ * This function is async safe.
+ */
+MONO_API void mono_profiler_set_cleanup_callback (MonoProfilerHandle handle, MonoProfilerCleanupCallback cb);
+
+/*
+ * Enables support for code coverage instrumentation. At the moment, this means
+ * enabling the debug info subsystem. If you do not call this function, you
+ * will not be able to use mono_profiler_get_coverage_data. Returns TRUE if
+ * code coverage support was enabled, or FALSE if the function was called too
+ * late for this to be possible.
+ *
+ * This function may only be called from your profiler's init function.
+ *
+ * This function is not async safe.
+ */
+MONO_API mono_bool mono_profiler_enable_coverage (void);
+
 typedef mono_bool (*MonoProfilerCoverageFilterCallback) (MonoProfiler *prof, MonoMethod *method);
 
 /*
@@ -91,11 +118,16 @@ typedef void (*MonoProfilerCoverageCallback) (MonoProfiler *prof, const MonoProf
 
 /*
  * Retrieves all coverage data for the specified method and invokes the given
- * callback for each entry.
+ * callback for each entry. Source location information will only be filled out
+ * if the given method has debug info available. Returns TRUE if the given
+ * method was instrumented for code coverage; otherwise, FALSE.
+ *
+ * Please note that the structure passed to the callback is only valid for the
+ * duration of the callback.
  *
  * This function is not async safe.
  */
-MONO_API void mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb);
+MONO_API mono_bool mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb);
 
 typedef enum {
        /*
@@ -168,14 +200,18 @@ MONO_API mono_bool mono_profiler_enable_allocations (void);
 typedef enum {
        /* Do not instrument calls. */
        MONO_PROFILER_CALL_INSTRUMENTATION_NONE = 0,
-       /* Instrument method prologues. */
-       MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE = 1 << 1,
-       /* Also capture a call context for prologues. */
-       MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT = 1 << 2,
-       /* Instrument method epilogues. */
-       MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE = 1 << 3,
-       /* Also capture a call context for epilogues. */
-       MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE_CONTEXT = 1 << 4,
+       /* Instrument method entries. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_ENTER = 1 << 1,
+       /* Also capture a call context for method entries. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT = 1 << 2,
+       /* Instrument method exits. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE = 1 << 3,
+       /* Also capture a call context for method exits. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT = 1 << 4,
+       /* Instrument method exits as a result of a tail call. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL = 1 << 5,
+       /* Instrument exceptional method exits. */
+       MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE = 1 << 6,
 } MonoProfilerCallInstrumentationFlags;
 
 typedef MonoProfilerCallInstrumentationFlags (*MonoProfilerCallInstrumentationFilterCallback) (MonoProfiler *prof, MonoMethod *method);
index fdbbe262ba4f2bb6d3e0fb1b6617b0a84511abdf..f09df220599504afa287a8721f1038197b05da23 100644 (file)
@@ -2436,6 +2436,10 @@ ves_exec_method_with_context (InterpFrame *frame, ThreadContext *context, unsign
                }
                MINT_IN_CASE(MINT_JMP) {
                        InterpMethod *new_method = rtm->data_items [* (guint16 *)(ip + 1)];
+
+                       if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL)
+                               MONO_PROFILER_RAISE (method_tail_call, (frame->imethod->method, new_method->method));
+
                        if (!new_method->transformed) {
                                frame->ip = ip;
                                frame->ex = mono_interp_transform_method (new_method, context);
@@ -4769,7 +4773,7 @@ array_constructed:
                        if (MONO_PROFILER_ENABLED (method_enter)) {
                                MonoProfilerCallContext *prof_ctx = NULL;
 
-                               if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT) {
+                               if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER_CONTEXT) {
                                        prof_ctx = g_new0 (MonoProfilerCallContext, 1);
                                        prof_ctx->interp_frame = frame;
                                        prof_ctx->method = frame->imethod->method;
@@ -5140,35 +5144,34 @@ die_on_ex:
        }
 exit_frame:
 
-       if (!frame->ex) {
-               if (MONO_PROFILER_ENABLED (method_leave) && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE) {
-                       MonoProfilerCallContext *prof_ctx = NULL;
-
-                       if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE_CONTEXT) {
-                               prof_ctx = g_new0 (MonoProfilerCallContext, 1);
-                               prof_ctx->interp_frame = frame;
-                               prof_ctx->method = frame->imethod->method;
-
-                               MonoType *rtype = mono_method_signature (frame->imethod->method)->ret;
-
-                               switch (rtype->type) {
-                               case MONO_TYPE_VOID:
-                                       break;
-                               case MONO_TYPE_VALUETYPE:
-                                       prof_ctx->return_value = frame->retval->data.p;
-                                       break;
-                               default:
-                                       prof_ctx->return_value = frame->retval;
-                                       break;
-                               }
-                       }
+       if (!frame->ex && MONO_PROFILER_ENABLED (method_leave) &&
+           frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE) {
+               MonoProfilerCallContext *prof_ctx = NULL;
 
-                       MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
+               if (frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE_CONTEXT) {
+                       prof_ctx = g_new0 (MonoProfilerCallContext, 1);
+                       prof_ctx->interp_frame = frame;
+                       prof_ctx->method = frame->imethod->method;
 
-                       g_free (prof_ctx);
+                       MonoType *rtype = mono_method_signature (frame->imethod->method)->ret;
+
+                       switch (rtype->type) {
+                       case MONO_TYPE_VOID:
+                               break;
+                       case MONO_TYPE_VALUETYPE:
+                               prof_ctx->return_value = frame->retval->data.p;
+                               break;
+                       default:
+                               prof_ctx->return_value = frame->retval;
+                               break;
+                       }
                }
-       } else
-               MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, (MonoObject *) frame->ex));
+
+               MONO_PROFILER_RAISE (method_leave, (frame->imethod->method, prof_ctx));
+
+               g_free (prof_ctx);
+       } else if (frame->ex && frame->imethod->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE)
+               MONO_PROFILER_RAISE (method_exception_leave, (frame->imethod->method, &frame->ex->object));
 
        DEBUG_LEAVE ();
 }
index 790f8b191d2ea048eeeaf1424f6d45477ea57212..f8144e1952ee2187b519ae719f1f8995dce8168b 100644 (file)
@@ -1514,7 +1514,7 @@ generate (MonoMethod *method, InterpMethod *rtm, unsigned char *is_bb_start, Mon
                }
        }
 
-       if (rtm->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE)
+       if (rtm->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ENTER)
                ADD_CODE (td, MINT_PROF_ENTER);
 
        if (sym_seq_points) {
@@ -3753,6 +3753,7 @@ generate (MonoMethod *method, InterpMethod *rtm, unsigned char *is_bb_start, Mon
                        case CEE_TAIL_:
                                ++td->ip;
                                /* FIX: should do something? */;
+                               // TODO: This should raise a method_tail_call profiler event.
                                break;
                        case CEE_INITOBJ:
                                CHECK_STACK(td, 1);
index 84c019460517374d6282b9245232d5c246680b22..a1f6e1fa9eee4b9f5cb060545bcf67a0c7b48e20 100644 (file)
@@ -2217,7 +2217,7 @@ check_method_sharing (MonoCompile *cfg, MonoMethod *cmethod, gboolean *out_pass_
 
 inline static MonoCallInst *
 mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, 
-                                        MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline)
+                                        MonoInst **args, int calli, int virtual_, int tail, int rgctx, int unbox_trampoline, MonoMethod *target)
 {
        MonoType *sig_ret;
        MonoCallInst *call;
@@ -2229,7 +2229,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig,
                tail = FALSE;
 
        if (tail) {
-               mini_profiler_emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE, NULL, NULL);
+               mini_profiler_emit_tail_call (cfg, target);
 
                MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL);
        } else
@@ -2362,7 +2362,7 @@ mini_emit_calli (MonoCompile *cfg, MonoMethodSignature *sig, MonoInst **args, Mo
                MONO_ADD_INS (cfg->cbb, ins);
        }
 
-       call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE);
+       call = mono_emit_call_args (cfg, sig, args, TRUE, FALSE, FALSE, rgctx_arg ? TRUE : FALSE, FALSE, NULL);
 
        call->inst.sreg1 = addr->dreg;
 
@@ -2456,7 +2456,7 @@ mono_emit_method_call_full (MonoCompile *cfg, MonoMethod *method, MonoMethodSign
 
        need_unbox_trampoline = method->klass == mono_defaults.object_class || mono_class_is_interface (method->klass);
 
-       call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline);
+       call = mono_emit_call_args (cfg, sig, args, FALSE, virtual_, tail, rgctx_arg ? TRUE : FALSE, need_unbox_trampoline, method);
 
 #ifndef DISABLE_REMOTING
        if (might_be_remote)
@@ -2586,7 +2586,7 @@ mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature
 
        g_assert (sig);
 
-       call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE);
+       call = mono_emit_call_args (cfg, sig, args, FALSE, FALSE, FALSE, FALSE, FALSE, NULL);
        call->fptr = func;
 
        MONO_ADD_INS (cfg->cbb, (MonoInst*)call);
@@ -8030,7 +8030,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        if (cfg->gshared && mono_method_check_context_used (cmethod))
                                GENERIC_SHARING_FAILURE (CEE_JMP);
 
-                       mini_profiler_emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE, NULL, NULL);
+                       mini_profiler_emit_tail_call (cfg, cmethod);
 
                        fsig = mono_method_signature (cmethod);
                        n = fsig->param_count + fsig->hasthis;
@@ -8972,7 +8972,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                                        /* Handle tail calls similarly to normal calls */
                                        tail_call = TRUE;
                                } else {
-                                       mini_profiler_emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE, NULL, NULL);
+                                       mini_profiler_emit_tail_call (cfg, cmethod);
 
                                        MONO_INST_NEW_CALL (cfg, call, OP_JMP);
                                        call->tail_call = TRUE;
@@ -9083,7 +9083,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        break;
                }
                case CEE_RET:
-                       mini_profiler_emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE, sp - 1, sig->ret);
+                       mini_profiler_emit_leave (cfg, sig->ret->type != MONO_TYPE_VOID ? sp [-1] : NULL);
 
                        if (cfg->method != method) {
                                /* return from inlined method */
@@ -12635,7 +12635,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        }
 
        cfg->cbb = init_localsbb;
-       mini_profiler_emit_instrumentation_call (cfg, mono_profiler_raise_method_enter, TRUE, NULL, NULL);
+       mini_profiler_emit_enter (cfg);
 
        if (seq_points) {
                MonoBasicBlock *bb;
index 348bc3948c5a30575db3dc0836e9b501c5a12380..4f81d7c4c37c42793c25b489ae438325e5c68dd7 100644 (file)
@@ -2230,9 +2230,12 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                        }
                }
 
-               jit_tls->orig_ex_ctx_set = TRUE;
-               MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
-               jit_tls->orig_ex_ctx_set = FALSE;
+               if (MONO_PROFILER_ENABLED (method_exception_leave) &&
+                   mono_profiler_get_call_instrumentation_flags (method) & MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE) {
+                       jit_tls->orig_ex_ctx_set = TRUE;
+                       MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj));
+                       jit_tls->orig_ex_ctx_set = FALSE;
+               }
 
                *ctx = new_ctx;
        }
index 33d39e26df6dfd138048a92d165837685dc546ea..c6c6158866223fe69f8b0664f722595d24136bd4 100644 (file)
 
 #ifndef DISABLE_JIT
 
-void
-mini_profiler_emit_instrumentation_call (MonoCompile *cfg, void *func, gboolean entry, MonoInst **ret, MonoType *rtype)
+static MonoInst *
+emit_fill_call_ctx (MonoCompile *cfg, MonoInst *method, MonoInst *ret)
 {
-       gboolean instrument, capture;
+       cfg->flags |= MONO_CFG_HAS_ALLOCA;
 
-       /*
-        * Do not instrument an inlined method - it becomes
-        * part of the current method.
-        */
-       if (cfg->current_method != cfg->method)
-               return;
+       MonoInst *alloc, *size, *fill_ctx;
+
+       EMIT_NEW_ICONST (cfg, size, sizeof (MonoProfilerCallContext));
+       MONO_INST_NEW (cfg, alloc, OP_LOCALLOC);
+       alloc->dreg = alloc_preg (cfg);
+       alloc->sreg1 = size->dreg;
+       alloc->flags |= MONO_INST_INIT;
+       MONO_ADD_INS (cfg->cbb, alloc);
+       MONO_INST_NEW (cfg, fill_ctx, OP_FILL_PROF_CALL_CTX);
+       fill_ctx->sreg1 = alloc->dreg;
+       MONO_ADD_INS (cfg->cbb, fill_ctx);
+       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, alloc->dreg, MONO_STRUCT_OFFSET (MonoProfilerCallContext, method), method->dreg);
+
+       if (ret) {
+               MonoInst *var = mono_compile_create_var (cfg, mono_method_signature (cfg->method)->ret, OP_LOCAL);
 
-       if (entry) {
-               instrument = cfg->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE;
-               capture = cfg->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT;
-       } else {
-               instrument = cfg->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE;
-               capture = cfg->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE_CONTEXT;
+               MonoInst *store, *addr;
+
+               EMIT_NEW_TEMPSTORE (cfg, store, var->inst_c0, ret);
+               EMIT_NEW_VARLOADA (cfg, addr, var, NULL);
+               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, alloc->dreg, MONO_STRUCT_OFFSET (MonoProfilerCallContext, return_value), addr->dreg);
        }
 
-       if (!instrument)
+       return alloc;
+}
+
+void
+mini_profiler_emit_enter (MonoCompile *cfg)
+{
+       if (!MONO_CFG_PROFILE (cfg, ENTER) || cfg->current_method != cfg->method)
+               return;
+
+       MonoInst *iargs [2];
+
+       EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
+
+       if (MONO_CFG_PROFILE (cfg, ENTER_CONTEXT) && !cfg->llvm_only)
+               iargs [1] = emit_fill_call_ctx (cfg, iargs [0], NULL);
+       else
+               EMIT_NEW_PCONST (cfg, iargs [1], NULL);
+
+       /* void mono_profiler_raise_method_enter (MonoMethod *method, MonoProfilerCallContext *ctx) */
+       mono_emit_jit_icall (cfg, mono_profiler_raise_method_enter, iargs);
+}
+
+void
+mini_profiler_emit_leave (MonoCompile *cfg, MonoInst *ret)
+{
+       if (!MONO_CFG_PROFILE (cfg, LEAVE) || cfg->current_method != cfg->method)
                return;
 
        MonoInst *iargs [2];
 
        EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
 
-       if (capture && !cfg->llvm_only) {
-               cfg->flags |= MONO_CFG_HAS_ALLOCA;
+       if (MONO_CFG_PROFILE (cfg, LEAVE_CONTEXT) && !cfg->llvm_only)
+               iargs [1] = emit_fill_call_ctx (cfg, iargs [0], ret);
+       else
+               EMIT_NEW_PCONST (cfg, iargs [1], NULL);
 
-               MonoInst *size, *fill_ctx;
+       /* void mono_profiler_raise_method_leave (MonoMethod *method, MonoProfilerCallContext *ctx) */
+       mono_emit_jit_icall (cfg, mono_profiler_raise_method_leave, iargs);
+}
 
-               EMIT_NEW_ICONST (cfg, size, sizeof (MonoProfilerCallContext));
-               MONO_INST_NEW (cfg, iargs [1], OP_LOCALLOC);
-               iargs [1]->dreg = alloc_preg (cfg);
-               iargs [1]->sreg1 = size->dreg;
-               iargs [1]->flags |= MONO_INST_INIT;
-               MONO_ADD_INS (cfg->cbb, iargs [1]);
-               MONO_INST_NEW (cfg, fill_ctx, OP_FILL_PROF_CALL_CTX);
-               fill_ctx->sreg1 = iargs [1]->dreg;
-               MONO_ADD_INS (cfg->cbb, fill_ctx);
-               MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, iargs [1]->dreg, MONO_STRUCT_OFFSET (MonoProfilerCallContext, method), iargs [0]->dreg);
+void
+mini_profiler_emit_tail_call (MonoCompile *cfg, MonoMethod *target)
+{
+       if (!MONO_CFG_PROFILE (cfg, TAIL_CALL) || cfg->current_method != cfg->method)
+               return;
 
-               if (rtype && rtype->type != MONO_TYPE_VOID) {
-                       MonoInst *var = mono_compile_create_var (cfg, rtype, OP_LOCAL);
+       g_assert (cfg->current_method == cfg->method);
 
-                       MonoInst *store, *addr;
+       MonoInst *iargs [2];
 
-                       EMIT_NEW_TEMPSTORE (cfg, store, var->inst_c0, *ret);
-                       EMIT_NEW_VARLOADA (cfg, addr, var, NULL);
-                       MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STORE_MEMBASE_REG, iargs [1]->dreg, MONO_STRUCT_OFFSET (MonoProfilerCallContext, return_value), addr->dreg);
-               }
-       else
+       EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method);
+
+       if (target)
+               EMIT_NEW_METHODCONST (cfg, iargs [1], target);
+       else
                EMIT_NEW_PCONST (cfg, iargs [1], NULL);
 
-       mono_emit_jit_icall (cfg, func, iargs);
+       /* void mono_profiler_raise_method_tail_call (MonoMethod *method, MonoMethod *target) */
+       mono_emit_jit_icall (cfg, mono_profiler_raise_method_tail_call, iargs);
 }
 
 #endif
index 745ede4dea08a2ce6f4e8a3ceaf84d03e1a39fcd..b839e49f09637e9d1314e10c13815ced0435d885 100644 (file)
@@ -4059,6 +4059,7 @@ register_icalls (void)
         */
        register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr ptr", TRUE);
        register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr ptr", TRUE);
+       register_icall (mono_profiler_raise_method_tail_call, "mono_profiler_raise_method_tail_call", "void ptr ptr", TRUE);
 
        register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE);
        register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE);
index 6d90abbd973af8cbc55408ece2ea5c4dea9a3246..9c6b71195f6d31104d14eb4b9734c7a3d01b423f 100644 (file)
@@ -1920,8 +1920,11 @@ typedef struct {
        MonoProfilerCallInstrumentationFlags prof_flags;
 } MonoCompile;
 
+#define MONO_CFG_PROFILE(cfg, flag) \
+       G_UNLIKELY ((cfg)->prof_flags & MONO_PROFILER_CALL_INSTRUMENTATION_ ## flag)
+
 #define MONO_CFG_PROFILE_CALL_CONTEXT(cfg) \
-       ((cfg)->prof_flags & (MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE_CONTEXT | MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE_CONTEXT))
+       (MONO_CFG_PROFILE (cfg, ENTER_CONTEXT) || MONO_CFG_PROFILE (cfg, LEAVE_CONTEXT))
 
 typedef enum {
        MONO_CFG_HAS_ALLOCA = 1 << 0,
@@ -2357,8 +2360,12 @@ MonoDomain* mini_init                      (const char *filename, const char *ru
 void        mini_cleanup                   (MonoDomain *domain);
 MONO_API MonoDebugOptions *mini_get_debug_options   (void);
 MONO_API gboolean    mini_parse_debug_option (const char *option);
+
+/* profiler support */
 void        mini_add_profiler_argument (const char *desc);
-void        mini_profiler_emit_instrumentation_call (MonoCompile *cfg, void *func, gboolean entry, MonoInst **ret, MonoType *rtype);
+void        mini_profiler_emit_enter (MonoCompile *cfg);
+void        mini_profiler_emit_leave (MonoCompile *cfg, MonoInst *ret);
+void        mini_profiler_emit_tail_call (MonoCompile *cfg, MonoMethod *target);
 void        mini_profiler_context_enable (void);
 gpointer    mini_profiler_context_get_this (MonoProfilerCallContext *ctx);
 gpointer    mini_profiler_context_get_argument (MonoProfilerCallContext *ctx, guint32 pos);
index 90f7309884796a55ac57dfb19aa89a76a192bffd..8a3790aac248ed44baa2d156137da838cfb65e42 100644 (file)
@@ -1791,6 +1791,12 @@ method_leave (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *c
        }
 }
 
+static void
+tail_call (MonoProfiler *prof, MonoMethod *method, MonoMethod *target)
+{
+       method_leave (prof, method, NULL);
+}
+
 static void
 method_exc_leave (MonoProfiler *prof, MonoMethod *method, MonoObject *exc)
 {
@@ -1810,7 +1816,10 @@ method_exc_leave (MonoProfiler *prof, MonoMethod *method, MonoObject *exc)
 static MonoProfilerCallInstrumentationFlags
 method_filter (MonoProfiler *prof, MonoMethod *method)
 {
-       return MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE | MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE;
+       return MONO_PROFILER_CALL_INSTRUMENTATION_ENTER |
+              MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE |
+              MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL |
+              MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE;
 }
 
 static void
@@ -4735,11 +4744,14 @@ mono_profiler_init_log (const char *desc)
                mono_profiler_set_call_instrumentation_filter_callback (handle, method_filter);
                mono_profiler_set_method_enter_callback (handle, method_enter);
                mono_profiler_set_method_leave_callback (handle, method_leave);
+               mono_profiler_set_method_tail_call_callback (handle, tail_call);
                mono_profiler_set_method_exception_leave_callback (handle, method_exc_leave);
        }
 
-       if (log_config.collect_coverage)
+       if (log_config.collect_coverage) {
+               mono_profiler_enable_coverage ();
                mono_profiler_set_coverage_filter_callback (handle, coverage_filter);
+       }
 
        mono_profiler_enable_allocations ();
        mono_profiler_enable_sampling (handle);
index a5ee4435ea6843b554b986cf344e6276d833619d..a210317e913b7740b4d564c94849c82c21902d8f 100644 (file)
@@ -2,9 +2,9 @@
 
 /*
  * Bare bones profiler. Compile with:
- * 
+ *
  * linux : gcc -fPIC -shared -o libmono-profiler-sample.so sample.c `pkg-config --cflags --libs mono-2`
- * mac : gcc sample.c -o mono-profiler-sample.dylib -Dmono_free=free -lz `pkg-config --cflags mono-2` -undefined suppress -flat_namespace  
+ * mac : gcc -o mono-profiler-sample.dylib sample.c -lz `pkg-config --cflags mono-2` -undefined suppress -flat_namespace
  * linux with a custom prefix (e.g. --prefix=/opt/my-mono-build):
  *     gcc -fPIC -shared -o libmono-profiler-sample.so sample.c `PKG_CONFIG_PATH=/opt/my-mono-build/lib/pkgconfig/ pkg-config --cflags --libs mono-2`
  *
@@ -35,15 +35,10 @@ sample_method_enter (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallCon
        prof->ncalls++;
 }
 
-static void
-sample_method_leave (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *ctx)
-{
-}
-
 static MonoProfilerCallInstrumentationFlags
 sample_instrumentation_filter (MonoProfiler *prof, MonoMethod *method)
 {
-       return MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE | MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE;
+       return MONO_PROFILER_CALL_INSTRUMENTATION_ENTER;
 }
 
 /* the entry point */
@@ -56,7 +51,6 @@ mono_profiler_init_sample (const char *desc)
        mono_profiler_set_runtime_shutdown_end_callback (handle, sample_shutdown);
        mono_profiler_set_call_instrumentation_filter_callback (handle, sample_instrumentation_filter);
        mono_profiler_set_method_enter_callback (handle, sample_method_enter);
-       mono_profiler_set_method_leave_callback (handle, sample_method_leave);
 }