Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Rønne Petersen <alexrp@xamarin.com>2015-03-09 21:03:44 +0300
committerAlex Rønne Petersen <alexrp@xamarin.com>2015-04-29 11:44:31 +0300
commite01c79dffdc6a791ee0a4643a08c0b182c95c343 (patch)
tree3e911f0ac750f347083efe463c84491767c9958f
parent373d6843971d192159fca5c884b53070258f0c25 (diff)
[profiler] Redesign buffer flushing and method reporting.
The main goal of this change is to ensure that all methods have a `TYPE_JIT` event emitted in the stream before they are referenced in other events. Before this change, `TYPE_JIT` events could arrive out of order or not be emitted at all because of generic sharing. We now use a separate thread for writing log buffers to the output file. Whenever a method is referenced in a TLS log buffer, we add it to a TLS list of methods. When we ship the TLS log buffer off to the writer thread, we also send the TLS list of methods. The writer thread first goes over all the methods and, if some of them haven't had a `TYPE_JIT` event emitted yet, emits them to a temporary buffer which is flushed just before flushing the main log buffer. This approach ensures that `TYPE_JIT` events will *always* come before the events that reference them. Bookkeeping of which methods have been emitted to the output stream is done in a global, concurrent hash table. Before a thread adds a method to its TLS list of methods, it checks if the method is in the hash table. If it is, we know that the method has already been emitted to the output stream, so it isn't added to the list. The writer thread is the only thread that updates the hash table (which happens when it flushes the temporary method buffer). So, eventually, all TLS method lists will end up being empty because all methods have been emitted to the output stream.
-rw-r--r--mono/profiler/proflog.c384
1 files changed, 271 insertions, 113 deletions
diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c
index f9bd6cee0e3..453fc5609fa 100644
--- a/mono/profiler/proflog.c
+++ b/mono/profiler/proflog.c
@@ -9,15 +9,19 @@
*/
#include <config.h>
+#include "../mini/jit.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-perfcounters.h>
+#include <mono/metadata/appdomain.h>
#include <mono/utils/atomic.h>
#include <mono/utils/mono-membar.h>
#include <mono/utils/mono-counters.h>
#include <mono/utils/mono-mutex.h>
+#include <mono/utils/mono-conc-hashtable.h>
+#include <mono/utils/lock-free-queue.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
@@ -401,28 +405,49 @@ struct _MonoProfiler {
int pipes [2];
#ifndef HOST_WIN32
pthread_t helper_thread;
+ pthread_t writer_thread;
#endif
+ volatile gint32 run_writer_thread;
+ MonoLockFreeQueue writer_queue;
+ MonoConcurrentHashTable *method_table;
+ mono_mutex_t method_table_mutex;
BinaryObject *binary_objects;
};
+typedef struct _WriterQueueEntry WriterQueueEntry;
+struct _WriterQueueEntry {
+ MonoLockFreeQueueNode node;
+ GPtrArray *methods;
+ LogBuffer *buffer;
+};
+
+typedef struct _MethodInfo MethodInfo;
+struct _MethodInfo {
+ MonoMethod *method;
+ MonoJitInfo *ji;
+};
+
#ifdef HOST_WIN32
-#define TLS_SET(x,y) TlsSetValue(x, y)
-#define TLS_GET(x) ((LogBuffer *) TlsGetValue(x))
-#define TLS_INIT(x) x = TlsAlloc ()
+#define TLS_SET(x,y) (TlsSetValue (x, y))
+#define TLS_GET(t,x) ((t *) TlsGetValue (x))
+#define TLS_INIT(x) (x = TlsAlloc ())
static int tlsbuffer;
+static int tlsmethodlist;
#elif HAVE_KW_THREAD
-#define TLS_SET(x,y) x = y
-#define TLS_GET(x) x
+#define TLS_SET(x,y) (x = y)
+#define TLS_GET(t,x) (x)
#define TLS_INIT(x)
static __thread LogBuffer* tlsbuffer = NULL;
+static __thread GPtrArray* tlsmethodlist = NULL;
#else
-#define TLS_SET(x,y) pthread_setspecific(x, y)
-#define TLS_GET(x) ((LogBuffer *) pthread_getspecific(x))
-#define TLS_INIT(x) pthread_key_create(&x, NULL)
+#define TLS_SET(x,y) (pthread_setspecific (x, y))
+#define TLS_GET(t,x) ((t *) pthread_getspecific (x))
+#define TLS_INIT(x) (pthread_key_create (&x, NULL))
static pthread_key_t tlsbuffer;
+static pthread_key_t tlsmethodlist;
#endif
-static void safe_dump (MonoProfiler *profiler, LogBuffer *logbuffer);
+static void safe_send (MonoProfiler *profiler, LogBuffer *logbuffer);
static char*
pstrdup (const char *s)
@@ -458,28 +483,48 @@ create_buffer (void)
static void
init_thread (void)
{
- LogBuffer *logbuffer;
- if (TLS_GET (tlsbuffer))
- return;
- logbuffer = create_buffer ();
- TLS_SET (tlsbuffer, logbuffer);
- logbuffer->thread_id = thread_id ();
+ if (!TLS_GET (LogBuffer, tlsbuffer)) {
+ LogBuffer *logbuffer = create_buffer ();
+ TLS_SET (tlsbuffer, logbuffer);
+ logbuffer->thread_id = thread_id ();
+ }
+ if (!TLS_GET (GPtrArray, tlsmethodlist)) {
+ GPtrArray *methodlist = g_ptr_array_new ();
+ TLS_SET (tlsmethodlist, methodlist);
+ }
+
//printf ("thread %p at time %llu\n", (void*)logbuffer->thread_id, logbuffer->time_base);
}
-static LogBuffer*
-ensure_logbuf (int bytes)
+static LogBuffer *
+ensure_logbuf_inner (LogBuffer *old, int bytes)
{
- LogBuffer *old = TLS_GET (tlsbuffer);
if (old && old->data + bytes + 100 < old->data_end)
return old;
- TLS_SET (tlsbuffer, NULL);
- init_thread ();
- TLS_GET (tlsbuffer)->next = old;
+
+ LogBuffer *new = create_buffer ();
+ new->thread_id = thread_id ();
+ new->next = old;
+
if (old)
- TLS_GET (tlsbuffer)->call_depth = old->call_depth;
- //printf ("new logbuffer\n");
- return TLS_GET (tlsbuffer);
+ new->call_depth = old->call_depth;
+
+ return new;
+}
+
+static LogBuffer*
+ensure_logbuf (int bytes)
+{
+ LogBuffer *old = TLS_GET (LogBuffer, tlsbuffer);
+ LogBuffer *new = ensure_logbuf_inner (old, bytes);
+
+ if (new == old)
+ return old; // Still enough space.
+
+ TLS_SET (tlsbuffer, new);
+ init_thread ();
+
+ return new;
}
static void
@@ -538,7 +583,7 @@ emit_ptr (LogBuffer *logbuffer, void *ptr)
}
static void
-emit_method (LogBuffer *logbuffer, void *method)
+emit_method_inner (LogBuffer *logbuffer, void *method)
{
if (!logbuffer->method_base) {
logbuffer->method_base = (intptr_t)method;
@@ -550,6 +595,42 @@ emit_method (LogBuffer *logbuffer, void *method)
}
static void
+register_method_local (MonoProfiler *prof, MonoDomain *domain, MonoMethod *method, MonoJitInfo *ji)
+{
+ if (!domain)
+ g_assert (ji);
+
+ if (!mono_conc_hashtable_lookup (prof->method_table, method)) {
+ if (!ji)
+ ji = mono_get_jit_info_from_method (domain, method);
+
+ // It could be AOT'd, so we need to force it to be loaded.
+ if (!ji) {
+ // Loads the method as a side effect.
+ mono_aot_get_method (domain, method);
+
+ ji = mono_get_jit_info_from_method (domain, method);
+ }
+
+ g_assert (ji);
+
+ MethodInfo *info = malloc (sizeof (MethodInfo));
+
+ info->method = method;
+ info->ji = ji;
+
+ g_ptr_array_add (TLS_GET (GPtrArray, tlsmethodlist), info);
+ }
+}
+
+static void
+emit_method (MonoProfiler *prof, LogBuffer *logbuffer, MonoDomain *domain, MonoMethod *method)
+{
+ register_method_local (prof, domain, method, NULL);
+ emit_method_inner (logbuffer, method);
+}
+
+static void
emit_obj (LogBuffer *logbuffer, void *ptr)
{
if (!logbuffer->obj_base)
@@ -648,6 +729,16 @@ dump_header (MonoProfiler *profiler)
}
static void
+send_buffer (MonoProfiler *prof, GPtrArray *methods, LogBuffer *buffer)
+{
+ WriterQueueEntry *entry = calloc (1, sizeof (WriterQueueEntry));
+ mono_lock_free_queue_node_init (&entry->node, FALSE);
+ entry->methods = methods;
+ entry->buffer = buffer;
+ mono_lock_free_queue_enqueue (&prof->writer_queue, &entry->node);
+}
+
+static void
dump_buffer (MonoProfiler *profiler, LogBuffer *buf)
{
char hbuf [128];
@@ -695,22 +786,25 @@ runtime_initialized (MonoProfiler *profiler)
counters_sample (profiler, 0);
#endif
/* ensure the main thread data and startup are available soon */
- safe_dump (profiler, ensure_logbuf (0));
+ safe_send (profiler, ensure_logbuf (0));
}
/*
* Can be called only at safe callback locations.
*/
static void
-safe_dump (MonoProfiler *profiler, LogBuffer *logbuffer)
+safe_send (MonoProfiler *profiler, LogBuffer *logbuffer)
{
int cd = logbuffer->call_depth;
- take_lock ();
- dump_buffer (profiler, TLS_GET (tlsbuffer));
- release_lock ();
+
+ send_buffer (profiler, TLS_GET (GPtrArray, tlsmethodlist), TLS_GET (LogBuffer, tlsbuffer));
+
TLS_SET (tlsbuffer, NULL);
+ TLS_SET (tlsmethodlist, NULL);
+
init_thread ();
- TLS_GET (tlsbuffer)->call_depth = cd;
+
+ TLS_GET (LogBuffer, tlsbuffer)->call_depth = cd;
}
static int
@@ -796,7 +890,7 @@ gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) {
heap_walk (profiler);
EXIT_LOG (logbuffer);
if (ev == MONO_GC_EVENT_POST_START_WORLD)
- safe_dump (profiler, logbuffer);
+ safe_send (profiler, logbuffer);
//printf ("gc event %d for generation %d\n", ev, generation);
}
@@ -890,7 +984,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass)
emit_bt (logbuffer, &data);
EXIT_LOG (logbuffer);
if (logbuffer->next)
- safe_dump (prof, logbuffer);
+ safe_send (prof, logbuffer);
process_requests (prof);
//printf ("gc alloc %s at %p\n", mono_class_get_name (klass), obj);
}
@@ -1011,7 +1105,7 @@ image_loaded (MonoProfiler *prof, MonoImage *image, int result)
//printf ("loaded image %p (%s)\n", image, name);
EXIT_LOG (logbuffer);
if (logbuffer->next)
- safe_dump (prof, logbuffer);
+ safe_send (prof, logbuffer);
process_requests (prof);
}
@@ -1049,7 +1143,7 @@ class_loaded (MonoProfiler *prof, MonoClass *klass, int result)
free (name);
EXIT_LOG (logbuffer);
if (logbuffer->next)
- safe_dump (prof, logbuffer);
+ safe_send (prof, logbuffer);
process_requests (prof);
}
@@ -1064,7 +1158,7 @@ method_enter (MonoProfiler *prof, MonoMethod *method)
ENTER_LOG (logbuffer, "enter");
emit_byte (logbuffer, TYPE_ENTER | TYPE_METHOD);
emit_time (logbuffer, now);
- emit_method (logbuffer, method);
+ emit_method (prof, logbuffer, mono_domain_get (), method);
EXIT_LOG (logbuffer);
process_requests (prof);
}
@@ -1080,10 +1174,10 @@ method_leave (MonoProfiler *prof, MonoMethod *method)
ENTER_LOG (logbuffer, "leave");
emit_byte (logbuffer, TYPE_LEAVE | TYPE_METHOD);
emit_time (logbuffer, now);
- emit_method (logbuffer, method);
+ emit_method (prof, logbuffer, mono_domain_get (), method);
EXIT_LOG (logbuffer);
if (logbuffer->next)
- safe_dump (prof, logbuffer);
+ safe_send (prof, logbuffer);
process_requests (prof);
}
@@ -1101,37 +1195,18 @@ method_exc_leave (MonoProfiler *prof, MonoMethod *method)
ENTER_LOG (logbuffer, "eleave");
emit_byte (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD);
emit_time (logbuffer, now);
- emit_method (logbuffer, method);
+ emit_method (prof, logbuffer, mono_domain_get (), method);
EXIT_LOG (logbuffer);
process_requests (prof);
}
static void
-method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result)
+method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji, int result)
{
- uint64_t now;
- char *name;
- int nlen;
- LogBuffer *logbuffer;
if (result != MONO_PROFILE_OK)
return;
- name = mono_method_full_name (method, 1);
- nlen = strlen (name) + 1;
- logbuffer = ensure_logbuf (32 + nlen);
- now = current_time ();
- ENTER_LOG (logbuffer, "jit");
- emit_byte (logbuffer, TYPE_JIT | TYPE_METHOD);
- emit_time (logbuffer, now);
- emit_method (logbuffer, method);
- emit_ptr (logbuffer, mono_jit_info_get_code_start (jinfo));
- emit_value (logbuffer, mono_jit_info_get_code_size (jinfo));
- memcpy (logbuffer->data, name, nlen);
- logbuffer->data += nlen;
- mono_free (name);
- EXIT_LOG (logbuffer);
- if (logbuffer->next)
- safe_dump (prof, logbuffer);
- process_requests (prof);
+
+ register_method_local (prof, NULL, method, ji);
}
static void
@@ -1196,7 +1271,7 @@ clause_exc (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_
emit_time (logbuffer, now);
emit_value (logbuffer, clause_type);
emit_value (logbuffer, clause_num);
- emit_method (logbuffer, method);
+ emit_method (prof, logbuffer, mono_domain_get (), method);
EXIT_LOG (logbuffer);
}
@@ -1231,11 +1306,11 @@ thread_start (MonoProfiler *prof, uintptr_t tid)
static void
thread_end (MonoProfiler *prof, uintptr_t tid)
{
- take_lock ();
- if (TLS_GET (tlsbuffer))
- dump_buffer (prof, TLS_GET (tlsbuffer));
- release_lock ();
+ if (TLS_GET (LogBuffer, tlsbuffer))
+ send_buffer (prof, TLS_GET (GPtrArray, tlsmethodlist), TLS_GET (LogBuffer, tlsbuffer));
+
TLS_SET (tlsbuffer, NULL);
+ TLS_SET (tlsmethodlist, NULL);
}
static void
@@ -1681,36 +1756,14 @@ dump_unmanaged_coderefs (MonoProfiler *prof)
}
static void
-dump_sample_hits_inner (MonoProfiler *prof, StatBuffer *sbuf, int recurse, GPtrArray **array);
-
-static void
-dump_sample_hits (MonoProfiler *prof, StatBuffer *sbuf, int recurse)
-{
- GPtrArray *array = NULL;
- dump_sample_hits_inner (prof, sbuf, recurse, &array);
-
- if (array) {
- int i;
- g_ptr_array_sort (array, g_direct_equal);
- for (i = 0; i < array->len; ++i) {
- MonoJitInfo *cur = array->pdata [i];
- //Ignore duplicates
- if (i > 0 && array->pdata [i - 1] == cur)
- continue;
- method_jitted (prof, mono_jit_info_get_method (cur), cur, MONO_PROFILE_OK);
- }
- }
-}
-
-static void
-dump_sample_hits_inner (MonoProfiler *prof, StatBuffer *sbuf, int recurse, GPtrArray **array)
+dump_sample_hits (MonoProfiler *prof, StatBuffer *sbuf)
{
uintptr_t *sample;
LogBuffer *logbuffer;
if (!sbuf)
return;
- if (recurse && sbuf->next) {
- dump_sample_hits_inner (prof, sbuf->next, 1, array);
+ if (sbuf->next) {
+ dump_sample_hits (prof, sbuf->next);
free_buffer (sbuf->next, sbuf->next->size);
sbuf->next = NULL;
}
@@ -1731,12 +1784,9 @@ dump_sample_hits_inner (MonoProfiler *prof, StatBuffer *sbuf, int recurse, GPtrA
if (!method) {
MonoJitInfo *ji = mono_jit_info_table_find (domain, address);
- if (ji) {
+
+ if (ji)
managed_sample_base [i * 4 + 0] = (uintptr_t)mono_jit_info_get_method (ji);
- if (!*array)
- *array = g_ptr_array_new ();
- g_ptr_array_add (*array, ji);
- }
}
}
logbuffer = ensure_logbuf (20 + count * 8);
@@ -1753,9 +1803,13 @@ dump_sample_hits_inner (MonoProfiler *prof, StatBuffer *sbuf, int recurse, GPtrA
/* new in data version 6 */
emit_uvalue (logbuffer, mbt_count);
for (i = 0; i < mbt_count; ++i) {
- emit_method (logbuffer, (void*)sample [i * 4]); /* method */
+ MonoMethod *method = (MonoMethod *) sample [i * 4 + 0];
+ MonoDomain *domain = (MonoDomain *) sample [i * 4 + 1];
+ uintptr_t native_offset = sample [i * 4 + 3];
+
+ emit_method (prof, logbuffer, domain, method);
emit_svalue (logbuffer, 0); /* il offset will always be 0 from now on */
- emit_svalue (logbuffer, sample [i * 4 + 3]); /* native offset */
+ emit_svalue (logbuffer, native_offset);
}
sample += 4 * mbt_count;
}
@@ -2135,7 +2189,7 @@ counters_emit (MonoProfiler *profiler)
}
EXIT_LOG (logbuffer);
- safe_dump (profiler, ensure_logbuf (0));
+ safe_send (profiler, ensure_logbuf (0));
mono_mutex_unlock (&counters_mutex);
}
@@ -2253,7 +2307,7 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp)
emit_value (logbuffer, 0);
EXIT_LOG (logbuffer);
- safe_dump (profiler, ensure_logbuf (0));
+ safe_send (profiler, ensure_logbuf (0));
mono_mutex_unlock (&counters_mutex);
}
@@ -2312,7 +2366,7 @@ perfcounters_emit (MonoProfiler *profiler)
}
EXIT_LOG (logbuffer);
- safe_dump (profiler, ensure_logbuf (0));
+ safe_send (profiler, ensure_logbuf (0));
}
static gboolean
@@ -2394,7 +2448,7 @@ perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp)
emit_value (logbuffer, 0);
EXIT_LOG (logbuffer);
- safe_dump (profiler, ensure_logbuf (0));
+ safe_send (profiler, ensure_logbuf (0));
mono_mutex_unlock (&counters_mutex);
}
@@ -2418,13 +2472,14 @@ counters_and_perfcounters_sample (MonoProfiler *prof)
static void
log_shutdown (MonoProfiler *prof)
{
+ void *res;
+
in_shutdown = 1;
#ifndef DISABLE_HELPER_THREAD
counters_and_perfcounters_sample (prof);
if (prof->command_port) {
char c = 1;
- void *res;
ign_res (write (prof->pipes [1], &c, 1));
pthread_join (prof->helper_thread, &res);
}
@@ -2436,12 +2491,17 @@ log_shutdown (MonoProfiler *prof)
read_perf_mmap (prof, i);
}
#endif
- dump_sample_hits (prof, prof->stat_buffers, 1);
- take_lock ();
- if (TLS_GET (tlsbuffer))
- dump_buffer (prof, TLS_GET (tlsbuffer));
+ dump_sample_hits (prof, prof->stat_buffers);
+
+ if (TLS_GET (LogBuffer, tlsbuffer))
+ send_buffer (prof, TLS_GET (GPtrArray, tlsmethodlist), TLS_GET (LogBuffer, tlsbuffer));
+
TLS_SET (tlsbuffer, NULL);
- release_lock ();
+ TLS_SET (tlsmethodlist, NULL);
+
+ InterlockedWrite (&prof->run_writer_thread, 0);
+ pthread_join (prof->writer_thread, &res);
+
#if defined (HAVE_SYS_ZLIB)
if (prof->gzfile)
gzclose (prof->gzfile);
@@ -2450,6 +2510,10 @@ log_shutdown (MonoProfiler *prof)
pclose (prof->file);
else
fclose (prof->file);
+
+ mono_conc_hashtable_destroy (prof->method_table);
+ mono_mutex_destroy (&prof->method_table_mutex);
+
free (prof);
}
@@ -2584,9 +2648,9 @@ helper_thread (void* arg)
if (do_debug)
fprintf (stderr, "stat buffer dump\n");
if (sbuf) {
- dump_sample_hits (prof, sbuf, 1);
+ dump_sample_hits (prof, sbuf);
free_buffer (sbuf, sbuf->size);
- safe_dump (prof, ensure_logbuf (0));
+ safe_send (prof, ensure_logbuf (0));
}
continue;
}
@@ -2606,7 +2670,7 @@ helper_thread (void* arg)
}
}
#endif
- safe_dump (prof, ensure_logbuf (0));
+ safe_send (prof, ensure_logbuf (0));
return NULL;
}
#if USE_PERF_EVENTS
@@ -2617,7 +2681,7 @@ helper_thread (void* arg)
continue;
if (FD_ISSET (perf_data [i].perf_fd, &rfds)) {
read_perf_mmap (prof, i);
- safe_dump (prof, ensure_logbuf (0));
+ safe_send (prof, ensure_logbuf (0));
}
}
}
@@ -2702,6 +2766,93 @@ start_helper_thread (MonoProfiler* prof)
}
#endif
+static void *
+writer_thread (void *arg)
+{
+ MonoProfiler *prof = arg;
+
+ mono_threads_attach_tools_thread ();
+
+ dump_header (prof);
+
+ while (InterlockedRead (&prof->run_writer_thread)) {
+ WriterQueueEntry *entry;
+
+ while ((entry = (WriterQueueEntry *) mono_lock_free_queue_dequeue (&prof->writer_queue))) {
+ LogBuffer *method_buffer = NULL;
+ gboolean new_methods = FALSE;
+
+ if (entry->methods->len)
+ method_buffer = create_buffer ();
+
+ /*
+ * Encode the method events in a temporary log buffer that we
+ * flush to disk before the main buffer, ensuring that all
+ * methods have metadata emitted before they're referenced.
+ */
+ for (guint i = 0; i < entry->methods->len; i++) {
+ MethodInfo *info = g_ptr_array_index (entry->methods, i);
+
+ if (mono_conc_hashtable_lookup (prof->method_table, info->method))
+ continue;
+
+ new_methods = TRUE;
+
+ /*
+ * Other threads use this hash table to get a general
+ * idea of whether a method has already been emitted to
+ * the stream. Due to the way we add to this table, it
+ * can easily happen that multiple threads queue up the
+ * same methods, but that's OK since eventually all
+ * methods will be in this table and the thread-local
+ * method lists will just be empty for the rest of the
+ * app's lifetime.
+ */
+ mono_conc_hashtable_insert (prof->method_table, info->method, info->method);
+
+ char *name = mono_method_full_name (info->method, 1);
+ int nlen = strlen (name) + 1;
+ uint64_t now = current_time ();
+
+ method_buffer = ensure_logbuf_inner (method_buffer, 32 + nlen);
+
+ emit_byte (method_buffer, TYPE_JIT | TYPE_METHOD);
+ emit_time (method_buffer, now);
+ emit_method_inner (method_buffer, info->method);
+ emit_ptr (method_buffer, mono_jit_info_get_code_start (info->ji));
+ emit_value (method_buffer, mono_jit_info_get_code_size (info->ji));
+
+ memcpy (method_buffer->data, name, nlen);
+ method_buffer->data += nlen;
+
+ mono_free (name);
+ free (info);
+ }
+
+ g_ptr_array_free (entry->methods, TRUE);
+
+ if (new_methods)
+ dump_buffer (prof, method_buffer);
+ else if (method_buffer)
+ free_buffer (method_buffer, method_buffer->size);
+
+ dump_buffer (prof, entry->buffer);
+
+ free (entry);
+ }
+ }
+
+ return NULL;
+}
+
+static int
+start_writer_thread (MonoProfiler* prof)
+{
+ InterlockedWrite (&prof->run_writer_thread, 1);
+
+ return !pthread_create (&prof->writer_thread, NULL, writer_thread, prof);
+}
+
static MonoProfiler*
create_profiler (const char *filename)
{
@@ -2776,8 +2927,14 @@ create_profiler (const char *filename)
if (hs_mode_ondemand)
fprintf (stderr, "Ondemand heapshot unavailable on this arch.\n");
#endif
+
+ mono_lock_free_queue_init (&prof->writer_queue);
+ mono_mutex_init (&prof->method_table_mutex);
+ prof->method_table = mono_conc_hashtable_new (&prof->method_table_mutex, NULL, NULL);
+
+ start_writer_thread (prof);
+
prof->startup_time = current_time ();
- dump_header (prof);
return prof;
}
@@ -3127,5 +3284,6 @@ mono_profiler_startup (const char *desc)
mono_profiler_set_events (events);
TLS_INIT (tlsbuffer);
+ TLS_INIT (tlsmethodlist);
}