[profiler] Move legacy profiler code to profiler.c.
[mono.git] / mono / metadata / profiler.c
index a1e222fc1e66c2c8c39b26ac6bff50ab6c9aa88b..fa3f4eec9d1a6dfff683034165b8f94baaaba0b8 100644 (file)
@@ -11,6 +11,7 @@
 #include <mono/metadata/profiler-private.h>
 #include <mono/utils/mono-dl.h>
 #include <mono/utils/mono-error-internals.h>
+#include <mono/utils/mono-logger-internals.h>
 
 MonoProfilerState mono_profiler_state;
 
@@ -20,24 +21,16 @@ typedef void (*MonoProfilerInitializer) (const char *);
 #define NEW_INITIALIZER_NAME "mono_profiler_init"
 
 static gboolean
-load_profiler (MonoDl *module, const char *desc, const char *suffix)
+load_profiler (MonoDl *module, const char *name, const char *desc)
 {
        if (!module)
                return FALSE;
 
-       char *old_name;
-
-       if (suffix)
-               old_name = g_strdup_printf (OLD_INITIALIZER_NAME "_%s", suffix);
-       else
-               old_name = g_strdup_printf (OLD_INITIALIZER_NAME);
-
+       char *err, *old_name = g_strdup_printf (OLD_INITIALIZER_NAME);
        MonoProfilerInitializer func;
 
-       char *err;
-
        if (!(err = mono_dl_symbol (module, old_name, (gpointer) &func))) {
-               g_warning ("Found old-style startup symbol %s; profiler has not been migrated to the new API.", old_name);
+               mono_profiler_printf_err ("Found old-style startup symbol '%s' for the '%s' profiler; it has not been migrated to the new API.", old_name, name);
                g_free (old_name);
                return FALSE;
        }
@@ -45,12 +38,7 @@ load_profiler (MonoDl *module, const char *desc, const char *suffix)
        g_free (err);
        g_free (old_name);
 
-       char *new_name;
-
-       if (suffix)
-               new_name = g_strdup_printf (NEW_INITIALIZER_NAME "_%s", suffix);
-       else
-               new_name = g_strdup_printf (NEW_INITIALIZER_NAME);
+       char *new_name = g_strdup_printf (NEW_INITIALIZER_NAME "_%s", name);
 
        if ((err = mono_dl_symbol (module, new_name, (gpointer *) &func))) {
                g_free (err);
@@ -66,7 +54,7 @@ load_profiler (MonoDl *module, const char *desc, const char *suffix)
 }
 
 static gboolean
-load_profiler_from_executable (const char *desc, const char *name)
+load_profiler_from_executable (const char *name, const char *desc)
 {
        char *err;
 
@@ -81,16 +69,16 @@ load_profiler_from_executable (const char *desc, const char *name)
        MonoDl *module = mono_dl_open (NULL, MONO_DL_EAGER, &err);
 
        if (!module) {
-               g_warning ("Could not open main executable (%s).", err);
+               mono_profiler_printf_err ("Could not open main executable: %s", err);
                g_free (err);
                return FALSE;
        }
 
-       return load_profiler (module, desc, name);
+       return load_profiler (module, name, desc);
 }
 
 static gboolean
-load_profiler_from_directory (const char *directory, const char *libname, const char *desc)
+load_profiler_from_directory (const char *directory, const char *libname, const char *name, const char *desc)
 {
        char* path;
        void *iter = NULL;
@@ -102,14 +90,14 @@ load_profiler_from_directory (const char *directory, const char *libname, const
                g_free (path);
 
                if (module)
-                       return load_profiler (module, desc, NULL);
+                       return load_profiler (module, name, desc);
        }
 
        return FALSE;
 }
 
 static gboolean
-load_profiler_from_installation (const char *libname, const char *desc)
+load_profiler_from_installation (const char *libname, const char *name, const char *desc)
 {
        char *err;
        MonoDl *module = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err);
@@ -117,7 +105,7 @@ load_profiler_from_installation (const char *libname, const char *desc)
        g_free (err);
 
        if (module)
-               return load_profiler (module, desc, NULL);
+               return load_profiler (module, name, desc);
 
        return FALSE;
 }
@@ -125,8 +113,6 @@ load_profiler_from_installation (const char *libname, const char *desc)
 void
 mono_profiler_load (const char *desc)
 {
-       mono_gc_base_init ();
-
        if (!desc || !strcmp ("default", desc))
                desc = "log:report";
 
@@ -139,18 +125,18 @@ mono_profiler_load (const char *desc)
        } else
                mname = g_strdup (desc);
 
-       if (!load_profiler_from_executable (desc, mname)) {
+       if (!load_profiler_from_executable (mname, desc)) {
                char *libname = g_strdup_printf ("mono-profiler-%s", mname);
-               gboolean res = load_profiler_from_installation (libname, desc);
+               gboolean res = load_profiler_from_installation (libname, mname, desc);
 
                if (!res && mono_config_get_assemblies_dir ())
-                       res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc);
+                       res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, mname, desc);
 
                if (!res)
-                       res = load_profiler_from_directory (NULL, libname, desc);
+                       res = load_profiler_from_directory (NULL, libname, mname, desc);
 
                if (!res)
-                       g_warning ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
+                       mono_profiler_printf_err ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
 
                g_free (libname);
        }
@@ -159,7 +145,7 @@ mono_profiler_load (const char *desc)
 }
 
 MonoProfilerHandle
-mono_profiler_install (MonoProfiler *prof)
+mono_profiler_create (MonoProfiler *prof)
 {
        MonoProfilerHandle handle = g_new0 (struct _MonoProfilerDesc, 1);
 
@@ -326,7 +312,7 @@ mono_profiler_enable_sampling (MonoProfilerHandle handle)
 }
 
 mono_bool
-mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint64_t freq)
+mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint32_t freq)
 {
        if (handle != mono_profiler_state.sampling_owner)
                return FALSE;
@@ -334,13 +320,13 @@ mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode
        mono_profiler_state.sample_mode = mode;
        mono_profiler_state.sample_freq = freq;
 
-       mono_os_sem_post (&mono_profiler_state.sampling_semaphore);
+       mono_profiler_sampling_thread_post ();
 
        return TRUE;
 }
 
 mono_bool
-mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint64_t *freq)
+mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint32_t *freq)
 {
        if (mode)
                *mode = mono_profiler_state.sample_mode;
@@ -358,7 +344,13 @@ mono_profiler_sampling_enabled (void)
 }
 
 void
-mono_profiler_sampling_thread_sleep (void)
+mono_profiler_sampling_thread_post (void)
+{
+       mono_os_sem_post (&mono_profiler_state.sampling_semaphore);
+}
+
+void
+mono_profiler_sampling_thread_wait (void)
 {
        mono_os_sem_wait (&mono_profiler_state.sampling_semaphore, MONO_SEM_FLAGS_NONE);
 }
@@ -369,9 +361,7 @@ mono_profiler_enable_allocations (void)
        if (mono_profiler_state.startup_done)
                return FALSE;
 
-       mono_profiler_state.allocations = TRUE;
-
-       return TRUE;
+       return mono_profiler_state.allocations = TRUE;
 }
 
 void
@@ -380,8 +370,61 @@ mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handl
        InterlockedWritePointer (&handle->call_instrumentation_filter, (gpointer) cb);
 }
 
-gboolean
-mono_profiler_should_instrument_method (MonoMethod *method, gboolean entry)
+mono_bool
+mono_profiler_enable_call_context_introspection (void)
+{
+       if (mono_profiler_state.startup_done)
+               return FALSE;
+
+       mono_profiler_state.context_enable ();
+
+       return mono_profiler_state.call_contexts = TRUE;
+}
+
+void *
+mono_profiler_call_context_get_this (MonoProfilerCallContext *context)
+{
+       if (!mono_profiler_state.call_contexts)
+               return NULL;
+
+       return mono_profiler_state.context_get_this (context);
+}
+
+void *
+mono_profiler_call_context_get_argument (MonoProfilerCallContext *context, uint32_t position)
+{
+       if (!mono_profiler_state.call_contexts)
+               return NULL;
+
+       return mono_profiler_state.context_get_argument (context, position);
+}
+
+void *
+mono_profiler_call_context_get_local (MonoProfilerCallContext *context, uint32_t position)
+{
+       if (!mono_profiler_state.call_contexts)
+               return NULL;
+
+       return mono_profiler_state.context_get_local (context, position);
+}
+
+void *
+mono_profiler_call_context_get_result (MonoProfilerCallContext *context)
+{
+       if (!mono_profiler_state.call_contexts)
+               return NULL;
+
+       return mono_profiler_state.context_get_result (context);
+}
+
+void
+mono_profiler_call_context_free_buffer (void *buffer)
+{
+       mono_profiler_state.context_free_buffer (buffer);
+}
+
+MonoProfilerCallInstrumentationFlags
+mono_profiler_get_call_instrumentation_flags (MonoMethod *method)
 {
        MonoProfilerCallInstrumentationFlags flags = MONO_PROFILER_CALL_INSTRUMENTATION_NONE;
 
@@ -392,10 +435,7 @@ mono_profiler_should_instrument_method (MonoMethod *method, gboolean entry)
                        flags |= cb (handle->prof, method);
        }
 
-       if (entry)
-               return flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE;
-       else
-               return flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE;
+       return flags;
 }
 
 void
@@ -527,3 +567,134 @@ update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *co
 #undef MONO_PROFILER_EVENT_3
 #undef MONO_PROFILER_EVENT_4
 #undef _MONO_PROFILER_EVENT
+
+/*
+ * The following code is here to maintain compatibility with a few profiler API
+ * functions used by Xamarin.{Android,iOS,Mac} so that they keep working
+ * regardless of which system Mono version is used.
+ *
+ * TODO: Remove this some day if we're OK with breaking compatibility.
+ */
+
+typedef void *MonoLegacyProfiler;
+
+typedef void (*MonoLegacyProfileFunc) (MonoLegacyProfiler *prof);
+typedef void (*MonoLegacyProfileThreadFunc) (MonoLegacyProfiler *prof, uintptr_t tid);
+typedef void (*MonoLegacyProfileGCFunc) (MonoLegacyProfiler *prof, MonoProfilerGCEvent event, int generation);
+typedef void (*MonoLegacyProfileGCResizeFunc) (MonoLegacyProfiler *prof, int64_t new_size);
+typedef void (*MonoLegacyProfileJitResult) (MonoLegacyProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result);
+
+struct _MonoProfiler {
+       MonoProfilerHandle handle;
+       MonoLegacyProfiler *profiler;
+       MonoLegacyProfileFunc shutdown_callback;
+       MonoLegacyProfileThreadFunc thread_start, thread_end;
+       MonoLegacyProfileGCFunc gc_event;
+       MonoLegacyProfileGCResizeFunc gc_heap_resize;
+       MonoLegacyProfileJitResult jit_end2;
+};
+
+static MonoProfiler *current;
+
+MONO_API void mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback);
+MONO_API void mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end);
+MONO_API void mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback);
+MONO_API void mono_profiler_install_jit_end (MonoLegacyProfileJitResult end);
+MONO_API void mono_profiler_set_events (int flags);
+
+static void
+shutdown_cb (MonoProfiler *prof)
+{
+       prof->shutdown_callback (prof->profiler);
+}
+
+void
+mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback)
+{
+       current = g_new0 (MonoProfiler, 1);
+       current->handle = mono_profiler_create (current);
+       current->profiler = prof;
+       current->shutdown_callback = callback;
+
+       if (callback)
+               mono_profiler_set_runtime_shutdown_end_callback (current->handle, shutdown_cb);
+}
+
+static void
+thread_start_cb (MonoProfiler *prof, uintptr_t tid)
+{
+       prof->thread_start (prof->profiler, tid);
+}
+
+static void
+thread_stop_cb (MonoProfiler *prof, uintptr_t tid)
+{
+       prof->thread_end (prof->profiler, tid);
+}
+
+void
+mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end)
+{
+       current->thread_start = start;
+       current->thread_end = end;
+
+       if (start)
+               mono_profiler_set_thread_started_callback (current->handle, thread_start_cb);
+
+       if (end)
+               mono_profiler_set_thread_stopped_callback (current->handle, thread_stop_cb);
+}
+
+static void
+gc_event_cb (MonoProfiler *prof, MonoProfilerGCEvent event, uint32_t generation)
+{
+       prof->gc_event (prof->profiler, event, generation);
+}
+
+static void
+gc_resize_cb (MonoProfiler *prof, uintptr_t size)
+{
+       prof->gc_heap_resize (prof->profiler, size);
+}
+
+void
+mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback)
+{
+       current->gc_event = callback;
+       current->gc_heap_resize = heap_resize_callback;
+
+       if (callback)
+               mono_profiler_set_gc_event_callback (current->handle, gc_event_cb);
+
+       if (heap_resize_callback)
+               mono_profiler_set_gc_resize_callback (current->handle, gc_resize_cb);
+}
+
+static void
+jit_done_cb (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
+{
+       prof->jit_end2 (prof->profiler, method, jinfo, 0);
+}
+
+static void
+jit_failed_cb (MonoProfiler *prof, MonoMethod *method)
+{
+       prof->jit_end2 (prof->profiler, method, NULL, 1);
+}
+
+void
+mono_profiler_install_jit_end (MonoLegacyProfileJitResult end)
+{
+       current->jit_end2 = end;
+
+       if (end) {
+               mono_profiler_set_jit_done_callback (current->handle, jit_done_cb);
+               mono_profiler_set_jit_failed_callback (current->handle, jit_failed_cb);
+       }
+}
+
+void
+mono_profiler_set_events (int flags)
+{
+       /* Do nothing. */
+}