[profiler] Add managed backtrace support to sampling mode for the signal-based impl.
authorPaolo Molaro <lupus@oddwiz.org>
Tue, 13 May 2014 15:40:51 +0000 (17:40 +0200)
committerPaolo Molaro <lupus@oddwiz.org>
Tue, 13 May 2014 15:42:04 +0000 (17:42 +0200)
mono/profiler/decode.c
mono/profiler/proflog.c
mono/profiler/proflog.h

index a3f422b36fa8ae97e7a6554bd5115b4f89fe2246..c588ea383c633a0841a054830c76fe3523658dbc 100644 (file)
@@ -2324,6 +2324,19 @@ decode_buffer (ProfContext *ctx)
                                        if (debug)
                                                fprintf (outfile, "sample hit, type: %d at %p\n", sample_type, (void*)ip);
                                }
+                               if (ctx->data_version > 5) {
+                                       count = decode_uleb128 (p, &p);
+                                       for (i = 0; i < count; ++i) {
+                                               MethodDesc *method;
+                                               int64_t ptrdiff = decode_sleb128 (p, &p);
+                                               int il_offset = decode_sleb128 (p, &p);
+                                               int native_offset = decode_sleb128 (p, &p);
+                                               method_base += ptrdiff;
+                                               method = lookup_method (method_base);
+                                               if (debug)
+                                                       fprintf (outfile, "sample hit bt %d: %s at IL offset %d (native: %d)\n", i, method->name, il_offset, native_offset);
+                                       }
+                               }
                        } else if (subtype == TYPE_SAMPLE_USYM) {
                                /* un unmanaged symbol description */
                                uintptr_t addr = ptr_base + decode_sleb128 (p + 1, &p);
index a67182f643e4b584274c337aab5229d1c8b4e730..16b9b781ae5d4ba56c9a52fe02fc1c8625733dcd 100644 (file)
@@ -295,6 +295,12 @@ typedef struct _LogBuffer LogBuffer;
  *     [timestamp: uleb128] nanoseconds since startup (note: different from other timestamps!)
  *     [count: uleb128] number of following instruction addresses
  *     [ip: sleb128]* instruction pointer as difference from ptr_base
+ *     if (format_version > 5)
+ *             [mbt_count: uleb128] number of managed backtrace info triplets (method + IL offset + native offset)
+ *             [method: sleb128]* MonoMethod* as a pointer difference from the last such
+ *             pointer or the buffer method_base (the first such method can be also indentified by ip, but this is not neccessarily true)
+ *             [il_offset: sleb128]* IL offset inside method where the hit occurred
+ *             [native_offset: sleb128]* native offset inside method where the hit occurred
  * if exinfo == TYPE_SAMPLE_USYM
  *     [address: sleb128] symbol address as a difference from ptr_base
  *     [size: uleb128] symbol size (may be 0 if unknown)
@@ -797,6 +803,8 @@ gc_resize (MonoProfiler *profiler, int64_t new_size) {
 typedef struct {
        int count;
        MonoMethod* methods [MAX_FRAMES];
+       int32_t il_offsets [MAX_FRAMES];
+       int32_t native_offsets [MAX_FRAMES];
 } FrameData;
 static int num_frames = MAX_FRAMES / 2;
 
@@ -805,8 +813,10 @@ walk_stack (MonoMethod *method, int32_t native_offset, int32_t il_offset, mono_b
 {
        FrameData *frame = data;
        if (method && frame->count < num_frames) {
+               frame->il_offsets [frame->count] = il_offset;
+               frame->native_offsets [frame->count] = native_offset;
                frame->methods [frame->count++] = method;
-               //printf ("In %d %s\n", frame->count, mono_method_get_name (method));
+               //printf ("In %d %s at %d (native: %d)\n", frame->count, mono_method_get_name (method), il_offset, native_offset);
        }
        return frame->count == num_frames;
 }
@@ -1207,13 +1217,16 @@ static void
 mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context)
 {
        StatBuffer *sbuf;
+       FrameData bt_data;
        uint64_t now;
        uintptr_t *data, *new_data, *old_data;
        uintptr_t elapsed;
        int timedout = 0;
+       int i;
        if (in_shutdown)
                return;
        now = current_time ();
+       collect_bt (&bt_data);
        elapsed = (now - profiler->startup_time) / 10000;
        if (do_debug) {
                int len;
@@ -1252,15 +1265,20 @@ mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context)
        }
        do {
                old_data = sbuf->data;
-               new_data = old_data + 4;
+               new_data = old_data + 4 + bt_data.count * 3;
                data = InterlockedCompareExchangePointer ((volatile void**)&sbuf->data, new_data, old_data);
        } while (data != old_data);
        if (old_data >= sbuf->data_end)
                return; /* lost event */
-       old_data [0] = 1 | (sample_type << 16);
+       old_data [0] = 1 | (sample_type << 16) | (bt_data.count << 8);
        old_data [1] = thread_id ();
        old_data [2] = elapsed;
        old_data [3] = (uintptr_t)ip;
+       for (i = 0; i < bt_data.count; ++i) {
+               old_data [4+3*i] = (uintptr_t)bt_data.methods [i];
+               old_data [4+3*i+1] = (uintptr_t)bt_data.il_offsets [i];
+               old_data [4+3*i+2] = (uintptr_t)bt_data.native_offsets [i];
+       }
 }
 
 static uintptr_t *code_pages = 0;
@@ -1592,9 +1610,10 @@ dump_sample_hits (MonoProfiler *prof, StatBuffer *sbuf, int recurse)
        }
        for (sample = sbuf->buf; sample < sbuf->data;) {
                int i;
-               int count = sample [0] & 0xffff;
+               int count = sample [0] & 0xff;
+               int mbt_count = (sample [0] & 0xff00) >> 8;
                int type = sample [0] >> 16;
-               if (sample + count + 3 > sbuf->data)
+               if (sample + count + 3 + mbt_count * 3 > sbuf->data)
                        break;
                logbuffer = ensure_logbuf (20 + count * 8);
                emit_byte (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT);
@@ -1606,6 +1625,14 @@ dump_sample_hits (MonoProfiler *prof, StatBuffer *sbuf, int recurse)
                        add_code_pointer (sample [i + 3]);
                }
                sample += count + 3;
+               /* new in data version 6 */
+               emit_uvalue (logbuffer, mbt_count);
+               for (i = 0; i < mbt_count; ++i) {
+                       emit_method (logbuffer, (void*)sample [i * 3]); /* method */
+                       emit_svalue (logbuffer, sample [i * 3 + 1]); /* il offset */
+                       emit_svalue (logbuffer, sample [i * 3 + 2]); /* native offset */
+               }
+               sample += 3 * mbt_count;
        }
        dump_unmanaged_coderefs (prof);
 }
@@ -1749,6 +1776,8 @@ dump_perf_hits (MonoProfiler *prof, void *buf, int size)
                emit_uvalue (logbuffer, s->timestamp - prof->startup_time);
                emit_value (logbuffer, 1); /* count */
                emit_ptr (logbuffer, (void*)(uintptr_t)s->ip);
+               /* no support here yet for the managed backtrace */
+               emit_uvalue (logbuffer, 0);
                add_code_pointer (s->ip);
                buf = (char*)buf + s->h.size;
                samples++;
index cbce62130d56284c42a11bf470a3ec2d58c972e6..034a348effbf4297d0e7dee48b6cf37833b478ec 100644 (file)
@@ -5,13 +5,14 @@
 #define LOG_HEADER_ID 0x4D505A01
 #define LOG_VERSION_MAJOR 0
 #define LOG_VERSION_MINOR 4
-#define LOG_DATA_VERSION 5
+#define LOG_DATA_VERSION 6
 /*
  * Changes in data versions:
  * version 2: added offsets in heap walk
  * version 3: added GC roots
  * version 4: added sample/statistical profiling
  * version 5: added counters sampling
+ * version 6: added optional backtrace in sampling info
  */
 
 enum {