#include <mono/metadata/mono-config-dirs.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/profiler-private.h>
+#include <mono/metadata/debug-internals.h>
#include <mono/utils/mono-dl.h>
#include <mono/utils/mono-error-internals.h>
#include <mono/utils/mono-logger-internals.h>
#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))) {
- mono_profiler_printf_err ("Found old-style startup symbol %s for %s; profiler has not been migrated to the new API.", old_name, desc);
+ 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;
}
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);
}
static gboolean
-load_profiler_from_executable (const char *desc, const char *name)
+load_profiler_from_executable (const char *name, const char *desc)
{
char *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;
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);
g_free (err);
if (module)
- return load_profiler (module, desc, NULL);
+ return load_profiler (module, name, desc);
return FALSE;
}
void
mono_profiler_load (const char *desc)
{
- mono_gc_base_init ();
-
if (!desc || !strcmp ("default", desc))
desc = "log:report";
} 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)
mono_profiler_printf_err ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
}
MonoProfilerHandle
-mono_profiler_install (MonoProfiler *prof)
+mono_profiler_create (MonoProfiler *prof)
{
MonoProfilerHandle handle = g_new0 (struct _MonoProfilerDesc, 1);
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 mono_profiler_state.code_coverage = TRUE;
}
static 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 ();
coverage_unlock ();
- if (!info)
- return;
-
MonoError error;
MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
mono_error_assert_ok (&error);
guint32 size;
const unsigned char *start = mono_method_header_get_code (header, &size, NULL);
- const unsigned char *end = start - size;
+ const unsigned char *end = start + size;
MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
+ if (!info) {
+ char *source_file;
+ int i, n_il_offsets;
+ int *source_files;
+ GPtrArray *source_file_list;
+ MonoSymSeqPoint *sym_seq_points;
+
+ /* Return 0 counts for all locations */
+
+ mono_debug_get_seq_points (minfo, &source_file, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets);
+ for (i = 0; i < n_il_offsets; ++i) {
+ MonoSymSeqPoint *sp = &sym_seq_points [i];
+ const char *srcfile = "";
+
+ if (source_files [i] != -1) {
+ MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, source_files [i]);
+ srcfile = sinfo->source_file;
+ }
+
+ MonoProfilerCoverageData data = {
+ .method = method,
+ .il_offset = sp->il_offset,
+ .counter = 0,
+ .file_name = srcfile,
+ .line = sp->line,
+ .column = 0,
+ };
+
+ cb (handle->prof, &data);
+ }
+
+ g_free (source_files);
+ g_free (sym_seq_points);
+ g_ptr_array_free (source_file_list, TRUE);
+
+ mono_metadata_free_mh (header);
+ return TRUE;
+ }
+
for (guint32 i = 0; i < info->entries; i++) {
guchar *cil_code = info->data [i].cil_code;
}
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;
+
+ if (method->wrapper_type)
+ return FALSE;
gboolean cover = FALSE;
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)
{
}
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;
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;
}
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);
}
if (mono_profiler_state.startup_done)
return FALSE;
- mono_profiler_state.allocations = TRUE;
-
- return TRUE;
+ return mono_profiler_state.allocations = TRUE;
}
void
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;
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
#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
#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. */
+}