#include "../metadata/metadata-internals.h"
#include <mono/metadata/profiler.h>
#include <mono/metadata/threads.h>
-#include <mono/metadata/mono-gc.h>
#include <mono/metadata/debug-helpers.h>
+#include <mono/metadata/mono-config.h>
+#include <mono/metadata/mono-gc.h>
#include <mono/metadata/mono-perfcounters.h>
#include <mono/metadata/appdomain.h>
#include <mono/metadata/assembly.h>
/* Worst-case size in bytes of a 64-bit value encoded with LEB128. */
#define LEB128_SIZE 10
-/* Size in bytes of the event ID prefix. */
-#define EVENT_SIZE 1
+/* Size of a value encoded as a single byte. */
+#define BYTE_SIZE 1
+/* Size in bytes of the event prefix (ID + time). */
+#define EVENT_SIZE (BYTE_SIZE + LEB128_SIZE)
static int nocalls = 0;
static int notraces = 0;
* [flags: 4 bytes] file format flags, should be 0 for now
* [pid: 4 bytes] pid of the profiled process
* [port: 2 bytes] tcp port for server if != 0
- * [sysid: 2 bytes] operating system and architecture identifier
+ * [args size: 4 bytes] size of args
+ * [args: string] arguments passed to the profiler
+ * [arch size: 4 bytes] size of arch
+ * [arch: string] architecture the profiler is running on
+ * [os size: 4 bytes] size of os
+ * [os: string] operating system the profiler is running on
*
* The multiple byte integers are in little-endian format.
*
* [method_base: 8 bytes] base value for MonoMethod pointers
*
* event format:
- * [extended info: upper 4 bits] [type: lower 4 bits] [data]*
+ * [extended info: upper 4 bits] [type: lower 4 bits]
+ * [time diff: uleb128] nanoseconds since last timing
+ * [data]*
* The data that follows depends on type and the extended info.
* Type is one of the enum values in proflog.h: TYPE_ALLOC, TYPE_GC,
* TYPE_METADATA, TYPE_METHOD, TYPE_EXCEPTION, TYPE_MONITOR, TYPE_HEAP.
* strings are represented as a 0-terminated utf8 sequence.
*
* backtrace format:
- * [flags: uleb128] must be 0
* [num: uleb128] number of frames following
- * [frame: sleb128]* num MonoMethod pointers as differences from ptr_base
+ * [frame: sleb128]* mum MonoMethod* as a pointer difference from the last such
+ * pointer or the buffer method_base
*
* type alloc format:
* type: TYPE_ALLOC
* exinfo: flags: TYPE_ALLOC_BT
- * [time diff: uleb128] nanoseconds since last timing
* [ptr: sleb128] class as a byte difference from ptr_base
* [obj: sleb128] object address as a byte difference from obj_base
* [size: uleb128] size of the object in the heap
* type GC format:
* type: TYPE_GC
* exinfo: one of TYPE_GC_EVENT, TYPE_GC_RESIZE, TYPE_GC_MOVE, TYPE_GC_HANDLE_CREATED[_BT],
- * TYPE_GC_HANDLE_DESTROYED[_BT]
- * [time diff: uleb128] nanoseconds since last timing
+ * TYPE_GC_HANDLE_DESTROYED[_BT], TYPE_GC_FINALIZE_START, TYPE_GC_FINALIZE_END,
+ * TYPE_GC_FINALIZE_OBJECT_START, TYPE_GC_FINALIZE_OBJECT_END
* if exinfo == TYPE_GC_RESIZE
* [heap_size: uleb128] new heap size
* if exinfo == TYPE_GC_EVENT
- * [event type: uleb128] GC event (MONO_GC_EVENT_* from profiler.h)
- * [generation: uleb128] GC generation event refers to
+ * [event type: byte] GC event (MONO_GC_EVENT_* from profiler.h)
+ * [generation: byte] GC generation event refers to
* if exinfo == TYPE_GC_MOVE
* [num_objects: uleb128] number of object moves that follow
* [objaddr: sleb128]+ num_objects object pointer differences from obj_base
* upper bits reserved as flags
* [handle: uleb128] GC handle value
* If exinfo == TYPE_GC_HANDLE_DESTROYED_BT, a backtrace follows.
+ * if exinfo == TYPE_GC_FINALIZE_OBJECT_{START,END}
+ * [object: sleb128] the object as a difference from obj_base
*
* type metadata format:
* type: TYPE_METADATA
* exinfo: one of: TYPE_END_LOAD, TYPE_END_UNLOAD (optional for TYPE_THREAD and TYPE_DOMAIN)
- * [time diff: uleb128] nanoseconds since last timing
* [mtype: byte] metadata type, one of: TYPE_CLASS, TYPE_IMAGE, TYPE_ASSEMBLY, TYPE_DOMAIN,
* TYPE_THREAD, TYPE_CONTEXT
* [pointer: sleb128] pointer of the metadata type depending on mtype
* if mtype == TYPE_CLASS
* [image: sleb128] MonoImage* as a pointer difference from ptr_base
- * [flags: uleb128] must be 0
* [name: string] full class name
* if mtype == TYPE_IMAGE
- * [flags: uleb128] must be 0
* [name: string] image file name
* if mtype == TYPE_ASSEMBLY
- * [flags: uleb128] must be 0
* [name: string] assembly name
- * if mtype == TYPE_DOMAIN
- * [flags: uleb128] must be 0
* if mtype == TYPE_DOMAIN && exinfo == 0
* [name: string] domain friendly name
* if mtype == TYPE_CONTEXT
- * [flags: uleb128] must be 0
* [domain: sleb128] domain id as pointer
- * if mtype == TYPE_THREAD && (format_version < 11 || (format_version > 10 && exinfo == 0))
- * [flags: uleb128] must be 0
+ * if mtype == TYPE_THREAD && exinfo == 0
* [name: string] thread name
*
* type method format:
* type: TYPE_METHOD
* exinfo: one of: TYPE_LEAVE, TYPE_ENTER, TYPE_EXC_LEAVE, TYPE_JIT
- * [time diff: uleb128] nanoseconds since last timing
* [method: sleb128] MonoMethod* as a pointer difference from the last such
* pointer or the buffer method_base
* if exinfo == TYPE_JIT
* [code size: uleb128] size of the generated code
* [name: string] full method name
*
+ * type exception format:
+ * type: TYPE_EXCEPTION
+ * exinfo: TYPE_THROW_BT flag or one of: TYPE_CLAUSE
+ * if exinfo == TYPE_CLAUSE
+ * [clause type: byte] MonoExceptionEnum enum value
+ * [clause index: uleb128] index of the current clause
+ * [method: sleb128] MonoMethod* as a pointer difference from the last such
+ * pointer or the buffer method_base
+ * else
+ * [object: sleb128] the exception object as a difference from obj_base
+ * if exinfo has TYPE_THROW_BT set, a backtrace follows.
+ *
* type runtime format:
* type: TYPE_RUNTIME
* exinfo: one of: TYPE_JITHELPER
- * [time diff: uleb128] nanoseconds since last timing
* if exinfo == TYPE_JITHELPER
- * [type: uleb128] MonoProfilerCodeBufferType enum value
+ * [type: byte] 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
* type monitor format:
* type: TYPE_MONITOR
* exinfo: TYPE_MONITOR_BT flag and one of: MONO_PROFILER_MONITOR_(CONTENTION|FAIL|DONE)
- * [time diff: uleb128] nanoseconds since last timing
* [object: sleb128] the lock object as a difference from obj_base
* if exinfo.low3bits == MONO_PROFILER_MONITOR_CONTENTION
* If the TYPE_MONITOR_BT flag is set, a backtrace follows.
* type heap format
* type: TYPE_HEAP
* exinfo: one of TYPE_HEAP_START, TYPE_HEAP_END, TYPE_HEAP_OBJECT, TYPE_HEAP_ROOT
- * if exinfo == TYPE_HEAP_START
- * [time diff: uleb128] nanoseconds since last timing
- * if exinfo == TYPE_HEAP_END
- * [time diff: uleb128] nanoseconds since last timing
* if exinfo == TYPE_HEAP_OBJECT
* [object: sleb128] the object as a difference from obj_base
* [class: sleb128] the object MonoClass* as a difference from ptr_base
* [size: uleb128] size of the object on the heap
* [num_refs: uleb128] number of object references
- * if (format version > 1) each referenced objref is preceded by a
- * uleb128 encoded offset: the first offset is from the object address
- * and each next offset is relative to the previous one
+ * each referenced objref is preceded by a uleb128 encoded offset: the
+ * first offset is from the object address and each next offset is relative
+ * to the previous one
* [objrefs: sleb128]+ object referenced as a difference from obj_base
* The same object can appear multiple times, but only the first time
* with size != 0: in the other cases this data will only be used to
* [num_roots: uleb128] number of root references
* [num_gc: uleb128] number of major gcs
* [object: sleb128] the object as a difference from obj_base
- * [root_type: uleb128] the root_type: MonoProfileGCRootType (profiler.h)
+ * [root_type: byte] the root_type: MonoProfileGCRootType (profiler.h)
* [extra_info: uleb128] the extra_info value
* object, root_type and extra_info are repeated num_roots times
*
* type: TYPE_SAMPLE
* exinfo: one of TYPE_SAMPLE_HIT, TYPE_SAMPLE_USYM, TYPE_SAMPLE_UBIN, TYPE_SAMPLE_COUNTERS_DESC, TYPE_SAMPLE_COUNTERS
* if exinfo == TYPE_SAMPLE_HIT
- * [sample_type: uleb128] type of sample (SAMPLE_*)
- * [timestamp: uleb128] nanoseconds since startup (note: different from other timestamps!)
- * if (format_version > 10)
- * [thread: sleb128] thread id as difference from ptr_base
+ * [sample_type: byte] type of sample (SAMPLE_*)
+ * [thread: sleb128] thread id as difference from ptr_base
* [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
+ * [mbt_count: uleb128] number of managed backtrace frames
+ * [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)
* if exinfo == TYPE_SAMPLE_USYM
* [address: sleb128] symbol address as a difference from ptr_base
* [size: uleb128] symbol size (may be 0 if unknown)
* [name: string] symbol name
* if exinfo == TYPE_SAMPLE_UBIN
- * [time diff: uleb128] nanoseconds since last timing
* [address: sleb128] address where binary has been loaded
* [offset: uleb128] file offset of mapping (the same file can be mapped multiple times)
* [size: uleb128] memory size
* if section == MONO_COUNTER_PERFCOUNTERS:
* [section_name: string] section name of counter
* [name: string] name of counter
- * [type: uleb128] type of counter
- * [unit: uleb128] unit of counter
- * [variance: uleb128] variance of counter
+ * [type: byte] type of counter
+ * [unit: byte] unit of counter
+ * [variance: byte] variance of counter
* [index: uleb128] unique index of counter
* if exinfo == TYPE_SAMPLE_COUNTERS
- * [timestamp: uleb128] sampling timestamp
* while true:
* [index: uleb128] unique index of counter
* if index == 0:
* break
- * [type: uleb128] type of counter value
+ * [type: byte] type of counter value
* if type == string:
* if value == null:
* [0: uleb128] 0 -> value is null
* [partially_covered: uleb128] the number of partially covered methods
* currently partially_covered will always be 0, and fully_covered is the
* 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.
+ * type meta format:
+ * type: TYPE_META
+ * exinfo: one of: TYPE_SYNC_POINT
+ * if exinfo == TYPE_SYNC_POINT
+ * [type: byte] MonoProfilerSyncPointType enum value
*/
// Pending data to be written to the log, for a single thread.
#if defined (HAVE_SYS_ZLIB)
gzFile gzfile;
#endif
+ char *args;
uint64_t startup_time;
int pipe_output;
int last_gc_gen_started;
assert (logbuffer->cursor <= logbuffer->buf_end);
}
+static void
+emit_event_time (LogBuffer *logbuffer, int event, uint64_t time)
+{
+ emit_byte (logbuffer, event);
+ emit_time (logbuffer, time);
+}
+
+static void
+emit_event (LogBuffer *logbuffer, int event)
+{
+ emit_event_time (logbuffer, event, current_time ());
+}
+
static void
emit_svalue (LogBuffer *logbuffer, int64_t value)
{
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)
{
return buf + 8;
}
+static char *
+write_header_string (char *p, const char *str)
+{
+ size_t len = strlen (str) + 1;
+
+ p = write_int32 (p, len);
+ strcpy (p, str);
+
+ return p + len;
+}
+
static void
dump_header (MonoProfiler *profiler)
{
- char hbuf [128];
+ const char *args = profiler->args;
+ const char *arch = mono_config_get_cpu ();
+ const char *os = mono_config_get_os ();
+
+ char *hbuf = malloc (
+ sizeof (gint32) /* header id */ +
+ sizeof (gint8) /* major version */ +
+ sizeof (gint8) /* minor version */ +
+ sizeof (gint8) /* data version */ +
+ sizeof (gint8) /* word size */ +
+ sizeof (gint64) /* startup time */ +
+ sizeof (gint32) /* timer overhead */ +
+ sizeof (gint32) /* flags */ +
+ sizeof (gint32) /* process id */ +
+ sizeof (gint16) /* command port */ +
+ sizeof (gint32) + strlen (args) + 1 /* arguments */ +
+ sizeof (gint32) + strlen (arch) + 1 /* architecture */ +
+ sizeof (gint32) + strlen (os) + 1 /* operating system */
+ );
char *p = hbuf;
+
p = write_int32 (p, LOG_HEADER_ID);
*p++ = LOG_VERSION_MAJOR;
*p++ = LOG_VERSION_MINOR;
*p++ = LOG_DATA_VERSION;
- *p++ = sizeof (void*);
- p = write_int64 (p, ((uint64_t)time (NULL)) * 1000); /* startup time */
- p = write_int32 (p, get_timer_overhead ()); /* timer overhead */
+ *p++ = sizeof (void *);
+ p = write_int64 (p, ((uint64_t) time (NULL)) * 1000);
+ p = write_int32 (p, get_timer_overhead ());
p = write_int32 (p, 0); /* flags */
- p = write_int32 (p, process_id ()); /* pid */
- p = write_int16 (p, profiler->command_port); /* port */
- p = write_int16 (p, 0); /* opsystem */
+ p = write_int32 (p, process_id ());
+ p = write_int16 (p, profiler->command_port);
+ p = write_header_string (p, args);
+ p = write_header_string (p, arch);
+ p = write_header_string (p, os);
+
#if defined (HAVE_SYS_ZLIB)
if (profiler->gzfile) {
gzwrite (profiler->gzfile, hbuf, p - hbuf);
- } else {
+ } else
+#endif
+ {
fwrite (hbuf, p - hbuf, 1, profiler->file);
+ fflush (profiler->file);
}
-#else
- fwrite (hbuf, p - hbuf, 1, profiler->file);
- fflush (profiler->file);
-#endif
+
+ free (hbuf);
}
static void
buffer = ensure_logbuf_inner (buffer,
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
- LEB128_SIZE /* tid */ +
- LEB128_SIZE /* flags */
+ BYTE_SIZE /* type */ +
+ LEB128_SIZE /* tid */
);
- uint64_t now = current_time ();
-
- emit_byte (buffer, TYPE_END_UNLOAD | TYPE_METADATA);
- emit_time (buffer, now);
+ emit_event (buffer, TYPE_END_UNLOAD | TYPE_METADATA);
emit_byte (buffer, TYPE_THREAD);
emit_ptr (buffer, (void *) thread->node.key);
- emit_value (buffer, 0); /* flags */
}
send_buffer (prof, thread);
{
char hbuf [128];
char *p = hbuf;
+
if (buf->next)
dump_buffer (profiler, buf->next);
+
p = write_int32 (p, BUF_ID);
p = write_int32 (p, buf->cursor - buf->buf);
p = write_int64 (p, buf->time_base);
p = write_int64 (p, buf->obj_base);
p = write_int64 (p, buf->thread_id);
p = write_int64 (p, buf->method_base);
+
#if defined (HAVE_SYS_ZLIB)
if (profiler->gzfile) {
gzwrite (profiler->gzfile, hbuf, p - hbuf);
gzwrite (profiler->gzfile, buf->buf, buf->cursor - buf->buf);
- } else {
+ } else
#endif
+ {
fwrite (hbuf, p - hbuf, 1, profiler->file);
fwrite (buf->buf, buf->cursor - buf->buf, 1, profiler->file);
fflush (profiler->file);
-#if defined (HAVE_SYS_ZLIB)
}
-#endif
+
free_buffer (buf, buf->size);
}
safe_send_threadless (prof);
}
+// Assumes that the exclusive lock is held.
+static void
+sync_point_flush (MonoProfiler *prof)
+{
+ g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
+
+ MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
+ send_buffer (prof, thread);
+ init_buffer_state (thread);
+ } MONO_LLS_FOREACH_SAFE_END
+}
+
+// Assumes that the exclusive lock is held.
+static void
+sync_point_mark (MonoProfiler *prof, MonoProfilerSyncPointType type)
+{
+ g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
+
+ ENTER_LOG;
+
+ LogBuffer *logbuffer = ensure_logbuf (
+ EVENT_SIZE /* event */ +
+ LEB128_SIZE /* type */
+ );
+
+ emit_event (logbuffer, TYPE_META | TYPE_SYNC_POINT);
+ emit_byte (logbuffer, type);
+
+ EXIT_LOG;
+
+ switch (type) {
+ case SYNC_POINT_PERIODIC:
+ safe_send_threadless (prof);
+ break;
+ case SYNC_POINT_WORLD_STOP:
+ case SYNC_POINT_WORLD_START:
+ safe_send (prof);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+// Assumes that the exclusive lock is held.
+static void
+sync_point (MonoProfiler *prof, MonoProfilerSyncPointType type)
+{
+ sync_point_flush (prof);
+ sync_point_mark (prof, type);
+}
+
static int
gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, MonoObject **refs, uintptr_t *offsets, void *data)
{
)
);
- emit_byte (logbuffer, TYPE_HEAP_OBJECT | TYPE_HEAP);
+ emit_event (logbuffer, TYPE_HEAP_OBJECT | TYPE_HEAP);
emit_obj (logbuffer, obj);
emit_ptr (logbuffer, klass);
emit_value (logbuffer, size);
ENTER_LOG;
LogBuffer *logbuffer = ensure_logbuf (
- EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */
+ EVENT_SIZE /* event */
);
- emit_byte (logbuffer, TYPE_HEAP_START | TYPE_HEAP);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_HEAP_START | TYPE_HEAP);
EXIT_LOG;
ENTER_LOG;
LogBuffer *logbuffer = ensure_logbuf (
- EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */
+ EVENT_SIZE /* event */
);
now = current_time ();
- emit_byte (logbuffer, TYPE_HEAP_END | TYPE_HEAP);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP);
EXIT_LOG;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- LEB128_SIZE /* gc event */ +
- LEB128_SIZE /* generation */
+ BYTE_SIZE /* gc event */ +
+ BYTE_SIZE /* generation */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_GC_EVENT | TYPE_GC);
- emit_time (logbuffer, now);
- emit_value (logbuffer, ev);
- emit_value (logbuffer, generation);
+ emit_event (logbuffer, TYPE_GC_EVENT | TYPE_GC);
+ emit_byte (logbuffer, ev);
+ emit_byte (logbuffer, generation);
EXIT_LOG;
* committed to the log file before any object move events
* that will be produced during this GC.
*/
- g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
-
- MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
- send_buffer (profiler, thread);
- init_buffer_state (thread);
- } MONO_LLS_FOREACH_SAFE_END
+ sync_point (profiler, SYNC_POINT_WORLD_STOP);
break;
case MONO_GC_EVENT_PRE_START_WORLD:
heap_walk (profiler);
* object allocation events for certain addresses could come
* after the move events that made those addresses available.
*/
- safe_send (profiler);
+ sync_point_mark (profiler, SYNC_POINT_WORLD_START);
/*
* Finally, it is safe to allow other threads to write to
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* new size */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_GC_RESIZE | TYPE_GC);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_GC_RESIZE | TYPE_GC);
emit_value (logbuffer, new_size);
EXIT_LOG;
*/
if (data->count > num_frames)
printf ("bad num frames: %d\n", data->count);
- emit_value (logbuffer, 0); /* flags */
emit_value (logbuffer, data->count);
//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->cursor); exit(0);}
while (data->count) {
- emit_method_as_ptr (prof, logbuffer, data->methods [--data->count]);
+ emit_method (prof, logbuffer, data->methods [--data->count]);
}
}
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* klass */ +
LEB128_SIZE /* obj */ +
LEB128_SIZE /* size */ +
(do_bt ? (
- LEB128_SIZE /* flags */ +
LEB128_SIZE /* count */ +
data.count * (
LEB128_SIZE /* method */
) : 0)
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, do_bt | TYPE_ALLOC);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, do_bt | TYPE_ALLOC);
emit_ptr (logbuffer, klass);
emit_obj (logbuffer, obj);
emit_value (logbuffer, len);
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* num */ +
num * (
LEB128_SIZE /* object */
)
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_GC_MOVE | TYPE_GC);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_GC_MOVE | TYPE_GC);
emit_value (logbuffer, num);
for (int i = 0; i < num; ++i)
)
);
- emit_byte (logbuffer, TYPE_HEAP_ROOT | TYPE_HEAP);
+ emit_event (logbuffer, TYPE_HEAP_ROOT | TYPE_HEAP);
emit_value (logbuffer, num);
emit_value (logbuffer, mono_gc_collection_count (mono_gc_max_generation ()));
for (int i = 0; i < num; ++i) {
emit_obj (logbuffer, objects [i]);
- emit_value (logbuffer, root_types [i]);
+ emit_byte (logbuffer, root_types [i]);
emit_value (logbuffer, extra_info [i]);
}
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* type */ +
LEB128_SIZE /* handle */ +
(op == MONO_PROFILER_GC_HANDLE_CREATED ? (
LEB128_SIZE /* obj */
) : 0) +
(do_bt ? (
- LEB128_SIZE /* flags */ +
LEB128_SIZE /* count */ +
data.count * (
LEB128_SIZE /* method */
) : 0)
);
- uint64_t now = current_time ();
-
if (op == MONO_PROFILER_GC_HANDLE_CREATED)
- emit_byte (logbuffer, (do_bt ? TYPE_GC_HANDLE_CREATED_BT : TYPE_GC_HANDLE_CREATED) | TYPE_GC);
+ emit_event (logbuffer, (do_bt ? TYPE_GC_HANDLE_CREATED_BT : TYPE_GC_HANDLE_CREATED) | TYPE_GC);
else if (op == MONO_PROFILER_GC_HANDLE_DESTROYED)
- emit_byte (logbuffer, (do_bt ? TYPE_GC_HANDLE_DESTROYED_BT : TYPE_GC_HANDLE_DESTROYED) | TYPE_GC);
+ emit_event (logbuffer, (do_bt ? TYPE_GC_HANDLE_DESTROYED_BT : TYPE_GC_HANDLE_DESTROYED) | TYPE_GC);
else
g_assert_not_reached ();
- emit_time (logbuffer, now);
emit_value (logbuffer, type);
emit_value (logbuffer, handle);
process_requests (prof);
}
+static void
+finalize_begin (MonoProfiler *prof)
+{
+ ENTER_LOG;
+
+ LogBuffer *buf = ensure_logbuf (
+ EVENT_SIZE /* event */
+ );
+
+ emit_event (buf, TYPE_GC_FINALIZE_START | TYPE_GC);
+
+ EXIT_LOG;
+
+ process_requests (prof);
+}
+
+static void
+finalize_end (MonoProfiler *prof)
+{
+ ENTER_LOG;
+
+ LogBuffer *buf = ensure_logbuf (
+ EVENT_SIZE /* event */
+ );
+
+ emit_event (buf, TYPE_GC_FINALIZE_END | TYPE_GC);
+
+ EXIT_LOG;
+
+ process_requests (prof);
+}
+
+static void
+finalize_object_begin (MonoProfiler *prof, MonoObject *obj)
+{
+ ENTER_LOG;
+
+ LogBuffer *buf = ensure_logbuf (
+ EVENT_SIZE /* event */ +
+ LEB128_SIZE /* obj */
+ );
+
+ emit_event (buf, TYPE_GC_FINALIZE_OBJECT_START | TYPE_GC);
+ emit_obj (buf, obj);
+
+ EXIT_LOG;
+
+ process_requests (prof);
+}
+
+static void
+finalize_object_end (MonoProfiler *prof, MonoObject *obj)
+{
+ ENTER_LOG;
+
+ LogBuffer *buf = ensure_logbuf (
+ EVENT_SIZE /* event */ +
+ LEB128_SIZE /* obj */
+ );
+
+ emit_event (buf, TYPE_GC_FINALIZE_OBJECT_END | TYPE_GC);
+ emit_obj (buf, obj);
+
+ EXIT_LOG;
+
+ process_requests (prof);
+}
+
static char*
push_nesting (char *p, MonoClass *klass)
{
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* image */ +
- LEB128_SIZE /* flags */ +
nlen /* name */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_IMAGE);
emit_ptr (logbuffer, image);
- emit_value (logbuffer, 0); /* flags */
memcpy (logbuffer->cursor, name, nlen);
logbuffer->cursor += nlen;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* image */ +
- LEB128_SIZE /* flags */ +
nlen /* name */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_IMAGE);
emit_ptr (logbuffer, image);
- emit_value (logbuffer, 0); /* flags */
memcpy (logbuffer->cursor, name, nlen);
logbuffer->cursor += nlen;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* assembly */ +
- LEB128_SIZE /* flags */ +
nlen /* name */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_ASSEMBLY);
emit_ptr (logbuffer, assembly);
- emit_value (logbuffer, 0); /* flags */
memcpy (logbuffer->cursor, name, nlen);
logbuffer->cursor += nlen;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* assembly */ +
- LEB128_SIZE /* flags */ +
nlen /* name */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_ASSEMBLY);
emit_ptr (logbuffer, assembly);
- emit_value (logbuffer, 0); /* flags */
memcpy (logbuffer->cursor, name, nlen);
logbuffer->cursor += nlen;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* klass */ +
LEB128_SIZE /* image */ +
- LEB128_SIZE /* flags */ +
nlen /* name */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_CLASS);
emit_ptr (logbuffer, klass);
emit_ptr (logbuffer, image);
- emit_value (logbuffer, 0); /* flags */
memcpy (logbuffer->cursor, name, nlen);
logbuffer->cursor += nlen;
if (runtime_inited)
mono_free (name);
else
- free (name);
+ g_free (name);
send_if_needed (prof);
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* klass */ +
LEB128_SIZE /* image */ +
- LEB128_SIZE /* flags */ +
nlen /* name */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_CLASS);
emit_ptr (logbuffer, klass);
emit_ptr (logbuffer, image);
- emit_value (logbuffer, 0); /* flags */
memcpy (logbuffer->cursor, name, nlen);
logbuffer->cursor += nlen;
if (runtime_inited)
mono_free (name);
else
- free (name);
+ g_free (name);
send_if_needed (prof);
static void
method_enter (MonoProfiler *prof, MonoMethod *method)
{
- uint64_t now = current_time ();
-
#ifndef DISABLE_HELPER_THREAD
process_method_enter_coverage (prof, method);
#endif /* DISABLE_HELPER_THREAD */
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* method */
);
- emit_byte (logbuffer, TYPE_ENTER | TYPE_METHOD);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_ENTER | TYPE_METHOD);
emit_method (prof, logbuffer, method);
EXIT_LOG;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* method */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_LEAVE | TYPE_METHOD);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_LEAVE | TYPE_METHOD);
emit_method (prof, logbuffer, method);
EXIT_LOG;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* method */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD);
emit_method (prof, logbuffer, method);
EXIT_LOG;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- LEB128_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* buffer */ +
LEB128_SIZE /* size */ +
(name ? (
) : 0)
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_JITHELPER | TYPE_RUNTIME);
- emit_time (logbuffer, now);
- emit_value (logbuffer, type);
+ emit_event (logbuffer, TYPE_JITHELPER | TYPE_RUNTIME);
+ emit_byte (logbuffer, type);
emit_ptr (logbuffer, buffer);
emit_value (logbuffer, size);
static void
throw_exc (MonoProfiler *prof, MonoObject *object)
{
- int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_EXCEPTION_BT : 0;
+ int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_THROW_BT : 0;
FrameData data;
if (do_bt)
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* object */ +
(do_bt ? (
- LEB128_SIZE /* flags */ +
LEB128_SIZE /* count */ +
data.count * (
LEB128_SIZE /* method */
) : 0)
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, do_bt | TYPE_EXCEPTION);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, do_bt | TYPE_EXCEPTION);
emit_obj (logbuffer, object);
if (do_bt)
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- LEB128_SIZE /* clause type */ +
+ BYTE_SIZE /* clause type */ +
LEB128_SIZE /* clause num */ +
LEB128_SIZE /* method */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_EXCEPTION | TYPE_CLAUSE);
- emit_time (logbuffer, now);
- emit_value (logbuffer, clause_type);
+ emit_event (logbuffer, TYPE_EXCEPTION | TYPE_CLAUSE);
+ emit_byte (logbuffer, clause_type);
emit_value (logbuffer, clause_num);
emit_method (prof, logbuffer, method);
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* object */ +
(do_bt ? (
- LEB128_SIZE /* flags */ +
LEB128_SIZE /* count */ +
data.count * (
LEB128_SIZE /* method */
) : 0)
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, (event << 4) | do_bt | TYPE_MONITOR);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, (event << 4) | do_bt | TYPE_MONITOR);
emit_obj (logbuffer, object);
if (do_bt)
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
- LEB128_SIZE /* tid */ +
- LEB128_SIZE /* flags */
+ BYTE_SIZE /* type */ +
+ LEB128_SIZE /* tid */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_THREAD);
emit_ptr (logbuffer, (void*) tid);
- emit_value (logbuffer, 0); /* flags */
EXIT_LOG;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
- LEB128_SIZE /* tid */ +
- LEB128_SIZE /* flags */
+ BYTE_SIZE /* type */ +
+ LEB128_SIZE /* tid */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_THREAD);
emit_ptr (logbuffer, (void*) tid);
- emit_value (logbuffer, 0); /* flags */
EXIT_LOG;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
- LEB128_SIZE /* domain id */ +
- LEB128_SIZE /* flags */
+ BYTE_SIZE /* type */ +
+ LEB128_SIZE /* domain id */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_DOMAIN);
emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
- emit_value (logbuffer, 0); /* flags */
EXIT_LOG;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
- LEB128_SIZE /* domain id */ +
- LEB128_SIZE /* flags */
+ BYTE_SIZE /* type */ +
+ LEB128_SIZE /* domain id */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_DOMAIN);
emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
- emit_value (logbuffer, 0); /* flags */
EXIT_LOG;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* domain id */ +
- LEB128_SIZE /* flags */ +
nlen /* name */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_METADATA);
emit_byte (logbuffer, TYPE_DOMAIN);
emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
- emit_value (logbuffer, 0); /* flags */
memcpy (logbuffer->cursor, name, nlen);
logbuffer->cursor += nlen;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* context id */ +
- LEB128_SIZE /* flags */ +
LEB128_SIZE /* domain id */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_LOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_CONTEXT);
emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context));
- emit_value (logbuffer, 0); /* flags */
emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
EXIT_LOG;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* context id */ +
- LEB128_SIZE /* flags */ +
LEB128_SIZE /* domain id */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_END_UNLOAD | TYPE_METADATA);
emit_byte (logbuffer, TYPE_CONTEXT);
emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context));
- emit_value (logbuffer, 0); /* flags */
emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
EXIT_LOG;
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- EVENT_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* tid */ +
- LEB128_SIZE /* flags */ +
len /* name */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_METADATA);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_METADATA);
emit_byte (logbuffer, TYPE_THREAD);
emit_ptr (logbuffer, (void*)tid);
- emit_value (logbuffer, 0); /* flags */
memcpy (logbuffer->cursor, name, len);
logbuffer->cursor += len;
typedef struct {
MonoLockFreeQueueNode node;
MonoProfiler *prof;
- uint64_t elapsed;
+ uint64_t time;
uintptr_t tid;
void *ip;
int count;
InterlockedIncrement (&sample_hits);
- uint64_t now = current_time ();
-
SampleHit *sample = (SampleHit *) mono_lock_free_queue_dequeue (&profiler->sample_reuse_queue);
if (!sample) {
sample->count = 0;
mono_stack_walk_async_safe (&async_walk_stack, context, sample);
- uintptr_t elapsed = (now - profiler->startup_time) / 10000;
-
- sample->elapsed = elapsed;
+ sample->time = current_time ();
sample->tid = thread_id ();
sample->ip = ip;
if (do_debug) {
int len;
char buf [256];
- snprintf (buf, sizeof (buf), "hit at %p in thread %p after %llu ms\n", ip, (void *) thread_id (), (unsigned long long int) elapsed / 100);
+ snprintf (buf, sizeof (buf), "hit at %p in thread %p after %llu ms\n", ip, (void *) sample->tid, (unsigned long long int) ((sample->time - profiler->startup_time) / 10000 / 100));
len = strlen (buf);
ign_res (write (2, buf, len));
}
add_code_page (n, size_code_pages, code_pages [i]);
}
if (code_pages)
- free (code_pages);
+ g_free (code_pages);
code_pages = n;
}
num_code_pages += add_code_page (code_pages, size_code_pages, ip & CPAGE_MASK);
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* load address */ +
LEB128_SIZE /* offset */ +
LEB128_SIZE /* size */ +
nlen /* file name */
);
- uint64_t now = current_time ();
-
- emit_byte (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_UBIN);
- emit_time (logbuffer, now);
+ emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_UBIN);
emit_svalue (logbuffer, load_addr);
emit_uvalue (logbuffer, offset);
emit_uvalue (logbuffer, size);
len /* name */
);
- emit_byte (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_USYM);
+ emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_USYM);
emit_ptr (logbuffer, (void*)value);
emit_value (logbuffer, size);
memcpy (logbuffer->cursor, name, len);
filename = buf;
}
}
- obj = calloc (sizeof (BinaryObject), 1);
+ obj = g_calloc (sizeof (BinaryObject), 1);
obj->addr = (void*)info->dlpi_addr;
obj->name = pstrdup (filename);
obj->next = prof->binary_objects;
names = backtrace_symbols (&ip, 1);
if (names) {
const char* p = names [0];
- free (names);
+ g_free (names);
return p;
}
*/
LogBuffer *logbuffer = ensure_logbuf (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* type */ +
- LEB128_SIZE /* time */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* tid */ +
LEB128_SIZE /* count */ +
count * (
) +
LEB128_SIZE /* managed count */ +
mbt_count * (
- LEB128_SIZE /* method */ +
- LEB128_SIZE /* il offset */ +
- LEB128_SIZE /* native offset */
+ LEB128_SIZE /* method */
)
);
- emit_byte (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT);
- emit_value (logbuffer, sample_type);
- emit_uvalue (logbuffer, s->timestamp - prof->startup_time);
+ emit_event (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT);
+ emit_byte (logbuffer, sample_type);
/*
* No useful thread ID to write here, since throughout the
* profiler we use pthread_self () but the ID we get from
int i, count = 0;
mmap_mask = num_pages * getpagesize () - 1;
num_perf = mono_cpu_count ();
- perf_data = calloc (num_perf, sizeof (PerfData));
+ perf_data = g_calloc (num_perf, sizeof (PerfData));
for (i = 0; i < num_perf; ++i) {
count += setup_perf_event_for_cpu (perf_data + i, i);
}
if (count)
return 1;
- free (perf_data);
+ g_free (perf_data);
perf_data = NULL;
return 0;
}
if (agent->counter == counter) {
agent->value_size = 0;
if (agent->value) {
- free (agent->value);
+ g_free (agent->value);
agent->value = NULL;
}
mono_os_mutex_unlock (&counters_mutex);
size +=
LEB128_SIZE /* section */ +
strlen (mono_counter_get_name (agent->counter)) + 1 /* name */ +
- LEB128_SIZE /* type */ +
- LEB128_SIZE /* unit */ +
- LEB128_SIZE /* variance */ +
+ BYTE_SIZE /* type */ +
+ BYTE_SIZE /* unit */ +
+ BYTE_SIZE /* variance */ +
LEB128_SIZE /* index */
;
LogBuffer *logbuffer = ensure_logbuf (size);
- emit_byte (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
+ emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
emit_value (logbuffer, len);
for (agent = counters; agent; agent = agent->next) {
name = mono_counter_get_name (agent->counter);
emit_value (logbuffer, mono_counter_get_section (agent->counter));
emit_string (logbuffer, name, strlen (name) + 1);
- emit_value (logbuffer, mono_counter_get_type (agent->counter));
- emit_value (logbuffer, mono_counter_get_unit (agent->counter));
- emit_value (logbuffer, mono_counter_get_variance (agent->counter));
+ emit_byte (logbuffer, mono_counter_get_type (agent->counter));
+ emit_byte (logbuffer, mono_counter_get_unit (agent->counter));
+ emit_byte (logbuffer, mono_counter_get_variance (agent->counter));
emit_value (logbuffer, agent->index);
agent->emitted = 1;
counters_emit (profiler);
buffer_size = 8;
- buffer = calloc (1, buffer_size);
+ buffer = g_calloc (1, buffer_size);
mono_os_mutex_lock (&counters_mutex);
size =
- EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */
+ EVENT_SIZE /* event */
;
for (agent = counters; agent; agent = agent->next) {
size +=
LEB128_SIZE /* index */ +
- LEB128_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
mono_counter_get_size (agent->counter) /* value */
;
}
LogBuffer *logbuffer = ensure_logbuf (size);
- emit_byte (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE);
- emit_uvalue (logbuffer, timestamp);
+ emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
for (agent = counters; agent; agent = agent->next) {
size_t size;
continue; // FIXME error
} else if (size > buffer_size) {
buffer_size = size;
- buffer = realloc (buffer, buffer_size);
+ buffer = g_realloc (buffer, buffer_size);
}
memset (buffer, 0, buffer_size);
type = mono_counter_get_type (counter);
if (!agent->value) {
- agent->value = calloc (1, size);
+ agent->value = g_calloc (1, size);
agent->value_size = size;
} else {
if (type == MONO_COUNTER_STRING) {
}
emit_uvalue (logbuffer, agent->index);
- emit_uvalue (logbuffer, type);
+ emit_byte (logbuffer, type);
switch (type) {
case MONO_COUNTER_INT:
#if SIZEOF_VOID_P == 4
}
if (type == MONO_COUNTER_STRING && size > agent->value_size) {
- agent->value = realloc (agent->value, size);
+ agent->value = g_realloc (agent->value, size);
agent->value_size = size;
}
if (size > 0)
memcpy (agent->value, buffer, size);
}
- free (buffer);
+ g_free (buffer);
emit_value (logbuffer, 0);
LEB128_SIZE /* section */ +
strlen (pcagent->category_name) + 1 /* category name */ +
strlen (pcagent->name) + 1 /* name */ +
- LEB128_SIZE /* type */ +
- LEB128_SIZE /* unit */ +
- LEB128_SIZE /* variance */ +
+ BYTE_SIZE /* type */ +
+ BYTE_SIZE /* unit */ +
+ BYTE_SIZE /* variance */ +
LEB128_SIZE /* index */
;
LogBuffer *logbuffer = ensure_logbuf (size);
- emit_byte (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
+ emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE);
emit_value (logbuffer, len);
for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
emit_value (logbuffer, MONO_COUNTER_PERFCOUNTERS);
emit_string (logbuffer, pcagent->category_name, strlen (pcagent->category_name) + 1);
emit_string (logbuffer, pcagent->name, strlen (pcagent->name) + 1);
- emit_value (logbuffer, MONO_COUNTER_LONG);
- emit_value (logbuffer, MONO_COUNTER_RAW);
- emit_value (logbuffer, MONO_COUNTER_VARIABLE);
+ emit_byte (logbuffer, MONO_COUNTER_LONG);
+ emit_byte (logbuffer, MONO_COUNTER_RAW);
+ emit_byte (logbuffer, MONO_COUNTER_VARIABLE);
emit_value (logbuffer, pcagent->index);
pcagent->emitted = 1;
perfcounters_emit (profiler);
size =
- EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */
+ EVENT_SIZE /* event */
;
for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
size +=
LEB128_SIZE /* index */ +
- LEB128_SIZE /* type */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* value */
;
}
LogBuffer *logbuffer = ensure_logbuf (size);
- emit_byte (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE);
- emit_uvalue (logbuffer, timestamp);
+ emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp);
for (pcagent = perfcounters; pcagent; pcagent = pcagent->next) {
if (pcagent->deleted || !pcagent->updated)
continue;
emit_uvalue (logbuffer, pcagent->index);
- emit_uvalue (logbuffer, MONO_COUNTER_LONG);
+ emit_byte (logbuffer, MONO_COUNTER_LONG);
emit_svalue (logbuffer, pcagent->value);
pcagent->updated = 0;
static void
counters_and_perfcounters_sample (MonoProfiler *prof)
{
- static uint64_t start = -1;
- uint64_t now;
-
- if (start == -1)
- start = current_time ();
+ uint64_t now = current_time ();
- now = current_time ();
- counters_sample (prof, (now - start) / 1000/ 1000);
- perfcounters_sample (prof, (now - start) / 1000/ 1000);
+ counters_sample (prof, now);
+ perfcounters_sample (prof, now);
}
#define COVERAGE_DEBUG(x) if (debug_coverage) {x}
LEB128_SIZE /* entries */
);
- emit_byte (logbuffer, TYPE_COVERAGE_METHOD | TYPE_COVERAGE);
+ emit_event (logbuffer, TYPE_COVERAGE_METHOD | TYPE_COVERAGE);
emit_string (logbuffer, image_name, strlen (image_name) + 1);
emit_string (logbuffer, class_name, strlen (class_name) + 1);
emit_string (logbuffer, method_name, strlen (method_name) + 1);
LEB128_SIZE /* column */
);
- emit_byte (logbuffer, TYPE_COVERAGE_STATEMENT | TYPE_COVERAGE);
+ emit_event (logbuffer, TYPE_COVERAGE_STATEMENT | TYPE_COVERAGE);
emit_uvalue (logbuffer, method_id);
emit_uvalue (logbuffer, entry->offset);
emit_uvalue (logbuffer, entry->counter);
LEB128_SIZE /* partially covered */
);
- emit_byte (logbuffer, TYPE_COVERAGE_CLASS | TYPE_COVERAGE);
+ emit_event (logbuffer, TYPE_COVERAGE_CLASS | TYPE_COVERAGE);
emit_string (logbuffer, assembly_name, strlen (assembly_name) + 1);
emit_string (logbuffer, class_name, strlen (class_name) + 1);
emit_uvalue (logbuffer, number_of_methods);
LEB128_SIZE /* partially covered */
);
- emit_byte (logbuffer, TYPE_COVERAGE_ASSEMBLY | TYPE_COVERAGE);
+ emit_event (logbuffer, TYPE_COVERAGE_ASSEMBLY | TYPE_COVERAGE);
emit_string (logbuffer, name, strlen (name) + 1);
emit_string (logbuffer, guid, strlen (guid) + 1);
emit_string (logbuffer, filename, strlen (filename) + 1);
cleanup_reusable_samples (prof);
+ /*
+ * Pump the entire hazard free queue to make sure that anything we allocated
+ * in the profiler will be freed. If we don't do this, the runtime could get
+ * around to freeing some items after the profiler has been unloaded, which
+ * would mean calling into functions in the profiler library, leading to a
+ * crash.
+ */
+ mono_thread_hazardous_try_free_all ();
+
g_assert (!InterlockedRead (&buffer_rwlock_count) && "Why is the reader count still non-zero?");
g_assert (!InterlockedReadPointer (&buffer_rwlock_exclusive) && "Why does someone still hold the exclusive lock?");
PROF_TLS_FREE ();
- free (prof);
+ g_free (prof->args);
+ g_free (prof);
}
static char*
int command_socket;
int len;
char buf [64];
- MonoThread *thread = NULL;
mono_threads_attach_tools_thread ();
mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler helper");
counters_and_perfcounters_sample (prof);
- send_if_needed_threadless (prof);
-
buffer_lock_excl ();
- // Periodically flush all thread-local buffers.
- MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
- send_buffer (prof, thread);
- init_buffer_state (thread);
- } MONO_LLS_FOREACH_SAFE_END
+ sync_point (prof, SYNC_POINT_PERIODIC);
buffer_unlock_excl ();
if (FD_ISSET (prof->pipes [0], &rfds)) {
char c;
read (prof->pipes [0], &c, 1);
- if (thread)
- mono_thread_detach (thread);
if (do_debug)
fprintf (stderr, "helper shutdown\n");
#if USE_PERF_EVENTS
continue;
}
buf [len] = 0;
- if (strcmp (buf, "heapshot\n") == 0) {
+ if (strcmp (buf, "heapshot\n") == 0 && hs_mode_ondemand) {
+ // Rely on the finalization callbacks invoking process_requests ().
heapshot_requested = 1;
- //fprintf (stderr, "perform heapshot\n");
- if (InterlockedRead (&runtime_inited) && !thread) {
- thread = mono_thread_attach (mono_get_root_domain ());
- /*fprintf (stderr, "attached\n");*/
- }
- if (thread) {
- process_requests (prof);
- mono_thread_detach (thread);
- thread = NULL;
- }
+ mono_gc_finalize_notify ();
}
continue;
}
buf = ensure_logbuf_unsafe (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
LEB128_SIZE /* method */ +
LEB128_SIZE /* start */ +
LEB128_SIZE /* size */ +
nlen /* name */
);
- emit_byte (buf, TYPE_JIT | TYPE_METHOD);
- emit_time (buf, info->time);
+ emit_event_time (buf, TYPE_JIT | TYPE_METHOD, info->time);
emit_method_inner (buf, info->method);
emit_ptr (buf, cstart);
emit_value (buf, csize);
mono_free (name);
free_info:
- free (info);
+ g_free (info);
}
g_ptr_array_free (entry->methods, TRUE);
LogBuffer *logbuffer = ensure_logbuf_unsafe (
EVENT_SIZE /* event */ +
- LEB128_SIZE /* type */ +
- LEB128_SIZE /* time */ +
+ BYTE_SIZE /* type */ +
LEB128_SIZE /* tid */ +
LEB128_SIZE /* count */ +
1 * (
) +
LEB128_SIZE /* managed count */ +
sample->count * (
- LEB128_SIZE /* method */ +
- LEB128_SIZE /* il offset */ +
- LEB128_SIZE /* native offset */
+ LEB128_SIZE /* method */
)
);
- emit_byte (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT);
- emit_value (logbuffer, sample_type);
- emit_uvalue (logbuffer, prof->startup_time + sample->elapsed * 10000);
+ emit_event_time (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT, sample->time);
+ emit_byte (logbuffer, sample_type);
emit_ptr (logbuffer, (void *) sample->tid);
emit_value (logbuffer, 1);
/* new in data version 6 */
emit_uvalue (logbuffer, sample->count);
- for (int i = 0; i < sample->count; ++i) {
+ for (int i = 0; i < sample->count; ++i)
emit_method (prof, logbuffer, sample->frames [i].method);
- emit_svalue (logbuffer, 0); /* il offset will always be 0 from now on */
- emit_svalue (logbuffer, sample->frames [i].offset);
- }
mono_thread_hazardous_try_free (sample, reuse_sample_hit);
static void
runtime_initialized (MonoProfiler *profiler)
{
+ InterlockedWrite (&runtime_inited, 1);
+
#ifndef DISABLE_HELPER_THREAD
if (hs_mode_ondemand || need_helper_thread) {
if (!start_helper_thread (profiler))
start_writer_thread (profiler);
start_dumper_thread (profiler);
- InterlockedWrite (&runtime_inited, 1);
+ mono_counters_register ("Sample hits", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_hits);
+ mono_counters_register ("Sample flushes", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_flushes);
+ mono_counters_register ("Sample events allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_allocations);
+ mono_counters_register ("Log buffers allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &buffer_allocations);
+ mono_counters_register ("Thread start events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_starts);
+ mono_counters_register ("Thread stop events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_ends);
+ mono_counters_register ("Domain load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_loads);
+ mono_counters_register ("Domain unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_unloads);
+ mono_counters_register ("Context load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_loads);
+ mono_counters_register ("Context unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_unloads);
+ mono_counters_register ("Assembly load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_loads);
+ mono_counters_register ("Assembly unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_unloads);
+ mono_counters_register ("Image load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_loads);
+ mono_counters_register ("Image unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_unloads);
+ mono_counters_register ("Class load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_loads);
+ mono_counters_register ("Class unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_unloads);
+
#ifndef DISABLE_HELPER_THREAD
counters_init (profiler);
counters_sample (profiler, 0);
}
static MonoProfiler*
-create_profiler (const char *filename, GPtrArray *filters)
+create_profiler (const char *args, const char *filename, GPtrArray *filters)
{
MonoProfiler *prof;
char *nf;
int force_delete = 0;
prof = (MonoProfiler *)calloc (1, sizeof (MonoProfiler));
+ prof->args = pstrdup (args);
prof->command_port = command_port;
if (filename && *filename == '-') {
force_delete = 1;
int s = strlen (nf) + 32;
char *p = (char *)malloc (s);
snprintf (p, s, "|mprof-report '--out=%s' -", nf);
- free (nf);
+ g_free (nf);
nf = p;
}
}
prof->gzfile = gzdopen (fileno (prof->file), "wb");
#endif
#if USE_PERF_EVENTS
- if (sample_type && !do_mono_sample)
+ if (sample_type && sample_freq && !do_mono_sample)
need_helper_thread = setup_perf_event ();
if (!perf_data) {
/* FIXME: warn if different freq or sample type */
// FIXME: We should free this stuff too.
mono_lock_free_allocator_init_size_class (&prof->sample_size_class, SAMPLE_SLOT_SIZE (num_frames), SAMPLE_BLOCK_SIZE);
- mono_lock_free_allocator_init_allocator (&prof->sample_allocator, &prof->sample_size_class);
+ mono_lock_free_allocator_init_allocator (&prof->sample_allocator, &prof->sample_size_class, MONO_MEM_ACCOUNT_PROFILER);
mono_lock_free_queue_init (&prof->sample_reuse_queue);
// FIXME: We should free this stuff too.
mono_lock_free_allocator_init_size_class (&prof->writer_entry_size_class, sizeof (WriterQueueEntry), WRITER_ENTRY_BLOCK_SIZE);
- mono_lock_free_allocator_init_allocator (&prof->writer_entry_allocator, &prof->writer_entry_size_class);
+ mono_lock_free_allocator_init_allocator (&prof->writer_entry_allocator, &prof->writer_entry_size_class, MONO_MEM_ACCOUNT_PROFILER);
mono_lock_free_queue_init (&prof->writer_queue);
mono_os_sem_init (&prof->writer_queue_sem, 0);
if (strcmp (val, "mono") == 0) {
do_mono_sample = 1;
sample_type = SAMPLE_CYCLES;
- free (val);
+ g_free (val);
return;
}
for (smode = sample_modes; smode->name; smode++) {
} else {
sample_freq = 100;
}
- free (val);
+ g_free (val);
}
static void
return;
if (strcmp (val, "ondemand") == 0) {
hs_mode_ondemand = 1;
- free (val);
+ g_free (val);
return;
}
count = strtoul (val, &end, 10);
hs_mode_gc = count;
else
usage (1);
- free (val);
+ g_free (val);
}
/*
MONO_PROFILE_ENTER_LEAVE|MONO_PROFILE_JIT_COMPILATION|MONO_PROFILE_EXCEPTIONS|
MONO_PROFILE_MONITOR_EVENTS|MONO_PROFILE_MODULE_EVENTS|MONO_PROFILE_GC_ROOTS|
MONO_PROFILE_INS_COVERAGE|MONO_PROFILE_APPDOMAIN_EVENTS|MONO_PROFILE_CONTEXT_EVENTS|
- MONO_PROFILE_ASSEMBLY_EVENTS;
+ MONO_PROFILE_ASSEMBLY_EVENTS|MONO_PROFILE_GC_FINALIZATION;
max_allocated_sample_hits = mono_cpu_count () * 1000;
- mono_counters_register ("Sample hits", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_hits);
- mono_counters_register ("Sample flushes", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_flushes);
- mono_counters_register ("Sample events allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &sample_allocations);
- mono_counters_register ("Log buffers allocated", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &buffer_allocations);
- mono_counters_register ("Thread start events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_starts);
- mono_counters_register ("Thread stop events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &thread_ends);
- mono_counters_register ("Domain load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_loads);
- mono_counters_register ("Domain unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &domain_unloads);
- mono_counters_register ("Context load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_loads);
- mono_counters_register ("Context unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &context_unloads);
- mono_counters_register ("Assembly load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_loads);
- mono_counters_register ("Assembly unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &assembly_unloads);
- mono_counters_register ("Image load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_loads);
- mono_counters_register ("Image unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &image_unloads);
- mono_counters_register ("Class load events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_loads);
- mono_counters_register ("Class unload events", MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, &class_unloads);
-
p = desc;
if (strncmp (p, "log", 3))
usage (1);
fast_time = 2;
else
usage (1);
- free (val);
+ g_free (val);
continue;
}
if ((opt = match_option (p, "report", NULL)) != p) {
if ((opt = match_option (p, "port", &val)) != p) {
char *end;
command_port = strtoul (val, &end, 10);
- free (val);
+ g_free (val);
continue;
}
if ((opt = match_option (p, "maxframes", &val)) != p) {
num_frames = strtoul (val, &end, 10);
if (num_frames > MAX_FRAMES)
num_frames = MAX_FRAMES;
- free (val);
+ g_free (val);
notraces = num_frames == 0;
continue;
}
max_allocated_sample_hits = strtoul (val, &end, 10);
if (!max_allocated_sample_hits)
max_allocated_sample_hits = G_MAXINT32;
- free (val);
+ g_free (val);
continue;
}
if ((opt = match_option (p, "calldepth", &val)) != p) {
char *end;
max_call_depth = strtoul (val, &end, 10);
- free (val);
+ g_free (val);
continue;
}
if ((opt = match_option (p, "counters", NULL)) != p) {
PROF_TLS_INIT ();
- prof = create_profiler (filename, filters);
+ prof = create_profiler (desc, filename, filters);
if (!prof) {
PROF_TLS_FREE ();
return;
mono_profiler_install_allocation (gc_alloc);
mono_profiler_install_gc_moves (gc_moves);
mono_profiler_install_gc_roots (gc_handle, gc_roots);
+ mono_profiler_install_gc_finalize (finalize_begin, finalize_object_begin, finalize_object_end, finalize_end);
mono_profiler_install_appdomain (NULL, domain_loaded, domain_unloaded, NULL);
mono_profiler_install_appdomain_name (domain_name);
mono_profiler_install_context (context_loaded, context_unloaded);
if (do_coverage)
mono_profiler_install_coverage_filter (coverage_filter);
- if (do_mono_sample && sample_type == SAMPLE_CYCLES && !only_counters) {
+ if (do_mono_sample && sample_type == SAMPLE_CYCLES && sample_freq && !only_counters) {
events |= MONO_PROFILE_STATISTICAL;
mono_profiler_set_statistical_mode (sampling_mode, sample_freq);
mono_profiler_install_statistical (mono_sample_hit);