X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fprofiler.c;h=8323e3984cfcae0522a6c33690a0f7d3a77f1cee;hb=57cd4050c4c46d4e39717dadeae9516f147af7f6;hp=d9bda6f7292079a556dde092e97cb71635fdcb61;hpb=93703b4ef8bdcf1d6cf336e14f534454221730c5;p=mono.git diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c index d9bda6f7292..8323e3984cf 100644 --- a/mono/metadata/profiler.c +++ b/mono/metadata/profiler.c @@ -18,9 +18,14 @@ #include "mono/metadata/domain-internals.h" #include "mono/metadata/gc-internal.h" #include "mono/io-layer/io-layer.h" +#include "mono/utils/mono-dl.h" #include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_TIME_H #include -#include +#endif #ifdef HAVE_BACKTRACE_SYMBOLS #include #endif @@ -50,12 +55,19 @@ static MonoProfileClassFunc class_end_unload; static MonoProfileMethodFunc jit_start; static MonoProfileMethodResult jit_end; static MonoProfileJitResult jit_end2; +static MonoProfileMethodFunc method_free; static MonoProfileMethodResult man_unman_transition; static MonoProfileAllocFunc allocation_cb; static MonoProfileStatFunc statistical_cb; +static MonoProfileStatCallChainFunc statistical_call_chain_cb; +static int statistical_call_chain_depth; static MonoProfileMethodFunc method_enter; static MonoProfileMethodFunc method_leave; +static MonoProfileExceptionFunc exception_throw_cb; +static MonoProfileMethodFunc exception_method_leave_cb; +static MonoProfileExceptionClauseFunc exception_clause_cb; + static MonoProfileThreadFunc thread_start; static MonoProfileThreadFunc thread_end; @@ -162,6 +174,12 @@ mono_profiler_install_jit_end (MonoProfileJitResult end) jit_end2 = end; } +void +mono_profiler_install_method_free (MonoProfileMethodFunc callback) +{ + method_free = callback; +} + void mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc end) { @@ -187,6 +205,31 @@ mono_profiler_install_statistical (MonoProfileStatFunc callback) statistical_cb = callback; } +void +mono_profiler_install_statistical_call_chain (MonoProfileStatCallChainFunc callback, int call_chain_depth) { + statistical_call_chain_cb = callback; + statistical_call_chain_depth = call_chain_depth; + if (statistical_call_chain_depth > MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH) { + statistical_call_chain_depth = MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH; + } +} + +int +mono_profiler_stat_get_call_chain_depth (void) { + if (statistical_call_chain_cb != NULL) { + return statistical_call_chain_depth; + } else { + return 0; + } +} + +void mono_profiler_install_exception (MonoProfileExceptionFunc throw_callback, MonoProfileMethodFunc exc_method_leave, MonoProfileExceptionClauseFunc clause_callback) +{ + exception_throw_cb = throw_callback; + exception_method_leave_cb = exc_method_leave; + exception_clause_cb = clause_callback; +} + void mono_profiler_install_coverage_filter (MonoProfileCoverageFilterFunc callback) { @@ -266,6 +309,13 @@ mono_profiler_method_end_jit (MonoMethod *method, MonoJitInfo* jinfo, int result } } +void +mono_profiler_method_free (MonoMethod *method) +{ + if ((mono_profiler_events & MONO_PROFILE_METHOD_EVENTS) && method_free) + method_free (current_profiler, method); +} + void mono_profiler_code_transition (MonoMethod *method, int result) { @@ -287,6 +337,34 @@ mono_profiler_stat_hit (guchar *ip, void *context) statistical_cb (current_profiler, ip, context); } +void +mono_profiler_stat_call_chain (int call_chain_depth, guchar **ips, void *context) +{ + if ((mono_profiler_events & MONO_PROFILE_STATISTICAL) && statistical_call_chain_cb) + statistical_call_chain_cb (current_profiler, call_chain_depth, ips, context); +} + +void +mono_profiler_exception_thrown (MonoObject *exception) +{ + if ((mono_profiler_events & MONO_PROFILE_EXCEPTIONS) && exception_throw_cb) + exception_throw_cb (current_profiler, exception); +} + +void +mono_profiler_exception_method_leave (MonoMethod *method) +{ + if ((mono_profiler_events & MONO_PROFILE_EXCEPTIONS) && exception_method_leave_cb) + exception_method_leave_cb (current_profiler, method); +} + +void +mono_profiler_exception_clause_handler (MonoMethod *method, int clause_type, int clause_num) +{ + if ((mono_profiler_events & MONO_PROFILE_EXCEPTIONS) && exception_clause_cb) + exception_clause_cb (current_profiler, method, clause_type, clause_num); +} + void mono_profiler_thread_start (gsize tid) { @@ -537,6 +615,7 @@ mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileC for (i = 0; i < info->entries; ++i) { cil_code = info->data [i].cil_code; if (cil_code && cil_code >= start && cil_code < end) { + char *fname = NULL; offset = cil_code - start; entry.iloffset = offset; entry.method = method; @@ -550,13 +629,13 @@ mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileC if (location) { entry.line = location->row; entry.col = location->column; - entry.filename = g_strdup (location->source_file); + entry.filename = fname = g_strdup (location->source_file); mono_debug_free_source_location (location); } } func (prof, &entry); - g_free (entry.filename); + g_free (fname); } } } @@ -811,6 +890,14 @@ method_get_name (MonoMethod* method) static void output_callers (MethodProfile *p); +/* This isn't defined on older glib versions and on some platforms */ +#ifndef G_GUINT64_FORMAT +#define G_GUINT64_FORMAT "ul" +#endif +#ifndef G_GINT64_FORMAT +#define G_GINT64_FORMAT "lld" +#endif + static void output_profile (GList *funcs) { @@ -829,7 +916,7 @@ output_profile (GList *funcs) m = method_get_name (p->method); fprintf (poutput, "########################\n"); fprintf (poutput, "% 8.3f ", (double) (p->total * 1000)); - fprintf (poutput, "%7llu ", (unsigned long long)p->count); + fprintf (poutput, "%7" G_GUINT64_FORMAT " ", (guint64)p->count); fprintf (poutput, "% 8.3f ", (double) (p->total * 1000)/(double)p->count); fprintf (poutput, " %s\n", m); @@ -837,7 +924,7 @@ output_profile (GList *funcs) /* callers */ output_callers (p); } - fprintf (poutput, "Total number of calls: %lld\n", (long long)total_calls); + fprintf (poutput, "Total number of calls: %" G_GINT64_FORMAT "\n", (gint64)total_calls); } typedef struct { @@ -927,11 +1014,6 @@ output_callers (MethodProfile *p) { } } -/* This isn't defined on older glib versions and on some platforms */ -#ifndef G_GUINT64_FORMAT -#define G_GUINT64_FORMAT "ul" -#endif - static void output_newobj_profile (GList *proflist) { @@ -1228,6 +1310,17 @@ try_addr2line (const char* binary, gpointer ip) const char *addr_argv[] = {"addr2line", "-f", "-e", binary, NULL}; int child_pid; int ch_in, ch_out; +#ifdef __linux__ + char monobin [1024]; + /* non-linux platforms will need different code here */ + if (strcmp (binary, "mono") == 0) { + int count = readlink ("/proc/self/exe", monobin, sizeof (monobin)); + if (count >= 0 && count < sizeof (monobin)) { + monobin [count] = 0; + addr_argv [3] = monobin; + } + } +#endif if (!g_spawn_async_with_pipes (NULL, (char**)addr_argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &child_pid, &ch_in, &ch_out, NULL, NULL)) { return g_strdup (binary); @@ -1325,12 +1418,13 @@ static void simple_appdomain_unload (MonoProfiler *prof, MonoDomain *domain) { /* FIXME: we should actually record partial data for each domain, - * since the ip->ji->method mappings are going away at domain unload time. + * but at this point it's must easier using the new logging profiler. */ - if (domain == mono_get_root_domain ()) - stat_prof_report (); + mono_profiler_shutdown (); } +static gint32 simple_shutdown_done = FALSE; + static void simple_shutdown (MonoProfiler *prof) { @@ -1338,7 +1432,22 @@ simple_shutdown (MonoProfiler *prof) MonoProfiler *tprof; GSList *tmp; char *str; + gint32 see_shutdown_done; + + mono_thread_attach(mono_get_root_domain()); + + // Make sure we execute simple_shutdown only once + see_shutdown_done = InterlockedExchange(& simple_shutdown_done, TRUE); + if (see_shutdown_done) + return; + if (mono_profiler_events & MONO_PROFILE_STATISTICAL) { + stat_prof_report (); + } + + // Stop all incoming events + mono_profiler_set_events (0); + for (tmp = prof->per_thread; tmp; tmp = tmp->next) { tprof = tmp->data; merge_thread_data (prof, tprof); @@ -1388,12 +1497,14 @@ mono_profiler_install_simple (const char *desc) for (ptr = args; ptr && *ptr; ptr++) { const char *arg = *ptr; + // Alwais listen to appdomaon events to shutdown at the first unload + flags |= MONO_PROFILE_APPDOMAIN_EVENTS; if (!strcmp (arg, "time")) - flags |= MONO_PROFILE_ENTER_LEAVE; + flags |= MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_EXCEPTIONS; else if (!strcmp (arg, "alloc")) flags |= MONO_PROFILE_ALLOCATIONS; else if (!strcmp (arg, "stat")) - flags |= MONO_PROFILE_STATISTICAL | MONO_PROFILE_APPDOMAIN_EVENTS; + flags |= MONO_PROFILE_STATISTICAL; else if (!strcmp (arg, "jit")) flags |= MONO_PROFILE_JIT_COMPILATION; else if (strncmp (arg, "file=", 5) == 0) { @@ -1408,6 +1519,10 @@ mono_profiler_install_simple (const char *desc) } } } + if (flags & MONO_PROFILE_ALLOCATIONS) + flags |= MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_EXCEPTIONS; + if (!flags) + flags = MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_ALLOCATIONS | MONO_PROFILE_JIT_COMPILATION | MONO_PROFILE_EXCEPTIONS; prof = create_profiler (); ALLOC_PROFILER (); @@ -1419,6 +1534,7 @@ mono_profiler_install_simple (const char *desc) mono_profiler_install (prof, simple_shutdown); mono_profiler_install_enter_leave (simple_method_enter, simple_method_leave); + mono_profiler_install_exception (NULL, simple_method_leave, NULL); mono_profiler_install_jit_compile (simple_method_jit, simple_method_end_jit); mono_profiler_install_allocation (simple_allocation); mono_profiler_install_appdomain (NULL, NULL, simple_appdomain_unload, NULL); @@ -1455,31 +1571,42 @@ mono_profiler_load (const char *desc) } #endif { - GModule *pmodule; + MonoDl *pmodule; const char* col = strchr (desc, ':'); char* libname; char* path; char *mname; + char *err; + void *iter; if (col != NULL) { - mname = g_memdup (desc, col - desc); + mname = g_memdup (desc, col - desc + 1); mname [col - desc] = 0; } else { mname = g_strdup (desc); } libname = g_strdup_printf ("mono-profiler-%s", mname); - path = g_module_build_path (NULL, libname); - pmodule = g_module_open (path, G_MODULE_BIND_LAZY); - if (pmodule) { - ProfilerInitializer func; - if (!g_module_symbol (pmodule, INITIALIZER_NAME, (gpointer *)&func)) { - g_warning ("Cannot find initializer function %s in profiler module: %s", INITIALIZER_NAME, libname); - } else { - func (desc); + 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; } - } else { - g_warning ("Error loading profiler module '%s': %s", libname, g_module_error ()); + g_free (path); + } + if (!pmodule) { + g_warning ("Error loading profiler module '%s': %s", libname, err); + g_free (err); } - g_free (libname); g_free (mname); g_free (path);