*/
#include <config.h>
-#include "../mini/jit.h"
-#include "../metadata/metadata-internals.h"
-#include <mono/metadata/profiler.h>
-#include <mono/metadata/threads.h>
+#include <mono/metadata/assembly.h>
#include <mono/metadata/debug-helpers.h>
+#include "../metadata/metadata-internals.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>
-#include <mono/metadata/tokentype.h>
-#include <mono/metadata/tabledefs.h>
+#include <mono/metadata/profiler.h>
#include <mono/utils/atomic.h>
+#include <mono/utils/hazard-pointer.h>
+#include <mono/utils/lock-free-alloc.h>
+#include <mono/utils/lock-free-queue.h>
+#include <mono/utils/mono-conc-hashtable.h>
+#include <mono/utils/mono-counters.h>
+#include <mono/utils/mono-linked-list-set.h>
#include <mono/utils/mono-membar.h>
#include <mono/utils/mono-mmap.h>
-#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-os-mutex.h>
#include <mono/utils/mono-os-semaphore.h>
-#include <mono/utils/mono-conc-hashtable.h>
-#include <mono/utils/mono-linked-list-set.h>
-#include <mono/utils/lock-free-alloc.h>
-#include <mono/utils/lock-free-queue.h>
-#include <mono/utils/hazard-pointer.h>
#include <mono/utils/mono-threads.h>
#include <mono/utils/mono-threads-api.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <glib.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SCHED_GETAFFINITY
-#include <sched.h>
-#endif
-#include <fcntl.h>
-#include <errno.h>
-#include <time.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#if defined(__APPLE__)
-#include <mach/mach_time.h>
-#endif
-#if defined(HOST_WIN32) || defined(DISABLE_SOCKETS)
-#define DISABLE_HELPER_THREAD 1
-#endif
+#include "mono-profiler-log.h"
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE
-#endif
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#endif
-#ifdef HAVE_EXECINFO_H
-#include <execinfo.h>
-#endif
#ifdef HAVE_LINK_H
#include <link.h>
#endif
-
-#ifndef DISABLE_HELPER_THREAD
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <sys/select.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
#endif
-
-#ifdef HOST_WIN32
-#include <windows.h>
-#else
-#include <pthread.h>
+#if defined(__APPLE__)
+#include <mach/mach_time.h>
#endif
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
+#include <netinet/in.h>
+#ifdef HAVE_SYS_MMAN_H
+#include <sys/mman.h>
#endif
-
-#include "mono-profiler-log.h"
-
+#include <sys/socket.h>
#if defined (HAVE_SYS_ZLIB)
#include <zlib.h>
#endif
-#if defined(__linux__)
+#if defined(__linux__) && defined (ENABLE_PERF_EVENTS)
-#include <unistd.h>
-#include <sys/syscall.h>
-
-#ifdef ENABLE_PERF_EVENTS
#include <linux/perf_event.h>
#define USE_PERF_EVENTS 1
static int read_perf_mmap (MonoProfiler* prof, int cpu);
-#endif
#endif
static int do_heap_shot = 0;
static int max_call_depth = 100;
static volatile int runtime_inited = 0;
-static int need_helper_thread = 0;
static int command_port = 0;
static int heapshot_requested = 0;
static int sample_type = 0;
typedef struct {
MonoLinkedListSetNode node;
+ // Convenience pointer to the profiler structure.
+ MonoProfiler *profiler;
+
+ // Was this thread added to the LLS?
+ gboolean attached;
+
// The current log buffer for this thread.
LogBuffer *buffer;
int call_depth;
// Indicates whether this thread is currently writing to its `buffer`.
- int busy;
-} MonoProfilerThread;
+ gboolean busy;
-static inline void
-ign_res (int G_GNUC_UNUSED unused, ...)
-{
-}
+ // Has this thread written a thread end event to `buffer`?
+ gboolean ended;
+} MonoProfilerThread;
static uintptr_t
thread_id (void)
#define ENTER_LOG(COUNTER, BUFFER, SIZE) \
do { \
- buffer_lock (); \
- g_assert (!PROF_TLS_GET ()->busy++ && "Why are we trying to write a new event while already writing one?"); \
+ MonoProfilerThread *thread__ = PROF_TLS_GET (); \
+ if (thread__->attached) \
+ buffer_lock (); \
+ g_assert (!thread__->busy && "Why are we trying to write a new event while already writing one?"); \
+ thread__->busy = TRUE; \
InterlockedIncrement ((COUNTER)); \
LogBuffer *BUFFER = ensure_logbuf_unsafe ((SIZE))
-#define EXIT_LOG \
- PROF_TLS_GET ()->busy--; \
- buffer_unlock (); \
+#define EXIT_LOG_EXPLICIT(SEND, REQUESTS) \
+ thread__->busy = FALSE; \
+ if ((SEND)) \
+ send_log_unsafe (FALSE, TRUE); \
+ if (thread__->attached) \
+ buffer_unlock (); \
+ if ((REQUESTS)) \
+ process_requests (); \
} while (0)
+#define EXIT_LOG EXIT_LOG_EXPLICIT (TRUE, TRUE)
+
static volatile gint32 buffer_rwlock_count;
static volatile gpointer buffer_rwlock_exclusive;
return buf;
}
+/*
+ * Must be called with the reader lock held if thread is the current thread, or
+ * the exclusive lock if thread is a different thread. However, if thread is
+ * the current thread, and init_thread () was called with add_to_lls = FALSE,
+ * then no locking is necessary.
+ */
static void
init_buffer_state (MonoProfilerThread *thread)
{
}
static MonoProfilerThread *
-init_thread (gboolean add_to_lls)
+init_thread (MonoProfiler *prof, gboolean add_to_lls)
{
MonoProfilerThread *thread = PROF_TLS_GET ();
thread = malloc (sizeof (MonoProfilerThread));
thread->node.key = thread_id ();
+ thread->profiler = prof;
+ thread->attached = add_to_lls;
thread->call_depth = 0;
thread->busy = 0;
+ thread->ended = FALSE;
init_buffer_state (thread);
static void
deinit_thread (MonoProfilerThread *thread)
{
+ g_assert (!thread->attached && "Why are we manually freeing an attached thread?");
+
free (thread);
PROF_TLS_SET (NULL);
}
{
logbuffer->cursor [0] = value;
logbuffer->cursor++;
- assert (logbuffer->cursor <= logbuffer->buf_end);
+
+ g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
}
static void
emit_value (LogBuffer *logbuffer, int value)
{
encode_uleb128 (value, logbuffer->cursor, &logbuffer->cursor);
- assert (logbuffer->cursor <= logbuffer->buf_end);
+
+ g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
}
static void
emit_time (LogBuffer *logbuffer, uint64_t value)
{
uint64_t tdiff = value - logbuffer->last_time;
- //if (value < logbuffer->last_time)
- // printf ("time went backwards\n");
- //if (tdiff > 1000000)
- // printf ("large time offset: %llu\n", tdiff);
encode_uleb128 (tdiff, logbuffer->cursor, &logbuffer->cursor);
- /*if (tdiff != decode_uleb128 (p, &p))
- printf ("incorrect encoding: %llu\n", tdiff);*/
logbuffer->last_time = value;
- assert (logbuffer->cursor <= logbuffer->buf_end);
+
+ g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
}
static void
emit_svalue (LogBuffer *logbuffer, int64_t value)
{
encode_sleb128 (value, logbuffer->cursor, &logbuffer->cursor);
- assert (logbuffer->cursor <= logbuffer->buf_end);
+
+ g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
}
static void
emit_uvalue (LogBuffer *logbuffer, uint64_t value)
{
encode_uleb128 (value, logbuffer->cursor, &logbuffer->cursor);
- assert (logbuffer->cursor <= logbuffer->buf_end);
+
+ g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
}
static void
emit_ptr (LogBuffer *logbuffer, void *ptr)
{
if (!logbuffer->ptr_base)
- logbuffer->ptr_base = (uintptr_t)ptr;
- emit_svalue (logbuffer, (intptr_t)ptr - logbuffer->ptr_base);
- assert (logbuffer->cursor <= logbuffer->buf_end);
+ logbuffer->ptr_base = (uintptr_t) ptr;
+
+ emit_svalue (logbuffer, (intptr_t) ptr - logbuffer->ptr_base);
+
+ g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
}
static void
emit_method_inner (LogBuffer *logbuffer, void *method)
{
if (!logbuffer->method_base) {
- logbuffer->method_base = (intptr_t)method;
- logbuffer->last_method = (intptr_t)method;
+ logbuffer->method_base = (intptr_t) method;
+ logbuffer->last_method = (intptr_t) method;
}
- encode_sleb128 ((intptr_t)((char*)method - (char*)logbuffer->last_method), logbuffer->cursor, &logbuffer->cursor);
- logbuffer->last_method = (intptr_t)method;
- assert (logbuffer->cursor <= logbuffer->buf_end);
-}
-
-/*
-typedef struct {
- MonoMethod *method;
- MonoJitInfo *found;
-} MethodSearch;
-
-static void
-find_method (MonoDomain *domain, void *user_data)
-{
- MethodSearch *search = user_data;
-
- if (search->found)
- return;
-
- MonoJitInfo *ji = mono_get_jit_info_from_method (domain, search->method);
-
- // It could be AOT'd, so we need to get it from the AOT runtime's cache.
- if (!ji) {
- void *ip = mono_aot_get_method (domain, search->method);
- // Avoid a slow path in mono_jit_info_table_find ().
- if (ip)
- ji = mono_jit_info_table_find (domain, ip);
- }
+ encode_sleb128 ((intptr_t) ((char *) method - (char *) logbuffer->last_method), logbuffer->cursor, &logbuffer->cursor);
+ logbuffer->last_method = (intptr_t) method;
- if (ji)
- search->found = ji;
+ g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
}
-*/
static void
-register_method_local (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji)
+register_method_local (MonoMethod *method, MonoJitInfo *ji)
{
- if (!mono_conc_hashtable_lookup (prof->method_table, method)) {
- /*
- * FIXME: In some cases, we crash while looking up JIT info for AOT'd methods.
- * This usually happens for static constructors. This code is disabled for now
- * as we don't need this info for anything critical.
- *
- * https://bugzilla.xamarin.com/show_bug.cgi?id=35171
- */
- /*
- if (!ji) {
- MethodSearch search = { method, NULL };
-
- mono_domain_foreach (find_method, &search);
-
- ji = search.found;
- }
- */
-
- /*
- * FIXME: We can't always find JIT info for a generic shared method, especially
- * if we obtained the MonoMethod during an async stack walk. For now, we deal
- * with this by giving the generic shared method name and dummy code start/size
- * information (i.e. zeroes).
- */
- //g_assert (ji);
+ MonoProfilerThread *thread = PROF_TLS_GET ();
+ if (!mono_conc_hashtable_lookup (thread->profiler->method_table, method)) {
MethodInfo *info = (MethodInfo *) malloc (sizeof (MethodInfo));
info->method = method;
info->ji = ji;
info->time = current_time ();
- MonoProfilerThread *thread = PROF_TLS_GET ();
GPtrArray *arr = thread->methods ? thread->methods : (thread->methods = g_ptr_array_new ());
g_ptr_array_add (arr, info);
}
}
static void
-emit_method (MonoProfiler *prof, LogBuffer *logbuffer, MonoMethod *method)
+emit_method (LogBuffer *logbuffer, MonoMethod *method)
{
- register_method_local (prof, method, NULL);
+ register_method_local (method, NULL);
emit_method_inner (logbuffer, method);
}
emit_obj (LogBuffer *logbuffer, void *ptr)
{
if (!logbuffer->obj_base)
- logbuffer->obj_base = (uintptr_t)ptr >> 3;
- emit_svalue (logbuffer, ((uintptr_t)ptr >> 3) - logbuffer->obj_base);
- assert (logbuffer->cursor <= logbuffer->buf_end);
+ logbuffer->obj_base = (uintptr_t) ptr >> 3;
+
+ emit_svalue (logbuffer, ((uintptr_t) ptr >> 3) - logbuffer->obj_base);
+
+ g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?");
}
static void
free (hbuf);
}
+/*
+ * Must be called with the reader lock held if thread is the current thread, or
+ * the exclusive lock if thread is a different thread. However, if thread is
+ * the current thread, and init_thread () was called with add_to_lls = FALSE,
+ * then no locking is necessary.
+ */
static void
-send_buffer (MonoProfiler *prof, MonoProfilerThread *thread)
+send_buffer (MonoProfilerThread *thread)
{
- WriterQueueEntry *entry = mono_lock_free_alloc (&prof->writer_entry_allocator);
+ WriterQueueEntry *entry = mono_lock_free_alloc (&thread->profiler->writer_entry_allocator);
entry->methods = thread->methods;
entry->buffer = thread->buffer;
mono_lock_free_queue_node_init (&entry->node, FALSE);
- mono_lock_free_queue_enqueue (&prof->writer_queue, &entry->node);
- mono_os_sem_post (&prof->writer_queue_sem);
+ mono_lock_free_queue_enqueue (&thread->profiler->writer_queue, &entry->node);
+ mono_os_sem_post (&thread->profiler->writer_queue_sem);
}
static void
-remove_thread (MonoProfiler *prof, MonoProfilerThread *thread, gboolean from_callback)
+free_thread (gpointer p)
{
- MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
+ MonoProfilerThread *thread = p;
- if (mono_lls_remove (&profiler_thread_list, hp, &thread->node)) {
+ if (!thread->ended) {
/*
- * No need to take the buffer lock here as no other threads can
- * be accessing this buffer anymore.
+ * The thread is being cleaned up by the main thread during
+ * shutdown. This typically happens for internal runtime
+ * threads. We need to synthesize a thread end event.
*/
- if (!from_callback) {
- /*
- * The thread is being cleaned up by the main thread during
- * shutdown. This typically happens for internal runtime
- * threads. We need to synthesize a thread end event.
- */
+ InterlockedIncrement (&thread_ends_ctr);
- InterlockedIncrement (&thread_ends_ctr);
+ thread->buffer = ensure_logbuf_inner (thread->buffer,
+ EVENT_SIZE /* event */ +
+ BYTE_SIZE /* type */ +
+ LEB128_SIZE /* tid */
+ );
- thread->buffer = ensure_logbuf_inner (thread->buffer,
- EVENT_SIZE /* event */ +
- BYTE_SIZE /* type */ +
- LEB128_SIZE /* tid */
- );
+ emit_event (thread->buffer, TYPE_END_UNLOAD | TYPE_METADATA);
+ emit_byte (thread->buffer, TYPE_THREAD);
+ emit_ptr (thread->buffer, (void *) thread->node.key);
+ }
- emit_event (thread->buffer, TYPE_END_UNLOAD | TYPE_METADATA);
- emit_byte (thread->buffer, TYPE_THREAD);
- emit_ptr (thread->buffer, (void *) thread->node.key);
- }
+ send_buffer (thread);
+
+ free (thread);
+}
- send_buffer (prof, thread);
+static void
+remove_thread (MonoProfilerThread *thread)
+{
+ MonoThreadHazardPointers *hp = mono_hazard_pointer_get ();
- mono_thread_hazardous_try_free (thread, free);
- }
+ if (mono_lls_remove (&profiler_thread_list, hp, &thread->node))
+ mono_thread_hazardous_try_free (thread, free_thread);
clear_hazard_pointers (hp);
-
- if (from_callback)
- PROF_TLS_SET (NULL);
}
static void
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->ptr_base);
- p = write_int64 (p, buf->obj_base);
- p = write_int64 (p, buf->thread_id);
- p = write_int64 (p, buf->method_base);
+ if (buf->cursor - buf->buf) {
+ 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->ptr_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
+ if (profiler->gzfile) {
+ gzwrite (profiler->gzfile, hbuf, p - hbuf);
+ gzwrite (profiler->gzfile, buf->buf, buf->cursor - buf->buf);
+ } else
#endif
- {
- fwrite (hbuf, p - hbuf, 1, profiler->file);
- fwrite (buf->buf, buf->cursor - buf->buf, 1, profiler->file);
- fflush (profiler->file);
+ {
+ fwrite (hbuf, p - hbuf, 1, profiler->file);
+ fwrite (buf->buf, buf->cursor - buf->buf, 1, profiler->file);
+ fflush (profiler->file);
+ }
}
free_buffer (buf, buf->size);
}
static void
-process_requests (MonoProfiler *profiler)
+process_requests (void)
{
if (heapshot_requested)
mono_gc_collect (mono_gc_max_generation ());
}
+// Avoid calling this directly if possible. Use the functions below.
static void
-safe_send (MonoProfiler *profiler)
+send_log_unsafe (gboolean lock, gboolean if_needed)
{
- /* We need the runtime initialized so that we have threads and hazard
- * pointers available. Otherwise, the lock free queue will not work and
- * there won't be a thread to process the data.
- *
- * While the runtime isn't initialized, we just accumulate data in the
- * thread local buffer list.
- */
- if (!InterlockedRead (&runtime_inited))
- return;
-
MonoProfilerThread *thread = PROF_TLS_GET ();
- buffer_lock ();
-
- send_buffer (profiler, thread);
- init_buffer_state (thread);
-
- buffer_unlock ();
-}
-
-static void
-send_if_needed (MonoProfiler *prof)
-{
- if (PROF_TLS_GET ()->buffer->next)
- safe_send (prof);
-}
+ if (lock)
+ buffer_lock ();
-static void
-safe_send_threadless (MonoProfiler *prof)
-{
- LogBuffer *buf = PROF_TLS_GET ()->buffer;
-
- for (LogBuffer *iter = buf; iter; iter = iter->next)
- iter->thread_id = 0;
+ if (!if_needed || (if_needed && thread->buffer->next)) {
+ if (!thread->attached)
+ for (LogBuffer *iter = thread->buffer; iter; iter = iter->next)
+ iter->thread_id = 0;
- safe_send (prof);
-}
+ send_buffer (thread);
+ init_buffer_state (thread);
+ }
-static void
-send_if_needed_threadless (MonoProfiler *prof)
-{
- if (PROF_TLS_GET ()->buffer->next)
- safe_send_threadless (prof);
+ if (lock)
+ buffer_unlock ();
}
// Assumes that the exclusive lock is held.
static void
-sync_point_flush (MonoProfiler *prof)
+sync_point_flush (void)
{
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);
+ send_buffer (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)
+sync_point_mark (MonoProfilerSyncPointType type)
{
g_assert (InterlockedReadPointer (&buffer_rwlock_exclusive) == (gpointer) thread_id () && "Why don't we hold the exclusive lock?");
emit_event (logbuffer, TYPE_META | TYPE_SYNC_POINT);
emit_byte (logbuffer, type);
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (FALSE, FALSE);
- 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;
- }
+ send_log_unsafe (FALSE, FALSE);
}
// Assumes that the exclusive lock is held.
static void
-sync_point (MonoProfiler *prof, MonoProfilerSyncPointType type)
+sync_point (MonoProfilerSyncPointType type)
{
- sync_point_flush (prof);
- sync_point_mark (prof, type);
+ sync_point_flush ();
+ sync_point_mark (type);
}
static int
emit_obj (logbuffer, refs [i]);
}
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
return 0;
}
emit_event (logbuffer, TYPE_HEAP_START | TYPE_HEAP);
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
mono_gc_walk_heap (0, gc_reference, NULL);
emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP);
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
}
static void
emit_value (logbuffer, extra_info [i]);
}
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
}
static void
emit_byte (logbuffer, ev);
emit_byte (logbuffer, generation);
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (FALSE, FALSE);
switch (ev) {
case MONO_GC_EVENT_START:
* committed to the log file before any object move events
* that will be produced during this GC.
*/
- sync_point (profiler, SYNC_POINT_WORLD_STOP);
+ sync_point (SYNC_POINT_WORLD_STOP);
break;
case MONO_GC_EVENT_PRE_START_WORLD:
if (do_heap_shot && do_heap_walk) {
* object allocation events for certain addresses could come
* after the move events that made those addresses available.
*/
- sync_point_mark (profiler, SYNC_POINT_WORLD_START);
+ sync_point_mark (SYNC_POINT_WORLD_START);
/*
* Finally, it is safe to allow other threads to write to
emit_event (logbuffer, TYPE_GC_RESIZE | TYPE_GC);
emit_value (logbuffer, new_size);
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
}
// If you alter MAX_FRAMES, you may need to alter SAMPLE_BLOCK_SIZE too.
//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 (prof, logbuffer, data->methods [--data->count]);
+ emit_method (logbuffer, data->methods [--data->count]);
}
}
static void
gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass)
{
- init_thread (TRUE);
+ init_thread (prof, TRUE);
int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_ALLOC_BT : 0;
FrameData data;
emit_bt (prof, logbuffer, &data);
EXIT_LOG;
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
for (int i = 0; i < num; ++i)
emit_obj (logbuffer, objects [i]);
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
}
static void
emit_bt (prof, logbuffer, &data);
EXIT_LOG;
-
- process_requests (prof);
}
static void
emit_event (buf, TYPE_GC_FINALIZE_START | TYPE_GC);
EXIT_LOG;
-
- process_requests (prof);
}
static void
emit_event (buf, TYPE_GC_FINALIZE_END | TYPE_GC);
EXIT_LOG;
-
- process_requests (prof);
}
static void
emit_obj (buf, obj);
EXIT_LOG;
-
- process_requests (prof);
}
static void
emit_obj (buf, obj);
EXIT_LOG;
-
- process_requests (prof);
}
static char*
logbuffer->cursor += nlen;
EXIT_LOG;
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
logbuffer->cursor += nlen;
EXIT_LOG;
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
EXIT_LOG;
mono_free (name);
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
EXIT_LOG;
mono_free (name);
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
mono_free (name);
else
g_free (name);
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
mono_free (name);
else
g_free (name);
-
- send_if_needed (prof);
-
- process_requests (prof);
}
-#ifndef DISABLE_HELPER_THREAD
static void process_method_enter_coverage (MonoProfiler *prof, MonoMethod *method);
-#endif /* DISABLE_HELPER_THREAD */
static void
method_enter (MonoProfiler *prof, MonoMethod *method)
{
-#ifndef DISABLE_HELPER_THREAD
process_method_enter_coverage (prof, method);
-#endif /* DISABLE_HELPER_THREAD */
if (PROF_TLS_GET ()->call_depth++ <= max_call_depth) {
ENTER_LOG (&method_entries_ctr, logbuffer,
);
emit_event (logbuffer, TYPE_ENTER | TYPE_METHOD);
- emit_method (prof, logbuffer, method);
+ emit_method (logbuffer, method);
EXIT_LOG;
}
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
);
emit_event (logbuffer, TYPE_LEAVE | TYPE_METHOD);
- emit_method (prof, logbuffer, method);
+ emit_method (logbuffer, method);
EXIT_LOG;
}
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
);
emit_event (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD);
- emit_method (prof, logbuffer, method);
+ emit_method (logbuffer, method);
EXIT_LOG;
}
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
if (result != MONO_PROFILE_OK)
return;
- register_method_local (prof, method, ji);
-
- process_requests (prof);
+ register_method_local (method, ji);
}
static void
}
EXIT_LOG;
-
- process_requests (prof);
}
static void
emit_bt (prof, logbuffer, &data);
EXIT_LOG;
-
- process_requests (prof);
}
static void
emit_event (logbuffer, TYPE_EXCEPTION | TYPE_CLAUSE);
emit_byte (logbuffer, clause_type);
emit_value (logbuffer, clause_num);
- emit_method (prof, logbuffer, method);
+ emit_method (logbuffer, method);
EXIT_LOG;
-
- process_requests (prof);
}
static void
emit_bt (profiler, logbuffer, &data);
EXIT_LOG;
-
- process_requests (profiler);
}
static void
thread_start (MonoProfiler *prof, uintptr_t tid)
{
- init_thread (TRUE);
+ init_thread (prof, TRUE);
ENTER_LOG (&thread_starts_ctr, logbuffer,
EVENT_SIZE /* event */ +
emit_ptr (logbuffer, (void*) tid);
EXIT_LOG;
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
emit_byte (logbuffer, TYPE_THREAD);
emit_ptr (logbuffer, (void*) tid);
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (FALSE, FALSE);
+
+ MonoProfilerThread *thread = PROF_TLS_GET ();
- // Don't process requests as the thread is detached from the runtime.
+ thread->ended = TRUE;
+ remove_thread (thread);
- remove_thread (prof, PROF_TLS_GET (), TRUE);
+ PROF_TLS_SET (NULL);
}
static void
logbuffer->cursor += len;
EXIT_LOG;
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
EXIT_LOG;
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain));
EXIT_LOG;
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
logbuffer->cursor += nlen;
EXIT_LOG;
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
EXIT_LOG;
-
- send_if_needed (prof);
-
- process_requests (prof);
}
static void
emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context));
EXIT_LOG;
-
- send_if_needed (prof);
-
- process_requests (prof);
}
typedef struct {
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 *) sample->tid, (unsigned long long int) ((sample->time - profiler->startup_time) / 10000 / 100));
- len = strlen (buf);
- ign_res (write (2, buf, len));
- }
-
mono_thread_hazardous_try_free (sample, enqueue_sample_hit);
}
//#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)
+dump_ubin (MonoProfiler *prof, const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t size)
{
int len = strlen (filename) + 1;
memcpy (logbuffer->cursor, filename, len);
logbuffer->cursor += len;
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
}
#endif
static void
-dump_usym (const char *name, uintptr_t value, uintptr_t size)
+dump_usym (MonoProfiler *prof, const char *name, uintptr_t value, uintptr_t size)
{
int len = strlen (name) + 1;
memcpy (logbuffer->cursor, name, len);
logbuffer->cursor += len;
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
}
/* ELF code crashes on some systems. */
#endif
static void
-dump_elf_symbols (ElfW(Sym) *symbols, int num_symbols, const char *strtab, void *load_addr)
+dump_elf_symbols (MonoProfiler *prof, ElfW(Sym) *symbols, int num_symbols, const char *strtab, void *load_addr)
{
int i;
for (i = 0; i < num_symbols; ++i) {
header->e_ident [EI_MAG3] != ELFMAG3 ) {
header = NULL;
}
- dump_ubin (filename, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
+ dump_ubin (prof, filename, info->dlpi_addr + info->dlpi_phdr[i].p_vaddr, info->dlpi_phdr[i].p_offset, info->dlpi_phdr[i].p_memsz);
} else if (info->dlpi_phdr[i].p_type == PT_DYNAMIC) {
dyn = (ElfW(Dyn) *)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
}
if (!hash_table)
return 0;
num_sym = hash_table [1];
- dump_elf_symbols (symtab, num_sym, strtab, (void*)info->dlpi_addr);
+ dump_elf_symbols (prof, symtab, num_sym, strtab, (void*)info->dlpi_addr);
return 0;
}
last_symbol = sym;
if (!sym)
continue;
- dump_usym (sym, addr, 0); /* let's not guess the size */
+ dump_usym (prof, sym, addr, 0); /* let's not guess the size */
//printf ("found symbol at %p: %s\n", (void*)addr, sym);
}
}
printf ("sample: %d, size: %d, ip: %p (%s), timestamp: %llu, nframes: %llu\n",
s->h.type, s->h.size, ip, symbol_for (ip), s->timestamp, s->nframes);*/
+ InterlockedIncrement (&sample_hits_ctr);
+
ENTER_LOG (&sample_hits_ctr, logbuffer,
EVENT_SIZE /* event */ +
BYTE_SIZE /* type */ +
/* no support here yet for the managed backtrace */
emit_uvalue (logbuffer, mbt_count);
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
add_code_pointer (s->ip);
buf = (char*)buf + s->h.size;
#endif /* USE_PERF_EVENTS */
-#ifndef DISABLE_HELPER_THREAD
-
typedef struct MonoCounterAgent {
MonoCounter *counter;
// MonoCounterAgent specific data :
agent->emitted = 1;
}
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
done:
mono_os_mutex_unlock (&counters_mutex);
}
break;
default:
- assert (0);
+ g_assert_not_reached ();
}
if (type == MONO_COUNTER_STRING && size > agent->value_size) {
emit_value (logbuffer, 0);
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
mono_os_mutex_unlock (&counters_mutex);
}
pcagent->emitted = 1;
}
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
}
static gboolean
emit_value (logbuffer, 0);
- EXIT_LOG;
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
done:
mono_os_mutex_unlock (&counters_mutex);
emit_uvalue (logbuffer, method_id);
emit_value (logbuffer, coverage_data->len);
- EXIT_LOG;
-
- send_if_needed (prof);
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
for (i = 0; i < coverage_data->len; i++) {
CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[i];
emit_uvalue (logbuffer, entry->line);
emit_uvalue (logbuffer, entry->column);
- EXIT_LOG;
-
- send_if_needed (prof);
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
}
method_id++;
{
MonoClass *klass = (MonoClass *)key;
MonoLockFreeQueue *class_methods = (MonoLockFreeQueue *)value;
- MonoProfiler *prof = (MonoProfiler *)userdata;
MonoImage *image;
char *class_name;
const char *assembly_name;
emit_uvalue (logbuffer, fully_covered);
emit_uvalue (logbuffer, partially_covered);
- EXIT_LOG;
-
- send_if_needed (prof);
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
g_free (class_name);
}
build_assembly_buffer (gpointer key, gpointer value, gpointer userdata)
{
MonoAssembly *assembly = (MonoAssembly *)value;
- MonoProfiler *prof = (MonoProfiler *)userdata;
MonoImage *image = mono_assembly_get_image (assembly);
const char *name, *guid, *filename;
int number_of_methods = 0, partially_covered = 0;
emit_uvalue (logbuffer, fully_covered);
emit_uvalue (logbuffer, partially_covered);
- EXIT_LOG;
-
- send_if_needed (prof);
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
}
static void
method_id = 0;
mono_os_mutex_lock (&coverage_mutex);
- mono_conc_hashtable_foreach (coverage_assemblies, build_assembly_buffer, prof);
- mono_conc_hashtable_foreach (coverage_classes, build_class_buffer, prof);
+ mono_conc_hashtable_foreach (coverage_assemblies, build_assembly_buffer, NULL);
+ mono_conc_hashtable_foreach (coverage_classes, build_class_buffer, NULL);
mono_conc_hashtable_foreach (coverage_methods, build_method_buffer, prof);
mono_os_mutex_unlock (&coverage_mutex);
MonoLockFreeQueue *image_methods, *class_methods;
MonoLockFreeQueueNode *node;
- if (!coverage_initialized)
- return FALSE;
+ g_assert (coverage_initialized && "Why are we being asked for coverage filter info when we're not doing coverage?");
COVERAGE_DEBUG(fprintf (stderr, "Coverage filter for %s\n", mono_method_get_name (method));)
fclose (sa_file);
}
-#endif /* DISABLE_HELPER_THREAD */
-
static void
coverage_init (MonoProfiler *prof)
{
-#ifndef DISABLE_HELPER_THREAD
- assert (!coverage_initialized);
+ g_assert (!coverage_initialized && "Why are we initializing coverage twice?");
COVERAGE_DEBUG(fprintf (stderr, "Coverage initialized\n");)
init_suppressed_assemblies ();
coverage_initialized = TRUE;
-#endif /* DISABLE_HELPER_THREAD */
}
static void
void *res;
in_shutdown = 1;
-#ifndef DISABLE_HELPER_THREAD
+
counters_and_perfcounters_sample (prof);
dump_coverage (prof);
- if (prof->command_port) {
- char c = 1;
- ign_res (write (prof->pipes [1], &c, 1));
- pthread_join (prof->helper_thread, &res);
+ char c = 1;
+
+ if (write (prof->pipes [1], &c, 1) != 1) {
+ fprintf (stderr, "Could not write to pipe: %s\n", strerror (errno));
+ exit (1);
}
+ pthread_join (prof->helper_thread, &res);
+
mono_os_mutex_destroy (&counters_mutex);
MonoCounterAgent *mc_next;
pc_next = cur->next;
g_free (cur);
}
-#endif
+
#if USE_PERF_EVENTS
if (perf_data) {
int i;
*/
while (profiler_thread_list.head) {
MONO_LLS_FOREACH_SAFE (&profiler_thread_list, MonoProfilerThread, thread) {
- remove_thread (prof, thread, FALSE);
+ remove_thread (thread);
} MONO_LLS_FOREACH_SAFE_END
}
+ /*
+ * Ensure that all threads have been freed, so that we don't miss any
+ * buffers when we shut down the writer thread below.
+ */
+ mono_thread_hazardous_try_free_all ();
+
InterlockedWrite (&prof->run_dumper_thread, 0);
mono_os_sem_post (&prof->dumper_queue_sem);
pthread_join (prof->dumper_thread, &res);
pthread_join (prof->writer_thread, &res);
mono_os_sem_destroy (&prof->writer_queue_sem);
+ /*
+ * Free all writer queue entries, and ensure that all sample hits will be
+ * added to the sample reuse queue.
+ */
+ mono_thread_hazardous_try_free_all ();
+
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.
+ * Finally, make sure that all sample hits are freed. This should cover all
+ * hazardous data from the profiler. We can now be sure that the runtime
+ * won't later invoke free functions in the profiler library after it has
+ * been unloaded.
*/
mono_thread_hazardous_try_free_all ();
return res;
}
-//this is exposed by the JIT, but it's not meant to be a supported API for now.
-extern void mono_threads_attach_tools_thread (void);
-
-#ifndef DISABLE_HELPER_THREAD
-
static void*
helper_thread (void* arg)
{
mono_threads_attach_tools_thread ();
mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler helper");
- init_thread (FALSE);
+ MonoProfilerThread *thread = init_thread (prof, FALSE);
//fprintf (stderr, "Server listening\n");
command_socket = -1;
buffer_lock_excl ();
- sync_point (prof, SYNC_POINT_PERIODIC);
+ sync_point (SYNC_POINT_PERIODIC);
buffer_unlock_excl ();
read (prof->pipes [0], &c, 1);
if (do_debug)
fprintf (stderr, "helper shutdown\n");
+
#if USE_PERF_EVENTS
if (perf_data) {
int i;
}
}
#endif
- safe_send_threadless (prof);
+
+ send_log_unsafe (FALSE, FALSE);
return NULL;
}
#if USE_PERF_EVENTS
for ( i = 0; i < num_perf; ++i) {
if (perf_data [i].perf_fd < 0)
continue;
- if (FD_ISSET (perf_data [i].perf_fd, &rfds)) {
+ if (FD_ISSET (perf_data [i].perf_fd, &rfds))
read_perf_mmap (prof, i);
- send_if_needed_threadless (prof);
- }
}
}
#endif
//fprintf (stderr, "Accepted connection\n");
}
+ deinit_thread (thread);
+
mono_thread_info_detach ();
return NULL;
}
-static int
+static void
start_helper_thread (MonoProfiler* prof)
{
- struct sockaddr_in server_address;
- int r;
- socklen_t slen;
- if (pipe (prof->pipes) < 0) {
- fprintf (stderr, "Cannot create pipe\n");
- return 0;
+ if (pipe (prof->pipes) == -1) {
+ fprintf (stderr, "Cannot create pipe: %s\n", strerror (errno));
+ exit (1);
}
+
prof->server_socket = socket (PF_INET, SOCK_STREAM, 0);
- if (prof->server_socket < 0) {
- fprintf (stderr, "Cannot create server socket\n");
- return 0;
+
+ if (prof->server_socket == -1) {
+ fprintf (stderr, "Cannot create server socket: %s\n", strerror (errno));
+ exit (1);
}
+
+ struct sockaddr_in server_address;
+
memset (&server_address, 0, sizeof (server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons (prof->command_port);
- if (bind (prof->server_socket, (struct sockaddr *) &server_address, sizeof (server_address)) < 0) {
- fprintf (stderr, "Cannot bind server socket, port: %d: %s\n", prof->command_port, strerror (errno));
+
+ if (bind (prof->server_socket, (struct sockaddr *) &server_address, sizeof (server_address)) == -1) {
+ fprintf (stderr, "Cannot bind server socket on port %d: %s\n", prof->command_port, strerror (errno));
close (prof->server_socket);
- return 0;
+ exit (1);
}
- if (listen (prof->server_socket, 1) < 0) {
- fprintf (stderr, "Cannot listen server socket\n");
+
+ if (listen (prof->server_socket, 1) == -1) {
+ fprintf (stderr, "Cannot listen on server socket: %s\n", strerror (errno));
close (prof->server_socket);
- return 0;
+ exit (1);
}
- slen = sizeof (server_address);
- if (getsockname (prof->server_socket, (struct sockaddr *)&server_address, &slen) == 0) {
- prof->command_port = ntohs (server_address.sin_port);
- /*fprintf (stderr, "Assigned server port: %d\n", prof->command_port);*/
+
+ socklen_t slen = sizeof (server_address);
+
+ if (getsockname (prof->server_socket, (struct sockaddr *)&server_address, &slen)) {
+ fprintf (stderr, "Could not get assigned port: %s\n", strerror (errno));
+ close (prof->server_socket);
+ exit (1);
}
- r = pthread_create (&prof->helper_thread, NULL, helper_thread, prof);
- if (r) {
+ prof->command_port = ntohs (server_address.sin_port);
+
+ int r;
+
+ if ((r = pthread_create (&prof->helper_thread, NULL, helper_thread, prof))) {
+ fprintf (stderr, "Could not start helper thread: %s\n", strerror (r));
close (prof->server_socket);
- return 0;
+ exit (1);
}
- return 1;
}
-#endif
static void
free_writer_entry (gpointer p)
if (!entry->methods)
goto no_methods;
- LogBuffer *buf = NULL;
+ gboolean wrote_methods = FALSE;
/*
* Encode the method events in a temporary log buffer that we
void *cstart = info->ji ? mono_jit_info_get_code_start (info->ji) : NULL;
int csize = info->ji ? mono_jit_info_get_code_size (info->ji) : 0;
- InterlockedIncrement (&method_jits_ctr);
-
- buf = ensure_logbuf_unsafe (
+ ENTER_LOG (&method_jits_ctr, logbuffer,
EVENT_SIZE /* event */ +
LEB128_SIZE /* method */ +
LEB128_SIZE /* start */ +
nlen /* name */
);
- emit_event_time (buf, TYPE_JIT | TYPE_METHOD, info->time);
- emit_method_inner (buf, info->method);
- emit_ptr (buf, cstart);
- emit_value (buf, csize);
+ emit_event_time (logbuffer, TYPE_JIT | TYPE_METHOD, info->time);
+ emit_method_inner (logbuffer, info->method);
+ emit_ptr (logbuffer, cstart);
+ emit_value (logbuffer, csize);
+
+ memcpy (logbuffer->cursor, name, nlen);
+ logbuffer->cursor += nlen;
- memcpy (buf->cursor, name, nlen);
- buf->cursor += nlen;
+ EXIT_LOG_EXPLICIT (FALSE, FALSE);
mono_free (name);
+ wrote_methods = TRUE;
+
free_info:
g_free (info);
}
g_ptr_array_free (entry->methods, TRUE);
- if (buf) {
- dump_buffer_threadless (prof, buf);
+ if (wrote_methods) {
+ dump_buffer_threadless (prof, PROF_TLS_GET ()->buffer);
init_buffer_state (PROF_TLS_GET ());
}
dump_header (prof);
- MonoProfilerThread *thread = init_thread (FALSE);
+ MonoProfilerThread *thread = init_thread (prof, FALSE);
while (InterlockedRead (&prof->run_writer_thread)) {
mono_os_sem_wait (&prof->writer_queue_sem, MONO_SEM_FLAGS_NONE);
return NULL;
}
-static int
+static void
start_writer_thread (MonoProfiler* prof)
{
InterlockedWrite (&prof->run_writer_thread, 1);
- return !pthread_create (&prof->writer_thread, NULL, writer_thread, prof);
+ int r;
+
+ if ((r = pthread_create (&prof->writer_thread, NULL, writer_thread, prof))) {
+ fprintf (stderr, "Could not start writer thread: %s\n", strerror (r));
+ exit (1);
+ }
}
static void
}
}
- InterlockedIncrement (&sample_hits_ctr);
-
- LogBuffer *logbuffer = ensure_logbuf_unsafe (
+ ENTER_LOG (&sample_hits_ctr, logbuffer,
EVENT_SIZE /* event */ +
BYTE_SIZE /* type */ +
LEB128_SIZE /* tid */ +
emit_uvalue (logbuffer, sample->count);
for (int i = 0; i < sample->count; ++i)
- emit_method (prof, logbuffer, sample->frames [i].method);
+ emit_method (logbuffer, sample->frames [i].method);
+
+ EXIT_LOG_EXPLICIT (TRUE, FALSE);
mono_thread_hazardous_try_free (sample, reuse_sample_hit);
dump_unmanaged_coderefs (prof);
-
- send_if_needed_threadless (prof);
}
return FALSE;
mono_threads_attach_tools_thread ();
mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler dumper");
- MonoProfilerThread *thread = init_thread (FALSE);
+ MonoProfilerThread *thread = init_thread (prof, FALSE);
while (InterlockedRead (&prof->run_dumper_thread)) {
mono_os_sem_wait (&prof->dumper_queue_sem, MONO_SEM_FLAGS_NONE);
/* Drain any remaining entries on shutdown. */
while (handle_dumper_queue_entry (prof));
- safe_send_threadless (prof);
+ send_log_unsafe (FALSE, FALSE);
deinit_thread (thread);
mono_thread_info_detach ();
return NULL;
}
-static int
+static void
start_dumper_thread (MonoProfiler* prof)
{
InterlockedWrite (&prof->run_dumper_thread, 1);
- return !pthread_create (&prof->dumper_thread, NULL, dumper_thread, prof);
+ int r;
+
+ if ((r = pthread_create (&prof->dumper_thread, NULL, dumper_thread, prof))) {
+ fprintf (stderr, "Could not start dumper thread: %s\n", strerror (r));
+ exit (1);
+ }
}
static void
register_counter ("Event: Coverage classes", &coverage_classes_ctr);
register_counter ("Event: Coverage assemblies", &coverage_assemblies_ctr);
-#ifndef DISABLE_HELPER_THREAD
counters_init (profiler);
- if (hs_mode_ondemand || need_helper_thread) {
- if (!start_helper_thread (profiler))
- profiler->command_port = 0;
- }
-#endif
-
- /* ensure the main thread data and startup are available soon */
- safe_send (profiler);
+ start_helper_thread (profiler);
}
static MonoProfiler*
fprintf (stderr, "Cannot create profiler output: %s\n", nf);
exit (1);
}
+
#if defined (HAVE_SYS_ZLIB)
if (use_zip)
prof->gzfile = gzdopen (fileno (prof->file), "wb");
#endif
+
#if USE_PERF_EVENTS
- if (sample_type && sample_freq && !do_mono_sample)
- need_helper_thread = setup_perf_event ();
+ setup_perf_event ();
+
if (!perf_data) {
/* FIXME: warn if different freq or sample type */
do_mono_sample = 1;
}
#endif
- if (do_mono_sample) {
- need_helper_thread = 1;
- }
- if (do_counters && !need_helper_thread) {
- need_helper_thread = 1;
- }
/*
* If you hit this assert while increasing MAX_FRAMES, you need to increase
mono_lock_free_queue_init (&prof->sample_reuse_queue);
-#ifdef DISABLE_HELPER_THREAD
- if (hs_mode_ondemand)
- fprintf (stderr, "Ondemand heapshot unavailable on this arch.\n");
-
- if (do_coverage)
- fprintf (stderr, "Coverage unavailable on this arch.\n");
-
-#endif
-
g_assert (sizeof (WriterQueueEntry) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (WRITER_ENTRY_BLOCK_SIZE));
// FIXME: We should free this stuff too.
mono_lls_init (&profiler_thread_list, NULL);
- init_thread (TRUE);
+ init_thread (prof, TRUE);
mono_profiler_install (prof, log_shutdown);
mono_profiler_install_gc (gc_event, gc_resize);