tracked_objects [num_tracked_objects - 1] = obj;
}
+static int num_jit_helpers = 0;
+static int jit_helpers_code_size = 0;
+
+static const char*
+code_buffer_desc (int type)
+{
+ switch (type) {
+ case MONO_PROFILER_CODE_BUFFER_METHOD:
+ return "method";
+ case MONO_PROFILER_CODE_BUFFER_METHOD_TRAMPOLINE:
+ return "method trampoline";
+ case MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE:
+ return "unbox trampoline";
+ case MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE:
+ return "imt trampoline";
+ case MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE:
+ return "generics trampoline";
+ case MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE:
+ return "specific trampoline";
+ case MONO_PROFILER_CODE_BUFFER_HELPER:
+ return "misc helper";
+ case MONO_PROFILER_CODE_BUFFER_MONITOR:
+ return "monitor/lock";
+ case MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE:
+ return "delegate invoke";
+ default:
+ return "unspecified";
+ }
+}
+
#define OBJ_ADDR(diff) ((obj_base + diff) << 3)
#define LOG_TIME(base,diff) /*fprintf("outfile, time %llu + %llu near offset %d\n", base, diff, p - ctx->buf)*/
}
break;
}
+ case TYPE_RUNTIME: {
+ int subtype = *p & 0xf0;
+ uint64_t tdiff = decode_uleb128 (p + 1, &p);
+ LOG_TIME (time_base, tdiff);
+ time_base += tdiff;
+ if (subtype == TYPE_JITHELPER) {
+ int type = decode_uleb128 (p, &p);
+ intptr_t codediff = decode_sleb128 (p, &p);
+ int codelen = decode_uleb128 (p, &p);
+ const char *name;
+ if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) {
+ name = (void*)p;
+ while (*p) p++;
+ p++;
+ } else {
+ name = code_buffer_desc (type);
+ }
+ num_jit_helpers++;
+ jit_helpers_code_size += codelen;
+ if (debug)
+ fprintf (outfile, "jit helper %s, size: %d, code: %p\n", name, codelen, (void*)(ptr_base + codediff));
+ }
+ break;
+ }
case TYPE_SAMPLE: {
int subtype = *p & 0xf0;
if (subtype == TYPE_SAMPLE_HIT) {
}
fprintf (outfile, "\tCompiled methods: %d\n", compiled_methods);
fprintf (outfile, "\tGenerated code size: %d\n", code_size);
+ fprintf (outfile, "\tJIT helpers: %d\n", num_jit_helpers);
+ fprintf (outfile, "\tJIT helpers code size: %d\n", jit_helpers_code_size);
}
static void
* [code size: uleb128] size of the generated code
* [name: string] full method name
*
- * type exception format:
- * type: TYPE_EXCEPTION
- * exinfo: TYPE_EXCEPTION_BT flag and one of: TYPE_THROW, TYPE_CLAUSE
+ * type runtime format:
+ * type: TYPE_RUNTIME
+ * exinfo: one of: TYPE_JITHELPER
* [time diff: uleb128] nanoseconds since last timing
- * if exinfo.low3bits == TYPE_CLAUSE
- * [clause type: uleb128] finally/catch/fault/filter
- * [clause num: uleb128] the clause number in the method header
- * [method: sleb128] MonoMethod* as a pointer difference from the last such
- * pointer or the buffer method_base
- * if exinfo.low3bits == TYPE_THROW
- * [object: sleb128] the object that was thrown as a difference from obj_base
- * If the TYPE_EXCEPTION_BT flag is set, a backtrace follows.
+ * if exinfo == TYPE_JITHELPER
+ * [type: uleb128] MonoProfilerCodeBufferType enum value
+ * [buffer address: sleb128] pointer to the native code as a diff from ptr_base
+ * [buffer size: uleb128] size of the generated code
+ * if type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE
+ * [name: string] buffer description name
*
* type monitor format:
* type: TYPE_MONITOR
process_requests (prof);
}
+static void
+code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBufferType type, void *data)
+{
+ uint64_t now;
+ int nlen;
+ char *name;
+ LogBuffer *logbuffer;
+ if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) {
+ name = data;
+ nlen = strlen (name) + 1;
+ } else {
+ name = NULL;
+ nlen = 0;
+ }
+ logbuffer = ensure_logbuf (32 + nlen);
+ now = current_time ();
+ ENTER_LOG (logbuffer, "code buffer");
+ emit_byte (logbuffer, TYPE_JITHELPER | TYPE_RUNTIME);
+ emit_time (logbuffer, now);
+ emit_value (logbuffer, type);
+ emit_ptr (logbuffer, buffer);
+ emit_value (logbuffer, size);
+ if (name) {
+ memcpy (logbuffer->data, name, nlen);
+ logbuffer->data += nlen;
+ }
+ EXIT_LOG (logbuffer);
+ process_requests (prof);
+}
+
static void
throw_exc (MonoProfiler *prof, MonoObject *object)
{
mono_profiler_install_thread_name (thread_name);
mono_profiler_install_enter_leave (method_enter, method_leave);
mono_profiler_install_jit_end (method_jitted);
+ mono_profiler_install_code_buffer_new (code_buffer_new);
mono_profiler_install_exception (throw_exc, method_exc_leave, clause_exc);
mono_profiler_install_monitor (monitor_event);
mono_profiler_install_runtime_initialized (runtime_initialized);
#define LOG_HEADER_ID 0x4D505A01
#define LOG_VERSION_MAJOR 0
#define LOG_VERSION_MINOR 4
-#define LOG_DATA_VERSION 7
+#define LOG_DATA_VERSION 8
/*
* Changes in data versions:
* version 2: added offsets in heap walk
* version 4: added sample/statistical profiling
* version 5: added counters sampling
* version 6: added optional backtrace in sampling info
+ * version 8: added TYPE_RUNTIME and JIT helpers/trampolines
*/
enum {
TYPE_MONITOR,
TYPE_HEAP,
TYPE_SAMPLE,
+ TYPE_RUNTIME,
/* extended type for TYPE_HEAP */
TYPE_HEAP_START = 0 << 4,
TYPE_HEAP_END = 1 << 4,
TYPE_SAMPLE_UBIN = 2 << 4,
TYPE_SAMPLE_COUNTERS_DESC = 3 << 4,
TYPE_SAMPLE_COUNTERS = 4 << 4,
+ /* extended type for TYPE_RUNTIME */
+ TYPE_JITHELPER = 1 << 4,
TYPE_END
};