Merge pull request #2816 from xmcclure/profile-clean-0
[mono.git] / mono / metadata / profiler.c
index e113e535a59c710993b8ca9312a6e929355424ea..d74a273d085bf0825656642a845a683722b5ea89 100644 (file)
@@ -3,10 +3,12 @@
  *
  * Author:
  *   Paolo Molaro (lupus@ximian.com)
+ *   Alex Rønne Petersen (alexrp@xamarin.com)
  *
  * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
  * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
  * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
  */
 
 #include "config.h"
 #include "mono/metadata/metadata-internals.h"
 #include "mono/metadata/class-internals.h"
 #include "mono/metadata/domain-internals.h"
-#include "mono/metadata/gc-internal.h"
+#include "mono/metadata/gc-internals.h"
 #include "mono/metadata/mono-config-dirs.h"
 #include "mono/io-layer/io-layer.h"
 #include "mono/utils/mono-dl.h"
+#include <mono/utils/mono-logger-internals.h>
 #include <string.h>
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
@@ -43,6 +46,10 @@ struct _ProfilerDesc {
        MonoProfileAppDomainResult domain_end_load;
        MonoProfileAppDomainFunc   domain_start_unload;
        MonoProfileAppDomainFunc   domain_end_unload;
+       MonoProfileAppDomainFriendlyNameFunc   domain_name;
+
+       MonoProfileContextFunc context_load;
+       MonoProfileContextFunc context_unload;
 
        MonoProfileAssemblyFunc   assembly_start_load;
        MonoProfileAssemblyResult assembly_end_load;
@@ -104,8 +111,8 @@ struct _ProfilerDesc {
 
 static ProfilerDesc *prof_list = NULL;
 
-#define mono_profiler_coverage_lock() mono_mutex_lock (&profiler_coverage_mutex)
-#define mono_profiler_coverage_unlock() mono_mutex_unlock (&profiler_coverage_mutex)
+#define mono_profiler_coverage_lock() mono_os_mutex_lock (&profiler_coverage_mutex)
+#define mono_profiler_coverage_unlock() mono_os_mutex_unlock (&profiler_coverage_mutex)
 static mono_mutex_t profiler_coverage_mutex;
 
 /* this is directly accessible to other mono libs.
@@ -116,7 +123,6 @@ MonoProfileFlags mono_profiler_events;
 /**
  * mono_profiler_install:
  * @prof: a MonoProfiler structure pointer, or a pointer to a derived structure.
- * @version: profiler API version (see profiler.h)
  * @callback: the function to invoke at shutdown
  *
  * Use mono_profiler_install to activate profiling in the Mono runtime.
@@ -126,14 +132,11 @@ MonoProfileFlags mono_profiler_events;
  *
  */
 void
-mono_profiler_install (MonoProfiler *prof, int version, MonoProfileFunc callback)
+mono_profiler_install (MonoProfiler *prof, MonoProfileFunc callback)
 {
-       if (version != MONO_PROFILER_VERSION)
-               g_warning ("Profiler module API version (%i) potentially incompatible with current API version (%i)", version, MONO_PROFILER_VERSION);
-
        ProfilerDesc *desc = g_new0 (ProfilerDesc, 1);
        if (!prof_list)
-               mono_mutex_init_recursive (&profiler_coverage_mutex);
+               mono_os_mutex_init_recursive (&profiler_coverage_mutex);
        desc->profiler = prof;
        desc->shutdown_callback = callback;
        desc->next = prof_list;
@@ -158,11 +161,11 @@ void
 mono_profiler_set_events (MonoProfileFlags events)
 {
        ProfilerDesc *prof;
-       MonoProfileFlags value = 0;
+       MonoProfileFlags value = (MonoProfileFlags)0;
        if (prof_list)
                prof_list->events = events;
        for (prof = prof_list; prof; prof = prof->next)
-               value |= prof->events;
+               value = (MonoProfileFlags)(value | prof->events);
        mono_profiler_events = value;
 }
 
@@ -265,6 +268,7 @@ mono_profiler_install_transition (MonoProfileMethodResult callback)
 void 
 mono_profiler_install_allocation (MonoProfileAllocFunc callback)
 {
+       mono_gc_enable_alloc_events ();
        if (!prof_list)
                return;
        prof_list->allocation_cb = callback;
@@ -383,6 +387,25 @@ mono_profiler_install_appdomain   (MonoProfileAppDomainFunc start_load, MonoProf
        prof_list->domain_end_unload = end_unload;
 }
 
+void
+mono_profiler_install_appdomain_name (MonoProfileAppDomainFriendlyNameFunc domain_name_cb)
+{
+       if (!prof_list)
+               return;
+
+       prof_list->domain_name = domain_name_cb;
+}
+
+void
+mono_profiler_install_context (MonoProfileContextFunc load, MonoProfileContextFunc unload)
+{
+       if (!prof_list)
+               return;
+
+       prof_list->context_load = load;
+       prof_list->context_unload = unload;
+}
+
 void 
 mono_profiler_install_assembly    (MonoProfileAssemblyFunc start_load, MonoProfileAssemblyResult end_load,
                                    MonoProfileAssemblyFunc start_unload, MonoProfileAssemblyFunc end_unload)
@@ -504,12 +527,12 @@ mono_profiler_code_transition (MonoMethod *method, int result)
 }
 
 void 
-mono_profiler_allocation (MonoObject *obj, MonoClass *klass)
+mono_profiler_allocation (MonoObject *obj)
 {
        ProfilerDesc *prof;
        for (prof = prof_list; prof; prof = prof->next) {
                if ((prof->events & MONO_PROFILE_ALLOCATIONS) && prof->allocation_cb)
-                       prof->allocation_cb (prof->profiler, obj, klass);
+                       prof->allocation_cb (prof->profiler, obj, obj->vtable->klass);
        }
 }
 
@@ -759,6 +782,30 @@ mono_profiler_appdomain_loaded (MonoDomain *domain, int result)
        }
 }
 
+void
+mono_profiler_appdomain_name (MonoDomain *domain, const char *name)
+{
+       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
+               if ((prof->events & MONO_PROFILE_APPDOMAIN_EVENTS) && prof->domain_name)
+                       prof->domain_name (prof->profiler, domain, name);
+}
+
+void
+mono_profiler_context_loaded (MonoAppContext *context)
+{
+       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
+               if ((prof->events & MONO_PROFILE_CONTEXT_EVENTS) && prof->context_load)
+                       prof->context_load (prof->profiler, context);
+}
+
+void
+mono_profiler_context_unloaded (MonoAppContext *context)
+{
+       for (ProfilerDesc *prof = prof_list; prof; prof = prof->next)
+               if ((prof->events & MONO_PROFILE_CONTEXT_EVENTS) && prof->context_unload)
+                       prof->context_unload (prof->profiler, context);
+}
+
 void 
 mono_profiler_shutdown (void)
 {
@@ -768,7 +815,7 @@ mono_profiler_shutdown (void)
                        prof->shutdown_callback (prof->profiler);
        }
 
-       mono_profiler_set_events (0);
+       mono_profiler_set_events ((MonoProfileFlags)0);
 }
 
 void
@@ -973,7 +1020,7 @@ mono_profiler_coverage_alloc (MonoMethod *method, int entries)
        if (!coverage_hash)
                coverage_hash = g_hash_table_new (NULL, NULL);
 
-       res = g_malloc0 (sizeof (MonoProfileCoverageInfo) + sizeof (void*) * 2 * entries);
+       res = (MonoProfileCoverageInfo *)g_malloc0 (sizeof (MonoProfileCoverageInfo) + sizeof (void*) * 2 * entries);
 
        res->entries = entries;
 
@@ -995,7 +1042,7 @@ mono_profiler_coverage_free (MonoMethod *method)
                return;
        }
 
-       info = g_hash_table_lookup (coverage_hash, method);
+       info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method);
        if (info) {
                g_free (info);
                g_hash_table_remove (coverage_hash, method);
@@ -1018,6 +1065,7 @@ mono_profiler_coverage_free (MonoMethod *method)
 void 
 mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileCoverageFunc func)
 {
+       MonoError error;
        MonoProfileCoverageInfo* info = NULL;
        int i, offset;
        guint32 code_size;
@@ -1028,13 +1076,14 @@ mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileC
 
        mono_profiler_coverage_lock ();
        if (coverage_hash)
-               info = g_hash_table_lookup (coverage_hash, method);
+               info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method);
        mono_profiler_coverage_unlock ();
 
        if (!info)
                return;
 
-       header = mono_method_get_header (method);
+       header = mono_method_get_header_checked (method, &error);
+       mono_error_assert_ok (&error);
        start = mono_method_header_get_code (header, &code_size, NULL);
        debug_minfo = mono_debug_lookup_method (method);
 
@@ -1120,10 +1169,13 @@ load_profiler_from_directory (const char *directory, const char *libname, const
        char *err;
        void *iter;
 
+       mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Attempting to load profiler %s from %s (desc %s)", libname, directory, desc);
+
        iter = NULL;
        err = NULL;
        while ((path = mono_dl_build_path (directory, libname, &iter))) {
                pmodule = mono_dl_open (path, MONO_DL_LAZY, &err);
+               mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Attempting to load profiler: %s %ssuccessful, err: %s", path, pmodule?"":"not ", err);
                g_free (path);
                g_free (err);
                if (pmodule)
@@ -1195,14 +1247,17 @@ mono_profiler_load (const char *desc)
                gboolean res = FALSE;
 
                if (col != NULL) {
-                       mname = g_memdup (desc, col - desc + 1);
+                       mname = (char *)g_memdup (desc, col - desc + 1);
                        mname [col - desc] = 0;
                } else {
                        mname = g_strdup (desc);
                }
                if (!load_embedded_profiler (desc, mname)) {
                        libname = g_strdup_printf ("mono-profiler-%s", mname);
-                       if (mono_config_get_assemblies_dir ())
+                       char *profiler_lib_dir = getenv ("MONO_PROFILER_LIB_DIR");
+                       if (profiler_lib_dir)
+                               res = load_profiler_from_directory (profiler_lib_dir, libname, desc);
+                       if (!res && mono_config_get_assemblies_dir ())
                                res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc);
                        if (!res)
                                res = load_profiler_from_directory (NULL, libname, desc);