* Alex Rønne Petersen (alexrp@xamarin.com)
*
* Copyright 2010 Novell, Inc (http://www.novell.com)
+ * Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
/*
case MONO_COUNTER_SECURITY: return "Mono Security";
case MONO_COUNTER_RUNTIME: return "Mono Runtime";
case MONO_COUNTER_SYSTEM: return "Mono System";
+ case MONO_COUNTER_PROFILER: return "Mono Profiler";
default: return "<unknown>";
}
}
case MONO_GC_EVENT_RECLAIM_END: return "reclaim end";
case MONO_GC_EVENT_END: return "end";
case MONO_GC_EVENT_PRE_STOP_WORLD: return "pre stop";
+ case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED: return "pre stop lock";
case MONO_GC_EVENT_POST_STOP_WORLD: return "post stop";
case MONO_GC_EVENT_PRE_START_WORLD: return "pre start";
case MONO_GC_EVENT_POST_START_WORLD: return "post start";
+ case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED: return "post start unlock";
+ default:
+ return "unknown";
+ }
+}
+
+static const char*
+sync_point_name (int type)
+{
+ switch (type) {
+ case SYNC_POINT_PERIODIC: return "periodic";
+ case SYNC_POINT_WORLD_STOP: return "world stop";
+ case SYNC_POINT_WORLD_START: return "world start";
default:
return "unknown";
}
}
static MethodDesc**
-decode_bt (MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base)
+decode_bt (ProfContext *ctx, MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base, intptr_t *method_base)
{
MethodDesc **frames;
int i;
- int flags = decode_uleb128 (p, &p);
+ if (ctx->data_version < 13)
+ decode_uleb128 (p, &p); /* flags */
int count = decode_uleb128 (p, &p);
- if (flags != 0)
- return NULL;
if (count > *size)
frames = (MethodDesc **)malloc (count * sizeof (void*));
else
frames = sframes;
for (i = 0; i < count; ++i) {
intptr_t ptrdiff = decode_sleb128 (p, &p);
- frames [i] = lookup_method (ptr_base + ptrdiff);
+ if (ctx->data_version > 12) {
+ *method_base += ptrdiff;
+ frames [i] = lookup_method (*method_base);
+ } else {
+ frames [i] = lookup_method (ptr_base + ptrdiff);
+ }
}
*size = count;
*endp = p;
time_from += startup_time;
time_to += startup_time;
}
- if (!thread->name)
- thread->name = pstrdup ("Main");
}
for (i = 0; i < thread->stack_id; ++i)
thread->stack [i]->recurse_count++;
if (new_size > max_heap_size)
max_heap_size = new_size;
} else if (subtype == TYPE_GC_EVENT) {
- uint64_t ev = decode_uleb128 (p, &p);
- int gen = decode_uleb128 (p, &p);
+ uint64_t ev;
+ if (ctx->data_version > 12)
+ ev = *p++;
+ else
+ ev = decode_uleb128 (p, &p);
+ int gen;
+ if (ctx->data_version > 12)
+ gen = *p++;
+ else
+ gen = decode_uleb128 (p, &p);
if (debug)
fprintf (outfile, "gc event for gen%d: %s at %llu (thread: 0x%zx)\n", gen, gc_event_name (ev), (unsigned long long) time_base, thread->thread_id);
if (gen > 2) {
intptr_t objdiff = decode_sleb128 (p, &p);
if (has_bt) {
num_bt = 8;
- frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+ frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
if (!frames) {
fprintf (outfile, "Cannot load backtrace\n");
return 0;
uint32_t handle = decode_uleb128 (p, &p);
if (has_bt) {
num_bt = 8;
- frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+ frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
if (!frames) {
fprintf (outfile, "Cannot load backtrace\n");
return 0;
fprintf (outfile, "handle (%s) %u destroyed\n", get_handle_name (htype), handle);
if (frames != sframes)
free (frames);
+ } else if (subtype == TYPE_GC_FINALIZE_START) {
+ // TODO: Generate a finalizer report based on these events.
+ if (debug)
+ fprintf (outfile, "gc finalizer queue being processed at %llu\n", (unsigned long long) time_base);
+ } else if (subtype == TYPE_GC_FINALIZE_END) {
+ if (debug)
+ fprintf (outfile, "gc finalizer queue finished processing at %llu\n", (unsigned long long) time_base);
+ } else if (subtype == TYPE_GC_FINALIZE_OBJECT_START) {
+ intptr_t objdiff = decode_sleb128 (p, &p);
+ if (debug)
+ fprintf (outfile, "gc finalizing object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
+ } else if (subtype == TYPE_GC_FINALIZE_OBJECT_END) {
+ intptr_t objdiff = decode_sleb128 (p, &p);
+ if (debug)
+ fprintf (outfile, "gc finalized object %p at %llu\n", (void *) OBJ_ADDR (objdiff), (unsigned long long) time_base);
}
break;
}
time_base += tdiff;
if (mtype == TYPE_CLASS) {
intptr_t imptrdiff = decode_sleb128 (p, &p);
- uint64_t flags = decode_uleb128 (p, &p);
- if (flags) {
- fprintf (outfile, "non-zero flags in class\n");
- return 0;
- }
+ if (ctx->data_version < 13)
+ decode_uleb128 (p, &p); /* flags */
if (debug)
fprintf (outfile, "%s class %p (%s in %p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (void*)(ptr_base + imptrdiff), (unsigned long long) time_base);
if (subtype == TYPE_END_LOAD)
while (*p) p++;
p++;
} else if (mtype == TYPE_IMAGE) {
- uint64_t flags = decode_uleb128 (p, &p);
- if (flags) {
- fprintf (outfile, "non-zero flags in image\n");
- return 0;
- }
+ if (ctx->data_version < 13)
+ decode_uleb128 (p, &p); /* flags */
if (debug)
fprintf (outfile, "%s image %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
if (subtype == TYPE_END_LOAD)
while (*p) p++;
p++;
} else if (mtype == TYPE_ASSEMBLY) {
- uint64_t flags = decode_uleb128 (p, &p);
- if (flags) {
- fprintf (outfile, "non-zero flags in assembly\n");
- return 0;
- }
+ if (ctx->data_version < 13)
+ decode_uleb128 (p, &p); /* flags */
if (debug)
fprintf (outfile, "%s assembly %p (%s) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), p, (unsigned long long) time_base);
if (subtype == TYPE_END_LOAD)
while (*p) p++;
p++;
} else if (mtype == TYPE_DOMAIN) {
- uint64_t flags = decode_uleb128 (p, &p);
- if (flags) {
- fprintf (outfile, "non-zero flags in domain\n");
- return 0;
- }
+ if (ctx->data_version < 13)
+ decode_uleb128 (p, &p); /* flags */
DomainContext *nd = get_domain (ctx, ptr_base + ptrdiff);
/* no subtype means it's a name event, rather than start/stop */
if (subtype == 0)
p++;
}
} else if (mtype == TYPE_CONTEXT) {
- uint64_t flags = decode_uleb128 (p, &p);
- if (flags) {
- fprintf (outfile, "non-zero flags in context\n");
- return 0;
- }
+ if (ctx->data_version < 13)
+ decode_uleb128 (p, &p); /* flags */
intptr_t domaindiff = decode_sleb128 (p, &p);
if (debug)
fprintf (outfile, "%s context %p (%p) at %llu\n", load_str, (void*)(ptr_base + ptrdiff), (void *) (ptr_base + domaindiff), (unsigned long long) time_base);
if (subtype == TYPE_END_LOAD)
get_remctx (ctx, ptr_base + ptrdiff)->domain_id = ptr_base + domaindiff;
} else if (mtype == TYPE_THREAD) {
- uint64_t flags = decode_uleb128 (p, &p);
- if (flags) {
- fprintf (outfile, "non-zero flags in thread\n");
- return 0;
- }
+ if (ctx->data_version < 13)
+ decode_uleb128 (p, &p); /* flags */
ThreadContext *nt = get_thread (ctx, ptr_base + ptrdiff);
/* no subtype means it's a name event, rather than start/stop */
if (subtype == 0)
fprintf (outfile, "alloced object %p, size %llu (%s) at %llu\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) len, lookup_class (ptr_base + ptrdiff)->name, (unsigned long long) time_base);
if (has_bt) {
num_bt = 8;
- frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+ frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
if (!frames) {
fprintf (outfile, "Cannot load backtrace\n");
return 0;
if (subtype == TYPE_HEAP_OBJECT) {
HeapObjectDesc *ho = NULL;
int i;
- intptr_t objdiff = decode_sleb128 (p + 1, &p);
+ intptr_t objdiff;
+ if (ctx->data_version > 12) {
+ uint64_t tdiff = decode_uleb128 (p + 1, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ objdiff = decode_sleb128 (p, &p);
+ } else
+ objdiff = decode_sleb128 (p + 1, &p);
intptr_t ptrdiff = decode_sleb128 (p, &p);
uint64_t size = decode_uleb128 (p, &p);
uintptr_t num = decode_uleb128 (p, &p);
if (debug && size)
fprintf (outfile, "traced object %p, size %llu (%s), refs: %zd\n", (void*)OBJ_ADDR (objdiff), (unsigned long long) size, cd->name, num);
} else if (subtype == TYPE_HEAP_ROOT) {
- uintptr_t num = decode_uleb128 (p + 1, &p);
+ uintptr_t num;
+ if (ctx->data_version > 12) {
+ uint64_t tdiff = decode_uleb128 (p + 1, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ num = decode_uleb128 (p, &p);
+ } else
+ num = decode_uleb128 (p + 1, &p);
uintptr_t gc_num G_GNUC_UNUSED = decode_uleb128 (p, &p);
int i;
for (i = 0; i < num; ++i) {
intptr_t objdiff = decode_sleb128 (p, &p);
- int root_type = decode_uleb128 (p, &p);
+ int root_type;
+ if (ctx->data_version > 12)
+ root_type = *p++;
+ else
+ root_type = decode_uleb128 (p, &p);
/* we just discard the extra info for now */
uintptr_t extra_info = decode_uleb128 (p, &p);
if (debug)
}
if (has_bt) {
num_bt = 8;
- frames = decode_bt (sframes, &num_bt, p, &p, ptr_base);
+ frames = decode_bt (ctx, sframes, &num_bt, p, &p, ptr_base, &method_base);
if (!frames) {
fprintf (outfile, "Cannot load backtrace\n");
return 0;
if (!(time_base >= time_from && time_base < time_to))
record = 0;
if (subtype == TYPE_CLAUSE) {
- int clause_type = decode_uleb128 (p, &p);
+ int clause_type;
+ if (ctx->data_version > 12)
+ clause_type = *p++;
+ else
+ clause_type = decode_uleb128 (p, &p);
int clause_num = decode_uleb128 (p, &p);
int64_t ptrdiff = decode_sleb128 (p, &p);
method_base += ptrdiff;
throw_count++;
if (has_bt) {
has_bt = 8;
- frames = decode_bt (sframes, &has_bt, p, &p, ptr_base);
+ frames = decode_bt (ctx, sframes, &has_bt, p, &p, ptr_base, &method_base);
if (!frames) {
fprintf (outfile, "Cannot load backtrace\n");
return 0;
LOG_TIME (time_base, tdiff);
time_base += tdiff;
if (subtype == TYPE_JITHELPER) {
- int type = decode_uleb128 (p, &p);
+ int type;
+ if (ctx->data_version > 12)
+ type = *p++;
+ else
+ type = decode_uleb128 (p, &p);
intptr_t codediff = decode_sleb128 (p, &p);
int codelen = decode_uleb128 (p, &p);
const char *name;
int subtype = *p & 0xf0;
if (subtype == TYPE_SAMPLE_HIT) {
int i;
- int sample_type = decode_uleb128 (p + 1, &p);
- uint64_t tstamp = decode_uleb128 (p, &p);
+ int sample_type;
+ uint64_t tstamp;
+ if (ctx->data_version > 12) {
+ uint64_t tdiff = decode_uleb128 (p + 1, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ sample_type = *p++;
+ tstamp = time_base;
+ } else {
+ sample_type = decode_uleb128 (p + 1, &p);
+ tstamp = decode_uleb128 (p, &p);
+ }
void *tid = (void *) thread_id;
if (ctx->data_version > 10)
tid = (void *) (ptr_base + decode_sleb128 (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);
+ fprintf (outfile, "sample hit bt %d: %s\n", i, method->name);
+ if (ctx->data_version < 13) {
+ decode_sleb128 (p, &p); /* il offset */
+ decode_sleb128 (p, &p); /* native offset */
+ }
}
}
} else if (subtype == TYPE_SAMPLE_USYM) {
/* un unmanaged symbol description */
- uintptr_t addr = ptr_base + decode_sleb128 (p + 1, &p);
+ uintptr_t addr;
+ if (ctx->data_version > 12) {
+ uint64_t tdiff = decode_uleb128 (p + 1, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ addr = ptr_base + decode_sleb128 (p, &p);
+ } else
+ addr = ptr_base + decode_sleb128 (p + 1, &p);
uintptr_t size = decode_uleb128 (p, &p);
char *name;
name = pstrdup ((char*)p);
while (*p) p++;
p++;
} else if (subtype == TYPE_SAMPLE_COUNTERS_DESC) {
- uint64_t i, len = decode_uleb128 (p + 1, &p);
+ uint64_t i, len;
+ if (ctx->data_version > 12) {
+ uint64_t tdiff = decode_uleb128 (p + 1, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ len = decode_uleb128 (p, &p);
+ } else
+ len = decode_uleb128 (p + 1, &p);
for (i = 0; i < len; i++) {
uint64_t type, unit, variance, index;
uint64_t section = decode_uleb128 (p, &p);
}
name = pstrdup ((char*)p);
while (*p++);
- type = decode_uleb128 (p, &p);
- unit = decode_uleb128 (p, &p);
- variance = decode_uleb128 (p, &p);
+ if (ctx->data_version > 12) {
+ type = *p++;
+ unit = *p++;
+ variance = *p++;
+ } else {
+ type = decode_uleb128 (p, &p);
+ unit = decode_uleb128 (p, &p);
+ variance = decode_uleb128 (p, &p);
+ }
index = decode_uleb128 (p, &p);
add_counter (section_str, name, (int)type, (int)unit, (int)variance, (int)index);
}
int i;
CounterValue *value, *previous = NULL;
CounterList *list;
- uint64_t timestamp = decode_uleb128 (p + 1, &p);
+ uint64_t timestamp; // milliseconds since startup
+ if (ctx->data_version > 12) {
+ uint64_t tdiff = decode_uleb128 (p + 1, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ timestamp = (time_base - startup_time) / 1000 / 1000;
+ } else
+ timestamp = decode_uleb128 (p + 1, &p);
uint64_t time_between = timestamp / 1000 * 1000 * 1000 * 1000 + startup_time;
while (1) {
uint64_t type, index = decode_uleb128 (p, &p);
}
}
- type = decode_uleb128 (p, &p);
+ if (ctx->data_version > 12)
+ type = *p++;
+ else
+ type = decode_uleb128 (p, &p);
value = (CounterValue *)calloc (1, sizeof (CounterValue));
value->timestamp = timestamp;
int token, n_offsets, method_id;
p++;
+
+ if (ctx->data_version > 12) {
+ uint64_t tdiff = decode_uleb128 (p, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ }
+
assembly = (const char *)p; while (*p) p++; p++;
klass = (const char *)p; while (*p) p++; p++;
name = (const char *)p; while (*p) p++; p++;
int offset, count, line, column, method_id;
p++;
+
+ if (ctx->data_version > 12) {
+ uint64_t tdiff = decode_uleb128 (p, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ }
+
method_id = decode_uleb128 (p, &p);
offset = decode_uleb128 (p, &p);
count = decode_uleb128 (p, &p);
int number_of_methods, fully_covered, partially_covered;
p++;
+ if (ctx->data_version > 12) {
+ uint64_t tdiff = decode_uleb128 (p, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ }
+
name = (char *)p; while (*p) p++; p++;
guid = (char *)p; while (*p) p++; p++;
filename = (char *)p; while (*p) p++; p++;
int number_of_methods, fully_covered, partially_covered;
p++;
+ if (ctx->data_version > 12) {
+ uint64_t tdiff = decode_uleb128 (p, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ }
+
assembly_name = (char *)p; while (*p) p++; p++;
class_name = (char *)p; while (*p) p++; p++;
number_of_methods = decode_uleb128 (p, &p);
}
break;
}
+ case TYPE_META: {
+ int subtype = *p & 0xf0;
+ uint64_t tdiff = decode_uleb128 (p + 1, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ if (subtype == TYPE_SYNC_POINT) {
+ int type = *p++;
+ if (debug)
+ fprintf (outfile, "sync point %i (%s)\n", type, sync_point_name (type));
+ }
+ break;
+ }
default:
fprintf (outfile, "unhandled profiler event: 0x%x at file offset: %llu + %lld (len: %d\n)\n", *p, (unsigned long long) file_offset, (long long) (p - ctx->buf), len);
exit (1);
ThreadContext *thread;
fprintf (outfile, "\nThread summary\n");
for (thread = ctx->threads; thread; thread = thread->next) {
- fprintf (outfile, "\tThread: %p, name: \"%s\"\n", (void*)thread->thread_id, thread->name? thread->name: "");
+ if (thread->thread_id) {
+ fprintf (outfile, "\tThread: %p, name: \"%s\"\n", (void*)thread->thread_id, thread->name? thread->name: "");
+ }
}
}
DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_METHOD);
DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_STATEMENT);
DUMP_EVENT_STAT (TYPE_COVERAGE, TYPE_COVERAGE_CLASS);
+
+ DUMP_EVENT_STAT (TYPE_META, TYPE_SYNC_POINT);
}