/*
* proflog.c: mono log profiler
*
- * Author:
+ * Authors:
* Paolo Molaro (lupus@ximian.com)
+ * Alex Rønne Petersen (alexrp@xamarin.com)
*
* Copyright 2010 Novell, Inc (http://www.novell.com)
* Copyright 2011 Xamarin Inc (http://www.xamarin.com)
static gboolean debug_coverage = FALSE;
static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
-/* For linux compile with:
- * gcc -fPIC -shared -o libmono-profiler-log.so proflog.c utils.c -Wall -g -lz `pkg-config --cflags --libs mono-2`
- * gcc -o mprof-report decode.c utils.c -Wall -g -lz -lrt -lpthread `pkg-config --cflags mono-2`
- *
- * For osx compile with:
- * gcc -m32 -Dmono_free=free shared -o libmono-profiler-log.dylib proflog.c utils.c -Wall -g -lz `pkg-config --cflags mono-2` -undefined suppress -flat_namespace
- * gcc -m32 -o mprof-report decode.c utils.c -Wall -g -lz -lrt -lpthread `pkg-config --cflags mono-2`
- *
- * Install with:
- * sudo cp mprof-report /usr/local/bin
- * sudo cp libmono-profiler-log.so /usr/local/lib
- * sudo ldconfig
- */
-
typedef struct _LogBuffer LogBuffer;
/*
* number of methods that are fully and partially covered.
*/
+/*
+ * Format oddities that we ought to fix:
+ *
+ * - Methods written in emit_bt () should be based on the buffer's base
+ * method instead of the base pointer.
+ * - The TYPE_SAMPLE_HIT event contains (currently) pointless data like
+ * always-one unmanaged frame count and always-zero IL offsets.
+ *
+ * These are mostly small things and are not worth a format change by
+ * themselves. They should be done when some other major change has to
+ * be done to the format.
+ */
+
struct _LogBuffer {
LogBuffer *next;
uint64_t time_base;
}
static void
-register_method_local (MonoProfiler *prof, MonoDomain *domain, MonoMethod *method, MonoJitInfo *ji)
+register_method_local (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji)
{
- if (!domain)
- g_assert (ji);
-
if (!mono_conc_hashtable_lookup (prof->method_table, method)) {
if (!ji) {
MethodSearch search = { method, NULL };
}
static void
-emit_method (MonoProfiler *prof, LogBuffer *logbuffer, MonoDomain *domain, MonoMethod *method)
+emit_method (MonoProfiler *prof, LogBuffer *logbuffer, MonoMethod *method)
{
- register_method_local (prof, domain, method, NULL);
+ register_method_local (prof, method, NULL);
emit_method_inner (logbuffer, method);
}
+static void
+emit_method_as_ptr (MonoProfiler *prof, LogBuffer *logbuffer, MonoMethod *method)
+{
+ register_method_local (prof, method, NULL);
+ emit_ptr (logbuffer, method);
+}
+
static void
emit_obj (LogBuffer *logbuffer, void *ptr)
{
}
static void
-emit_bt (LogBuffer *logbuffer, FrameData *data)
+emit_bt (MonoProfiler *prof, LogBuffer *logbuffer, FrameData *data)
{
/* FIXME: this is actually tons of data and we should
* just output it the first time and use an id the next
//if (*p != data.count) {
// printf ("bad num frames enc at %d: %d -> %d\n", count, data.count, *p); printf ("frames end: %p->%p\n", p, logbuffer->data); exit(0);}
while (data->count) {
- emit_ptr (logbuffer, data->methods [--data->count]);
+ emit_method_as_ptr (prof, logbuffer, data->methods [--data->count]);
}
}
emit_obj (logbuffer, obj);
emit_value (logbuffer, len);
if (do_bt)
- emit_bt (logbuffer, &data);
+ emit_bt (prof, logbuffer, &data);
EXIT_LOG (logbuffer);
if (logbuffer->next)
safe_send (prof, logbuffer);
}
#ifndef DISABLE_HELPER_THREAD
-static void process_method_enter (MonoProfiler *prof, MonoMethod *method);
+static void process_method_enter_coverage (MonoProfiler *prof, MonoMethod *method);
#endif /* DISABLE_HELPER_THREAD */
static void
method_enter (MonoProfiler *prof, MonoMethod *method)
{
- uint64_t now;
+ uint64_t now = current_time ();
+
+#ifndef DISABLE_HELPER_THREAD
+ process_method_enter_coverage (prof, method);
+#endif /* DISABLE_HELPER_THREAD */
+
LogBuffer *logbuffer = ensure_logbuf (16);
if (logbuffer->call_depth++ > max_call_depth)
return;
- now = current_time ();
ENTER_LOG (logbuffer, "enter");
emit_byte (logbuffer, TYPE_ENTER | TYPE_METHOD);
emit_time (logbuffer, now);
- emit_method (prof, logbuffer, mono_domain_get (), method);
+ emit_method (prof, logbuffer, method);
EXIT_LOG (logbuffer);
-#ifndef DISABLE_HELPER_THREAD
- process_method_enter (prof, method);
-#endif /* DISABLE_HELPER_THREAD */
-
process_requests (prof);
}
ENTER_LOG (logbuffer, "leave");
emit_byte (logbuffer, TYPE_LEAVE | TYPE_METHOD);
emit_time (logbuffer, now);
- emit_method (prof, logbuffer, mono_domain_get (), method);
+ emit_method (prof, logbuffer, method);
EXIT_LOG (logbuffer);
if (logbuffer->next)
safe_send (prof, logbuffer);
ENTER_LOG (logbuffer, "eleave");
emit_byte (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD);
emit_time (logbuffer, now);
- emit_method (prof, logbuffer, mono_domain_get (), method);
+ emit_method (prof, logbuffer, method);
EXIT_LOG (logbuffer);
process_requests (prof);
}
if (result != MONO_PROFILE_OK)
return;
- register_method_local (prof, NULL, method, ji);
+ register_method_local (prof, method, ji);
}
static void
emit_time (logbuffer, now);
emit_obj (logbuffer, object);
if (do_bt)
- emit_bt (logbuffer, &data);
+ emit_bt (prof, logbuffer, &data);
EXIT_LOG (logbuffer);
process_requests (prof);
}
emit_time (logbuffer, now);
emit_value (logbuffer, clause_type);
emit_value (logbuffer, clause_num);
- emit_method (prof, logbuffer, mono_domain_get (), method);
+ emit_method (prof, logbuffer, method);
EXIT_LOG (logbuffer);
}
emit_time (logbuffer, now);
emit_obj (logbuffer, object);
if (do_bt)
- emit_bt (logbuffer, &data);
+ emit_bt (profiler, logbuffer, &data);
EXIT_LOG (logbuffer);
process_requests (profiler);
}
num_code_pages += add_code_page (code_pages, size_code_pages, ip & CPAGE_MASK);
}
-#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
+/* ELF code crashes on some systems. */
+//#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
+#if 0
static void
dump_ubin (const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t size)
{
logbuffer->data += len;
}
-#ifdef ELFMAG0
+/* ELF code crashes on some systems. */
+//#if defined(ELFMAG0)
+#if 0
#if SIZEOF_VOID_P == 4
#define ELF_WSIZE 32
}
#endif
-#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
+/* ELF code crashes on some systems. */
+//#if defined(HAVE_DL_ITERATE_PHDR) && defined(ELFMAG0)
+#if 0
static int
elf_dl_callback (struct dl_phdr_info *info, size_t size, void *data)
{
emit_uvalue (logbuffer, mbt_count);
for (i = 0; i < mbt_count; ++i) {
MonoMethod *method = (MonoMethod *) sample [i * 4 + 0];
- MonoDomain *domain = (MonoDomain *) sample [i * 4 + 1];
uintptr_t native_offset = sample [i * 4 + 3];
- emit_method (prof, logbuffer, domain, method);
+ emit_method (prof, logbuffer, method);
emit_svalue (logbuffer, 0); /* il offset will always be 0 from now on */
emit_svalue (logbuffer, native_offset);
}
}
static void
-process_method_enter (MonoProfiler *prof, MonoMethod *method)
+process_method_enter_coverage (MonoProfiler *prof, MonoMethod *method)
{
MonoClass *klass;
MonoImage *image;