Fix warnings.
[mono.git] / mono / metadata / profiler.c
index ab61fbea1e9fdf1d1cad3dead71eb49cb7cefcf8..b67945aa2ba17543732caf5e5305b58e075e1e6f 100644 (file)
@@ -6,11 +6,12 @@
  *
  * 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).
  */
 
 #include "config.h"
 #include "mono/metadata/profiler-private.h"
-#include "mono/metadata/profiler-default.h"
+#include "mono/metadata/assembly.h"
 #include "mono/metadata/debug-helpers.h"
 #include "mono/metadata/mono-debug.h"
 #include "mono/metadata/debug-mono-symfile.h"
@@ -81,6 +82,7 @@ struct _ProfilerDesc {
 
        MonoProfileThreadFunc   thread_start;
        MonoProfileThreadFunc   thread_end;
+       MonoProfileThreadNameFunc   thread_name;
 
        MonoProfileCoverageFilterFunc coverage_filter_cb;
 
@@ -89,6 +91,8 @@ struct _ProfilerDesc {
        MonoProfileGCFunc        gc_event;
        MonoProfileGCResizeFunc  gc_heap_resize;
        MonoProfileGCMoveFunc    gc_moves;
+       MonoProfileGCHandleFunc  gc_handle;
+       MonoProfileGCRootFunc    gc_roots;
 
        MonoProfileFunc          runtime_initialized_event;
 
@@ -237,6 +241,14 @@ mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc
        prof_list->thread_end = end;
 }
 
+void 
+mono_profiler_install_thread_name (MonoProfileThreadNameFunc thread_name_cb)
+{
+       if (!prof_list)
+               return;
+       prof_list->thread_name = thread_name_cb;
+}
+
 void 
 mono_profiler_install_transition (MonoProfileMethodResult callback)
 {
@@ -541,6 +553,16 @@ mono_profiler_thread_end (gsize tid)
        }
 }
 
+void
+mono_profiler_thread_name (gsize tid, const char *name)
+{
+       ProfilerDesc *prof;
+       for (prof = prof_list; prof; prof = prof->next) {
+               if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_name)
+                       prof->thread_name (prof->profiler, tid, name);
+       }
+}
+
 void 
 mono_profiler_assembly_event  (MonoAssembly *assembly, int code)
 {
@@ -740,6 +762,26 @@ mono_profiler_gc_moves (void **objects, int num)
        }
 }
 
+void
+mono_profiler_gc_handle (int op, int type, uintptr_t handle, MonoObject *obj)
+{
+       ProfilerDesc *prof;
+       for (prof = prof_list; prof; prof = prof->next) {
+               if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_handle)
+                       prof->gc_handle (prof->profiler, op, type, handle, obj);
+       }
+}
+
+void
+mono_profiler_gc_roots (int num, void **objects, int *root_types, uintptr_t *extra_info)
+{
+       ProfilerDesc *prof;
+       for (prof = prof_list; prof; prof = prof->next) {
+               if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_roots)
+                       prof->gc_roots (prof->profiler, num, objects, root_types, extra_info);
+       }
+}
+
 void
 mono_profiler_install_gc (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback)
 {
@@ -772,6 +814,31 @@ mono_profiler_install_gc_moves (MonoProfileGCMoveFunc callback)
        prof_list->gc_moves = callback;
 }
 
+/**
+ * mono_profiler_install_gc_roots:
+ * @handle_callback: callback function
+ * @roots_callback: callback function
+ *
+ * Install the @handle_callback function that the GC will call when GC
+ * handles are created or destroyed.
+ * The callback receives an operation, which is either #MONO_PROFILER_GC_HANDLE_CREATED
+ * or #MONO_PROFILER_GC_HANDLE_DESTROYED, the handle type, the handle value and the
+ * object pointer, if present.
+ * Install the @roots_callback function that the GC will call when tracing
+ * the roots for a collection.
+ * The callback receives the number of elements and three arrays: an array
+ * of objects, an array of root types and flags and an array of extra info.
+ * The size of each array is given by the first argument.
+ */
+void
+mono_profiler_install_gc_roots (MonoProfileGCHandleFunc handle_callback, MonoProfileGCRootFunc roots_callback)
+{
+       if (!prof_list)
+               return;
+       prof_list->gc_handle = handle_callback;
+       prof_list->gc_roots = roots_callback;
+}
+
 void
 mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback)
 {
@@ -964,6 +1031,38 @@ mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileC
 typedef void (*ProfilerInitializer) (const char*);
 #define INITIALIZER_NAME "mono_profiler_startup"
 
+
+static gboolean
+load_profiler_from_directory (const char *directory, const char *libname, const char *desc)
+{
+       MonoDl *pmodule = NULL;
+       char* path;
+       char *err;
+       void *iter;
+
+       iter = NULL;
+       err = NULL;
+       while ((path = mono_dl_build_path (directory, libname, &iter))) {
+               g_free (err);
+               pmodule = mono_dl_open (path, MONO_DL_LAZY, &err);
+               if (pmodule) {
+                       ProfilerInitializer func;
+                       if ((err = mono_dl_symbol (pmodule, INITIALIZER_NAME, (gpointer *)&func))) {
+                               g_warning ("Cannot find initializer function %s in profiler module: %s (%s)", INITIALIZER_NAME, libname, err);
+                               g_free (err);
+                               err = NULL;
+                       } else {
+                               func (desc);
+                       }
+                       g_free (path);
+                       return TRUE;
+               }
+               g_free (path);
+       }
+               
+       return FALSE;
+}
+
 /**
  * mono_profiler_load:
  * @desc: arguments to configure the profiler
@@ -977,26 +1076,41 @@ typedef void (*ProfilerInitializer) (const char*);
 void 
 mono_profiler_load (const char *desc)
 {
+       char *cdesc = NULL;
        mono_gc_base_init ();
 
-#ifndef DISABLE_PROFILER
-       if (!desc || (strcmp ("default", desc) == 0) || (strncmp (desc, "default:", 8) == 0)) {
-               mono_profiler_install_simple (desc);
-               return;
+       if (!desc || (strcmp ("default", desc) == 0)) {
+               desc = "log:report";
        }
-#else
-       if (!desc) {
-               desc = "default";
+       /* we keep command-line compat with the old version here */
+       if (strncmp (desc, "default:", 8) == 0) {
+               gchar **args, **ptr;
+               GString *str = g_string_new ("log:report");
+               args = g_strsplit (desc + 8, ",", -1);
+               for (ptr = args; ptr && *ptr; ptr++) {
+                       const char *arg = *ptr;
+
+                       if (!strcmp (arg, "time"))
+                               g_string_append (str, ",calls");
+                       else if (!strcmp (arg, "alloc"))
+                               g_string_append (str, ",alloc");
+                       else if (!strcmp (arg, "stat"))
+                               g_string_append (str, ",sample");
+                       else if (!strcmp (arg, "jit"))
+                               continue; /* accept and do nothing */
+                       else if (strncmp (arg, "file=", 5) == 0) {
+                               g_string_append_printf (str, ",output=%s", arg + 5);
+                       } else {
+                               fprintf (stderr, "profiler : Unknown argument '%s'.\n", arg);
+                               return;
+                       }
+               }
+               desc = cdesc = g_string_free (str, FALSE);
        }
-#endif
        {
-               MonoDl *pmodule = NULL;
                const char* col = strchr (desc, ':');
                char* libname;
-               char* path;
                char *mname;
-               char *err;
-               void *iter;
                if (col != NULL) {
                        mname = g_memdup (desc, col - desc + 1);
                        mname [col - desc] = 0;
@@ -1004,31 +1118,13 @@ mono_profiler_load (const char *desc)
                        mname = g_strdup (desc);
                }
                libname = g_strdup_printf ("mono-profiler-%s", mname);
-               iter = NULL;
-               err = NULL;
-               while ((path = mono_dl_build_path (NULL, libname, &iter))) {
-                       g_free (err);
-                       pmodule = mono_dl_open (path, MONO_DL_LAZY, &err);
-                       if (pmodule) {
-                               ProfilerInitializer func;
-                               if ((err = mono_dl_symbol (pmodule, INITIALIZER_NAME, (gpointer *)&func))) {
-                                       g_warning ("Cannot find initializer function %s in profiler module: %s (%s)", INITIALIZER_NAME, libname, err);
-                                       g_free (err);
-                                       err = NULL;
-                               } else {
-                                       func (desc);
-                               }
-                               break;
-                       }
-                       g_free (path);
-               }
-               if (!pmodule) {
-                       g_warning ("Error loading profiler module '%s': %s", libname, err);
-                       g_free (err);
-               }
+               if (!load_profiler_from_directory (NULL, libname, desc))
+                       if (!load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc))
+                               g_warning ("Error loading profiler module '%s'", libname);
+                       
                g_free (libname);
                g_free (mname);
-               g_free (path);
        }
+       g_free (cdesc);
 }