*
* 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"
MonoProfileGCResizeFunc gc_heap_resize;
MonoProfileGCMoveFunc gc_moves;
MonoProfileGCHandleFunc gc_handle;
+ MonoProfileGCRootFunc gc_roots;
MonoProfileFunc runtime_initialized_event;
}
}
+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)
{
/**
* 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)
+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
typedef void (*ProfilerInitializer) (const char*);
#define INITIALIZER_NAME "mono_profiler_startup"
+
+static gboolean
+load_profiler (MonoDl *pmodule, const char *desc, const char *symbol)
+{
+ char *err;
+ ProfilerInitializer func;
+
+ if (!pmodule)
+ return FALSE;
+
+ if ((err = mono_dl_symbol (pmodule, symbol, (gpointer *) &func))) {
+ g_free (err);
+ return FALSE;
+ } else {
+ func (desc);
+ }
+ return TRUE;
+}
+
+static gboolean
+load_embedded_profiler (const char *desc, const char *name)
+{
+ char *err = NULL;
+ char *symbol;
+ MonoDl *pmodule = NULL;
+ gboolean result;
+
+ pmodule = mono_dl_open (NULL, MONO_DL_LAZY, &err);
+ if (!pmodule) {
+ g_warning ("Could not open main executable (%s)", err);
+ g_free (err);
+ return FALSE;
+ }
+
+ symbol = g_strdup_printf (INITIALIZER_NAME "_%s", name);
+ result = load_profiler (pmodule, desc, symbol);
+ g_free (symbol);
+
+ return result;
+}
+
+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))) {
+ pmodule = mono_dl_open (path, MONO_DL_LAZY, &err);
+ g_free (path);
+ g_free (err);
+ if (pmodule)
+ return load_profiler (pmodule, desc, INITIALIZER_NAME);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+load_profiler_from_mono_instalation (const char *libname, const char *desc)
+{
+ char *err = NULL;
+ MonoDl *pmodule = mono_dl_open_runtime_lib (libname, MONO_DL_LAZY, &err);
+ g_free (err);
+ if (pmodule)
+ return load_profiler (pmodule, desc, INITIALIZER_NAME);
+ return FALSE;
+}
+
/**
* mono_profiler_load:
* @desc: arguments to configure the profiler
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;
+ gboolean res = FALSE;
+
if (col != NULL) {
mname = g_memdup (desc, col - desc + 1);
mname [col - desc] = 0;
} else {
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;
+ if (!load_embedded_profiler (desc, mname)) {
+ libname = g_strdup_printf ("mono-profiler-%s", mname);
+ if (!load_profiler_from_directory (NULL, libname, desc)) {
+ res = FALSE;
+#if defined (MONO_ASSEMBLIES)
+ res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc);
+#endif
+ if (!res)
+ res = load_profiler_from_mono_instalation (libname, desc);
+
+ if (!res)
+ g_warning ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
}
- g_free (path);
+ g_free (libname);
}
- if (!pmodule) {
- g_warning ("Error loading profiler module '%s': %s", libname, err);
- g_free (err);
- }
- g_free (libname);
g_free (mname);
- g_free (path);
}
+ g_free (cdesc);
}