From a91319333f06da91253eb71ba823ea87b7aec9b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 07:02:21 +0200 Subject: [PATCH 01/50] [profiler] Add counters for all event types. --- mono/profiler/proflog.c | 510 +++++++++++++++++++--------------------- 1 file changed, 239 insertions(+), 271 deletions(-) diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c index 17f43836afde..73937d5d0b83 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/proflog.c @@ -134,22 +134,61 @@ static gboolean debug_coverage = FALSE; static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS; static int max_allocated_sample_hits; -static gint32 sample_hits; -static gint32 sample_flushes; -static gint32 sample_allocations; -static gint32 buffer_allocations; -static gint32 thread_starts; -static gint32 thread_ends; -static gint32 domain_loads; -static gint32 domain_unloads; -static gint32 context_loads; -static gint32 context_unloads; -static gint32 assembly_loads; -static gint32 assembly_unloads; -static gint32 image_loads; -static gint32 image_unloads; -static gint32 class_loads; -static gint32 class_unloads; +// Statistics for internal profiler data structures. +static gint32 sample_allocations_ctr, + buffer_allocations_ctr; + +// Statistics for profiler events. +static gint32 sync_points_ctr, + heap_objects_ctr, + heap_starts_ctr, + heap_ends_ctr, + heap_roots_ctr, + gc_events_ctr, + gc_resizes_ctr, + gc_allocs_ctr, + gc_moves_ctr, + gc_handle_creations_ctr, + gc_handle_deletions_ctr, + finalize_begins_ctr, + finalize_ends_ctr, + finalize_object_begins_ctr, + finalize_object_ends_ctr, + image_loads_ctr, + image_unloads_ctr, + assembly_loads_ctr, + assembly_unloads_ctr, + class_loads_ctr, + class_unloads_ctr, + method_entries_ctr, + method_exits_ctr, + method_exception_exits_ctr, + method_jits_ctr, + code_buffers_ctr, + exception_throws_ctr, + exception_clauses_ctr, + monitor_contentions_ctr, + monitor_acquisitions_ctr, + monitor_failures_ctr, + thread_starts_ctr, + thread_ends_ctr, + thread_names_ctr, + domain_loads_ctr, + domain_unloads_ctr, + domain_names_ctr, + context_loads_ctr, + context_unloads_ctr, + sample_ubins_ctr, + sample_usyms_ctr, + sample_hits_ctr, + counter_descriptors_ctr, + counter_samples_ctr, + perfcounter_descriptors_ctr, + perfcounter_samples_ctr, + coverage_methods_ctr, + coverage_statements_ctr, + coverage_classes_ctr, + coverage_assemblies_ctr; static MonoLinkedListSet profiler_thread_list; @@ -492,10 +531,12 @@ ign_res (int G_GNUC_UNUSED unused, ...) * FALSE, then don't use these macros. */ -#define ENTER_LOG \ +#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?") + g_assert (!PROF_TLS_GET ()->busy++ && "Why are we trying to write a new event while already writing one?"); \ + InterlockedIncrement ((COUNTER)); \ + LogBuffer *BUFFER = ensure_logbuf_unsafe ((SIZE)) #define EXIT_LOG \ PROF_TLS_GET ()->busy--; \ @@ -678,7 +719,7 @@ create_buffer (void) { LogBuffer* buf = (LogBuffer *)alloc_buffer (BUFFER_SIZE); - InterlockedIncrement (&buffer_allocations); + InterlockedIncrement (&buffer_allocations_ctr); buf->size = BUFFER_SIZE; buf->time_base = current_time (); @@ -780,26 +821,6 @@ ensure_logbuf_unsafe (int bytes) return new_; } -/* - * Any calls to this function should be wrapped in the ENTER_LOG and - * EXIT_LOG macros to prevent the returned pointer from leaking - * outside of the critical region created by the calls to buffer_lock () - * and buffer_unlock () that those macros insert. If the pointer leaks, - * it can and will lead to crashes as the GC or helper thread may - * invalidate the pointer at any time. - * - * Note: If you're calling from a thread that called init_thread () with - * add_to_lls = FALSE, you should use ensure_logbuf_unsafe () and omit - * the macros. - */ -static LogBuffer* -ensure_logbuf (int bytes) -{ - g_assert (PROF_TLS_GET ()->busy && "Why are we trying to expand our buffer without the busy flag set?"); - - return ensure_logbuf_unsafe (bytes); -} - static void emit_byte (LogBuffer *logbuffer, int value) { @@ -1121,6 +1142,8 @@ remove_thread (MonoProfiler *prof, MonoProfilerThread *thread, gboolean from_cal * threads. We need to synthesize a thread end event. */ + InterlockedIncrement (&thread_ends_ctr); + buffer = ensure_logbuf_inner (buffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + @@ -1260,9 +1283,7 @@ 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 ( + ENTER_LOG (&sync_points_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* type */ ); @@ -1301,9 +1322,7 @@ gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, size += 7; size &= ~7; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&heap_objects_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* obj */ + LEB128_SIZE /* klass */ + @@ -1363,9 +1382,7 @@ heap_walk (MonoProfiler *profiler) heapshot_requested = 0; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&heap_starts_ctr, logbuffer, EVENT_SIZE /* event */ ); @@ -1375,14 +1392,10 @@ heap_walk (MonoProfiler *profiler) mono_gc_walk_heap (0, gc_reference, NULL); - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&heap_ends_ctr, logbuffer, EVENT_SIZE /* event */ ); - now = current_time (); - emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP); EXIT_LOG; @@ -1391,11 +1404,36 @@ heap_walk (MonoProfiler *profiler) } static void -gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) +gc_roots (MonoProfiler *prof, int num, void **objects, int *root_types, uintptr_t *extra_info) { - ENTER_LOG; + ENTER_LOG (&heap_roots_ctr, logbuffer, + EVENT_SIZE /* event */ + + LEB128_SIZE /* num */ + + LEB128_SIZE /* collections */ + + num * ( + LEB128_SIZE /* object */ + + LEB128_SIZE /* root type */ + + LEB128_SIZE /* extra info */ + ) + ); + + 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_byte (logbuffer, root_types [i]); + emit_value (logbuffer, extra_info [i]); + } + + EXIT_LOG; +} - LogBuffer *logbuffer = ensure_logbuf ( +static void +gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) +{ + ENTER_LOG (&gc_events_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* gc event */ + BYTE_SIZE /* generation */ @@ -1458,9 +1496,7 @@ gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) static void gc_resize (MonoProfiler *profiler, int64_t new_size) { - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&gc_resizes_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* new size */ ); @@ -1539,9 +1575,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass) if (do_bt) collect_bt (&data); - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&gc_allocs_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* klass */ + LEB128_SIZE /* obj */ + @@ -1572,9 +1606,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass) static void gc_moves (MonoProfiler *prof, void **objects, int num) { - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&gc_moves_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* num */ + num * ( @@ -1591,35 +1623,6 @@ gc_moves (MonoProfiler *prof, void **objects, int num) EXIT_LOG; } -static void -gc_roots (MonoProfiler *prof, int num, void **objects, int *root_types, uintptr_t *extra_info) -{ - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( - EVENT_SIZE /* event */ + - LEB128_SIZE /* num */ + - LEB128_SIZE /* collections */ + - num * ( - LEB128_SIZE /* object */ + - LEB128_SIZE /* root type */ + - LEB128_SIZE /* extra info */ - ) - ); - - 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_byte (logbuffer, root_types [i]); - emit_value (logbuffer, extra_info [i]); - } - - EXIT_LOG; -} - static void gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *obj) { @@ -1629,9 +1632,9 @@ gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *o if (do_bt) collect_bt (&data); - ENTER_LOG; + gint32 *ctr = op == MONO_PROFILER_GC_HANDLE_CREATED ? &gc_handle_creations_ctr : &gc_handle_deletions_ctr; - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* type */ + LEB128_SIZE /* handle */ + @@ -1670,9 +1673,7 @@ gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *o static void finalize_begin (MonoProfiler *prof) { - ENTER_LOG; - - LogBuffer *buf = ensure_logbuf ( + ENTER_LOG (&finalize_begins_ctr, buf, EVENT_SIZE /* event */ ); @@ -1686,9 +1687,7 @@ finalize_begin (MonoProfiler *prof) static void finalize_end (MonoProfiler *prof) { - ENTER_LOG; - - LogBuffer *buf = ensure_logbuf ( + ENTER_LOG (&finalize_ends_ctr, buf, EVENT_SIZE /* event */ ); @@ -1702,9 +1701,7 @@ finalize_end (MonoProfiler *prof) static void finalize_object_begin (MonoProfiler *prof, MonoObject *obj) { - ENTER_LOG; - - LogBuffer *buf = ensure_logbuf ( + ENTER_LOG (&finalize_object_begins_ctr, buf, EVENT_SIZE /* event */ + LEB128_SIZE /* obj */ ); @@ -1720,9 +1717,7 @@ finalize_object_begin (MonoProfiler *prof, MonoObject *obj) static void finalize_object_end (MonoProfiler *prof, MonoObject *obj) { - ENTER_LOG; - - LogBuffer *buf = ensure_logbuf ( + ENTER_LOG (&finalize_object_ends_ctr, buf, EVENT_SIZE /* event */ + LEB128_SIZE /* obj */ ); @@ -1780,9 +1775,7 @@ image_loaded (MonoProfiler *prof, MonoImage *image, int result) const char *name = mono_image_get_filename (image); int nlen = strlen (name) + 1; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&image_loads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* image */ + @@ -1800,8 +1793,6 @@ image_loaded (MonoProfiler *prof, MonoImage *image, int result) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&image_loads); } static void @@ -1810,9 +1801,7 @@ image_unloaded (MonoProfiler *prof, MonoImage *image) const char *name = mono_image_get_filename (image); int nlen = strlen (name) + 1; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&image_unloads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* image */ + @@ -1830,8 +1819,6 @@ image_unloaded (MonoProfiler *prof, MonoImage *image) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&image_unloads); } static void @@ -1843,9 +1830,7 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly, int result) char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly)); int nlen = strlen (name) + 1; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&assembly_loads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* assembly */ + @@ -1865,8 +1850,6 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly, int result) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&assembly_loads); } static void @@ -1875,9 +1858,7 @@ assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly) char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly)); int nlen = strlen (name) + 1; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&assembly_unloads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* assembly */ + @@ -1897,8 +1878,6 @@ assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&assembly_unloads); } static void @@ -1917,9 +1896,7 @@ class_loaded (MonoProfiler *prof, MonoClass *klass, int result) int nlen = strlen (name) + 1; MonoImage *image = mono_class_get_image (klass); - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&class_loads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* klass */ + @@ -1944,8 +1921,6 @@ class_loaded (MonoProfiler *prof, MonoClass *klass, int result) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&class_loads); } static void @@ -1961,9 +1936,7 @@ class_unloaded (MonoProfiler *prof, MonoClass *klass) int nlen = strlen (name) + 1; MonoImage *image = mono_class_get_image (klass); - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&class_unloads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* klass */ + @@ -1988,8 +1961,6 @@ class_unloaded (MonoProfiler *prof, MonoClass *klass) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&class_unloads); } #ifndef DISABLE_HELPER_THREAD @@ -2004,9 +1975,7 @@ method_enter (MonoProfiler *prof, MonoMethod *method) #endif /* DISABLE_HELPER_THREAD */ if (PROF_TLS_GET ()->call_depth++ <= max_call_depth) { - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&method_entries_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* method */ ); @@ -2026,9 +1995,7 @@ static void method_leave (MonoProfiler *prof, MonoMethod *method) { if (--PROF_TLS_GET ()->call_depth <= max_call_depth) { - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&method_exits_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* method */ ); @@ -2048,9 +2015,7 @@ static void method_exc_leave (MonoProfiler *prof, MonoMethod *method) { if (!nocalls && --PROF_TLS_GET ()->call_depth <= max_call_depth) { - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&method_exception_exits_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* method */ ); @@ -2091,9 +2056,7 @@ code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBuf nlen = 0; } - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&code_buffers_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* buffer */ + @@ -2127,9 +2090,7 @@ throw_exc (MonoProfiler *prof, MonoObject *object) if (do_bt) collect_bt (&data); - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&exception_throws_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* object */ + (do_bt ? ( @@ -2154,9 +2115,7 @@ throw_exc (MonoProfiler *prof, MonoObject *object) static void clause_exc (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_num) { - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&exception_clauses_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* clause type */ + LEB128_SIZE /* clause num */ + @@ -2182,9 +2141,24 @@ monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEv if (do_bt) collect_bt (&data); - ENTER_LOG; + gint32 *ctr; + + switch (event) { + case MONO_PROFILER_MONITOR_CONTENTION: + ctr = &monitor_contentions_ctr; + break; + case MONO_PROFILER_MONITOR_DONE: + ctr = &monitor_acquisitions_ctr; + break; + case MONO_PROFILER_MONITOR_FAIL: + ctr = &monitor_failures_ctr; + break; + default: + g_assert_not_reached (); + break; + } - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* object */ + (do_bt ? ( @@ -2211,9 +2185,7 @@ thread_start (MonoProfiler *prof, uintptr_t tid) { init_thread (TRUE); - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&thread_starts_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* tid */ @@ -2228,16 +2200,12 @@ thread_start (MonoProfiler *prof, uintptr_t tid) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&thread_starts); } static void thread_end (MonoProfiler *prof, uintptr_t tid) { - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&thread_ends_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* tid */ @@ -2252,8 +2220,31 @@ thread_end (MonoProfiler *prof, uintptr_t tid) // Don't process requests as the thread is detached from the runtime. remove_thread (prof, PROF_TLS_GET (), TRUE); +} - InterlockedIncrement (&thread_ends); +static void +thread_name (MonoProfiler *prof, uintptr_t tid, const char *name) +{ + int len = strlen (name) + 1; + + ENTER_LOG (&thread_names_ctr, logbuffer, + EVENT_SIZE /* event */ + + BYTE_SIZE /* type */ + + LEB128_SIZE /* tid */ + + len /* name */ + ); + + emit_event (logbuffer, TYPE_METADATA); + emit_byte (logbuffer, TYPE_THREAD); + emit_ptr (logbuffer, (void*)tid); + memcpy (logbuffer->cursor, name, len); + logbuffer->cursor += len; + + EXIT_LOG; + + send_if_needed (prof); + + process_requests (prof); } static void @@ -2262,9 +2253,7 @@ domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result) if (result != MONO_PROFILE_OK) return; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&domain_loads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* domain id */ @@ -2279,16 +2268,12 @@ domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&domain_loads); } static void domain_unloaded (MonoProfiler *prof, MonoDomain *domain) { - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&domain_unloads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* domain id */ @@ -2303,8 +2288,6 @@ domain_unloaded (MonoProfiler *prof, MonoDomain *domain) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&domain_unloads); } static void @@ -2312,9 +2295,7 @@ domain_name (MonoProfiler *prof, MonoDomain *domain, const char *name) { int nlen = strlen (name) + 1; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&domain_names_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* domain id */ + @@ -2337,9 +2318,7 @@ domain_name (MonoProfiler *prof, MonoDomain *domain, const char *name) static void context_loaded (MonoProfiler *prof, MonoAppContext *context) { - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&context_loads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* context id */ + @@ -2356,16 +2335,12 @@ context_loaded (MonoProfiler *prof, MonoAppContext *context) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&context_loads); } static void context_unloaded (MonoProfiler *prof, MonoAppContext *context) { - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&context_unloads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* context id */ + @@ -2382,35 +2357,6 @@ context_unloaded (MonoProfiler *prof, MonoAppContext *context) send_if_needed (prof); process_requests (prof); - - InterlockedIncrement (&context_unloads); -} - -static void -thread_name (MonoProfiler *prof, uintptr_t tid, const char *name) -{ - int len = strlen (name) + 1; - - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( - EVENT_SIZE /* event */ + - BYTE_SIZE /* type */ + - LEB128_SIZE /* tid */ + - len /* name */ - ); - - emit_event (logbuffer, TYPE_METADATA); - emit_byte (logbuffer, TYPE_THREAD); - emit_ptr (logbuffer, (void*)tid); - memcpy (logbuffer->cursor, name, len); - logbuffer->cursor += len; - - EXIT_LOG; - - send_if_needed (prof); - - process_requests (prof); } typedef struct { @@ -2460,8 +2406,6 @@ enqueue_sample_hit (gpointer p) mono_lock_free_queue_node_unpoison (&sample->node); mono_lock_free_queue_enqueue (&sample->prof->dumper_queue, &sample->node); mono_os_sem_post (&sample->prof->dumper_queue_sem); - - InterlockedIncrement (&sample_flushes); } static void @@ -2478,8 +2422,6 @@ mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context) if (in_shutdown) return; - InterlockedIncrement (&sample_hits); - SampleHit *sample = (SampleHit *) mono_lock_free_queue_dequeue (&profiler->sample_reuse_queue); if (!sample) { @@ -2487,14 +2429,14 @@ mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context) * If we're out of reusable sample events and we're not allowed to * allocate more, we have no choice but to drop the event. */ - if (InterlockedRead (&sample_allocations) >= max_allocated_sample_hits) + if (InterlockedRead (&sample_allocations_ctr) >= max_allocated_sample_hits) return; sample = mono_lock_free_alloc (&profiler->sample_allocator); sample->prof = profiler; mono_lock_free_queue_node_init (&sample->node, TRUE); - InterlockedIncrement (&sample_allocations); + InterlockedIncrement (&sample_allocations_ctr); } sample->count = 0; @@ -2576,9 +2518,7 @@ dump_ubin (const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t { int len = strlen (filename) + 1; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&sample_ubins_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* load address */ + LEB128_SIZE /* offset */ + @@ -2602,9 +2542,7 @@ dump_usym (const char *name, uintptr_t value, uintptr_t size) { int len = strlen (name) + 1; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&sample_usyms_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* value */ + LEB128_SIZE /* size */ + @@ -3013,9 +2951,7 @@ dump_perf_hits (MonoProfiler *prof, void *buf, int size) 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);*/ - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&sample_hits_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* tid */ + @@ -3271,9 +3207,8 @@ counters_emit (MonoProfiler *profiler) return; } - ENTER_LOG; - LogBuffer *logbuffer = ensure_logbuf (size); + ENTER_LOG (&counter_descriptors_ctr, logbuffer, size); emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE); emit_value (logbuffer, len); @@ -3336,9 +3271,7 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp) LEB128_SIZE /* stop marker */ ; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf (size); + ENTER_LOG (&counter_samples_ctr, logbuffer, size); emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp); @@ -3474,9 +3407,7 @@ perfcounters_emit (MonoProfiler *profiler) if (!len) return; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf (size); + ENTER_LOG (&perfcounter_descriptors_ctr, logbuffer, size); emit_event (logbuffer, TYPE_SAMPLE_COUNTERS_DESC | TYPE_SAMPLE); emit_value (logbuffer, len); @@ -3570,9 +3501,7 @@ perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp) LEB128_SIZE /* stop marker */ ; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf (size); + ENTER_LOG (&perfcounter_samples_ctr, logbuffer, size); emit_event_time (logbuffer, TYPE_SAMPLE_COUNTERS | TYPE_SAMPLE, timestamp); @@ -3737,9 +3666,7 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata) sig = sig ? sig : ""; method_name = method_name ? method_name : ""; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&coverage_methods_ctr, logbuffer, EVENT_SIZE /* event */ + strlen (image_name) + 1 /* image name */ + strlen (class_name) + 1 /* class name */ + @@ -3769,9 +3696,7 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata) for (i = 0; i < coverage_data->len; i++) { CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[i]; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&coverage_statements_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* method id */ + LEB128_SIZE /* offset */ + @@ -3838,9 +3763,7 @@ build_class_buffer (gpointer key, gpointer value, gpointer userdata) /* We don't handle partial covered yet */ partially_covered = 0; - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&coverage_classes_ctr, logbuffer, EVENT_SIZE /* event */ + strlen (assembly_name) + 1 /* assembly name */ + strlen (class_name) + 1 /* class name */ + @@ -3898,9 +3821,7 @@ build_assembly_buffer (gpointer key, gpointer value, gpointer userdata) get_coverage_for_image (image, &number_of_methods, &fully_covered, &partially_covered); - ENTER_LOG; - - LogBuffer *logbuffer = ensure_logbuf ( + ENTER_LOG (&coverage_assemblies_ctr, logbuffer, EVENT_SIZE /* event */ + strlen (name) + 1 /* name */ + strlen (guid) + 1 /* guid */ + @@ -4641,6 +4562,8 @@ handle_writer_queue_entry (MonoProfiler *prof) 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 ( EVENT_SIZE /* event */ + LEB128_SIZE /* method */ + @@ -4748,6 +4671,8 @@ handle_dumper_queue_entry (MonoProfiler *prof) } } + InterlockedIncrement (&sample_hits_ctr); + LogBuffer *logbuffer = ensure_logbuf_unsafe ( EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + @@ -4823,6 +4748,12 @@ start_dumper_thread (MonoProfiler* prof) return !pthread_create (&prof->dumper_thread, NULL, dumper_thread, prof); } +static void +register_counter (const char *name, gint32 *counter) +{ + mono_counters_register (name, MONO_COUNTER_UINT | MONO_COUNTER_PROFILER | MONO_COUNTER_MONOTONIC, counter); +} + static void runtime_initialized (MonoProfiler *profiler) { @@ -4838,22 +4769,59 @@ runtime_initialized (MonoProfiler *profiler) start_writer_thread (profiler); start_dumper_thread (profiler); - 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); + register_counter ("Sample events allocated", &sample_allocations_ctr); + register_counter ("Log buffers allocated", &buffer_allocations_ctr); + + register_counter ("Event: Sync points", &sync_points_ctr); + register_counter ("Event: Heap objects", &heap_objects_ctr); + register_counter ("Event: Heap starts", &heap_starts_ctr); + register_counter ("Event: Heap ends", &heap_ends_ctr); + register_counter ("Event: Heap roots", &heap_roots_ctr); + register_counter ("Event: GC events", &gc_events_ctr); + register_counter ("Event: GC resizes", &gc_resizes_ctr); + register_counter ("Event: GC allocations", &gc_allocs_ctr); + register_counter ("Event: GC moves", &gc_moves_ctr); + register_counter ("Event: GC handle creations", &gc_handle_creations_ctr); + register_counter ("Event: GC handle deletions", &gc_handle_deletions_ctr); + register_counter ("Event: GC finalize starts", &finalize_begins_ctr); + register_counter ("Event: GC finalize ends", &finalize_ends_ctr); + register_counter ("Event: GC finalize object starts", &finalize_object_begins_ctr); + register_counter ("Event: GC finalize object ends", &finalize_object_ends_ctr); + register_counter ("Event: Image loads", &image_loads_ctr); + register_counter ("Event: Image unloads", &image_unloads_ctr); + register_counter ("Event: Assembly loads", &assembly_loads_ctr); + register_counter ("Event: Assembly unloads", &assembly_unloads_ctr); + register_counter ("Event: Class loads", &class_loads_ctr); + register_counter ("Event: Class unloads", &class_unloads_ctr); + register_counter ("Event: Method entries", &method_entries_ctr); + register_counter ("Event: Method exits", &method_exits_ctr); + register_counter ("Event: Method exception leaves", &method_exception_exits_ctr); + register_counter ("Event: Method JITs", &method_jits_ctr); + register_counter ("Event: Code buffers", &code_buffers_ctr); + register_counter ("Event: Exception throws", &exception_throws_ctr); + register_counter ("Event: Exception clauses", &exception_clauses_ctr); + register_counter ("Event: Monitor contentions", &monitor_contentions_ctr); + register_counter ("Event: Monitor acquisitions", &monitor_acquisitions_ctr); + register_counter ("Event: Monitor failures", &monitor_failures_ctr); + register_counter ("Event: Thread starts", &thread_starts_ctr); + register_counter ("Event: Thread ends", &thread_ends_ctr); + register_counter ("Event: Thread names", &thread_names_ctr); + register_counter ("Event: Domain loads", &domain_loads_ctr); + register_counter ("Event: Domain unloads", &domain_unloads_ctr); + register_counter ("Event: Domain names", &domain_names_ctr); + register_counter ("Event: Context loads", &context_loads_ctr); + register_counter ("Event: Context unloads", &context_unloads_ctr); + register_counter ("Event: Sample binaries", &sample_ubins_ctr); + register_counter ("Event: Sample symbols", &sample_usyms_ctr); + register_counter ("Event: Sample hits", &sample_hits_ctr); + register_counter ("Event: Counter descriptors", &counter_descriptors_ctr); + register_counter ("Event: Counter samples", &counter_samples_ctr); + register_counter ("Event: Performance counter descriptors", &perfcounter_descriptors_ctr); + register_counter ("Event: Performance counter samples", &perfcounter_samples_ctr); + register_counter ("Event: Coverage methods", &coverage_methods_ctr); + register_counter ("Event: Coverage statements", &coverage_statements_ctr); + register_counter ("Event: Coverage classes", &coverage_classes_ctr); + register_counter ("Event: Coverage assemblies", &coverage_assemblies_ctr); #ifndef DISABLE_HELPER_THREAD counters_init (profiler); From ae0828fcee2bd9c69e6391f021e681d8670ca83b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 07:03:29 +0200 Subject: [PATCH 02/50] [profiler] Fix the code that synthesizes thread end events. It could previously fail to process a newly allocated buffer. --- mono/profiler/proflog.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c index 73937d5d0b83..b49a494c5eac 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/proflog.c @@ -1128,8 +1128,6 @@ remove_thread (MonoProfiler *prof, MonoProfilerThread *thread, gboolean from_cal MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); if (mono_lls_remove (&profiler_thread_list, hp, &thread->node)) { - LogBuffer *buffer = thread->buffer; - /* * No need to take the buffer lock here as no other threads can * be accessing this buffer anymore. @@ -1144,15 +1142,15 @@ remove_thread (MonoProfiler *prof, MonoProfilerThread *thread, gboolean from_cal InterlockedIncrement (&thread_ends_ctr); - buffer = ensure_logbuf_inner (buffer, + thread->buffer = ensure_logbuf_inner (thread->buffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* tid */ ); - emit_event (buffer, TYPE_END_UNLOAD | TYPE_METADATA); - emit_byte (buffer, TYPE_THREAD); - emit_ptr (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 (prof, thread); From d933617f693797a1fbe0356f7958415fec8fbf0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 07:04:13 +0200 Subject: [PATCH 03/50] [profiler] Don't emit a perf counters sample event if none are registered. --- mono/profiler/proflog.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c index b49a494c5eac..568d896d9191 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/proflog.c @@ -3197,14 +3197,11 @@ counters_emit (MonoProfiler *profiler) LEB128_SIZE /* index */ ; - len += 1; - } - - if (!len) { - mono_os_mutex_unlock (&counters_mutex); - return; + len++; } + if (!len) + goto done; ENTER_LOG (&counter_descriptors_ctr, logbuffer, size); @@ -3230,6 +3227,7 @@ counters_emit (MonoProfiler *profiler) EXIT_LOG; +done: mono_os_mutex_unlock (&counters_mutex); } @@ -3399,7 +3397,7 @@ perfcounters_emit (MonoProfiler *profiler) LEB128_SIZE /* index */ ; - len += 1; + len++; } if (!len) @@ -3465,6 +3463,7 @@ static void perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp) { PerfCounterAgent *pcagent; + int len = 0; int size; if (!counters_initialized) @@ -3493,8 +3492,13 @@ perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp) BYTE_SIZE /* type */ + LEB128_SIZE /* value */ ; + + len++; } + if (!len) + goto done; + size += LEB128_SIZE /* stop marker */ ; @@ -3517,6 +3521,7 @@ perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp) EXIT_LOG; +done: mono_os_mutex_unlock (&counters_mutex); } From 0db428169a42373a73cd5c502bd40033629f3f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 07:07:55 +0200 Subject: [PATCH 04/50] [profiler] Simplify counters initialization. --- mono/profiler/proflog.c | 38 ++++++++------------------------------ 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c index 568d896d9191..50f8276ed06e 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/proflog.c @@ -1212,9 +1212,6 @@ process_requests (MonoProfiler *profiler) mono_gc_collect (mono_gc_max_generation ()); } -static void counters_init (MonoProfiler *profiler); -static void counters_sample (MonoProfiler *profiler, uint64_t timestamp); - static void safe_send (MonoProfiler *profiler) { @@ -3103,7 +3100,6 @@ typedef struct MonoCounterAgent { } MonoCounterAgent; static MonoCounterAgent* counters; -static gboolean counters_initialized = FALSE; static int counters_index = 1; static mono_mutex_t counters_mutex; @@ -3112,9 +3108,6 @@ counters_add_agent (MonoCounter *counter) { MonoCounterAgent *agent, *item; - if (!counters_initialized) - return; - mono_os_mutex_lock (&counters_mutex); for (agent = counters; agent; agent = agent->next) { @@ -3124,8 +3117,7 @@ counters_add_agent (MonoCounter *counter) g_free (agent->value); agent->value = NULL; } - mono_os_mutex_unlock (&counters_mutex); - return; + goto done; } } @@ -3146,6 +3138,7 @@ counters_add_agent (MonoCounter *counter) item->next = agent; } +done: mono_os_mutex_unlock (&counters_mutex); } @@ -3159,12 +3152,8 @@ counters_init_foreach_callback (MonoCounter *counter, gpointer data) static void counters_init (MonoProfiler *profiler) { - assert (!counters_initialized); - mono_os_mutex_init (&counters_mutex); - counters_initialized = TRUE; - mono_counters_on_register (&counters_add_agent); mono_counters_foreach (counters_init_foreach_callback, NULL); } @@ -3179,9 +3168,6 @@ counters_emit (MonoProfiler *profiler) LEB128_SIZE /* len */ ; - if (!counters_initialized) - return; - mono_os_mutex_lock (&counters_mutex); for (agent = counters; agent; agent = agent->next) { @@ -3241,9 +3227,6 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp) void *buffer; int size; - if (!counters_initialized) - return; - counters_emit (profiler); buffer_size = 8; @@ -3466,9 +3449,6 @@ perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp) int len = 0; int size; - if (!counters_initialized) - return; - mono_os_mutex_lock (&counters_mutex); /* mark all perfcounters as deleted, foreach will unmark them as necessary */ @@ -4762,13 +4742,6 @@ runtime_initialized (MonoProfiler *profiler) { InterlockedWrite (&runtime_inited, 1); -#ifndef DISABLE_HELPER_THREAD - if (hs_mode_ondemand || need_helper_thread) { - if (!start_helper_thread (profiler)) - profiler->command_port = 0; - } -#endif - start_writer_thread (profiler); start_dumper_thread (profiler); @@ -4828,8 +4801,13 @@ runtime_initialized (MonoProfiler *profiler) #ifndef DISABLE_HELPER_THREAD counters_init (profiler); - counters_sample (profiler, 0); + + 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); } From 03d693565455be984c1165ad15e3b3daf531f096 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 07:21:17 +0200 Subject: [PATCH 05/50] [profiler] Don't leak counter data structures on shutdown. --- mono/profiler/proflog.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c index 50f8276ed06e..a6c1cb1da73a 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/proflog.c @@ -3106,6 +3106,9 @@ static mono_mutex_t counters_mutex; static void counters_add_agent (MonoCounter *counter) { + if (in_shutdown) + return; + MonoCounterAgent *agent, *item; mono_os_mutex_lock (&counters_mutex); @@ -4180,6 +4183,22 @@ log_shutdown (MonoProfiler *prof) ign_res (write (prof->pipes [1], &c, 1)); pthread_join (prof->helper_thread, &res); } + + mono_os_mutex_destroy (&counters_mutex); + + MonoCounterAgent *mc_next; + + for (MonoCounterAgent *cur = counters; cur; cur = mc_next) { + mc_next = cur->next; + g_free (cur); + } + + PerfCounterAgent *pc_next; + + for (PerfCounterAgent *cur = perfcounters; cur; cur = pc_next) { + pc_next = cur->next; + g_free (cur); + } #endif #if USE_PERF_EVENTS if (perf_data) { From 46b3f65045e95d173c6bcd056617ee2d4033ba8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 10:16:26 +0200 Subject: [PATCH 06/50] [profiler] Lift profiler limitation in mono_class_get_allocation_ftn (). This has not actually been necessary since allocation reporting was moved into the GC implementations. --- mono/metadata/object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mono/metadata/object.c b/mono/metadata/object.c index 9db69581fbcc..0603774589ed 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -5457,7 +5457,7 @@ mono_class_get_allocation_ftn (MonoVTable *vtable, gboolean for_box, gboolean *p *pass_size_in_words = FALSE; - if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass) || (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS)) + if (mono_class_has_finalizer (vtable->klass) || mono_class_is_marshalbyref (vtable->klass)) return ves_icall_object_new_specific; if (vtable->gc_descr != MONO_GC_DESCRIPTOR_NULL) { From b6518ecfb83a93a6daf74055ca81d1c21bab12fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 10:23:41 +0200 Subject: [PATCH 07/50] [profiler] Remove some indirection in setting up GC events. * mono_gc_enable_events: This did nothing for SGen and we called it unconditionally for Boehm. So no point in having it around. * mono_gc_enable_alloc_events: The performance difference between checking a static alloc_events variable versus checking mono_profiler_events is marginal at best and doesn't justify the indirection, especially now that we support managed allocators while profiling. --- mono/metadata/boehm-gc.c | 29 +++++++++-------------------- mono/metadata/gc-internals.h | 2 -- mono/metadata/null-gc.c | 10 ---------- mono/metadata/profiler.c | 2 -- mono/metadata/sgen-mono.c | 25 ++++++------------------- 5 files changed, 15 insertions(+), 53 deletions(-) diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c index e7ee0517dd22..d084501c9294 100644 --- a/mono/metadata/boehm-gc.c +++ b/mono/metadata/boehm-gc.c @@ -99,6 +99,9 @@ mono_gc_warning (char *msg, GC_word arg) mono_trace (G_LOG_LEVEL_WARNING, MONO_TRACE_GC, msg, (unsigned long)arg); } +static void on_gc_notification (GC_EventType event); +static void on_gc_heap_resize (size_t new_size); + void mono_gc_base_init (void) { @@ -251,7 +254,8 @@ mono_gc_base_init (void) mono_thread_info_attach (&dummy); - mono_gc_enable_events (); + GC_set_on_collection_event (on_gc_notification); + GC_on_heap_resize = on_gc_heap_resize; MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_NORMAL].entries, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table"); MONO_GC_REGISTER_ROOT_FIXED (gc_handles [HANDLE_PINNED].entries, MONO_ROOT_SOURCE_GC_HANDLE, "gc handles table"); @@ -523,21 +527,6 @@ on_gc_heap_resize (size_t new_size) mono_profiler_gc_heap_resize (new_size); } -void -mono_gc_enable_events (void) -{ - GC_set_on_collection_event (on_gc_notification); - GC_on_heap_resize = on_gc_heap_resize; -} - -static gboolean alloc_events = FALSE; - -void -mono_gc_enable_alloc_events (void) -{ - alloc_events = TRUE; -} - int mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg) { @@ -679,7 +668,7 @@ mono_gc_alloc_obj (MonoVTable *vtable, size_t size) obj->vtable = vtable; } - if (G_UNLIKELY (alloc_events)) + if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) mono_profiler_allocation (obj); return obj; @@ -713,7 +702,7 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length) obj->max_length = max_length; - if (G_UNLIKELY (alloc_events)) + if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) mono_profiler_allocation (&obj->obj); return obj; @@ -750,7 +739,7 @@ mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uint if (bounds_size) obj->bounds = (MonoArrayBounds *) ((char *) obj + size - bounds_size); - if (G_UNLIKELY (alloc_events)) + if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) mono_profiler_allocation (&obj->obj); return obj; @@ -768,7 +757,7 @@ mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len) obj->length = len; obj->chars [len] = 0; - if (G_UNLIKELY (alloc_events)) + if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) mono_profiler_allocation (&obj->object); return obj; diff --git a/mono/metadata/gc-internals.h b/mono/metadata/gc-internals.h index cd9408df98bb..d3d81f272a88 100644 --- a/mono/metadata/gc-internals.h +++ b/mono/metadata/gc-internals.h @@ -103,8 +103,6 @@ extern void mono_gc_set_stack_end (void *stack_end); gboolean mono_object_is_alive (MonoObject* obj); gboolean mono_gc_is_finalizer_thread (MonoThread *thread); gpointer mono_gc_out_of_memory (size_t size); -void mono_gc_enable_events (void); -void mono_gc_enable_alloc_events (void); void mono_gchandle_set_target (guint32 gchandle, MonoObject *obj); diff --git a/mono/metadata/null-gc.c b/mono/metadata/null-gc.c index 0f47c00fa62f..aa8bc0259bb9 100644 --- a/mono/metadata/null-gc.c +++ b/mono/metadata/null-gc.c @@ -111,16 +111,6 @@ mono_object_is_alive (MonoObject* o) return TRUE; } -void -mono_gc_enable_events (void) -{ -} - -void -mono_gc_enable_alloc_events (void) -{ -} - int mono_gc_register_root (char *start, size_t size, void *descr, MonoGCRootSource source, const char *msg) { diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c index fb4cdeca08b8..99c490fb75d1 100644 --- a/mono/metadata/profiler.c +++ b/mono/metadata/profiler.c @@ -273,7 +273,6 @@ mono_profiler_install_transition (MonoProfileMethodResult callback) void mono_profiler_install_allocation (MonoProfileAllocFunc callback) { - mono_gc_enable_alloc_events (); if (!prof_list) return; prof_list->allocation_cb = callback; @@ -876,7 +875,6 @@ mono_profiler_gc_roots (int num, void **objects, int *root_types, uintptr_t *ext void mono_profiler_install_gc (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback) { - mono_gc_enable_events (); if (!prof_list) return; prof_list->gc_event = callback; diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index 4b6a5d355ef9..7966d8f6ab05 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -917,20 +917,12 @@ mono_gc_clear_domain (MonoDomain * domain) * Allocation */ -static gboolean alloc_events = FALSE; - -void -mono_gc_enable_alloc_events (void) -{ - alloc_events = TRUE; -} - void* mono_gc_alloc_obj (MonoVTable *vtable, size_t size) { MonoObject *obj = sgen_alloc_obj (vtable, size); - if (G_UNLIKELY (alloc_events)) { + if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) { if (obj) mono_profiler_allocation (obj); } @@ -943,7 +935,7 @@ mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size) { MonoObject *obj = sgen_alloc_obj_pinned (vtable, size); - if (G_UNLIKELY (alloc_events)) { + if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) { if (obj) mono_profiler_allocation (obj); } @@ -956,7 +948,7 @@ mono_gc_alloc_mature (MonoVTable *vtable, size_t size) { MonoObject *obj = sgen_alloc_obj_mature (vtable, size); - if (G_UNLIKELY (alloc_events)) { + if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) { if (obj) mono_profiler_allocation (obj); } @@ -1753,7 +1745,7 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length) UNLOCK_GC; done: - if (G_UNLIKELY (alloc_events)) + if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) mono_profiler_allocation (&arr->obj); SGEN_ASSERT (6, SGEN_ALIGN_UP (size) == SGEN_ALIGN_UP (sgen_client_par_object_get_size (vtable, (GCObject*)arr)), "Vector has incorrect size."); @@ -1801,7 +1793,7 @@ mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uint UNLOCK_GC; done: - if (G_UNLIKELY (alloc_events)) + if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) mono_profiler_allocation (&arr->obj); SGEN_ASSERT (6, SGEN_ALIGN_UP (size) == SGEN_ALIGN_UP (sgen_client_par_object_get_size (vtable, (GCObject*)arr)), "Array has incorrect size."); @@ -1842,7 +1834,7 @@ mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len) UNLOCK_GC; done: - if (G_UNLIKELY (alloc_events)) + if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) mono_profiler_allocation (&str->object); return str; @@ -2512,11 +2504,6 @@ mono_gc_get_generation (MonoObject *obj) return 1; } -void -mono_gc_enable_events (void) -{ -} - const char * mono_gc_get_gc_name (void) { From b334afdbd094aa57df59a60a5048575749780545 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 11:11:21 +0200 Subject: [PATCH 08/50] [profiler] Use the signal shutdown logic for the sampling thread for more cases. --- mono/mini/mini-posix.c | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/mono/mini/mini-posix.c b/mono/mini/mini-posix.c index b0d7a0709db7..f8a02816291f 100644 --- a/mono/mini/mini-posix.c +++ b/mono/mini/mini-posix.c @@ -335,14 +335,8 @@ MONO_SIG_HANDLER_FUNC (static, profiler_signal_handler) /* See the comment in mono_runtime_shutdown_stat_profiler (). */ if (mono_native_thread_id_get () == sampling_thread) { -#ifdef HAVE_CLOCK_NANOSLEEP - if (mono_profiler_get_sampling_mode () == MONO_PROFILER_STAT_MODE_PROCESS) { - InterlockedIncrement (&profiler_interrupt_signals_received); - return; - } -#endif - - g_error ("%s: Unexpected profiler signal received by the sampler thread", __func__); + InterlockedIncrement (&profiler_interrupt_signals_received); + return; } InterlockedIncrement (&profiler_signals_received); @@ -761,7 +755,7 @@ mono_runtime_shutdown_stat_profiler (void) { InterlockedWrite (&sampling_thread_running, 0); -#ifdef HAVE_CLOCK_NANOSLEEP +#ifndef PLATFORM_MACOSX /* * There is a slight problem when we're using CLOCK_PROCESS_CPUTIME_ID: If * we're shutting down and there's largely no activity in the process other @@ -774,24 +768,18 @@ mono_runtime_shutdown_stat_profiler (void) * sampling_thread_running upon an interrupt and return immediately if it's * zero. profiler_signal_handler () has a special case to ignore the signal * for the sampler thread. - * - * We do not need to do this on platforms where we use a regular sleep - * based on a monotonic clock. The sleep will return in a reasonable amount - * of time in those cases. */ - if (mono_profiler_get_sampling_mode () == MONO_PROFILER_STAT_MODE_PROCESS) { - MonoThreadInfo *info; - - // Did it shut down already? - if ((info = mono_thread_info_lookup (sampling_thread))) { - while (!InterlockedRead (&sampling_thread_exiting)) { - mono_threads_pthread_kill (info, profiler_signal); - mono_thread_info_usleep (10 * 1000 /* 10ms */); - } + MonoThreadInfo *info; - // Make sure info can be freed. - mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); + // Did it shut down already? + if ((info = mono_thread_info_lookup (sampling_thread))) { + while (!InterlockedRead (&sampling_thread_exiting)) { + mono_threads_pthread_kill (info, profiler_signal); + mono_thread_info_usleep (10 * 1000 /* 10ms */); } + + // Make sure info can be freed. + mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); } #endif From b9d7a08f264747d8845fcc60a2407076e95bf91d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 11:21:20 +0200 Subject: [PATCH 09/50] [man] Update mprof-report.1 to indicate the correct default maxframes value. --- man/mprof-report.1 | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/man/mprof-report.1 b/man/mprof-report.1 index c4fd545dd104..cdc3c9a8f653 100644 --- a/man/mprof-report.1 +++ b/man/mprof-report.1 @@ -92,7 +92,7 @@ provided by the Mono runtime and write them to a file named \f[I]output.mlpd\f[]. When no option is specified, it is equivalent to using: .PP -\f[B]--profile=log:calls,alloc,output=output.mlpd,maxframes=8,calldepth=100\f[] +\f[B]--profile=log:calls,alloc,output=output.mlpd,maxframes=32,calldepth=100\f[] .PP The following options can be used to modify this default behaviour. Each option is separated from the next by a \f[B],\f[] character, @@ -173,7 +173,7 @@ TIMER can have the following values: .IP \[bu] 2 \f[I]maxframes=NUM\f[]: when a stack trace needs to be performed, collect \f[I]NUM\f[] frames at the most. -The default is 8. +The default is 32. .IP \[bu] 2 \f[I]maxsamples=NUM\f[]: stop allocating reusable sample events once \f[I]NUM\f[] events have been allocated (a value of zero for @@ -274,10 +274,6 @@ with the \f[I]--maxframes=NUM\f[] option: The stack trace info will be available if method enter/leave events have been recorded or if stack trace collection wasn't explicitly disabled with the \f[I]maxframes=0\f[] profiler option. -Note that the profiler will collect up to 8 frames by default at -specific events when the \f[I]nocalls\f[] option is used, so in -that case, if more stack frames are required in mprof-report, a -bigger value for maxframes when profiling must be used, too. .PP The \f[I]--traces\f[] option also controls the reverse reference feature in the heapshot report: for each class it reports how many From 4199952108d135dcbcbd6e1b4a2e63a711155eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 11:33:31 +0200 Subject: [PATCH 10/50] [profiler] Remove the countersonly option. It was never documented and is no longer functional. --- mono/profiler/proflog.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c index a6c1cb1da73a..e36cf57648dd 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/proflog.c @@ -5123,7 +5123,6 @@ mono_profiler_startup (const char *desc) int fast_time = 0; int calls_enabled = 0; int allocs_enabled = 0; - int only_counters = 0; int only_coverage = 0; int events = MONO_PROFILE_GC|MONO_PROFILE_ALLOCATIONS| MONO_PROFILE_GC_MOVES|MONO_PROFILE_CLASS_EVENTS|MONO_PROFILE_THREADS| @@ -5254,10 +5253,6 @@ mono_profiler_startup (const char *desc) do_counters = 1; continue; } - if ((opt = match_option (p, "countersonly", NULL)) != p) { - only_counters = 1; - continue; - } if ((opt = match_option (p, "coverage", NULL)) != p) { do_coverage = 1; events |= MONO_PROFILE_ENTER_LEAVE; @@ -5310,8 +5305,6 @@ mono_profiler_startup (const char *desc) } if (allocs_enabled) events |= MONO_PROFILE_ALLOCATIONS; - if (only_counters) - events = 0; if (only_coverage) events = MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_INS_COVERAGE; @@ -5352,7 +5345,7 @@ mono_profiler_startup (const char *desc) if (do_coverage) mono_profiler_install_coverage_filter (coverage_filter); - if (do_mono_sample && sample_type == SAMPLE_CYCLES && sample_freq && !only_counters) { + if (do_mono_sample && sample_type == SAMPLE_CYCLES && sample_freq) { events |= MONO_PROFILE_STATISTICAL; mono_profiler_set_statistical_mode (sampling_mode, sample_freq); mono_profiler_install_statistical (mono_sample_hit); From 129560cb97131f9ce1326a6683a519707bd98585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 11:46:15 +0200 Subject: [PATCH 11/50] [profiler] Document and fix the onlycoverage option. --- man/mprof-report.1 | 4 ++++ mono/profiler/proflog.c | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/man/mprof-report.1 b/man/mprof-report.1 index cdc3c9a8f653..c9b756bd9905 100644 --- a/man/mprof-report.1 +++ b/man/mprof-report.1 @@ -244,6 +244,10 @@ Private Bytes, Virtual Bytes, Page Faults and CPU Load Average (1min, .IP \[bu] 2 \f[I]coverage\f[]: collect code coverage data. This implies enabling the \f[I]calls\f[] option. +.IP \[bu] 2 +\f[I]onlycoverage\f[]: can only be used with \f[I]coverage\f[]. This +disables most other events so that the profiler mostly only collects +coverage data. .RE .SS Analyzing the profile data .PP diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c index e36cf57648dd..39197205efaa 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/proflog.c @@ -5305,8 +5305,16 @@ mono_profiler_startup (const char *desc) } if (allocs_enabled) events |= MONO_PROFILE_ALLOCATIONS; - if (only_coverage) - events = MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_INS_COVERAGE; + + // Only activate the bare minimum events the profiler needs to function. + if (only_coverage) { + if (!do_coverage) { + fprintf (stderr, "The onlycoverage option is only valid when paired with the coverage option\n"); + exit (1); + } + + events = MONO_PROFILE_GC | MONO_PROFILE_THREADS | MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_INS_COVERAGE; + } utils_init (fast_time); From c4f5bc940289f124942a486018e8747d0405f92e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 12:12:27 +0200 Subject: [PATCH 12/50] [profiler] Remove the long-obsolete hsmode option. Also refactor the heap walk code a bit. --- mono/profiler/proflog.c | 51 +++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 32 deletions(-) diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c index 39197205efaa..6a860e051c6d 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/proflog.c @@ -636,7 +636,6 @@ struct _MonoProfiler { char *args; uint64_t startup_time; int pipe_output; - int last_gc_gen_started; int command_port; int server_socket; int pipes [2]; @@ -1353,30 +1352,11 @@ static unsigned int hs_mode_gc = 0; static unsigned int hs_mode_ondemand = 0; static unsigned int gc_count = 0; static uint64_t last_hs_time = 0; +static gboolean do_heap_walk = FALSE; static void heap_walk (MonoProfiler *profiler) { - if (!do_heap_shot) - return; - - gboolean do_walk = 0; - uint64_t now = current_time (); - - if (hs_mode_ms && (now - last_hs_time) / 1000000 >= hs_mode_ms) - do_walk = TRUE; - else if (hs_mode_gc && (gc_count % hs_mode_gc) == 0) - do_walk = TRUE; - else if (hs_mode_ondemand) - do_walk = heapshot_requested; - else if (!hs_mode_ms && !hs_mode_gc && profiler->last_gc_gen_started == mono_gc_max_generation ()) - do_walk = TRUE; - - if (!do_walk) - return; - - heapshot_requested = 0; - ENTER_LOG (&heap_starts_ctr, logbuffer, EVENT_SIZE /* event */ ); @@ -1394,8 +1374,6 @@ heap_walk (MonoProfiler *profiler) emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP); EXIT_LOG; - - last_hs_time = now; } static void @@ -1442,11 +1420,19 @@ gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) switch (ev) { case MONO_GC_EVENT_START: - /* to deal with nested gen1 after gen0 started */ - profiler->last_gc_gen_started = generation; - if (generation == mono_gc_max_generation ()) gc_count++; + + uint64_t now = current_time (); + + if (hs_mode_ms && (now - last_hs_time) / 1000 * 1000 >= hs_mode_ms) + do_heap_walk = TRUE; + else if (hs_mode_gc && !(gc_count % hs_mode_gc)) + do_heap_walk = TRUE; + else if (hs_mode_ondemand) + do_heap_walk = heapshot_requested; + else if (!hs_mode_ms && !hs_mode_gc && generation == mono_gc_max_generation ()) + do_heap_walk = TRUE; break; case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED: /* @@ -1466,7 +1452,13 @@ gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) sync_point (profiler, SYNC_POINT_WORLD_STOP); break; case MONO_GC_EVENT_PRE_START_WORLD: - heap_walk (profiler); + if (do_heap_shot && do_heap_walk) { + heap_walk (profiler); + + do_heap_walk = FALSE; + heapshot_requested = 0; + last_hs_time = current_time (); + } break; case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED: /* @@ -5207,11 +5199,6 @@ mono_profiler_startup (const char *desc) set_sample_mode (val, 1); continue; } - if ((opt = match_option (p, "hsmode", &val)) != p) { - fprintf (stderr, "The hsmode profiler option is obsolete, use heapshot=MODE.\n"); - set_hsmode (val, 0); - continue; - } if ((opt = match_option (p, "zip", NULL)) != p) { use_zip = 1; continue; From 39080bf5f086d61647b378858f993679867b2bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 12:26:04 +0200 Subject: [PATCH 13/50] [utils] Move MONO_DEPRECATED to mono-publib.h and make it imply MONO_API + MONO_RT_EXTERNAL_ONLY. Also make it work with MSVC. --- configure.ac | 14 -------------- mono/utils/mono-compiler.h | 6 ------ mono/utils/mono-publib.h | 9 +++++++++ 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/configure.ac b/configure.ac index 7700a3fa1e54..d79db4cadec8 100644 --- a/configure.ac +++ b/configure.ac @@ -1162,20 +1162,6 @@ AC_COMPILE_IFELSE([ AC_MSG_RESULT(no) ]) -AC_MSG_CHECKING(for deprecated __attribute__) -AC_TRY_COMPILE([ - int doit (void) __attribute__ ((deprecated)); - int doit (void) { return 0; } -], [ - return 0; -], [ - have_deprecated=yes - AC_MSG_RESULT(yes) -], [ - have_deprecated=no - AC_MSG_RESULT(no) -]) - dnl dnl Boehm GC configuration dnl diff --git a/mono/utils/mono-compiler.h b/mono/utils/mono-compiler.h index d03ba8051aa5..5c942e06fa2e 100644 --- a/mono/utils/mono-compiler.h +++ b/mono/utils/mono-compiler.h @@ -275,12 +275,6 @@ typedef SSIZE_T ssize_t; #define MONO_LLVM_INTERNAL #endif -#if HAVE_DEPRECATED -#define MONO_DEPRECATED __attribute__ ((deprecated)) -#else -#define MONO_DEPRECATED -#endif - #ifdef __GNUC__ #define MONO_ALWAYS_INLINE __attribute__((always_inline)) #elif defined(_MSC_VER) diff --git a/mono/utils/mono-publib.h b/mono/utils/mono-publib.h index 89d4fb68b759..e2614388ce96 100644 --- a/mono/utils/mono-publib.h +++ b/mono/utils/mono-publib.h @@ -116,6 +116,15 @@ mono_set_allocator_vtable (MonoAllocatorVTable* vtable); #define MONO_RT_EXTERNAL_ONLY #endif /* MONO_INSIDE_RUNTIME */ +#ifdef __GNUC__ +#define _MONO_DEPRECATED __attribute__ ((deprecated)) +#elif defined (_MSC_VER) +#define _MONO_DEPRECATED __declspec (deprecated) +#else +#define _MONO_DEPRECATED +#endif + +#define MONO_DEPRECATED MONO_API MONO_RT_EXTERNAL_ONLY _MONO_DEPRECATED MONO_END_DECLS From e9a95b9b3f730f6079ef145bc8eaaf7e0eae6c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 18:00:36 +0200 Subject: [PATCH 14/50] [sgen] Remove bogus mono_profiler_events assert. This variable can be changed at any time by any thread. It makes no sense to assert that it has a particular flag. --- mono/metadata/sgen-mono.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index 7966d8f6ab05..500e8114abd6 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -2056,8 +2056,6 @@ static int moved_objects_idx = 0; void mono_sgen_register_moved_object (void *obj, void *destination) { - g_assert (mono_profiler_events & MONO_PROFILE_GC_MOVES); - if (moved_objects_idx == MOVED_OBJECTS_NUM) { mono_profiler_gc_moves (moved_objects, moved_objects_idx); moved_objects_idx = 0; From 77bf968f69f672cce306bba8c056674454383a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 10 Sep 2016 12:22:58 +0200 Subject: [PATCH 15/50] [ci] Bump the timeout of the profiler stress test suite to 24 hours. --- scripts/ci/run-test-profiler-stress-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci/run-test-profiler-stress-tests.sh b/scripts/ci/run-test-profiler-stress-tests.sh index 52d6f1668003..05f5015611ec 100755 --- a/scripts/ci/run-test-profiler-stress-tests.sh +++ b/scripts/ci/run-test-profiler-stress-tests.sh @@ -2,4 +2,4 @@ export TESTCMD=`dirname "${BASH_SOURCE[0]}"`/run-step.sh -${TESTCMD} --label=check-profiler-stress --timeout=20h make -C acceptance-tests check-profiler-stress +${TESTCMD} --label=check-profiler-stress --timeout=24h make -C acceptance-tests check-profiler-stress From a2f06128c6bfed681a3b358ba04c0c978ab00a63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 10 Sep 2016 12:38:01 +0200 Subject: [PATCH 16/50] [acceptance-tests] Improve the profiler-stress test runner. * Emit an NUnit test report file. * Set a timeout of 6 hours per test. * Do a thread dump for timed-out tests. * Don't print stdout/stderr for passing tests. --- acceptance-tests/profiler-stress.mk | 3 +- acceptance-tests/profiler-stress/runner.cs | 204 +++++++++++++++++++-- 2 files changed, 189 insertions(+), 18 deletions(-) diff --git a/acceptance-tests/profiler-stress.mk b/acceptance-tests/profiler-stress.mk index 9188b174a954..ff67772a1d47 100644 --- a/acceptance-tests/profiler-stress.mk +++ b/acceptance-tests/profiler-stress.mk @@ -4,7 +4,8 @@ SYS_REFS = \ System.Data.dll \ System.Runtime.Serialization.dll \ System.Xml.dll \ - System.Xml.Linq.dll + System.Xml.Linq.dll \ + Mono.Posix.dll check-profiler-stress: @$(MAKE) validate-benchmarker RESET_VERSIONS=1 diff --git a/acceptance-tests/profiler-stress/runner.cs b/acceptance-tests/profiler-stress/runner.cs index b2638c1273a7..5ef4ab02a2eb 100644 --- a/acceptance-tests/profiler-stress/runner.cs +++ b/acceptance-tests/profiler-stress/runner.cs @@ -1,7 +1,14 @@ using System; +using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Xml; +using Mono.Unix.Native; using Newtonsoft.Json; // Shut up CLS compliance warnings from Json.NET. @@ -10,7 +17,8 @@ namespace Mono.Profiling.Tests.Stress { // https://github.com/xamarin/benchmarker/blob/master/tools/libdbmodel/Benchmark.cs - class Benchmark { + sealed class Benchmark { + public string Name { get; set; } public string TestDirectory { get; set; } public bool OnlyExplicit { get; set; } @@ -24,8 +32,24 @@ public static Benchmark Load (string file) } } + sealed class TestResult { + + public Benchmark Benchmark { get; set; } + public ProcessStartInfo StartInfo { get; set; } + public Stopwatch Stopwatch { get; set; } = new Stopwatch (); + public int? ExitCode { get; set; } + public StringBuilder StandardOutput { get; set; } = new StringBuilder (); + public StringBuilder StandardError { get; set; } = new StringBuilder (); + } + static class Program { + static readonly TimeSpan _timeout = TimeSpan.FromHours (6); + + static string FilterInvalidXmlChars (string text) { + return Regex.Replace (text, @"[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]", string.Empty); + } + static int Main () { var depDir = Path.Combine ("..", "external", "benchmarker"); @@ -44,8 +68,7 @@ static int Main () var rand = new Random (); var cpus = Environment.ProcessorCount; - var successes = 0; - var failures = 0; + var results = new List (benchmarks.Length); var sw = Stopwatch.StartNew (); @@ -66,6 +89,8 @@ static int Main () WorkingDirectory = Path.Combine (testDir, bench.TestDirectory), FileName = monoPath, Arguments = $"--debug --profile=log:{profOptions} " + string.Join (" ", bench.CommandLine), + RedirectStandardOutput = true, + RedirectStandardError = true, }; info.EnvironmentVariables.Clear (); @@ -77,32 +102,177 @@ static int Main () Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] {progress} Running {bench.Name} with profiler options: {profOptions}"); Console.ResetColor (); - var sw2 = Stopwatch.StartNew (); + var result = new TestResult { + Benchmark = bench, + StartInfo = info, + }; + + using (var proc = new Process ()) { + proc.StartInfo = info; + + proc.OutputDataReceived += (sender, args) => { + if (args.Data != null) + result.StandardOutput.AppendLine (args.Data); + }; + + proc.ErrorDataReceived += (sender, args) => { + if (args.Data != null) + result.StandardError.AppendLine (args.Data); + }; + + result.Stopwatch.Start (); - using (var proc = Process.Start (info)) { - proc.WaitForExit (); - sw2.Stop (); + proc.Start (); - Console.WriteLine (); + proc.BeginOutputReadLine (); + proc.BeginErrorReadLine (); - if (proc.ExitCode != 0) - failures++; - else - successes++; + if (!proc.WaitForExit ((int) _timeout.TotalMilliseconds)) { + // Force a thread dump. + Syscall.kill (proc.Id, Signum.SIGQUIT); + Thread.Sleep (1000); - Console.ForegroundColor = proc.ExitCode != 0 ? ConsoleColor.Red : ConsoleColor.Green; - Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] {progress} {bench.Name} took {sw2.Elapsed.ToString ("G")} and exited with code: {proc.ExitCode}"); + try { + proc.Kill (); + } catch (Exception) { + } + } else + result.ExitCode = proc.ExitCode; + + result.Stopwatch.Stop (); + } + + var resultStr = result.ExitCode == null ? "timed out" : $"exited with code: {result.ExitCode}"; + + Console.ForegroundColor = result.ExitCode != 0 ? ConsoleColor.Red : ConsoleColor.Green; + Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] {progress} {bench.Name} took {result.Stopwatch.Elapsed.ToString ("G")} and {resultStr}"); + Console.ResetColor (); + + if (result.ExitCode != 0) { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine ("===== stdout ====="); Console.ResetColor (); + + Console.WriteLine (result.StandardOutput.ToString ()); + + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine ("===== stderr ====="); + Console.ResetColor (); + + Console.WriteLine (result.StandardError.ToString ()); } + + results.Add (result); } sw.Stop (); - Console.ForegroundColor = failures != 0 ? ConsoleColor.Red : ConsoleColor.Green; - Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] Finished with {successes}/{benchmarks.Length} passing tests"); + var successes = results.Count (r => r.ExitCode == 0); + var failures = results.Count (r => r.ExitCode != null && r.ExitCode != 0); + var timeouts = results.Count (r => r.ExitCode == null); + + var settings = new XmlWriterSettings { + NewLineOnAttributes = true, + Indent = true, + }; + + using (var writer = XmlWriter.Create ("TestResult-profiler-stress.xml", settings)) { + writer.WriteStartDocument (); + writer.WriteComment ("This file represents the results of running a test suite"); + + writer.WriteStartElement ("test-results"); + writer.WriteAttributeString ("name", "profiler-stress-tests.dummy"); + writer.WriteAttributeString ("total", results.Count.ToString ()); + writer.WriteAttributeString ("failures", failures.ToString ()); + writer.WriteAttributeString ("not-run", "0"); + writer.WriteAttributeString ("date", DateTime.Now.ToString ("yyyy-MM-dd")); + writer.WriteAttributeString ("time", DateTime.Now.ToString ("HH:mm:ss")); + + writer.WriteStartElement ("environment"); + writer.WriteAttributeString ("nunit-version", "2.4.8.0"); + writer.WriteAttributeString ("clr-version", Environment.Version.ToString ()); + writer.WriteAttributeString ("os-version", Environment.OSVersion.ToString ()); + writer.WriteAttributeString ("platform", Environment.OSVersion.Platform.ToString ()); + writer.WriteAttributeString ("cwd", Environment.CurrentDirectory); + writer.WriteAttributeString ("machine-name", Environment.MachineName); + writer.WriteAttributeString ("user", Environment.UserName); + writer.WriteAttributeString ("user-domain", Environment.UserDomainName); + writer.WriteEndElement (); + + writer.WriteStartElement ("culture-info"); + writer.WriteAttributeString ("current-culture", CultureInfo.CurrentCulture.Name); + writer.WriteAttributeString ("current-uiculture", CultureInfo.CurrentUICulture.Name); + writer.WriteEndElement (); + + writer.WriteStartElement ("test-suite"); + writer.WriteAttributeString ("name", "profiler-stress-tests.dummy"); + writer.WriteAttributeString ("success", (failures + timeouts == 0).ToString ()); + writer.WriteAttributeString ("time", ((int) sw.Elapsed.TotalSeconds).ToString ()); + writer.WriteAttributeString ("asserts", (failures + timeouts).ToString ()); + writer.WriteStartElement ("results"); + + writer.WriteStartElement ("test-suite"); + writer.WriteAttributeString ("name", "MonoTests"); + writer.WriteAttributeString ("success", (failures + timeouts == 0).ToString ()); + writer.WriteAttributeString ("time", ((int) sw.Elapsed.TotalSeconds).ToString ()); + writer.WriteAttributeString ("asserts", (failures + timeouts).ToString ()); + writer.WriteStartElement ("results"); + + writer.WriteStartElement ("test-suite"); + writer.WriteAttributeString ("name", "profiler-stress"); + writer.WriteAttributeString ("success", (failures + timeouts == 0).ToString ()); + writer.WriteAttributeString ("time", ((int) sw.Elapsed.TotalSeconds).ToString ()); + writer.WriteAttributeString ("asserts", (failures + timeouts).ToString ()); + writer.WriteStartElement ("results"); + + foreach (var result in results) { + var timeoutStr = result.ExitCode == null ? "_timeout" : string.Empty; + + writer.WriteStartElement ("test-case"); + writer.WriteAttributeString ("name", $"MonoTests.profiler-stress.{result.Benchmark.Name}{timeoutStr}"); + writer.WriteAttributeString ("executed", "True"); + writer.WriteAttributeString ("success", (result.ExitCode == 0).ToString ()); + writer.WriteAttributeString ("time", ((int) result.Stopwatch.Elapsed.TotalSeconds).ToString ()); + writer.WriteAttributeString ("asserts", result.ExitCode == 0 ? "0" : "1"); + + if (result.ExitCode != 0) { + writer.WriteStartElement ("failure"); + + writer.WriteStartElement ("message"); + writer.WriteCData (FilterInvalidXmlChars (result.StandardOutput.ToString ())); + writer.WriteEndElement (); + + writer.WriteStartElement ("stack-trace"); + writer.WriteCData (FilterInvalidXmlChars (result.StandardError.ToString ())); + writer.WriteEndElement (); + + writer.WriteEndElement (); + } + + writer.WriteEndElement (); + } + + writer.WriteEndElement (); + writer.WriteEndElement (); + + writer.WriteEndElement (); + writer.WriteEndElement (); + + writer.WriteEndElement (); + writer.WriteEndElement (); + + writer.WriteEndElement (); + + writer.WriteEndDocument (); + } + + var failureStr = failures + timeouts != 0 ? $" ({failures} failures, {timeouts} timeouts)" : string.Empty; + + Console.ForegroundColor = failures + timeouts != 0 ? ConsoleColor.Red : ConsoleColor.Green; + Console.WriteLine ($"[{sw.Elapsed.ToString ("G")}] Finished with {successes}/{results.Count} passing tests{failureStr}"); Console.ResetColor (); - return failures; + return failures + timeouts; } } } From f1c948536d6f4b9025b8593dc3f285f3ccf84db6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Fri, 9 Sep 2016 18:50:56 +0200 Subject: [PATCH 17/50] [profiler] Remove utils.c/utils.h, move the code to proflog.c/decode.c, and clean it up. * Drop support for fast/null timers. * Use Mono runtime functions for getting the thread ID and allocating buffers. --- man/mprof-report.1 | 16 -- mono/profiler/Makefile.am | 5 +- mono/profiler/decode.c | 50 ++++- mono/profiler/proflog.c | 163 ++++++++++++++- mono/profiler/utils.c | 426 -------------------------------------- mono/profiler/utils.h | 24 --- 6 files changed, 204 insertions(+), 480 deletions(-) delete mode 100644 mono/profiler/utils.c delete mode 100644 mono/profiler/utils.h diff --git a/man/mprof-report.1 b/man/mprof-report.1 index c9b756bd9905..b96001d2c63c 100644 --- a/man/mprof-report.1 +++ b/man/mprof-report.1 @@ -164,13 +164,6 @@ In this case, \f[I]TYPE\f[] can be one of: \f[I]branchmiss\f[]: mispredicted branches .RE .IP \[bu] 2 -\f[I]time=TIMER\f[]: use the TIMER timestamp mode. -TIMER can have the following values: -.RS 2 -.IP \[bu] 2 -\f[I]fast\f[]: a usually faster but possibly more inaccurate timer -.RE -.IP \[bu] 2 \f[I]maxframes=NUM\f[]: when a stack trace needs to be performed, collect \f[I]NUM\f[] frames at the most. The default is 32. @@ -487,15 +480,6 @@ option: especially if the managed heap is big, since every object needs to be inspected. The \f[I]MODE\f[] parameter of the \f[I]heapshot\f[] option can be used to reduce the frequency of the heap shots. -.IP "\f[I]Reduce the timestamp overhead\f[]" 4 -.Sp -On many operating systems or architectures what actually slows down -profiling is the function provided by the system to get timestamp -information. -The \f[I]time=fast\f[] profiler option can be usually used to speed -up this operation, but, depending on the system, time accounting -may have some level of approximation (though statistically the data -should be still fairly valuable). .SS Dealing with the size of the data files .PP When collecting a lot of information about a profiled program, huge diff --git a/mono/profiler/Makefile.am b/mono/profiler/Makefile.am index 3d7eb62e4004..86ca6bdfd41a 100644 --- a/mono/profiler/Makefile.am +++ b/mono/profiler/Makefile.am @@ -110,6 +110,7 @@ testlog: $(PLOG_TESTS) check-local: $(check_targets) -EXTRA_DIST=utils.c utils.h proflog.h \ - $(PLOG_TESTS_SRC) ptestrunner.pl \ +EXTRA_DIST=proflog.h \ + $(PLOG_TESTS_SRC) \ + ptestrunner.pl \ $(suppression_DATA) diff --git a/mono/profiler/decode.c b/mono/profiler/decode.c index 338150494dd0..a80e01e201fb 100644 --- a/mono/profiler/decode.c +++ b/mono/profiler/decode.c @@ -54,11 +54,11 @@ * - column: The column on the line */ #include -#include "utils.c" #include "proflog.h" #include #include #include +#include #if !defined(__APPLE__) && !defined(__FreeBSD__) #include #endif @@ -1972,6 +1972,54 @@ get_root_name (int rtype) } } +static uint64_t +decode_uleb128 (uint8_t *buf, uint8_t **endbuf) +{ + uint64_t res = 0; + int shift = 0; + + while (1) { + uint8_t b = *buf++; + res |= (((uint64_t) (b & 0x7f)) << shift); + + if (!(b & 0x80)) + break; + + shift += 7; + } + + *endbuf = buf; + + return res; +} + +static intptr_t +decode_sleb128 (uint8_t *buf, uint8_t **endbuf) +{ + uint8_t *p = buf; + intptr_t res = 0; + int shift = 0; + + while (1) { + uint8_t b = *p; + p++; + + res = res | (((intptr_t) (b & 0x7f)) << shift); + shift += 7; + + if (!(b & 0x80)) { + if (shift < sizeof (intptr_t) * 8 && (b & 0x40)) + res |= - ((intptr_t) 1 << shift); + + break; + } + } + + *endbuf = p; + + return res; +} + static MethodDesc** decode_bt (ProfContext *ctx, MethodDesc** sframes, int *size, unsigned char *p, unsigned char **endp, intptr_t ptr_base, intptr_t *method_base) { diff --git a/mono/profiler/proflog.c b/mono/profiler/proflog.c index 6a860e051c6d..03e7e093efab 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/proflog.c @@ -48,6 +48,13 @@ #endif #include #include +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#if defined(__APPLE__) +#include +#endif #if defined(HOST_WIN32) || defined(DISABLE_SOCKETS) #define DISABLE_HELPER_THREAD 1 #endif @@ -82,7 +89,6 @@ #include #endif -#include "utils.c" #include "proflog.h" #if defined (HAVE_SYS_ZLIB) @@ -524,6 +530,82 @@ ign_res (int G_GNUC_UNUSED unused, ...) { } +static uintptr_t +thread_id (void) +{ + return (uintptr_t) mono_native_thread_id_get (); +} + +static uintptr_t +process_id (void) +{ +#ifdef HOST_WIN32 + return (uintptr_t) GetCurrentProcessId (); +#else + return (uintptr_t) getpid (); +#endif +} + +#ifdef __APPLE__ +static mach_timebase_info_data_t timebase_info; +#elif defined (HOST_WIN32) +static LARGE_INTEGER pcounter_freq; +#endif + +#define TICKS_PER_SEC 1000000000LL + +static uint64_t +current_time (void) +{ +#ifdef __APPLE__ + uint64_t time = mach_absolute_time (); + + time *= timebase_info.numer; + time /= timebase_info.denom; + + return time; +#elif defined (HOST_WIN32) + LARGE_INTEGER value; + + QueryPerformanceCounter (&value); + + return value.QuadPart * TICKS_PER_SEC / pcounter_freq.QuadPart; +#elif defined (CLOCK_MONOTONIC) + struct timespec tspec; + + clock_gettime (CLOCK_MONOTONIC, &tspec); + + return ((uint64_t) tspec.tv_sec * TICKS_PER_SEC + tspec.tv_nsec); +#else + struct timeval tv; + + gettimeofday (&tv, NULL); + + return ((uint64_t) tv.tv_sec * TICKS_PER_SEC + tv.tv_usec * 1000); +#endif +} + +static int timer_overhead; + +static void +init_time (void) +{ +#ifdef __APPLE__ + mach_timebase_info (&timebase_info); +#elif defined (HOST_WIN32) + QueryPerformanceFrequency (&pcounter_freq); +#endif + + uint64_t time_start = current_time (); + + for (int i = 0; i < 256; ++i) + current_time (); + + uint64_t time_end = current_time (); + + timer_overhead = (time_end - time_start) / 256; +} + /* * These macros create a scope to avoid leaking the buffer returned * from ensure_logbuf () as it may have been invalidated by a GC @@ -713,10 +795,22 @@ pstrdup (const char *s) return p; } +static void * +alloc_buffer (int size) +{ + return mono_valloc (NULL, size, MONO_MMAP_READ | MONO_MMAP_WRITE | MONO_MMAP_ANON | MONO_MMAP_PRIVATE, MONO_MEM_ACCOUNT_PROFILER); +} + +static void +free_buffer (void *buf, int size) +{ + mono_vfree (buf, size, MONO_MEM_ACCOUNT_PROFILER); +} + static LogBuffer* create_buffer (void) { - LogBuffer* buf = (LogBuffer *)alloc_buffer (BUFFER_SIZE); + LogBuffer* buf = (LogBuffer *) alloc_buffer (BUFFER_SIZE); InterlockedIncrement (&buffer_allocations_ctr); @@ -725,6 +819,7 @@ create_buffer (void) buf->last_time = buf->time_base; buf->buf_end = (unsigned char*)buf + buf->size; buf->cursor = buf->buf; + return buf; } @@ -820,6 +915,58 @@ ensure_logbuf_unsafe (int bytes) return new_; } +static void +encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf) +{ + uint8_t *p = buf; + + do { + uint8_t b = value & 0x7f; + value >>= 7; + + if (value != 0) /* more bytes to come */ + b |= 0x80; + + *p ++ = b; + } while (value); + + *endbuf = p; +} + +static void +encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf) +{ + int more = 1; + int negative = (value < 0); + unsigned int size = sizeof (intptr_t) * 8; + uint8_t byte; + uint8_t *p = buf; + + while (more) { + byte = value & 0x7f; + value >>= 7; + + /* the following is unnecessary if the + * implementation of >>= uses an arithmetic rather + * than logical shift for a signed left operand + */ + if (negative) + /* sign extend */ + value |= - ((intptr_t) 1 <<(size - 7)); + + /* sign bit of byte is second high order bit (0x40) */ + if ((value == 0 && !(byte & 0x40)) || + (value == -1 && (byte & 0x40))) + more = 0; + else + byte |= 0x80; + + *p ++= byte; + } + + *endbuf = p; +} + static void emit_byte (LogBuffer *logbuffer, int value) { @@ -1087,7 +1234,7 @@ dump_header (MonoProfiler *profiler) *p++ = LOG_DATA_VERSION; *p++ = sizeof (void *); p = write_int64 (p, ((uint64_t) time (NULL)) * 1000); - p = write_int32 (p, get_timer_overhead ()); + p = write_int32 (p, timer_overhead); p = write_int32 (p, 0); /* flags */ p = write_int32 (p, process_id ()); p = write_int16 (p, profiler->command_port); @@ -4946,7 +5093,6 @@ usage (int do_exit) printf ("\tsample[=TYPE] use statistical sampling mode (by default cycles/100)\n"); printf ("\t TYPE: cycles,instr,cacherefs,cachemiss,branches,branchmiss\n"); printf ("\t TYPE can be followed by /FREQUENCY\n"); - printf ("\ttime=fast use a faster (but more inaccurate) timer\n"); printf ("\tmaxframes=NUM collect up to NUM stack frames\n"); printf ("\tcalldepth=NUM ignore method events for call chain depth bigger than NUM\n"); printf ("\toutput=FILENAME write the data to file FILENAME (-FILENAME to overwrite)\n"); @@ -5112,7 +5258,6 @@ mono_profiler_startup (const char *desc) char *filename = NULL; const char *p; const char *opt; - int fast_time = 0; int calls_enabled = 0; int allocs_enabled = 0; int only_coverage = 0; @@ -5159,11 +5304,7 @@ mono_profiler_startup (const char *desc) continue; } if ((opt = match_option (p, "time", &val)) != p) { - if (strcmp (val, "fast") == 0) - fast_time = 1; - else if (strcmp (val, "null") == 0) - fast_time = 2; - else + if (strcmp (val, "fast") && strcmp (val, "null")) usage (1); g_free (val); continue; @@ -5303,7 +5444,7 @@ mono_profiler_startup (const char *desc) events = MONO_PROFILE_GC | MONO_PROFILE_THREADS | MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_INS_COVERAGE; } - utils_init (fast_time); + init_time (); PROF_TLS_INIT (); diff --git a/mono/profiler/utils.c b/mono/profiler/utils.c deleted file mode 100644 index cfa7589a6b2b..000000000000 --- a/mono/profiler/utils.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * utils.c: log profiler and reporter utils - * - * We have here the minimal needed portability functions: we can't depend - * on the ones provided by the runtime, since they are internal and, - * especially mprof-report is an external program. - * Note also that we don't take a glib/eglib dependency here for mostly - * the same reason (but also because we need tight control in the profiler - * over memory allocation, which needs to work with the world stopped). - * - * Author: - * Paolo Molaro (lupus@ximian.com) - * - * Copyright 2010 Novell, Inc (http://www.novell.com) - * Licensed under the MIT license. See LICENSE file in the project root for full license information. - */ -#include "utils.h" -#include -#include -#include -#include -#include -#ifdef HOST_WIN32 -#include -#else -#include -#include -#endif -#include - -#ifdef HAVE_SYS_TIME_H -#include -#endif -#if HAVE_SYS_MMAN_H -#include -#endif - -#if defined(__APPLE__) -#include -#include - -static mach_timebase_info_data_t timebase_info; -#endif - -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -#define TICKS_PER_SEC 1000000000LL - -#if (defined(TARGET_X86) || defined(TARGET_AMD64)) && defined(__linux__) && defined(HAVE_SCHED_GETCPU) -#define HAVE_RDTSC 1 -#endif - -typedef struct { - unsigned int timer_count; - int last_cpu; - uint64_t last_rdtsc; - uint64_t last_time; -} TlsData; - -#ifdef HOST_WIN32 -static int tls_data; -#define DECL_TLS_DATA TlsData *tls; tls = (TlsData *) TlsGetValue (tls_data); if (tls == NULL) { tls = (TlsData *) g_calloc (sizeof (TlsData), 1); TlsSetValue (tls_data, tls); } -#define TLS_INIT(x) x = TlsAlloc() -#elif HAVE_KW_THREAD -static __thread TlsData tls_data; -#define DECL_TLS_DATA TlsData *tls = &tls_data -#define TLS_INIT(x) -#else -static pthread_key_t tls_data; -#define DECL_TLS_DATA TlsData *tls; tls = (TlsData *) pthread_getspecific (tls_data); if (tls == NULL) { tls = (TlsData *) g_calloc (sizeof (TlsData), 1); pthread_setspecific (tls_data, tls); } -#define TLS_INIT(x) pthread_key_create(&x, NULL) -#endif - -#ifdef HOST_WIN32 -static CRITICAL_SECTION log_lock; -static LARGE_INTEGER pcounter_freq; -#else -static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER; -#endif - -static int timer_overhead = 0; -static uint64_t time_inc = 0; -typedef uint64_t (*TimeFunc)(void); - -static TimeFunc time_func; - -static uint64_t -clock_time (void) -{ -#if defined(__APPLE__) - uint64_t time = mach_absolute_time (); - - time *= timebase_info.numer; - time /= timebase_info.denom; - - return time; -#elif defined(HOST_WIN32) - LARGE_INTEGER value; - QueryPerformanceCounter (&value); - return value.QuadPart * TICKS_PER_SEC / pcounter_freq.QuadPart; -#elif defined(CLOCK_MONOTONIC) - struct timespec tspec; - clock_gettime (CLOCK_MONOTONIC, &tspec); - return ((uint64_t)tspec.tv_sec * TICKS_PER_SEC + tspec.tv_nsec); -#else - struct timeval tv; - gettimeofday (&tv, NULL); - return ((uint64_t)tv.tv_sec * TICKS_PER_SEC + tv.tv_usec * 1000); -#endif -} - -/* must be power of two */ -#define TIME_ADJ 8 - -static uint64_t -fast_current_time (void) -{ - DECL_TLS_DATA; - if (tls->timer_count++ & (TIME_ADJ - 1)) { - tls->last_time += time_inc; - return tls->last_time; - } - tls->last_time = clock_time (); - return tls->last_time; -} - -#if HAVE_RDTSC - -#define rdtsc(low,high) \ - __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) - -static uint64_t -safe_rdtsc (int *cpu) -{ - unsigned int low, high; - int c1 = sched_getcpu (); - int c2; - rdtsc (low, high); - c2 = sched_getcpu (); - if (c1 != c2) { - *cpu = -1; - return 0; - } - *cpu = c1; - return (((uint64_t) high) << 32) + (uint64_t)low; -} - -static double cpu_freq; - -static int -have_rdtsc (void) { - char buf[256]; - int have_freq = 0; - int have_flag = 0; - float val; - FILE *cpuinfo; - int cpu = sched_getcpu (); - - if (cpu < 0) - return 0; - - if (!(cpuinfo = fopen ("/proc/cpuinfo", "r"))) - return 0; - while (fgets (buf, sizeof(buf), cpuinfo)) { - if (sscanf (buf, "cpu MHz : %f", &val) == 1) { - /*printf ("got mh: %f\n", val);*/ - have_freq = 1; - cpu_freq = val * 1000000; - } - if (strncmp (buf, "flags :", 5) == 0) { - if (strstr (buf, "constant_tsc")) { - have_flag = 1; - /*printf ("have tsc\n");*/ - } - } - } - fclose (cpuinfo); - return have_flag? have_freq: 0; -} - -static uint64_t -rdtsc_current_time (void) -{ - DECL_TLS_DATA; - if (tls->timer_count++ & (TIME_ADJ*8 - 1)) { - int cpu; - uint64_t tsc = safe_rdtsc (&cpu); - if (cpu != -1 && cpu == tls->last_cpu) { - int64_t diff = tsc - tls->last_rdtsc; - uint64_t nsecs; - if (diff > 0) { - nsecs = (double)diff/cpu_freq; - //printf ("%llu cycles: %llu nsecs\n", diff, nsecs); - return tls->last_time + nsecs; - } else { - printf ("tsc went backwards\n"); - } - } else { - //printf ("wrong cpu: %d\n", cpu); - } - } - tls->last_time = clock_time (); - tls->last_rdtsc = safe_rdtsc (&tls->last_cpu); - return tls->last_time; -} -#else -#define have_rdtsc() 0 -#define rdtsc_current_time fast_current_time -#endif - -static uint64_t -null_time (void) -{ - static uint64_t timer = 0; - return timer++; -} - -void -utils_init (int fast_time) -{ - int i; - uint64_t time_start, time_end; - TLS_INIT (tls_data); -#ifdef HOST_WIN32 - InitializeCriticalSection (&log_lock); - QueryPerformanceFrequency (&pcounter_freq); -#endif -#if defined (__APPLE__) - mach_timebase_info (&timebase_info); -#endif - - if (fast_time > 1) { - time_func = null_time; - } else if (fast_time) { - uint64_t timea; - uint64_t timeb; - clock_time (); - timea = clock_time (); - timeb = clock_time (); - time_inc = (timeb - timea) / TIME_ADJ; - /*printf ("time inc: %llu, timea: %llu, timeb: %llu, diff: %llu\n", time_inc, timea, timeb, timec-timeb);*/ - if (have_rdtsc ()) - time_func = rdtsc_current_time; - else - time_func = fast_current_time; - } else { - time_func = clock_time; - } - time_start = time_func (); - for (i = 0; i < 256; ++i) - time_func (); - time_end = time_func (); - timer_overhead = (time_end - time_start) / 256; -} - -int -get_timer_overhead (void) -{ - return timer_overhead; -} - -uint64_t -current_time (void) -{ - return time_func (); -} - -void* -alloc_buffer (int size) -{ - void *ptr; -#ifdef HOST_WIN32 - ptr = VirtualAlloc (NULL, size, MEM_COMMIT, PAGE_READWRITE); - return ptr; -#else - ptr = mmap (NULL, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); - if (ptr == MAP_FAILED) - return NULL; - return ptr; -#endif -} - -void -free_buffer (void *buf, int size) -{ -#ifdef HOST_WIN32 - VirtualFree (buf, 0, MEM_RELEASE); -#else - munmap (buf, size); -#endif -} - -void -take_lock (void) -{ -#ifdef HOST_WIN32 - EnterCriticalSection (&log_lock); -#else - pthread_mutex_lock (&log_lock); -#endif -} - -void -release_lock (void) -{ -#ifdef HOST_WIN32 - LeaveCriticalSection (&log_lock); -#else - pthread_mutex_unlock (&log_lock); -#endif -} - -void -encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf) -{ - uint8_t *p = buf; - - do { - uint8_t b = value & 0x7f; - value >>= 7; - if (value != 0) /* more bytes to come */ - b |= 0x80; - *p ++ = b; - } while (value); - - *endbuf = p; -} - -void -encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf) -{ - int more = 1; - int negative = (value < 0); - unsigned int size = sizeof (intptr_t) * 8; - uint8_t byte; - uint8_t *p = buf; - - while (more) { - byte = value & 0x7f; - value >>= 7; - /* the following is unnecessary if the - * implementation of >>= uses an arithmetic rather - * than logical shift for a signed left operand - */ - if (negative) - /* sign extend */ - value |= - ((intptr_t)1 <<(size - 7)); - /* sign bit of byte is second high order bit (0x40) */ - if ((value == 0 && !(byte & 0x40)) || - (value == -1 && (byte & 0x40))) - more = 0; - else - byte |= 0x80; - *p ++= byte; - } - - *endbuf = p; -} - -uint64_t -decode_uleb128 (uint8_t *buf, uint8_t **endbuf) -{ - uint64_t res = 0; - int shift = 0; - - while (1) { - uint8_t b = *buf++; - - res |= (((uint64_t)(b & 0x7f)) << shift); - if (!(b & 0x80)) - break; - shift += 7; - } - - *endbuf = buf; - - return res; -} - -intptr_t -decode_sleb128 (uint8_t *buf, uint8_t **endbuf) -{ - uint8_t *p = buf; - intptr_t res = 0; - int shift = 0; - - while (1) { - uint8_t b = *p; - p ++; - - res = res | (((intptr_t)(b & 0x7f)) << shift); - shift += 7; - if (!(b & 0x80)) { - if (shift < sizeof (intptr_t) * 8 && (b & 0x40)) - res |= - ((intptr_t)1 << shift); - break; - } - } - - *endbuf = p; - - return res; -} - -uintptr_t -thread_id (void) -{ -#ifdef HOST_WIN32 - return (uintptr_t)GetCurrentThreadId (); -#else - return (uintptr_t)pthread_self (); -#endif -} - -uintptr_t -process_id (void) -{ -#ifdef HOST_WIN32 - return GetCurrentProcessId (); -#else - return (uintptr_t)getpid (); -#endif -} - diff --git a/mono/profiler/utils.h b/mono/profiler/utils.h deleted file mode 100644 index 3af56d202c6c..000000000000 --- a/mono/profiler/utils.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef __MONO_MPLOG_UTILS_H__ -#define __MONO_MPLOG_UTILS_H__ - -#include "config.h" -#include "mono/utils/mono-publib.h" - -void utils_init (int fast_time); -int get_timer_overhead (void); -uint64_t current_time (void); -void* alloc_buffer (int size); -void free_buffer (void *buf, int size); -void take_lock (void); -void release_lock (void); -uintptr_t thread_id (void); -uintptr_t process_id (void); - -void encode_uleb128 (uint64_t value, uint8_t *buf, uint8_t **endbuf); -void encode_sleb128 (intptr_t value, uint8_t *buf, uint8_t **endbuf); -uint64_t decode_uleb128 (uint8_t *buf, uint8_t **endbuf); -intptr_t decode_sleb128 (uint8_t *buf, uint8_t **endbuf); - - -#endif /* __MONO_MPLOG_UTILS_H__ */ - From 5640531d0bf496c61e0e8822de06683af5256b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 10 Sep 2016 07:15:50 +0200 Subject: [PATCH 18/50] [profiler] Rename proflog.{c,h} to mono-profiler-log.{c,h} for consistency with other profilers. --- mono/profiler/Makefile.am | 6 +++--- mono/profiler/decode.c | 2 +- mono/profiler/{proflog.c => mono-profiler-log.c} | 8 ++++---- mono/profiler/{proflog.h => mono-profiler-log.h} | 0 4 files changed, 8 insertions(+), 8 deletions(-) rename mono/profiler/{proflog.c => mono-profiler-log.c} (99%) rename mono/profiler/{proflog.h => mono-profiler-log.h} (100%) diff --git a/mono/profiler/Makefile.am b/mono/profiler/Makefile.am index 86ca6bdfd41a..a9e67ad6cbf8 100644 --- a/mono/profiler/Makefile.am +++ b/mono/profiler/Makefile.am @@ -73,10 +73,10 @@ libmono_profiler_iomap_la_LDFLAGS = $(prof_ldflags) libmono_profiler_iomap_static_la_SOURCES = mono-profiler-iomap.c libmono_profiler_iomap_static_la_LDFLAGS = -static -libmono_profiler_log_la_SOURCES = proflog.c +libmono_profiler_log_la_SOURCES = mono-profiler-log.c libmono_profiler_log_la_LIBADD = $(monodir)/mono/mini/$(LIBMONO_LA) $(GLIB_LIBS) $(Z_LIBS) libmono_profiler_log_la_LDFLAGS = $(prof_ldflags) -libmono_profiler_log_static_la_SOURCES = proflog.c +libmono_profiler_log_static_la_SOURCES = mono-profiler-log.c libmono_profiler_log_static_la_LDFLAGS = -static if HAVE_VTUNE @@ -110,7 +110,7 @@ testlog: $(PLOG_TESTS) check-local: $(check_targets) -EXTRA_DIST=proflog.h \ +EXTRA_DIST=mono-profiler-log.h \ $(PLOG_TESTS_SRC) \ ptestrunner.pl \ $(suppression_DATA) diff --git a/mono/profiler/decode.c b/mono/profiler/decode.c index a80e01e201fb..cb9ddbf36849 100644 --- a/mono/profiler/decode.c +++ b/mono/profiler/decode.c @@ -54,7 +54,7 @@ * - column: The column on the line */ #include -#include "proflog.h" +#include "mono-profiler-log.h" #include #include #include diff --git a/mono/profiler/proflog.c b/mono/profiler/mono-profiler-log.c similarity index 99% rename from mono/profiler/proflog.c rename to mono/profiler/mono-profiler-log.c index 03e7e093efab..091272e5f669 100644 --- a/mono/profiler/proflog.c +++ b/mono/profiler/mono-profiler-log.c @@ -1,5 +1,5 @@ /* - * proflog.c: mono log profiler + * mono-profiler-log.c: mono log profiler * * Authors: * Paolo Molaro (lupus@ximian.com) @@ -89,7 +89,7 @@ #include #endif -#include "proflog.h" +#include "mono-profiler-log.h" #if defined (HAVE_SYS_ZLIB) #include @@ -262,7 +262,7 @@ static MonoLinkedListSet profiler_thread_list; * [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 is one of the enum values in mono-profiler-log.h: TYPE_ALLOC, TYPE_GC, * TYPE_METADATA, TYPE_METHOD, TYPE_EXCEPTION, TYPE_MONITOR, TYPE_HEAP. * The extended info bits are interpreted based on type, see * each individual event description below. @@ -4539,7 +4539,7 @@ helper_thread (void* arg) if (errno == EINTR) continue; - g_warning ("Error in proflog server: %s", strerror (errno)); + g_warning ("Error in mono-profiler-log server: %s", strerror (errno)); return NULL; } diff --git a/mono/profiler/proflog.h b/mono/profiler/mono-profiler-log.h similarity index 100% rename from mono/profiler/proflog.h rename to mono/profiler/mono-profiler-log.h From bb1813cca6e36a20d33750a535bd03de8f254716 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 10 Sep 2016 07:22:25 +0200 Subject: [PATCH 19/50] [profiler] Rename decode.c to mprof-report.c. --- mono/profiler/Makefile.am | 2 +- mono/profiler/{decode.c => mprof-report.c} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename mono/profiler/{decode.c => mprof-report.c} (99%) diff --git a/mono/profiler/Makefile.am b/mono/profiler/Makefile.am index a9e67ad6cbf8..4f6c4acb204f 100644 --- a/mono/profiler/Makefile.am +++ b/mono/profiler/Makefile.am @@ -88,7 +88,7 @@ libmono_profiler_vtune_static_la_SOURCES = mono-profiler-vtune.c libmono_profiler_vtune_static_la_LDFLAGS = -static endif -mprof_report_SOURCES = decode.c +mprof_report_SOURCES = mprof-report.c mprof_report_LDADD = $(Z_LIBS) $(GLIB_LIBS) $(LIBICONV) PLOG_TESTS_SRC=test-alloc.cs test-busy.cs test-monitor.cs test-excleave.cs \ diff --git a/mono/profiler/decode.c b/mono/profiler/mprof-report.c similarity index 99% rename from mono/profiler/decode.c rename to mono/profiler/mprof-report.c index cb9ddbf36849..7be6dcb54918 100644 --- a/mono/profiler/decode.c +++ b/mono/profiler/mprof-report.c @@ -1,5 +1,5 @@ /* - * decode.c: mprof-report program source: decode and analyze the log profiler data + * mprof-report.c: mprof-report program source: decode and analyze the log profiler data * * Authors: * Paolo Molaro (lupus@ximian.com) From 4acc3dfeedb4087a99179cd64b59419c931a6c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 10 Sep 2016 23:09:48 +0200 Subject: [PATCH 20/50] [sgen] Always report object moves on the GC thread. This avoids exposing the SGen worker threads through the profiler APIs. Doing so had two main problems: * It's easy for a user of the profiler API to accidentally mess with the state of the worker thread in all sorts of ways, which could break the GC. * It's been a long-standing guarantee that any profiler API callback will be invoked on a thread that is, at the very least, attached to the runtime via the mono-threads infrastructure. This is not the case for SGen workers. This fixes a deadlock in the log profiler when using major=marksweep-conc. --- mono/metadata/sgen-client-mono.h | 1 + mono/metadata/sgen-mono.c | 40 ++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/mono/metadata/sgen-client-mono.h b/mono/metadata/sgen-client-mono.h index 332ed1df8f69..eee26b706018 100644 --- a/mono/metadata/sgen-client-mono.h +++ b/mono/metadata/sgen-client-mono.h @@ -84,6 +84,7 @@ extern void mono_sgen_init_stw (void); enum { INTERNAL_MEM_EPHEMERON_LINK = INTERNAL_MEM_FIRST_CLIENT, + INTERNAL_MEM_MOVED_OBJECT, INTERNAL_MEM_MAX }; diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index 500e8114abd6..725a7eccc638 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -16,6 +16,7 @@ #include "sgen/sgen-client.h" #include "sgen/sgen-cardtable.h" #include "sgen/sgen-pinning.h" +#include "sgen/sgen-thread-pool.h" #include "metadata/marshal.h" #include "metadata/method-builder.h" #include "metadata/abi-details.h" @@ -2053,20 +2054,45 @@ sgen_client_collecting_major_3 (SgenPointerQueue *fin_ready_queue, SgenPointerQu static void *moved_objects [MOVED_OBJECTS_NUM]; static int moved_objects_idx = 0; +static SgenPointerQueue moved_objects_queue = SGEN_POINTER_QUEUE_INIT (INTERNAL_MEM_MOVED_OBJECT); + void mono_sgen_register_moved_object (void *obj, void *destination) { - if (moved_objects_idx == MOVED_OBJECTS_NUM) { - mono_profiler_gc_moves (moved_objects, moved_objects_idx); - moved_objects_idx = 0; + /* + * This function can be called from SGen's worker threads. We want to try + * and avoid exposing those threads to the profiler API, so queue up move + * events and send them later when the main GC thread calls + * mono_sgen_gc_event_moves (). + * + * TODO: Once SGen has multiple worker threads, we need to switch to a + * lock-free data structure for the queue as multiple threads will be + * adding to it at the same time. + */ + if (sgen_thread_pool_is_thread_pool_thread (mono_native_thread_id_get ())) { + sgen_pointer_queue_add (&moved_objects_queue, obj); + sgen_pointer_queue_add (&moved_objects_queue, destination); + } else { + if (moved_objects_idx == MOVED_OBJECTS_NUM) { + mono_profiler_gc_moves (moved_objects, moved_objects_idx); + moved_objects_idx = 0; + } + + moved_objects [moved_objects_idx++] = obj; + moved_objects [moved_objects_idx++] = destination; } - moved_objects [moved_objects_idx++] = obj; - moved_objects [moved_objects_idx++] = destination; } void mono_sgen_gc_event_moves (void) { + while (!sgen_pointer_queue_is_empty (&moved_objects_queue)) { + void *dst = sgen_pointer_queue_pop (&moved_objects_queue); + void *src = sgen_pointer_queue_pop (&moved_objects_queue); + + mono_sgen_register_moved_object (src, dst); + } + if (moved_objects_idx) { mono_profiler_gc_moves (moved_objects, moved_objects_idx); moved_objects_idx = 0; @@ -2773,6 +2799,7 @@ sgen_client_description_for_internal_mem_type (int type) { switch (type) { case INTERNAL_MEM_EPHEMERON_LINK: return "ephemeron-link"; + case INTERNAL_MEM_MOVED_OBJECT: return "moved-object"; default: return NULL; } @@ -2987,6 +3014,9 @@ void mono_gc_base_cleanup (void) { sgen_thread_pool_shutdown (); + + // We should have consumed any outstanding moves. + g_assert (sgen_pointer_queue_is_empty (&moved_objects_queue)); } gboolean From 348688ad75b0474399bc84e02ae1480ae49e1021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 10:43:38 +0200 Subject: [PATCH 21/50] [profiler] Add an extra assert. --- mono/profiler/mono-profiler-log.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 091272e5f669..0785378f04bf 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -512,6 +512,9 @@ struct _LogBuffer { typedef struct { MonoLinkedListSetNode node; + // Was this thread added to the LLS? + gboolean attached; + // The current log buffer for this thread. LogBuffer *buffer; @@ -823,6 +826,12 @@ create_buffer (void) 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) { @@ -859,6 +868,7 @@ init_thread (gboolean add_to_lls) thread = malloc (sizeof (MonoProfilerThread)); thread->node.key = thread_id (); + thread->attached = add_to_lls; thread->call_depth = 0; thread->busy = 0; @@ -883,6 +893,8 @@ init_thread (gboolean add_to_lls) static void deinit_thread (MonoProfilerThread *thread) { + g_assert (!thread->attached && "Why are we manually freeing an attached thread?"); + free (thread); PROF_TLS_SET (NULL); } @@ -1255,6 +1267,12 @@ dump_header (MonoProfiler *profiler) 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) { From 4533cd91b27686c4e453323ce90fb432db33a790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 10:44:00 +0200 Subject: [PATCH 22/50] [profiler] Don't flush empty log buffers. --- mono/profiler/mono-profiler-log.c | 32 ++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 0785378f04bf..87bf160c10a9 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -1337,24 +1337,26 @@ dump_buffer (MonoProfiler *profiler, LogBuffer *buf) 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); From 51a03a73134b3b2f1c1d216e306616305814cfec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 10:44:34 +0200 Subject: [PATCH 23/50] [profiler] Fix several race conditions in accessing MonoProfilerThread.buffer. Only in very few situations is it okay to access this field without first taking the reader lock or exclusive lock. Fixes some crashes observed in the profiler stress tests. --- mono/profiler/mono-profiler-log.c | 103 +++++++++++++++--------------- 1 file changed, 50 insertions(+), 53 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 87bf160c10a9..0ad70cf9ba55 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -1378,52 +1378,48 @@ process_requests (MonoProfiler *profiler) mono_gc_collect (mono_gc_max_generation ()); } +// Avoid calling this directly. Use the functions below. static void -safe_send (MonoProfiler *profiler) +safe_send (MonoProfiler *profiler, gboolean if_needed, gboolean threadless) { - /* 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); + if (!if_needed || (if_needed && thread->buffer->next)) { + if (threadless) + for (LogBuffer *iter = thread->buffer; iter; iter = iter->next) + iter->thread_id = 0; + + send_buffer (profiler, thread); + init_buffer_state (thread); + } buffer_unlock (); } static void -send_if_needed (MonoProfiler *prof) +send_log (MonoProfiler *prof) { - if (PROF_TLS_GET ()->buffer->next) - safe_send (prof); + safe_send (prof, FALSE, FALSE); } static void -safe_send_threadless (MonoProfiler *prof) +send_log_if_needed (MonoProfiler *prof) { - LogBuffer *buf = PROF_TLS_GET ()->buffer; - - for (LogBuffer *iter = buf; iter; iter = iter->next) - iter->thread_id = 0; + safe_send (prof, TRUE, FALSE); +} - safe_send (prof); +static void +send_log_threadless (MonoProfiler *prof) +{ + safe_send (prof, FALSE, TRUE); } static void -send_if_needed_threadless (MonoProfiler *prof) +send_log_if_needed_threadless (MonoProfiler *prof) { - if (PROF_TLS_GET ()->buffer->next) - safe_send_threadless (prof); + safe_send (prof, TRUE, TRUE); } // Assumes that the exclusive lock is held. @@ -1456,11 +1452,12 @@ sync_point_mark (MonoProfiler *prof, MonoProfilerSyncPointType type) switch (type) { case SYNC_POINT_PERIODIC: - safe_send_threadless (prof); + // This is done from the helper thread. + send_log_threadless (prof); break; case SYNC_POINT_WORLD_STOP: case SYNC_POINT_WORLD_START: - safe_send (prof); + send_log (prof); break; default: g_assert_not_reached (); @@ -1752,7 +1749,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -1944,7 +1941,7 @@ image_loaded (MonoProfiler *prof, MonoImage *image, int result) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -1970,7 +1967,7 @@ image_unloaded (MonoProfiler *prof, MonoImage *image) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2001,7 +1998,7 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly, int result) mono_free (name); - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2029,7 +2026,7 @@ assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly) mono_free (name); - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2072,7 +2069,7 @@ class_loaded (MonoProfiler *prof, MonoClass *klass, int result) else g_free (name); - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2112,7 +2109,7 @@ class_unloaded (MonoProfiler *prof, MonoClass *klass) else g_free (name); - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2140,7 +2137,7 @@ method_enter (MonoProfiler *prof, MonoMethod *method) EXIT_LOG; } - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2160,7 +2157,7 @@ method_leave (MonoProfiler *prof, MonoMethod *method) EXIT_LOG; } - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2180,7 +2177,7 @@ method_exc_leave (MonoProfiler *prof, MonoMethod *method) EXIT_LOG; } - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2351,7 +2348,7 @@ thread_start (MonoProfiler *prof, uintptr_t tid) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2396,7 +2393,7 @@ thread_name (MonoProfiler *prof, uintptr_t tid, const char *name) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2419,7 +2416,7 @@ domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2439,7 +2436,7 @@ domain_unloaded (MonoProfiler *prof, MonoDomain *domain) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2464,7 +2461,7 @@ domain_name (MonoProfiler *prof, MonoDomain *domain, const char *name) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2486,7 +2483,7 @@ context_loaded (MonoProfiler *prof, MonoAppContext *context) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -2508,7 +2505,7 @@ context_unloaded (MonoProfiler *prof, MonoAppContext *context) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); process_requests (prof); } @@ -3836,7 +3833,7 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); for (i = 0; i < coverage_data->len; i++) { CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[i]; @@ -3859,7 +3856,7 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); } method_id++; @@ -3926,7 +3923,7 @@ build_class_buffer (gpointer key, gpointer value, gpointer userdata) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); g_free (class_name); } @@ -3986,7 +3983,7 @@ build_assembly_buffer (gpointer key, gpointer value, gpointer userdata) EXIT_LOG; - send_if_needed (prof); + send_log_if_needed (prof); } static void @@ -4579,7 +4576,7 @@ helper_thread (void* arg) } } #endif - safe_send_threadless (prof); + send_log_threadless (prof); return NULL; } #if USE_PERF_EVENTS @@ -4590,7 +4587,7 @@ helper_thread (void* arg) continue; if (FD_ISSET (perf_data [i].perf_fd, &rfds)) { read_perf_mmap (prof, i); - send_if_needed_threadless (prof); + send_log_if_needed_threadless (prof); } } } @@ -4869,7 +4866,7 @@ handle_dumper_queue_entry (MonoProfiler *prof) dump_unmanaged_coderefs (prof); - send_if_needed_threadless (prof); + send_log_if_needed_threadless (prof); } return FALSE; @@ -4893,7 +4890,7 @@ dumper_thread (void *arg) /* Drain any remaining entries on shutdown. */ while (handle_dumper_queue_entry (prof)); - safe_send_threadless (prof); + send_log_threadless (prof); deinit_thread (thread); mono_thread_info_detach (); @@ -4987,7 +4984,7 @@ runtime_initialized (MonoProfiler *profiler) #endif /* ensure the main thread data and startup are available soon */ - safe_send (profiler); + send_log (profiler); } static MonoProfiler* From f802cbb584eba916d8cb0dbab36b03542b5cdfe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 12:27:21 +0200 Subject: [PATCH 24/50] [profiler] Add a missing deinit_thread () call to the helper thread. --- mono/profiler/mono-profiler-log.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 0ad70cf9ba55..95f5cdc09062 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -4508,7 +4508,7 @@ 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 (FALSE); //fprintf (stderr, "Server listening\n"); command_socket = -1; @@ -4618,6 +4618,8 @@ helper_thread (void* arg) //fprintf (stderr, "Accepted connection\n"); } + deinit_thread (thread); + mono_thread_info_detach (); return NULL; From 99aa56a5b1c7a4f54c074fa57d9b66f05c0119c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 12:27:39 +0200 Subject: [PATCH 25/50] [profiler] Encapsulate some common logic in the ENTER_LOG/EXIT_LOG macros. This also has the nice effect of reducing the amount of times we attempt to take the reader lock. Now we take it and release it once for a single event. --- mono/profiler/mono-profiler-log.c | 324 ++++++++++-------------------- 1 file changed, 102 insertions(+), 222 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 95f5cdc09062..cb2117cb5926 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -525,7 +525,7 @@ typedef struct { int call_depth; // Indicates whether this thread is currently writing to its `buffer`. - int busy; + gboolean busy; } MonoProfilerThread; static inline void @@ -618,16 +618,26 @@ init_time (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(PROFILER, SEND, REQUESTS) \ + thread__->busy = FALSE; \ + if ((SEND)) \ + send_log_unsafe ((PROFILER), FALSE, TRUE); \ + if (thread__->attached) \ + buffer_unlock (); \ + if ((REQUESTS)) \ + process_requests ((PROFILER)); \ } while (0) +#define EXIT_LOG(PROFILER) EXIT_LOG_EXPLICIT ((PROFILER), TRUE, TRUE) + static volatile gint32 buffer_rwlock_count; static volatile gpointer buffer_rwlock_exclusive; @@ -1378,16 +1388,17 @@ process_requests (MonoProfiler *profiler) mono_gc_collect (mono_gc_max_generation ()); } -// Avoid calling this directly. Use the functions below. +// Avoid calling this directly if possible. Use the functions below. static void -safe_send (MonoProfiler *profiler, gboolean if_needed, gboolean threadless) +send_log_unsafe (MonoProfiler *profiler, gboolean lock, gboolean if_needed) { MonoProfilerThread *thread = PROF_TLS_GET (); - buffer_lock (); + if (lock) + buffer_lock (); if (!if_needed || (if_needed && thread->buffer->next)) { - if (threadless) + if (!thread->attached) for (LogBuffer *iter = thread->buffer; iter; iter = iter->next) iter->thread_id = 0; @@ -1395,31 +1406,8 @@ safe_send (MonoProfiler *profiler, gboolean if_needed, gboolean threadless) init_buffer_state (thread); } - buffer_unlock (); -} - -static void -send_log (MonoProfiler *prof) -{ - safe_send (prof, FALSE, FALSE); -} - -static void -send_log_if_needed (MonoProfiler *prof) -{ - safe_send (prof, TRUE, FALSE); -} - -static void -send_log_threadless (MonoProfiler *prof) -{ - safe_send (prof, FALSE, TRUE); -} - -static void -send_log_if_needed_threadless (MonoProfiler *prof) -{ - safe_send (prof, TRUE, TRUE); + if (lock) + buffer_unlock (); } // Assumes that the exclusive lock is held. @@ -1448,21 +1436,9 @@ sync_point_mark (MonoProfiler *prof, MonoProfilerSyncPointType type) emit_event (logbuffer, TYPE_META | TYPE_SYNC_POINT); emit_byte (logbuffer, type); - EXIT_LOG; + EXIT_LOG_EXPLICIT (prof, FALSE, FALSE); - switch (type) { - case SYNC_POINT_PERIODIC: - // This is done from the helper thread. - send_log_threadless (prof); - break; - case SYNC_POINT_WORLD_STOP: - case SYNC_POINT_WORLD_START: - send_log (prof); - break; - default: - g_assert_not_reached (); - break; - } + send_log_unsafe (prof, FALSE, FALSE); } // Assumes that the exclusive lock is held. @@ -1476,6 +1452,8 @@ sync_point (MonoProfiler *prof, MonoProfilerSyncPointType type) static int gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, MonoObject **refs, uintptr_t *offsets, void *data) { + MonoProfiler *prof = data; + /* account for object alignment in the heap */ size += 7; size &= ~7; @@ -1506,7 +1484,7 @@ gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, emit_obj (logbuffer, refs [i]); } - EXIT_LOG; + EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); return 0; } @@ -1527,9 +1505,9 @@ heap_walk (MonoProfiler *profiler) emit_event (logbuffer, TYPE_HEAP_START | TYPE_HEAP); - EXIT_LOG; + EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); - mono_gc_walk_heap (0, gc_reference, NULL); + mono_gc_walk_heap (0, gc_reference, profiler); ENTER_LOG (&heap_ends_ctr, logbuffer, EVENT_SIZE /* event */ @@ -1537,7 +1515,7 @@ heap_walk (MonoProfiler *profiler) emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP); - EXIT_LOG; + EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); } static void @@ -1564,7 +1542,7 @@ gc_roots (MonoProfiler *prof, int num, void **objects, int *root_types, uintptr_ emit_value (logbuffer, extra_info [i]); } - EXIT_LOG; + EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); } static void @@ -1580,7 +1558,7 @@ gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) emit_byte (logbuffer, ev); emit_byte (logbuffer, generation); - EXIT_LOG; + EXIT_LOG_EXPLICIT (profiler, FALSE, FALSE); switch (ev) { case MONO_GC_EVENT_START: @@ -1655,7 +1633,7 @@ gc_resize (MonoProfiler *profiler, int64_t new_size) emit_event (logbuffer, TYPE_GC_RESIZE | TYPE_GC); emit_value (logbuffer, new_size); - EXIT_LOG; + EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); } // If you alter MAX_FRAMES, you may need to alter SAMPLE_BLOCK_SIZE too. @@ -1747,11 +1725,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass) if (do_bt) emit_bt (prof, logbuffer, &data); - EXIT_LOG; - - send_log_if_needed (prof); - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -1771,7 +1745,7 @@ gc_moves (MonoProfiler *prof, void **objects, int num) for (int i = 0; i < num; ++i) emit_obj (logbuffer, objects [i]); - EXIT_LOG; + EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); } static void @@ -1816,9 +1790,7 @@ gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *o if (do_bt) emit_bt (prof, logbuffer, &data); - EXIT_LOG; - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -1830,9 +1802,7 @@ finalize_begin (MonoProfiler *prof) emit_event (buf, TYPE_GC_FINALIZE_START | TYPE_GC); - EXIT_LOG; - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -1844,9 +1814,7 @@ finalize_end (MonoProfiler *prof) emit_event (buf, TYPE_GC_FINALIZE_END | TYPE_GC); - EXIT_LOG; - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -1860,9 +1828,7 @@ finalize_object_begin (MonoProfiler *prof, MonoObject *obj) emit_event (buf, TYPE_GC_FINALIZE_OBJECT_START | TYPE_GC); emit_obj (buf, obj); - EXIT_LOG; - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -1876,9 +1842,7 @@ finalize_object_end (MonoProfiler *prof, MonoObject *obj) emit_event (buf, TYPE_GC_FINALIZE_OBJECT_END | TYPE_GC); emit_obj (buf, obj); - EXIT_LOG; - - process_requests (prof); + EXIT_LOG (prof); } static char* @@ -1939,11 +1903,7 @@ image_loaded (MonoProfiler *prof, MonoImage *image, int result) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG; - - send_log_if_needed (prof); - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -1965,11 +1925,7 @@ image_unloaded (MonoProfiler *prof, MonoImage *image) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG; - - send_log_if_needed (prof); - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -1994,13 +1950,9 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly, int result) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG; + EXIT_LOG (prof); mono_free (name); - - send_log_if_needed (prof); - - process_requests (prof); } static void @@ -2022,13 +1974,9 @@ assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG; + EXIT_LOG (prof); mono_free (name); - - send_log_if_needed (prof); - - process_requests (prof); } static void @@ -2062,16 +2010,12 @@ class_loaded (MonoProfiler *prof, MonoClass *klass, int result) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG; + EXIT_LOG (prof); if (runtime_inited) mono_free (name); else g_free (name); - - send_log_if_needed (prof); - - process_requests (prof); } static void @@ -2102,16 +2046,12 @@ class_unloaded (MonoProfiler *prof, MonoClass *klass) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG; + EXIT_LOG (prof); if (runtime_inited) mono_free (name); else g_free (name); - - send_log_if_needed (prof); - - process_requests (prof); } #ifndef DISABLE_HELPER_THREAD @@ -2134,12 +2074,8 @@ method_enter (MonoProfiler *prof, MonoMethod *method) emit_event (logbuffer, TYPE_ENTER | TYPE_METHOD); emit_method (prof, logbuffer, method); - EXIT_LOG; + EXIT_LOG (prof); } - - send_log_if_needed (prof); - - process_requests (prof); } static void @@ -2154,12 +2090,8 @@ method_leave (MonoProfiler *prof, MonoMethod *method) emit_event (logbuffer, TYPE_LEAVE | TYPE_METHOD); emit_method (prof, logbuffer, method); - EXIT_LOG; + EXIT_LOG (prof); } - - send_log_if_needed (prof); - - process_requests (prof); } static void @@ -2174,12 +2106,8 @@ method_exc_leave (MonoProfiler *prof, MonoMethod *method) emit_event (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD); emit_method (prof, logbuffer, method); - EXIT_LOG; + EXIT_LOG (prof); } - - send_log_if_needed (prof); - - process_requests (prof); } static void @@ -2189,8 +2117,6 @@ method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji, int resu return; register_method_local (prof, method, ji); - - process_requests (prof); } static void @@ -2227,9 +2153,7 @@ code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBuf logbuffer->cursor += nlen; } - EXIT_LOG; - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -2258,9 +2182,7 @@ throw_exc (MonoProfiler *prof, MonoObject *object) if (do_bt) emit_bt (prof, logbuffer, &data); - EXIT_LOG; - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -2278,9 +2200,7 @@ clause_exc (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_ emit_value (logbuffer, clause_num); emit_method (prof, logbuffer, method); - EXIT_LOG; - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -2326,9 +2246,7 @@ monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEv if (do_bt) emit_bt (profiler, logbuffer, &data); - EXIT_LOG; - - process_requests (profiler); + EXIT_LOG (profiler); } static void @@ -2346,11 +2264,7 @@ thread_start (MonoProfiler *prof, uintptr_t tid) emit_byte (logbuffer, TYPE_THREAD); emit_ptr (logbuffer, (void*) tid); - EXIT_LOG; - - send_log_if_needed (prof); - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -2366,9 +2280,7 @@ thread_end (MonoProfiler *prof, uintptr_t tid) emit_byte (logbuffer, TYPE_THREAD); emit_ptr (logbuffer, (void*) tid); - EXIT_LOG; - - // Don't process requests as the thread is detached from the runtime. + EXIT_LOG_EXPLICIT (prof, FALSE, FALSE); remove_thread (prof, PROF_TLS_GET (), TRUE); } @@ -2391,11 +2303,7 @@ thread_name (MonoProfiler *prof, uintptr_t tid, const char *name) memcpy (logbuffer->cursor, name, len); logbuffer->cursor += len; - EXIT_LOG; - - send_log_if_needed (prof); - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -2414,11 +2322,7 @@ domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result) emit_byte (logbuffer, TYPE_DOMAIN); emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain)); - EXIT_LOG; - - send_log_if_needed (prof); - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -2434,11 +2338,7 @@ domain_unloaded (MonoProfiler *prof, MonoDomain *domain) emit_byte (logbuffer, TYPE_DOMAIN); emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain)); - EXIT_LOG; - - send_log_if_needed (prof); - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -2459,11 +2359,7 @@ domain_name (MonoProfiler *prof, MonoDomain *domain, const char *name) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG; - - send_log_if_needed (prof); - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -2481,11 +2377,7 @@ context_loaded (MonoProfiler *prof, MonoAppContext *context) emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context)); emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context)); - EXIT_LOG; - - send_log_if_needed (prof); - - process_requests (prof); + EXIT_LOG (prof); } static void @@ -2503,11 +2395,7 @@ context_unloaded (MonoProfiler *prof, MonoAppContext *context) emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context)); emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context)); - EXIT_LOG; - - send_log_if_needed (prof); - - process_requests (prof); + EXIT_LOG (prof); } typedef struct { @@ -2665,7 +2553,7 @@ add_code_pointer (uintptr_t ip) //#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; @@ -2684,12 +2572,12 @@ dump_ubin (const char *filename, uintptr_t load_addr, uint64_t offset, uintptr_t memcpy (logbuffer->cursor, filename, len); logbuffer->cursor += len; - EXIT_LOG; + EXIT_LOG_EXPLICIT (prof, 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; @@ -2706,7 +2594,7 @@ dump_usym (const char *name, uintptr_t value, uintptr_t size) memcpy (logbuffer->cursor, name, len); logbuffer->cursor += len; - EXIT_LOG; + EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); } /* ELF code crashes on some systems. */ @@ -2725,7 +2613,7 @@ dump_usym (const char *name, uintptr_t value, uintptr_t size) #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) { @@ -2848,7 +2736,7 @@ elf_dl_callback (struct dl_phdr_info *info, size_t size, void *data) 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); } @@ -2873,7 +2761,7 @@ elf_dl_callback (struct dl_phdr_info *info, size_t size, void *data) 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; } @@ -2939,7 +2827,7 @@ dump_unmanaged_coderefs (MonoProfiler *prof) 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); } } @@ -3102,6 +2990,8 @@ dump_perf_hits (MonoProfiler *prof, void *buf, int size) 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 */ + @@ -3129,7 +3019,7 @@ dump_perf_hits (MonoProfiler *prof, void *buf, int size) /* no support here yet for the managed backtrace */ emit_uvalue (logbuffer, mbt_count); - EXIT_LOG; + EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); add_code_pointer (s->ip); buf = (char*)buf + s->h.size; @@ -3370,7 +3260,7 @@ counters_emit (MonoProfiler *profiler) agent->emitted = 1; } - EXIT_LOG; + EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); done: mono_os_mutex_unlock (&counters_mutex); @@ -3495,7 +3385,7 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp) emit_value (logbuffer, 0); - EXIT_LOG; + EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); mono_os_mutex_unlock (&counters_mutex); } @@ -3565,7 +3455,7 @@ perfcounters_emit (MonoProfiler *profiler) pcagent->emitted = 1; } - EXIT_LOG; + EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); } static gboolean @@ -3658,7 +3548,7 @@ perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp) emit_value (logbuffer, 0); - EXIT_LOG; + EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); done: mono_os_mutex_unlock (&counters_mutex); @@ -3831,9 +3721,7 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata) emit_uvalue (logbuffer, method_id); emit_value (logbuffer, coverage_data->len); - EXIT_LOG; - - send_log_if_needed (prof); + EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); for (i = 0; i < coverage_data->len; i++) { CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[i]; @@ -3854,9 +3742,7 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata) emit_uvalue (logbuffer, entry->line); emit_uvalue (logbuffer, entry->column); - EXIT_LOG; - - send_log_if_needed (prof); + EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); } method_id++; @@ -3921,9 +3807,7 @@ build_class_buffer (gpointer key, gpointer value, gpointer userdata) emit_uvalue (logbuffer, fully_covered); emit_uvalue (logbuffer, partially_covered); - EXIT_LOG; - - send_log_if_needed (prof); + EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); g_free (class_name); } @@ -3981,9 +3865,7 @@ build_assembly_buffer (gpointer key, gpointer value, gpointer userdata) emit_uvalue (logbuffer, fully_covered); emit_uvalue (logbuffer, partially_covered); - EXIT_LOG; - - send_log_if_needed (prof); + EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); } static void @@ -4576,7 +4458,7 @@ helper_thread (void* arg) } } #endif - send_log_threadless (prof); + send_log_unsafe (prof, FALSE, FALSE); return NULL; } #if USE_PERF_EVENTS @@ -4585,10 +4467,8 @@ helper_thread (void* arg) 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_log_if_needed_threadless (prof); - } } } #endif @@ -4684,7 +4564,7 @@ handle_writer_queue_entry (MonoProfiler *prof) if (!entry->methods) goto no_methods; - LogBuffer *buf = NULL; + gboolean wrote_methods = FALSE; /* * Encode the method events in a temporary log buffer that we @@ -4722,9 +4602,7 @@ handle_writer_queue_entry (MonoProfiler *prof) 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 */ + @@ -4732,24 +4610,28 @@ handle_writer_queue_entry (MonoProfiler *prof) 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 (buf->cursor, name, nlen); - buf->cursor += nlen; + memcpy (logbuffer->cursor, name, nlen); + logbuffer->cursor += nlen; + + EXIT_LOG_EXPLICIT (prof, 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 ()); } @@ -4831,9 +4713,7 @@ handle_dumper_queue_entry (MonoProfiler *prof) } } - InterlockedIncrement (&sample_hits_ctr); - - LogBuffer *logbuffer = ensure_logbuf_unsafe ( + ENTER_LOG (&sample_hits_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + LEB128_SIZE /* tid */ + @@ -4864,11 +4744,11 @@ handle_dumper_queue_entry (MonoProfiler *prof) for (int i = 0; i < sample->count; ++i) emit_method (prof, logbuffer, sample->frames [i].method); + EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + mono_thread_hazardous_try_free (sample, reuse_sample_hit); dump_unmanaged_coderefs (prof); - - send_log_if_needed_threadless (prof); } return FALSE; @@ -4892,7 +4772,7 @@ dumper_thread (void *arg) /* Drain any remaining entries on shutdown. */ while (handle_dumper_queue_entry (prof)); - send_log_threadless (prof); + send_log_unsafe (prof, FALSE, FALSE); deinit_thread (thread); mono_thread_info_detach (); @@ -4986,7 +4866,7 @@ runtime_initialized (MonoProfiler *profiler) #endif /* ensure the main thread data and startup are available soon */ - send_log (profiler); + send_log_unsafe (profiler, TRUE, FALSE); } static MonoProfiler* From d4374ae1c342fc5b1c6d76538a95469c1a940d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 12:49:10 +0200 Subject: [PATCH 26/50] [profiler] Always enable the helper thread. We need it in all cases now that we use it to periodically flush all buffers. The only platforms it was disabled on was NaCl, which we haven't bothered to support in a while anyway. --- mono/profiler/mono-profiler-log.c | 138 +++++++++++++----------------- 1 file changed, 58 insertions(+), 80 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index cb2117cb5926..36e661853e4a 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -55,9 +55,6 @@ #if defined(__APPLE__) #include #endif -#if defined(HOST_WIN32) || defined(DISABLE_SOCKETS) -#define DISABLE_HELPER_THREAD 1 -#endif #ifndef _GNU_SOURCE #define _GNU_SOURCE @@ -72,12 +69,10 @@ #include #endif -#ifndef DISABLE_HELPER_THREAD #include #include #include #include -#endif #ifdef HOST_WIN32 #include @@ -126,7 +121,6 @@ static int do_report = 0; 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; @@ -2054,16 +2048,12 @@ class_unloaded (MonoProfiler *prof, MonoClass *klass) g_free (name); } -#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, @@ -3133,8 +3123,6 @@ setup_perf_event (void) #endif /* USE_PERF_EVENTS */ -#ifndef DISABLE_HELPER_THREAD - typedef struct MonoCounterAgent { MonoCounter *counter; // MonoCounterAgent specific data : @@ -4160,12 +4148,9 @@ init_suppressed_assemblies (void) fclose (sa_file); } -#endif /* DISABLE_HELPER_THREAD */ - static void coverage_init (MonoProfiler *prof) { -#ifndef DISABLE_HELPER_THREAD assert (!coverage_initialized); COVERAGE_DEBUG(fprintf (stderr, "Coverage initialized\n");) @@ -4180,7 +4165,6 @@ coverage_init (MonoProfiler *prof) init_suppressed_assemblies (); coverage_initialized = TRUE; -#endif /* DISABLE_HELPER_THREAD */ } static void @@ -4211,16 +4195,14 @@ log_shutdown (MonoProfiler *prof) 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; + ign_res (write (prof->pipes [1], &c, 1)); + pthread_join (prof->helper_thread, &res); mono_os_mutex_destroy (&counters_mutex); @@ -4237,7 +4219,7 @@ log_shutdown (MonoProfiler *prof) pc_next = cur->next; g_free (cur); } -#endif + #if USE_PERF_EVENTS if (perf_data) { int i; @@ -4377,8 +4359,6 @@ new_filename (const char* filename) //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) { @@ -4505,49 +4485,58 @@ helper_thread (void* arg) 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) @@ -4674,12 +4663,17 @@ writer_thread (void *arg) 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 @@ -4780,12 +4774,17 @@ dumper_thread (void *arg) 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 @@ -4856,17 +4855,9 @@ runtime_initialized (MonoProfiler *profiler) 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 */ - send_log_unsafe (profiler, TRUE, FALSE); + start_helper_thread (profiler); } static MonoProfiler* @@ -4914,24 +4905,20 @@ create_profiler (const char *args, const char *filename, GPtrArray *filters) 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 @@ -4945,15 +4932,6 @@ create_profiler (const char *args, const char *filename, GPtrArray *filters) 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. From 2a45034926e5f97099f6904f562694ef80e837ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 13:06:54 +0200 Subject: [PATCH 27/50] [profiler] assert () -> g_assert (). --- mono/profiler/mono-profiler-log.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 36e661853e4a..ecef98e652d7 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -988,14 +988,14 @@ emit_byte (LogBuffer *logbuffer, int value) { logbuffer->cursor [0] = value; logbuffer->cursor++; - assert (logbuffer->cursor <= logbuffer->buf_end); + g_assert (logbuffer->cursor <= logbuffer->buf_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); } static void @@ -1010,7 +1010,7 @@ emit_time (LogBuffer *logbuffer, uint64_t value) /*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); } static void @@ -1030,14 +1030,14 @@ 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); } 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); } static void @@ -1046,7 +1046,7 @@ 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); + g_assert (logbuffer->cursor <= logbuffer->buf_end); } static void @@ -1058,7 +1058,7 @@ emit_method_inner (LogBuffer *logbuffer, void *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); + g_assert (logbuffer->cursor <= logbuffer->buf_end); } /* @@ -1145,7 +1145,7 @@ 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); + g_assert (logbuffer->cursor <= logbuffer->buf_end); } static void @@ -3358,7 +3358,7 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp) } break; default: - assert (0); + g_assert_not_reached (); } if (type == MONO_COUNTER_STRING && size > agent->value_size) { @@ -4151,7 +4151,7 @@ init_suppressed_assemblies (void) static void coverage_init (MonoProfiler *prof) { - assert (!coverage_initialized); + g_assert (!coverage_initialized); COVERAGE_DEBUG(fprintf (stderr, "Coverage initialized\n");) From 9f7349c7c19a7e1addf554818a9d371863ce8274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 13:51:45 +0200 Subject: [PATCH 28/50] [profiler] Remove some broken, commented-out code from register_method_local (). --- mono/profiler/mono-profiler-log.c | 55 ------------------------------- 1 file changed, 55 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index ecef98e652d7..7d3311491d07 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -1061,65 +1061,10 @@ emit_method_inner (LogBuffer *logbuffer, void *method) g_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); - } - - if (ji) - search->found = ji; -} -*/ - static void register_method_local (MonoProfiler *prof, 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); - MethodInfo *info = (MethodInfo *) malloc (sizeof (MethodInfo)); info->method = method; From b73e63c5dc9917f6996034d57765820371421406 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 13:58:25 +0200 Subject: [PATCH 29/50] [profiler] Remove mono_threads_attach_tools_thread () declaration. We get this from mono-threads.h now. --- mono/profiler/mono-profiler-log.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 7d3311491d07..c614c6752ede 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -4301,9 +4301,6 @@ new_filename (const char* filename) 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); - static void* helper_thread (void* arg) { From 82f2c9bccacde08c86f43df4a55dde0ad22e223c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 14:15:16 +0200 Subject: [PATCH 30/50] [profiler] Clean up the #include mess in mono-profiler-log.c. Half of these aren't even needed - get rid of those. Sort the rest. --- mono/profiler/mono-profiler-log.c | 81 ++++++++----------------------- 1 file changed, 20 insertions(+), 61 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index c614c6752ede..3e663cc1c66b 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -11,97 +11,56 @@ */ #include -#include "../mini/jit.h" -#include "../metadata/metadata-internals.h" -#include -#include +#include #include +#include "../metadata/metadata-internals.h" #include #include #include -#include -#include -#include -#include +#include #include +#include +#include +#include +#include +#include +#include #include #include -#include #include #include -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_SCHED_GETAFFINITY -#include -#endif -#include -#include -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#if defined(__APPLE__) -#include -#endif +#include "mono-profiler-log.h" -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif #ifdef HAVE_DLFCN_H #include #endif -#ifdef HAVE_EXECINFO_H -#include -#endif #ifdef HAVE_LINK_H #include #endif - -#include -#include -#include -#include - -#ifdef HOST_WIN32 -#include -#else -#include +#ifdef HAVE_UNISTD_H +#include #endif - -#ifdef HAVE_SYS_STAT_H -#include +#if defined(__APPLE__) +#include #endif - -#include "mono-profiler-log.h" - +#include +#ifdef HAVE_SYS_MMAN_H +#include +#endif +#include #if defined (HAVE_SYS_ZLIB) #include #endif -#if defined(__linux__) +#if defined(__linux__) && defined (ENABLE_PERF_EVENTS) -#include -#include - -#ifdef ENABLE_PERF_EVENTS #include #define USE_PERF_EVENTS 1 static int read_perf_mmap (MonoProfiler* prof, int cpu); -#endif #endif From f9ad9d913c2a60a354db2a901fb35a0fc0979e94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 14:31:16 +0200 Subject: [PATCH 31/50] [profiler] Remove the ign_res () hack. --- mono/profiler/mono-profiler-log.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 3e663cc1c66b..94b5b2f4de74 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -481,11 +481,6 @@ typedef struct { gboolean busy; } MonoProfilerThread; -static inline void -ign_res (int G_GNUC_UNUSED unused, ...) -{ -} - static uintptr_t thread_id (void) { @@ -2379,14 +2374,6 @@ mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context) 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); } @@ -4105,7 +4092,12 @@ log_shutdown (MonoProfiler *prof) dump_coverage (prof); char c = 1; - ign_res (write (prof->pipes [1], &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); From 96f9415c5b663456204803f0f6f70b2808b5aaf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 14:44:01 +0200 Subject: [PATCH 32/50] [profiler] Add messages to most assertions. --- mono/profiler/mono-profiler-log.c | 51 +++++++++++++++++-------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 94b5b2f4de74..efba296c7dc8 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -942,29 +942,26 @@ emit_byte (LogBuffer *logbuffer, int value) { logbuffer->cursor [0] = value; logbuffer->cursor++; - g_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); - g_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; - g_assert (logbuffer->cursor <= logbuffer->buf_end); + + g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?"); } static void @@ -984,35 +981,41 @@ static void emit_svalue (LogBuffer *logbuffer, int64_t value) { encode_sleb128 (value, logbuffer->cursor, &logbuffer->cursor); - g_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); - g_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); - g_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; - g_assert (logbuffer->cursor <= logbuffer->buf_end); + + encode_sleb128 ((intptr_t) ((char *) method - (char *) logbuffer->last_method), logbuffer->cursor, &logbuffer->cursor); + logbuffer->last_method = (intptr_t) method; + + g_assert (logbuffer->cursor <= logbuffer->buf_end && "Why are we writing past the buffer end?"); } static void @@ -1042,9 +1045,11 @@ static void 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); - g_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 @@ -4042,7 +4047,7 @@ init_suppressed_assemblies (void) static void coverage_init (MonoProfiler *prof) { - g_assert (!coverage_initialized); + g_assert (!coverage_initialized && "Why are we initializing coverage twice?"); COVERAGE_DEBUG(fprintf (stderr, "Coverage initialized\n");) From 99af8b644bb7ecd5fb624a11d51cb487d2cf8e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 14:48:51 +0200 Subject: [PATCH 33/50] [profiler] Replace a check with an assert in coverage_filter (). --- mono/profiler/mono-profiler-log.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index efba296c7dc8..48904d2b9d0b 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -3814,8 +3814,7 @@ coverage_filter (MonoProfiler *prof, MonoMethod *method) 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));) From 1e4e265ba528519aa1c95c0779ea7e3479423609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 15:35:24 +0200 Subject: [PATCH 34/50] [profiler] Fix the way the profiler frees hazardous data on shutdown. --- mono/profiler/mono-profiler-log.c | 105 ++++++++++++++++++------------ 1 file changed, 64 insertions(+), 41 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 48904d2b9d0b..f6c6a4be3498 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -465,6 +465,9 @@ struct _LogBuffer { typedef struct { MonoLinkedListSetNode node; + // Convenience pointer to the profiler structure. + MonoProfiler *profiler; + // Was this thread added to the LLS? gboolean attached; @@ -479,6 +482,9 @@ typedef struct { // Indicates whether this thread is currently writing to its `buffer`. gboolean busy; + + // Has this thread written a thread end event to `buffer`? + gboolean ended; } MonoProfilerThread; static uintptr_t @@ -806,7 +812,7 @@ clear_hazard_pointers (MonoThreadHazardPointers *hp) } static MonoProfilerThread * -init_thread (gboolean add_to_lls) +init_thread (MonoProfiler *prof, gboolean add_to_lls) { MonoProfilerThread *thread = PROF_TLS_GET (); @@ -826,9 +832,11 @@ init_thread (gboolean add_to_lls) 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); @@ -1195,45 +1203,44 @@ send_buffer (MonoProfiler *prof, MonoProfilerThread *thread) } 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->profiler, thread); - send_buffer (prof, thread); + free (thread); +} - mono_thread_hazardous_try_free (thread, free); - } +static void +remove_thread (MonoProfilerThread *thread) +{ + MonoThreadHazardPointers *hp = mono_hazard_pointer_get (); - clear_hazard_pointers (hp); + if (mono_lls_remove (&profiler_thread_list, hp, &thread->node)) + mono_thread_hazardous_try_free (thread, free_thread); - if (from_callback) - PROF_TLS_SET (NULL); + clear_hazard_pointers (hp); } static void @@ -1590,7 +1597,7 @@ emit_bt (MonoProfiler *prof, LogBuffer *logbuffer, FrameData *data) 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; @@ -2146,7 +2153,7 @@ monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEv 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 */ + @@ -2176,7 +2183,12 @@ thread_end (MonoProfiler *prof, uintptr_t tid) EXIT_LOG_EXPLICIT (prof, FALSE, FALSE); - remove_thread (prof, PROF_TLS_GET (), TRUE); + MonoProfilerThread *thread = PROF_TLS_GET (); + + thread->ended = TRUE; + remove_thread (thread); + + PROF_TLS_SET (NULL); } static void @@ -4135,10 +4147,16 @@ log_shutdown (MonoProfiler *prof) */ 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); @@ -4149,14 +4167,19 @@ log_shutdown (MonoProfiler *prof) 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 (); @@ -4267,7 +4290,7 @@ helper_thread (void* arg) mono_threads_attach_tools_thread (); mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler helper"); - MonoProfilerThread *thread = init_thread (FALSE); + MonoProfilerThread *thread = init_thread (prof, FALSE); //fprintf (stderr, "Server listening\n"); command_socket = -1; @@ -4542,7 +4565,7 @@ writer_thread (void *arg) 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); @@ -4653,7 +4676,7 @@ dumper_thread (void *arg) 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); @@ -5230,7 +5253,7 @@ mono_profiler_startup (const char *desc) 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); From a22f5779d2b9850e227c3153296f2e2378a1a719 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 15:53:37 +0200 Subject: [PATCH 35/50] [profiler] Remove the need to pass a MonoProfiler argument to some functions. This is now available on the MonoProfilerThread structure. --- mono/profiler/mono-profiler-log.c | 181 +++++++++++++++--------------- 1 file changed, 90 insertions(+), 91 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index f6c6a4be3498..78dbc8c91611 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -580,17 +580,17 @@ init_time (void) InterlockedIncrement ((COUNTER)); \ LogBuffer *BUFFER = ensure_logbuf_unsafe ((SIZE)) -#define EXIT_LOG_EXPLICIT(PROFILER, SEND, REQUESTS) \ +#define EXIT_LOG_EXPLICIT(SEND, REQUESTS) \ thread__->busy = FALSE; \ if ((SEND)) \ - send_log_unsafe ((PROFILER), FALSE, TRUE); \ + send_log_unsafe (FALSE, TRUE); \ if (thread__->attached) \ buffer_unlock (); \ if ((REQUESTS)) \ - process_requests ((PROFILER)); \ + process_requests (); \ } while (0) -#define EXIT_LOG(PROFILER) EXIT_LOG_EXPLICIT ((PROFILER), TRUE, TRUE) +#define EXIT_LOG EXIT_LOG_EXPLICIT (TRUE, TRUE) static volatile gint32 buffer_rwlock_count; static volatile gpointer buffer_rwlock_exclusive; @@ -1027,25 +1027,26 @@ emit_method_inner (LogBuffer *logbuffer, void *method) } 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)) { + 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); } @@ -1190,16 +1191,16 @@ dump_header (MonoProfiler *profiler) * 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 @@ -1227,7 +1228,7 @@ free_thread (gpointer p) emit_ptr (thread->buffer, (void *) thread->node.key); } - send_buffer (thread->profiler, thread); + send_buffer (thread); free (thread); } @@ -1287,7 +1288,7 @@ dump_buffer_threadless (MonoProfiler *profiler, LogBuffer *buf) } static void -process_requests (MonoProfiler *profiler) +process_requests (void) { if (heapshot_requested) mono_gc_collect (mono_gc_max_generation ()); @@ -1295,7 +1296,7 @@ process_requests (MonoProfiler *profiler) // Avoid calling this directly if possible. Use the functions below. static void -send_log_unsafe (MonoProfiler *profiler, gboolean lock, gboolean if_needed) +send_log_unsafe (gboolean lock, gboolean if_needed) { MonoProfilerThread *thread = PROF_TLS_GET (); @@ -1307,7 +1308,7 @@ send_log_unsafe (MonoProfiler *profiler, gboolean lock, gboolean if_needed) for (LogBuffer *iter = thread->buffer; iter; iter = iter->next) iter->thread_id = 0; - send_buffer (profiler, thread); + send_buffer (thread); init_buffer_state (thread); } @@ -1317,19 +1318,19 @@ send_log_unsafe (MonoProfiler *profiler, gboolean lock, gboolean if_needed) // 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?"); @@ -1341,24 +1342,22 @@ sync_point_mark (MonoProfiler *prof, MonoProfilerSyncPointType type) emit_event (logbuffer, TYPE_META | TYPE_SYNC_POINT); emit_byte (logbuffer, type); - EXIT_LOG_EXPLICIT (prof, FALSE, FALSE); + EXIT_LOG_EXPLICIT (FALSE, FALSE); - send_log_unsafe (prof, FALSE, FALSE); + 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 gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, MonoObject **refs, uintptr_t *offsets, void *data) { - MonoProfiler *prof = data; - /* account for object alignment in the heap */ size += 7; size &= ~7; @@ -1389,7 +1388,7 @@ gc_reference (MonoObject *obj, MonoClass *klass, uintptr_t size, uintptr_t num, emit_obj (logbuffer, refs [i]); } - EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); return 0; } @@ -1410,9 +1409,9 @@ heap_walk (MonoProfiler *profiler) emit_event (logbuffer, TYPE_HEAP_START | TYPE_HEAP); - EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); - mono_gc_walk_heap (0, gc_reference, profiler); + mono_gc_walk_heap (0, gc_reference, NULL); ENTER_LOG (&heap_ends_ctr, logbuffer, EVENT_SIZE /* event */ @@ -1420,7 +1419,7 @@ heap_walk (MonoProfiler *profiler) emit_event (logbuffer, TYPE_HEAP_END | TYPE_HEAP); - EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); } static void @@ -1447,7 +1446,7 @@ gc_roots (MonoProfiler *prof, int num, void **objects, int *root_types, uintptr_ emit_value (logbuffer, extra_info [i]); } - EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); } static void @@ -1463,7 +1462,7 @@ gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) emit_byte (logbuffer, ev); emit_byte (logbuffer, generation); - EXIT_LOG_EXPLICIT (profiler, FALSE, FALSE); + EXIT_LOG_EXPLICIT (FALSE, FALSE); switch (ev) { case MONO_GC_EVENT_START: @@ -1496,7 +1495,7 @@ gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) * 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) { @@ -1514,7 +1513,7 @@ gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) * 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 @@ -1538,7 +1537,7 @@ gc_resize (MonoProfiler *profiler, int64_t new_size) emit_event (logbuffer, TYPE_GC_RESIZE | TYPE_GC); emit_value (logbuffer, new_size); - EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); } // If you alter MAX_FRAMES, you may need to alter SAMPLE_BLOCK_SIZE too. @@ -1590,7 +1589,7 @@ emit_bt (MonoProfiler *prof, LogBuffer *logbuffer, FrameData *data) //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]); } } @@ -1630,7 +1629,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass) if (do_bt) emit_bt (prof, logbuffer, &data); - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -1650,7 +1649,7 @@ gc_moves (MonoProfiler *prof, void **objects, int num) for (int i = 0; i < num; ++i) emit_obj (logbuffer, objects [i]); - EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); } static void @@ -1695,7 +1694,7 @@ gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *o if (do_bt) emit_bt (prof, logbuffer, &data); - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -1707,7 +1706,7 @@ finalize_begin (MonoProfiler *prof) emit_event (buf, TYPE_GC_FINALIZE_START | TYPE_GC); - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -1719,7 +1718,7 @@ finalize_end (MonoProfiler *prof) emit_event (buf, TYPE_GC_FINALIZE_END | TYPE_GC); - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -1733,7 +1732,7 @@ finalize_object_begin (MonoProfiler *prof, MonoObject *obj) emit_event (buf, TYPE_GC_FINALIZE_OBJECT_START | TYPE_GC); emit_obj (buf, obj); - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -1747,7 +1746,7 @@ finalize_object_end (MonoProfiler *prof, MonoObject *obj) emit_event (buf, TYPE_GC_FINALIZE_OBJECT_END | TYPE_GC); emit_obj (buf, obj); - EXIT_LOG (prof); + EXIT_LOG; } static char* @@ -1808,7 +1807,7 @@ image_loaded (MonoProfiler *prof, MonoImage *image, int result) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -1830,7 +1829,7 @@ image_unloaded (MonoProfiler *prof, MonoImage *image) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -1855,7 +1854,7 @@ assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly, int result) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG (prof); + EXIT_LOG; mono_free (name); } @@ -1879,7 +1878,7 @@ assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG (prof); + EXIT_LOG; mono_free (name); } @@ -1915,7 +1914,7 @@ class_loaded (MonoProfiler *prof, MonoClass *klass, int result) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG (prof); + EXIT_LOG; if (runtime_inited) mono_free (name); @@ -1951,7 +1950,7 @@ class_unloaded (MonoProfiler *prof, MonoClass *klass) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG (prof); + EXIT_LOG; if (runtime_inited) mono_free (name); @@ -1973,9 +1972,9 @@ method_enter (MonoProfiler *prof, MonoMethod *method) ); emit_event (logbuffer, TYPE_ENTER | TYPE_METHOD); - emit_method (prof, logbuffer, method); + emit_method (logbuffer, method); - EXIT_LOG (prof); + EXIT_LOG; } } @@ -1989,9 +1988,9 @@ method_leave (MonoProfiler *prof, MonoMethod *method) ); emit_event (logbuffer, TYPE_LEAVE | TYPE_METHOD); - emit_method (prof, logbuffer, method); + emit_method (logbuffer, method); - EXIT_LOG (prof); + EXIT_LOG; } } @@ -2005,9 +2004,9 @@ method_exc_leave (MonoProfiler *prof, MonoMethod *method) ); emit_event (logbuffer, TYPE_EXC_LEAVE | TYPE_METHOD); - emit_method (prof, logbuffer, method); + emit_method (logbuffer, method); - EXIT_LOG (prof); + EXIT_LOG; } } @@ -2017,7 +2016,7 @@ method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji, int resu if (result != MONO_PROFILE_OK) return; - register_method_local (prof, method, ji); + register_method_local (method, ji); } static void @@ -2054,7 +2053,7 @@ code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBuf logbuffer->cursor += nlen; } - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -2083,7 +2082,7 @@ throw_exc (MonoProfiler *prof, MonoObject *object) if (do_bt) emit_bt (prof, logbuffer, &data); - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -2099,9 +2098,9 @@ clause_exc (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_ 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 (prof); + EXIT_LOG; } static void @@ -2147,7 +2146,7 @@ monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEv if (do_bt) emit_bt (profiler, logbuffer, &data); - EXIT_LOG (profiler); + EXIT_LOG; } static void @@ -2165,7 +2164,7 @@ thread_start (MonoProfiler *prof, uintptr_t tid) emit_byte (logbuffer, TYPE_THREAD); emit_ptr (logbuffer, (void*) tid); - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -2181,7 +2180,7 @@ thread_end (MonoProfiler *prof, uintptr_t tid) emit_byte (logbuffer, TYPE_THREAD); emit_ptr (logbuffer, (void*) tid); - EXIT_LOG_EXPLICIT (prof, FALSE, FALSE); + EXIT_LOG_EXPLICIT (FALSE, FALSE); MonoProfilerThread *thread = PROF_TLS_GET (); @@ -2209,7 +2208,7 @@ thread_name (MonoProfiler *prof, uintptr_t tid, const char *name) memcpy (logbuffer->cursor, name, len); logbuffer->cursor += len; - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -2228,7 +2227,7 @@ domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result) emit_byte (logbuffer, TYPE_DOMAIN); emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain)); - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -2244,7 +2243,7 @@ domain_unloaded (MonoProfiler *prof, MonoDomain *domain) emit_byte (logbuffer, TYPE_DOMAIN); emit_ptr (logbuffer, (void*)(uintptr_t) mono_domain_get_id (domain)); - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -2265,7 +2264,7 @@ domain_name (MonoProfiler *prof, MonoDomain *domain, const char *name) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -2283,7 +2282,7 @@ context_loaded (MonoProfiler *prof, MonoAppContext *context) emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context)); emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context)); - EXIT_LOG (prof); + EXIT_LOG; } static void @@ -2301,7 +2300,7 @@ context_unloaded (MonoProfiler *prof, MonoAppContext *context) emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_id (context)); emit_ptr (logbuffer, (void*)(uintptr_t) mono_context_get_domain_id (context)); - EXIT_LOG (prof); + EXIT_LOG; } typedef struct { @@ -2470,7 +2469,7 @@ dump_ubin (MonoProfiler *prof, const char *filename, uintptr_t load_addr, uint64 memcpy (logbuffer->cursor, filename, len); logbuffer->cursor += len; - EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); } #endif @@ -2492,7 +2491,7 @@ dump_usym (MonoProfiler *prof, const char *name, uintptr_t value, uintptr_t size memcpy (logbuffer->cursor, name, len); logbuffer->cursor += len; - EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); } /* ELF code crashes on some systems. */ @@ -2917,7 +2916,7 @@ dump_perf_hits (MonoProfiler *prof, void *buf, int size) /* no support here yet for the managed backtrace */ emit_uvalue (logbuffer, mbt_count); - EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); add_code_pointer (s->ip); buf = (char*)buf + s->h.size; @@ -3156,7 +3155,7 @@ counters_emit (MonoProfiler *profiler) agent->emitted = 1; } - EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); done: mono_os_mutex_unlock (&counters_mutex); @@ -3281,7 +3280,7 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp) emit_value (logbuffer, 0); - EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); mono_os_mutex_unlock (&counters_mutex); } @@ -3351,7 +3350,7 @@ perfcounters_emit (MonoProfiler *profiler) pcagent->emitted = 1; } - EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); } static gboolean @@ -3444,7 +3443,7 @@ perfcounters_sample (MonoProfiler *profiler, uint64_t timestamp) emit_value (logbuffer, 0); - EXIT_LOG_EXPLICIT (profiler, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); done: mono_os_mutex_unlock (&counters_mutex); @@ -3617,7 +3616,7 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata) emit_uvalue (logbuffer, method_id); emit_value (logbuffer, coverage_data->len); - EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); for (i = 0; i < coverage_data->len; i++) { CoverageEntry *entry = (CoverageEntry *)coverage_data->pdata[i]; @@ -3638,7 +3637,7 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata) emit_uvalue (logbuffer, entry->line); emit_uvalue (logbuffer, entry->column); - EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); } method_id++; @@ -3670,7 +3669,6 @@ build_class_buffer (gpointer key, gpointer value, gpointer userdata) { MonoClass *klass = (MonoClass *)key; MonoLockFreeQueue *class_methods = (MonoLockFreeQueue *)value; - MonoProfiler *prof = (MonoProfiler *)userdata; MonoImage *image; char *class_name; const char *assembly_name; @@ -3703,7 +3701,7 @@ build_class_buffer (gpointer key, gpointer value, gpointer userdata) emit_uvalue (logbuffer, fully_covered); emit_uvalue (logbuffer, partially_covered); - EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); g_free (class_name); } @@ -3727,7 +3725,6 @@ static void 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; @@ -3761,7 +3758,7 @@ build_assembly_buffer (gpointer key, gpointer value, gpointer userdata) emit_uvalue (logbuffer, fully_covered); emit_uvalue (logbuffer, partially_covered); - EXIT_LOG_EXPLICIT (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); } static void @@ -3774,8 +3771,8 @@ dump_coverage (MonoProfiler *prof) 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); @@ -4326,7 +4323,7 @@ helper_thread (void* arg) buffer_lock_excl (); - sync_point (prof, SYNC_POINT_PERIODIC); + sync_point (SYNC_POINT_PERIODIC); buffer_unlock_excl (); @@ -4347,6 +4344,7 @@ helper_thread (void* arg) read (prof->pipes [0], &c, 1); if (do_debug) fprintf (stderr, "helper shutdown\n"); + #if USE_PERF_EVENTS if (perf_data) { int i; @@ -4358,7 +4356,8 @@ helper_thread (void* arg) } } #endif - send_log_unsafe (prof, FALSE, FALSE); + + send_log_unsafe (FALSE, FALSE); return NULL; } #if USE_PERF_EVENTS @@ -4527,7 +4526,7 @@ handle_writer_queue_entry (MonoProfiler *prof) memcpy (logbuffer->cursor, name, nlen); logbuffer->cursor += nlen; - EXIT_LOG_EXPLICIT (prof, FALSE, FALSE); + EXIT_LOG_EXPLICIT (FALSE, FALSE); mono_free (name); @@ -4656,9 +4655,9 @@ handle_dumper_queue_entry (MonoProfiler *prof) 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 (prof, TRUE, FALSE); + EXIT_LOG_EXPLICIT (TRUE, FALSE); mono_thread_hazardous_try_free (sample, reuse_sample_hit); @@ -4686,7 +4685,7 @@ dumper_thread (void *arg) /* Drain any remaining entries on shutdown. */ while (handle_dumper_queue_entry (prof)); - send_log_unsafe (prof, FALSE, FALSE); + send_log_unsafe (FALSE, FALSE); deinit_thread (thread); mono_thread_info_detach (); From 9127dfaf88a3b0b10a642f110d3b4f2e0e9ddbc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 12 Sep 2016 19:29:05 +0200 Subject: [PATCH 36/50] [profiler] Process requests in method_jitted (). --- mono/profiler/mono-profiler-log.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 78dbc8c91611..68a6fc083697 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -2017,6 +2017,8 @@ method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji, int resu return; register_method_local (method, ji); + + process_requests (); } static void From b5205f797ced7bff985d9328dfbc058bd0beb6a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Tue, 13 Sep 2016 11:34:22 +0200 Subject: [PATCH 37/50] [profiler] Clean up and improve the helper thread code. * Don't invoke undefined behavior if an fd is >= FD_SETSIZE. * Allow multiple command sockets. * Close the command socket(s) on shutdown. * Properly run cleanup logic on shutdown. --- mono/profiler/mono-profiler-log.c | 168 +++++++++++++++++------------- 1 file changed, 93 insertions(+), 75 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 68a6fc083697..addac610deac 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -4278,49 +4278,72 @@ new_filename (const char* filename) return res; } -static void* -helper_thread (void* arg) +static void +add_to_fd_set (fd_set *set, int fd, int *max_fd) +{ + /* + * This should only trigger for the basic FDs (server socket, pipe, perf + * events) at startup if for some mysterious reason they're too large. In + * this case, the profiler really can't function, and we're better off + * printing an error and exiting. + */ + if (fd >= FD_SETSIZE) { + fprintf (stderr, "File descriptor is out of bounds for fd_set: %d\n", fd); + exit (1); + } + + FD_SET (fd, set); + + if (*max_fd < fd) + *max_fd = fd; +} + +static void * +helper_thread (void *arg) { - MonoProfiler* prof = (MonoProfiler *)arg; - int command_socket; - int len; - char buf [64]; + MonoProfiler *prof = (MonoProfiler *) arg; mono_threads_attach_tools_thread (); mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler helper"); MonoProfilerThread *thread = init_thread (prof, FALSE); - //fprintf (stderr, "Server listening\n"); - command_socket = -1; + GArray *command_sockets = g_array_new (FALSE, FALSE, sizeof (int)); + while (1) { fd_set rfds; - struct timeval tv; int max_fd = -1; + FD_ZERO (&rfds); - FD_SET (prof->server_socket, &rfds); - max_fd = prof->server_socket; - FD_SET (prof->pipes [0], &rfds); - if (max_fd < prof->pipes [0]) - max_fd = prof->pipes [0]; - if (command_socket >= 0) { - FD_SET (command_socket, &rfds); - if (max_fd < command_socket) - max_fd = command_socket; - } + + add_to_fd_set (&rfds, prof->server_socket, &max_fd); + add_to_fd_set (&rfds, prof->pipes [0], &max_fd); + + for (gint i = 0; i < command_sockets->len; i++) + add_to_fd_set (&rfds, g_array_index (command_sockets, int, i), &max_fd); + #if USE_PERF_EVENTS if (perf_data) { - int i; - for ( i = 0; i < num_perf; ++i) { + for (int i = 0; i < num_perf; ++i) { if (perf_data [i].perf_fd < 0) continue; - FD_SET (perf_data [i].perf_fd, &rfds); - if (max_fd < perf_data [i].perf_fd) - max_fd = perf_data [i].perf_fd; + + add_to_fd_set (&rfds, perf_data [i].perf_fd, &max_fd); } } #endif + struct timeval tv = { .tv_sec = 1, .tv_usec = 0 }; + + // Sleep for 1sec or until a file descriptor has data. + if (select (max_fd + 1, &rfds, NULL, NULL, &tv) == -1) { + if (errno == EINTR) + continue; + + fprintf (stderr, "Error in mono-profiler-log server: %s", strerror (errno)); + exit (1); + } + counters_and_perfcounters_sample (prof); buffer_lock_excl (); @@ -4329,76 +4352,71 @@ helper_thread (void* arg) buffer_unlock_excl (); - tv.tv_sec = 1; - tv.tv_usec = 0; - len = select (max_fd + 1, &rfds, NULL, NULL, &tv); - - if (len < 0) { - if (errno == EINTR) - continue; +#if USE_PERF_EVENTS + if (perf_data) { + for (int i = 0; i < num_perf; ++i) { + if (perf_data [i].perf_fd < 0 || !FD_ISSET (perf_data [i].perf_fd, &rfds)) + continue; - g_warning ("Error in mono-profiler-log server: %s", strerror (errno)); - return NULL; + read_perf_mmap (prof, i); + } } +#endif + // Are we shutting down? if (FD_ISSET (prof->pipes [0], &rfds)) { char c; read (prof->pipes [0], &c, 1); - if (do_debug) - fprintf (stderr, "helper shutdown\n"); + break; + } -#if USE_PERF_EVENTS - if (perf_data) { - int i; - for ( i = 0; i < num_perf; ++i) { - if (perf_data [i].perf_fd < 0) - continue; - if (FD_ISSET (perf_data [i].perf_fd, &rfds)) - read_perf_mmap (prof, i); - } - } -#endif + for (gint i = 0; i < command_sockets->len; i++) { + int fd = g_array_index (command_sockets, int, i); - send_log_unsafe (FALSE, FALSE); - return NULL; - } -#if USE_PERF_EVENTS - if (perf_data) { - int i; - for ( i = 0; i < num_perf; ++i) { - if (perf_data [i].perf_fd < 0) - continue; - if (FD_ISSET (perf_data [i].perf_fd, &rfds)) - read_perf_mmap (prof, i); - } - } -#endif - if (command_socket >= 0 && FD_ISSET (command_socket, &rfds)) { - len = read (command_socket, buf, sizeof (buf) - 1); - if (len < 0) + if (!FD_ISSET (fd, &rfds)) continue; - if (len == 0) { - close (command_socket); - command_socket = -1; + + char buf [64]; + int len = read (fd, buf, sizeof (buf) - 1); + + if (len == -1) + continue; + + if (!len) { + // The other end disconnected. + g_array_remove_index (command_sockets, i); + close (fd); + continue; } + buf [len] = 0; - if (strcmp (buf, "heapshot\n") == 0 && hs_mode_ondemand) { + + if (!strcmp (buf, "heapshot\n") && hs_mode_ondemand) { // Rely on the finalization callbacks invoking process_requests (). heapshot_requested = 1; mono_gc_finalize_notify (); } - continue; } - if (!FD_ISSET (prof->server_socket, &rfds)) { - continue; + + if (FD_ISSET (prof->server_socket, &rfds)) { + int fd = accept (prof->server_socket, NULL, NULL); + + if (fd != -1) { + if (fd >= FD_SETSIZE) + close (fd); + else + g_array_append_val (command_sockets, fd); + } } - command_socket = accept (prof->server_socket, NULL, NULL); - if (command_socket < 0) - continue; - //fprintf (stderr, "Accepted connection\n"); } + for (gint i = 0; i < command_sockets->len; i++) + close (g_array_index (command_sockets, int, i)); + + g_array_free (command_sockets, TRUE); + + send_log_unsafe (FALSE, FALSE); deinit_thread (thread); mono_thread_info_detach (); @@ -4442,7 +4460,7 @@ start_helper_thread (MonoProfiler* prof) socklen_t slen = sizeof (server_address); - if (getsockname (prof->server_socket, (struct sockaddr *)&server_address, &slen)) { + 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); From 3e9a0d4575aae234d184b6f2493353d7c58048bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Tue, 13 Sep 2016 13:09:24 +0200 Subject: [PATCH 38/50] [profiler] Disable GC move events when allocation events are disabled. They serve no purpose when allocation profiling is enabled, and just make log files bigger than they have to be. --- mono/profiler/mono-profiler-log.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index addac610deac..78cb4bc6e0ae 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -5117,6 +5117,7 @@ mono_profiler_startup (const char *desc) } if ((opt = match_option (p, "noalloc", NULL)) != p) { events &= ~MONO_PROFILE_ALLOCATIONS; + events &= ~MONO_PROFILE_GC_MOVES; continue; } if ((opt = match_option (p, "time", &val)) != p) { @@ -5143,6 +5144,7 @@ mono_profiler_startup (const char *desc) } if ((opt = match_option (p, "heapshot", &val)) != p) { events &= ~MONO_PROFILE_ALLOCATIONS; + events &= ~MONO_PROFILE_GC_MOVES; events &= ~MONO_PROFILE_ENTER_LEAVE; nocalls = 1; do_heap_shot = 1; @@ -5151,6 +5153,7 @@ mono_profiler_startup (const char *desc) } if ((opt = match_option (p, "sample", &val)) != p) { events &= ~MONO_PROFILE_ALLOCATIONS; + events &= ~MONO_PROFILE_GC_MOVES; events &= ~MONO_PROFILE_ENTER_LEAVE; nocalls = 1; set_sample_mode (val, 1); @@ -5243,12 +5246,16 @@ mono_profiler_startup (const char *desc) exit (0); } } + if (calls_enabled) { events |= MONO_PROFILE_ENTER_LEAVE; nocalls = 0; } - if (allocs_enabled) + + if (allocs_enabled) { events |= MONO_PROFILE_ALLOCATIONS; + events |= MONO_PROFILE_GC_MOVES; + } // Only activate the bare minimum events the profiler needs to function. if (only_coverage) { From a6f95ab511fdecca6ef675ca3527e64aca0cb606 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Tue, 13 Sep 2016 17:57:54 +0200 Subject: [PATCH 39/50] [utils/lfa] Add a missing #include to fix the profiler build. --- mono/utils/lock-free-alloc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mono/utils/lock-free-alloc.h b/mono/utils/lock-free-alloc.h index 70d550d95c23..9501307fc1dd 100644 --- a/mono/utils/lock-free-alloc.h +++ b/mono/utils/lock-free-alloc.h @@ -27,8 +27,8 @@ #define __MONO_LOCKFREEALLOC_H__ #include - -#include "lock-free-queue.h" +#include +#include typedef struct { MonoLockFreeQueue partial; From e998d8808fa3c7466d95387f749087c11e7692fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 18:20:14 +0200 Subject: [PATCH 40/50] [profiler] Drop support for perf events on Linux. --- configure.ac | 6 - man/mprof-report.1 | 22 +- mono/profiler/mono-profiler-log.c | 368 +++--------------------------- 3 files changed, 40 insertions(+), 356 deletions(-) diff --git a/configure.ac b/configure.ac index d79db4cadec8..27a9d3249913 100644 --- a/configure.ac +++ b/configure.ac @@ -2658,12 +2658,6 @@ fi AC_ARG_ENABLE(bcl-opt, [ --disable-bcl-opt BCL is compiled with no optimizations (allows accurate BCL debugging)], test_bcl_opt=$enableval, test_bcl_opt=yes) -AC_ARG_ENABLE(perf-events, [ --enable-perf-events Enable using `perf` for profiling on Linux], test_perf_events=$enableval, test_perf_events=no) -if test "x$test_perf_events" = "xyes"; then - AC_DEFINE(ENABLE_PERF_EVENTS, 1, [Enable using `perf` for profiling on Linux]) - AC_SUBST(ENABLE_PERF_EVENTS) -fi - AC_MSG_CHECKING([if big-arrays are to be enabled]) AC_ARG_ENABLE(big-arrays, [ --enable-big-arrays Enable the allocation and indexing of arrays greater than Int32.MaxValue], enable_big_arrays=$enableval, enable_big_arrays=no) if test "x$enable_big_arrays" = "xyes" ; then diff --git a/man/mprof-report.1 b/man/mprof-report.1 index b96001d2c63c..168759897a91 100644 --- a/man/mprof-report.1 +++ b/man/mprof-report.1 @@ -139,30 +139,12 @@ garbage collections to the control port .RE .IP \[bu] 2 -\f[I]sample[=TYPE[/FREQ]]\f[]: collect statistical samples of the +\f[I]sample[=FREQ]\f[]: collect statistical samples of the program behaviour. The default is to collect a 100 times per second (100 Hz) the instruction pointer. -This is equivalent to the value \[lq]cycles/100\[rq]. +This is equivalent to the value \[lq]100\[rq]. A value of zero for \f[I]FREQ\f[] effectively disables sampling. -On some systems, like with recent Linux kernels, it is possible to -cause the sampling to happen for other events provided by the -performance counters of the cpu. -In this case, \f[I]TYPE\f[] can be one of: -.RS 2 -.IP \[bu] 2 -\f[I]cycles\f[]: processor cycles -.IP \[bu] 2 -\f[I]instr\f[]: executed instructions -.IP \[bu] 2 -\f[I]cacherefs\f[]: cache references -.IP \[bu] 2 -\f[I]cachemiss\f[]: cache misses -.IP \[bu] 2 -\f[I]branches\f[]: executed branches -.IP \[bu] 2 -\f[I]branchmiss\f[]: mispredicted branches -.RE .IP \[bu] 2 \f[I]maxframes=NUM\f[]: when a stack trace needs to be performed, collect \f[I]NUM\f[] frames at the most. diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 78cb4bc6e0ae..97f662fa5bcd 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -54,16 +54,6 @@ #include #endif -#if defined(__linux__) && defined (ENABLE_PERF_EVENTS) - -#include - -#define USE_PERF_EVENTS 1 - -static int read_perf_mmap (MonoProfiler* prof, int cpu); - -#endif - #define BUFFER_SIZE (4096 * 16) /* Worst-case size in bytes of a 64-bit value encoded with LEB128. */ @@ -82,7 +72,6 @@ static int max_call_depth = 100; static volatile int runtime_inited = 0; static int command_port = 0; static int heapshot_requested = 0; -static int sample_type = 0; static int sample_freq = 0; static int do_mono_sample = 0; static int in_shutdown = 0; @@ -349,7 +338,6 @@ static MonoLinkedListSet profiler_thread_list; * 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: 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 @@ -2810,228 +2798,6 @@ mono_cpu_count (void) return 1; } -#if USE_PERF_EVENTS - -typedef struct { - int perf_fd; - unsigned int prev_pos; - void *mmap_base; - struct perf_event_mmap_page *page_desc; -} PerfData ; - -static PerfData *perf_data = NULL; -static int num_perf; -#define PERF_PAGES_SHIFT 4 -static int num_pages = 1 << PERF_PAGES_SHIFT; -static unsigned int mmap_mask; - -typedef struct { - struct perf_event_header h; - uint64_t ip; - uint32_t pid; - uint32_t tid; - uint64_t timestamp; - uint64_t period; - uint64_t nframes; -} PSample; - -static int -perf_event_syscall (struct perf_event_attr *attr, pid_t pid, int cpu, int group_fd, unsigned long flags) -{ - attr->size = PERF_ATTR_SIZE_VER0; - //printf ("perf attr size: %d\n", attr->size); -#if defined(__x86_64__) - return syscall(/*__NR_perf_event_open*/ 298, attr, pid, cpu, group_fd, flags); -#elif defined(__i386__) - return syscall(/*__NR_perf_event_open*/ 336, attr, pid, cpu, group_fd, flags); -#elif defined(__arm__) || defined (__aarch64__) - return syscall(/*__NR_perf_event_open*/ 364, attr, pid, cpu, group_fd, flags); -#else - return -1; -#endif -} - -static int -setup_perf_map (PerfData *perf) -{ - perf->mmap_base = mmap (NULL, (num_pages + 1) * getpagesize (), PROT_READ|PROT_WRITE, MAP_SHARED, perf->perf_fd, 0); - if (perf->mmap_base == MAP_FAILED) { - if (do_debug) - printf ("failed mmap\n"); - return 0; - } - perf->page_desc = perf->mmap_base; - if (do_debug) - printf ("mmap version: %d\n", perf->page_desc->version); - return 1; -} - -static void -dump_perf_hits (MonoProfiler *prof, void *buf, int size) -{ - int count = 1; - int mbt_count = 0; - void *end = (char*)buf + size; - int samples = 0; - int pid = getpid (); - - while (buf < end) { - PSample *s = buf; - if (s->h.size == 0) - break; - if (pid != s->pid) { - if (do_debug) - printf ("event for different pid: %d\n", s->pid); - buf = (char*)buf + s->h.size; - continue; - } - /*ip = (void*)s->ip; - 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 */ + - LEB128_SIZE /* tid */ + - LEB128_SIZE /* count */ + - count * ( - LEB128_SIZE /* ip */ - ) + - LEB128_SIZE /* managed count */ + - mbt_count * ( - LEB128_SIZE /* method */ - ) - ); - - 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 - * perf is the kernel's thread ID. - */ - emit_ptr (logbuffer, 0); - emit_value (logbuffer, count); - emit_ptr (logbuffer, (void*)(uintptr_t)s->ip); - /* no support here yet for the managed backtrace */ - emit_uvalue (logbuffer, mbt_count); - - EXIT_LOG_EXPLICIT (TRUE, FALSE); - - add_code_pointer (s->ip); - buf = (char*)buf + s->h.size; - samples++; - } - if (do_debug) - printf ("dumped %d samples\n", samples); - dump_unmanaged_coderefs (prof); -} - -/* read events from the ring buffer */ -static int -read_perf_mmap (MonoProfiler* prof, int cpu) -{ - PerfData *perf = perf_data + cpu; - unsigned char *buf; - unsigned char *data = (unsigned char*)perf->mmap_base + getpagesize (); - unsigned int head = perf->page_desc->data_head; - int diff, size; - unsigned int old; - - mono_memory_read_barrier (); - - old = perf->prev_pos; - diff = head - old; - if (diff < 0) { - if (do_debug) - printf ("lost mmap events: old: %d, head: %d\n", old, head); - old = head; - } - size = head - old; - if ((old & mmap_mask) + size != (head & mmap_mask)) { - buf = data + (old & mmap_mask); - size = mmap_mask + 1 - (old & mmap_mask); - old += size; - /* size bytes at buf */ - if (do_debug) - printf ("found1 bytes of events: %d\n", size); - dump_perf_hits (prof, buf, size); - } - buf = data + (old & mmap_mask); - size = head - old; - /* size bytes at buf */ - if (do_debug) - printf ("found bytes of events: %d\n", size); - dump_perf_hits (prof, buf, size); - old += size; - perf->prev_pos = old; - perf->page_desc->data_tail = old; - return 0; -} - -static int -setup_perf_event_for_cpu (PerfData *perf, int cpu) -{ - struct perf_event_attr attr; - memset (&attr, 0, sizeof (attr)); - attr.type = PERF_TYPE_HARDWARE; - switch (sample_type) { - case SAMPLE_CYCLES: attr.config = PERF_COUNT_HW_CPU_CYCLES; break; - case SAMPLE_INSTRUCTIONS: attr.config = PERF_COUNT_HW_INSTRUCTIONS; break; - case SAMPLE_CACHE_MISSES: attr.config = PERF_COUNT_HW_CACHE_MISSES; break; - case SAMPLE_CACHE_REFS: attr.config = PERF_COUNT_HW_CACHE_REFERENCES; break; - case SAMPLE_BRANCHES: attr.config = PERF_COUNT_HW_BRANCH_INSTRUCTIONS; break; - case SAMPLE_BRANCH_MISSES: attr.config = PERF_COUNT_HW_BRANCH_MISSES; break; - default: attr.config = PERF_COUNT_HW_CPU_CYCLES; break; - } - attr.sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_PERIOD | PERF_SAMPLE_TIME; -// attr.sample_type |= PERF_SAMPLE_CALLCHAIN; - attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; - attr.inherit = 1; - attr.freq = 1; - attr.sample_freq = sample_freq; - - perf->perf_fd = perf_event_syscall (&attr, getpid (), cpu, -1, 0); - if (do_debug) - printf ("perf fd: %d, freq: %d, event: %llu\n", perf->perf_fd, sample_freq, attr.config); - if (perf->perf_fd < 0) { - if (perf->perf_fd == -EPERM) { - fprintf (stderr, "Perf syscall denied, do \"echo 1 > /proc/sys/kernel/perf_event_paranoid\" as root to enable.\n"); - } else { - if (do_debug) - perror ("open perf event"); - } - return 0; - } - if (!setup_perf_map (perf)) { - close (perf->perf_fd); - perf->perf_fd = -1; - return 0; - } - return 1; -} - -static int -setup_perf_event (void) -{ - int i, count = 0; - mmap_mask = num_pages * getpagesize () - 1; - num_perf = mono_cpu_count (); - 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; - g_free (perf_data); - perf_data = NULL; - return 0; -} - -#endif /* USE_PERF_EVENTS */ - typedef struct MonoCounterAgent { MonoCounter *counter; // MonoCounterAgent specific data : @@ -4131,14 +3897,6 @@ log_shutdown (MonoProfiler *prof) g_free (cur); } -#if USE_PERF_EVENTS - if (perf_data) { - int i; - for (i = 0; i < num_perf; ++i) - read_perf_mmap (prof, i); - } -#endif - /* * Ensure that we empty the LLS completely, even if some nodes are * not immediately removed upon calling mono_lls_remove (), by @@ -4282,10 +4040,10 @@ static void add_to_fd_set (fd_set *set, int fd, int *max_fd) { /* - * This should only trigger for the basic FDs (server socket, pipe, perf - * events) at startup if for some mysterious reason they're too large. In - * this case, the profiler really can't function, and we're better off - * printing an error and exiting. + * This should only trigger for the basic FDs (server socket, pipes) at + * startup if for some mysterious reason they're too large. In this case, + * the profiler really can't function, and we're better off printing an + * error and exiting. */ if (fd >= FD_SETSIZE) { fprintf (stderr, "File descriptor is out of bounds for fd_set: %d\n", fd); @@ -4322,17 +4080,6 @@ helper_thread (void *arg) for (gint i = 0; i < command_sockets->len; i++) add_to_fd_set (&rfds, g_array_index (command_sockets, int, i), &max_fd); -#if USE_PERF_EVENTS - if (perf_data) { - for (int i = 0; i < num_perf; ++i) { - if (perf_data [i].perf_fd < 0) - continue; - - add_to_fd_set (&rfds, perf_data [i].perf_fd, &max_fd); - } - } -#endif - struct timeval tv = { .tv_sec = 1, .tv_usec = 0 }; // Sleep for 1sec or until a file descriptor has data. @@ -4352,17 +4099,6 @@ helper_thread (void *arg) buffer_unlock_excl (); -#if USE_PERF_EVENTS - if (perf_data) { - for (int i = 0; i < num_perf; ++i) { - if (perf_data [i].perf_fd < 0 || !FD_ISSET (perf_data [i].perf_fd, &rfds)) - continue; - - read_perf_mmap (prof, i); - } - } -#endif - // Are we shutting down? if (FD_ISSET (prof->pipes [0], &rfds)) { char c; @@ -4661,7 +4397,7 @@ handle_dumper_queue_entry (MonoProfiler *prof) ); emit_event_time (logbuffer, TYPE_SAMPLE | TYPE_SAMPLE_HIT, sample->time); - emit_byte (logbuffer, sample_type); + emit_byte (logbuffer, SAMPLE_CYCLES); emit_ptr (logbuffer, (void *) sample->tid); emit_value (logbuffer, 1); @@ -4850,15 +4586,6 @@ create_profiler (const char *args, const char *filename, GPtrArray *filters) prof->gzfile = gzdopen (fileno (prof->file), "wb"); #endif -#if USE_PERF_EVENTS - setup_perf_event (); - - if (!perf_data) { - /* FIXME: warn if different freq or sample type */ - do_mono_sample = 1; - } -#endif - /* * If you hit this assert while increasing MAX_FRAMES, you need to increase * SAMPLE_BLOCK_SIZE as well. @@ -4963,62 +4690,43 @@ match_option (const char* p, const char *opt, char **rval) return p; } -typedef struct { - const char *name; - int sample_mode; -} SampleMode; - -static const SampleMode sample_modes [] = { - {"cycles", SAMPLE_CYCLES}, - {"instr", SAMPLE_INSTRUCTIONS}, - {"cachemiss", SAMPLE_CACHE_MISSES}, - {"cacherefs", SAMPLE_CACHE_REFS}, - {"branches", SAMPLE_BRANCHES}, - {"branchmiss", SAMPLE_BRANCH_MISSES}, - {NULL, 0} -}; - static void -set_sample_mode (char* val, int allow_empty) +set_sample_freq (char *val) { - char *end; - char *maybe_freq = NULL; - unsigned int count; - const SampleMode *smode = sample_modes; -#ifndef USE_PERF_EVENTS do_mono_sample = 1; -#endif - if (allow_empty && !val) { - sample_type = SAMPLE_CYCLES; - sample_freq = 100; - return; - } - if (strcmp (val, "mono") == 0) { - do_mono_sample = 1; - sample_type = SAMPLE_CYCLES; - g_free (val); + sample_freq = 100; + + if (!val) return; - } - for (smode = sample_modes; smode->name; smode++) { - int l = strlen (smode->name); - if (strncmp (val, smode->name, l) == 0) { - sample_type = smode->sample_mode; - maybe_freq = val + l; - break; - } - } - if (!smode->name) - usage (1); - if (*maybe_freq == '/') { - count = strtoul (maybe_freq + 1, &end, 10); - if (maybe_freq + 1 == end) + + char *p = val; + + // Is it only the frequency (new option style)? + if (isdigit (*p)) + goto parse; + + // Skip the sample type for backwards compatibility. + while (isalpha (*p)) + p++; + + // Skip the forward slash only if we got a sample type. + if (p != val && *p == '/') { + p++; + + char *end; + + parse: + sample_freq = strtoul (p, &end, 10); + + if (p == end) usage (1); - sample_freq = count; - } else if (*maybe_freq != 0) { - usage (1); - } else { - sample_freq = 100; + + p = end; } + + if (*p) + usage (1); + g_free (val); } @@ -5156,7 +4864,7 @@ mono_profiler_startup (const char *desc) events &= ~MONO_PROFILE_GC_MOVES; events &= ~MONO_PROFILE_ENTER_LEAVE; nocalls = 1; - set_sample_mode (val, 1); + set_sample_freq (val); continue; } if ((opt = match_option (p, "zip", NULL)) != p) { @@ -5304,7 +5012,7 @@ mono_profiler_startup (const char *desc) if (do_coverage) mono_profiler_install_coverage_filter (coverage_filter); - if (do_mono_sample && sample_type == SAMPLE_CYCLES && sample_freq) { + if (do_mono_sample && sample_freq) { events |= MONO_PROFILE_STATISTICAL; mono_profiler_set_statistical_mode (sampling_mode, sample_freq); mono_profiler_install_statistical (mono_sample_hit); From 36cb2ec977b24fdb472bdace0c6bcd518712a440 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 14:31:32 +0200 Subject: [PATCH 41/50] [profiler] Access in_shutdown atomically. --- mono/profiler/mono-profiler-log.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 97f662fa5bcd..4504f1dcb68c 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -63,18 +63,19 @@ /* Size in bytes of the event prefix (ID + time). */ #define EVENT_SIZE (BYTE_SIZE + LEB128_SIZE) +static volatile gint32 runtime_inited; +static volatile gint32 in_shutdown; + static int nocalls = 0; static int notraces = 0; static int use_zip = 0; static int do_report = 0; static int do_heap_shot = 0; static int max_call_depth = 100; -static volatile int runtime_inited = 0; static int command_port = 0; static int heapshot_requested = 0; static int sample_freq = 0; static int do_mono_sample = 0; -static int in_shutdown = 0; static int do_debug = 0; static int do_counters = 0; static int do_coverage = 0; @@ -2353,7 +2354,7 @@ mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context) * invoking runtime functions, which is not async-signal-safe. */ - if (in_shutdown) + if (InterlockedRead (&in_shutdown)) return; SampleHit *sample = (SampleHit *) mono_lock_free_queue_dequeue (&profiler->sample_reuse_queue); @@ -2815,7 +2816,7 @@ static mono_mutex_t counters_mutex; static void counters_add_agent (MonoCounter *counter) { - if (in_shutdown) + if (InterlockedRead (&in_shutdown)) return; MonoCounterAgent *agent, *item; @@ -3864,9 +3865,7 @@ cleanup_reusable_samples (MonoProfiler *prof) static void log_shutdown (MonoProfiler *prof) { - void *res; - - in_shutdown = 1; + InterlockedWrite (&in_shutdown, 1); counters_and_perfcounters_sample (prof); @@ -3879,6 +3878,8 @@ log_shutdown (MonoProfiler *prof) exit (1); } + void *res; + pthread_join (prof->helper_thread, &res); mono_os_mutex_destroy (&counters_mutex); From 7883db95e30867f6802a68c90b74c902aefb2607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 14:36:54 +0200 Subject: [PATCH 42/50] [utils/threads] Export all native thread functions. --- mono/utils/mono-threads.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mono/utils/mono-threads.h b/mono/utils/mono-threads.h index 5e31607c176e..a6798a19e617 100644 --- a/mono/utils/mono-threads.h +++ b/mono/utils/mono-threads.h @@ -531,10 +531,10 @@ void mono_threads_coop_end_global_suspend (void); MONO_API MonoNativeThreadId mono_native_thread_id_get (void); -gboolean +MONO_API gboolean mono_native_thread_id_equals (MonoNativeThreadId id1, MonoNativeThreadId id2); -gboolean +MONO_API gboolean mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg); MONO_API void From d78ba0e327ec1c16b5820b05f4deac6389eeff69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 14:59:42 +0200 Subject: [PATCH 43/50] [utils/threads] Add and export a mono_native_thread_join () function. --- mono/metadata/threads.c | 4 ++-- mono/mini/mini-posix.c | 2 +- mono/utils/mono-threads-posix.c | 8 ++++++++ mono/utils/mono-threads-windows.c | 15 +++++++++++++++ mono/utils/mono-threads.h | 3 +++ 5 files changed, 29 insertions(+), 3 deletions(-) diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index 2f19acf04e44..0b8aa7c4fb9a 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -4921,7 +4921,7 @@ mono_threads_join_threads (void) if (thread != pthread_self ()) { MONO_ENTER_GC_SAFE; /* This shouldn't block */ - pthread_join (thread, NULL); + mono_native_thread_join (thread); MONO_EXIT_GC_SAFE; } } else { @@ -4957,7 +4957,7 @@ mono_thread_join (gpointer tid) return; thread = (pthread_t)tid; MONO_ENTER_GC_SAFE; - pthread_join (thread, NULL); + mono_native_thread_join (thread); MONO_EXIT_GC_SAFE; #endif } diff --git a/mono/mini/mini-posix.c b/mono/mini/mini-posix.c index f8a02816291f..bdd3149c25bf 100644 --- a/mono/mini/mini-posix.c +++ b/mono/mini/mini-posix.c @@ -783,7 +783,7 @@ mono_runtime_shutdown_stat_profiler (void) } #endif - pthread_join (sampling_thread, NULL); + mono_native_thread_join (sampling_thread); /* * We can't safely remove the signal handler because we have no guarantee diff --git a/mono/utils/mono-threads-posix.c b/mono/utils/mono-threads-posix.c index 9e6ebe712c2c..7d656132b590 100644 --- a/mono/utils/mono-threads-posix.c +++ b/mono/utils/mono-threads-posix.c @@ -288,6 +288,14 @@ mono_native_thread_set_name (MonoNativeThreadId tid, const char *name) #endif } +gboolean +mono_native_thread_join (MonoNativeThreadId tid) +{ + void *res; + + return !pthread_join (tid, &res); +} + void mono_threads_platform_set_exited (gpointer handle) { diff --git a/mono/utils/mono-threads-windows.c b/mono/utils/mono-threads-windows.c index 7beb557fc70e..5d6774ed4d7e 100644 --- a/mono/utils/mono-threads-windows.c +++ b/mono/utils/mono-threads-windows.c @@ -187,6 +187,21 @@ mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg) return CreateThread (NULL, 0, (func), (arg), 0, (tid)) != NULL; } +gboolean +mono_native_thread_join (MonoNativeThreadId tid) +{ + HANDLE handle; + + if (!(handle = OpenThread (THREAD_ALL_ACCESS, TRUE, tid))) + return FALSE; + + DWORD res = WaitForSingleObject (handle, INFINITE); + + CloseHandle (handle); + + return res != WAIT_FAILED; +} + #if HAVE_DECL___READFSDWORD==0 static MONO_ALWAYS_INLINE unsigned long long __readfsdword (unsigned long offset) diff --git a/mono/utils/mono-threads.h b/mono/utils/mono-threads.h index a6798a19e617..72f90e381571 100644 --- a/mono/utils/mono-threads.h +++ b/mono/utils/mono-threads.h @@ -540,6 +540,9 @@ mono_native_thread_create (MonoNativeThreadId *tid, gpointer func, gpointer arg) MONO_API void mono_native_thread_set_name (MonoNativeThreadId tid, const char *name); +MONO_API gboolean +mono_native_thread_join (MonoNativeThreadId tid); + /*Mach specific internals */ void mono_threads_init_dead_letter (void); void mono_threads_install_dead_letter (void); From 76c2b6720782ee0924ebbd1f0e250009b1ba7423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 15:20:15 +0200 Subject: [PATCH 44/50] [profiler] Use the native thread wrapper functions to manage threads. --- mono/profiler/mono-profiler-log.c | 34 +++++++++++-------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 4504f1dcb68c..35e093b22a46 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -677,11 +677,9 @@ struct _MonoProfiler { int command_port; int server_socket; int pipes [2]; -#ifndef HOST_WIN32 - pthread_t helper_thread; - pthread_t writer_thread; - pthread_t dumper_thread; -#endif + MonoNativeThreadId helper_thread; + MonoNativeThreadId writer_thread; + MonoNativeThreadId dumper_thread; volatile gint32 run_writer_thread; MonoLockFreeAllocSizeClass writer_entry_size_class; MonoLockFreeAllocator writer_entry_allocator; @@ -3878,9 +3876,7 @@ log_shutdown (MonoProfiler *prof) exit (1); } - void *res; - - pthread_join (prof->helper_thread, &res); + mono_native_thread_join (prof->helper_thread); mono_os_mutex_destroy (&counters_mutex); @@ -3917,12 +3913,12 @@ log_shutdown (MonoProfiler *prof) InterlockedWrite (&prof->run_dumper_thread, 0); mono_os_sem_post (&prof->dumper_queue_sem); - pthread_join (prof->dumper_thread, &res); + mono_native_thread_join (prof->dumper_thread); mono_os_sem_destroy (&prof->dumper_queue_sem); InterlockedWrite (&prof->run_writer_thread, 0); mono_os_sem_post (&prof->writer_queue_sem); - pthread_join (prof->writer_thread, &res); + mono_native_thread_join (prof->writer_thread); mono_os_sem_destroy (&prof->writer_queue_sem); /* @@ -4205,10 +4201,8 @@ start_helper_thread (MonoProfiler* prof) 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)); + if (!mono_native_thread_create (&prof->helper_thread, helper_thread, prof)) { + fprintf (stderr, "Could not start helper thread\n"); close (prof->server_socket); exit (1); } @@ -4344,10 +4338,8 @@ start_writer_thread (MonoProfiler* prof) { InterlockedWrite (&prof->run_writer_thread, 1); - int r; - - if ((r = pthread_create (&prof->writer_thread, NULL, writer_thread, prof))) { - fprintf (stderr, "Could not start writer thread: %s\n", strerror (r)); + if (!mono_native_thread_create (&prof->writer_thread, writer_thread, prof)) { + fprintf (stderr, "Could not start writer thread\n"); exit (1); } } @@ -4455,10 +4447,8 @@ start_dumper_thread (MonoProfiler* prof) { InterlockedWrite (&prof->run_dumper_thread, 1); - int r; - - if ((r = pthread_create (&prof->dumper_thread, NULL, dumper_thread, prof))) { - fprintf (stderr, "Could not start dumper thread: %s\n", strerror (r)); + if (!mono_native_thread_create (&prof->dumper_thread, dumper_thread, prof)) { + fprintf (stderr, "Could not start dumper thread\n"); exit (1); } } From ffbf54045753de993036a0402de08da65adbeb1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 15:38:06 +0200 Subject: [PATCH 45/50] [profiler] Warn if we can't detect the CPU count. --- mono/profiler/mono-profiler-log.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 35e093b22a46..df0071ef1ecf 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -2793,7 +2793,14 @@ mono_cpu_count (void) return info.dwNumberOfProcessors; } #endif - /* FIXME: warn */ + + static gboolean warned; + + if (!warned) { + g_warning ("Don't know how to determine CPU count on this platform; assuming 1"); + warned = TRUE; + } + return 1; } From d3ff7dca3e8e1f63e3ff88e611cc8b268a50055b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 15:42:26 +0200 Subject: [PATCH 46/50] [profiler] Use eglib alloc/free functions everywhere. --- mono/profiler/mono-profiler-log.c | 40 +++++----- mono/profiler/mprof-report.c | 122 +++++++++++++++--------------- 2 files changed, 81 insertions(+), 81 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index df0071ef1ecf..64abb62179af 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -744,7 +744,7 @@ static char* pstrdup (const char *s) { int len = strlen (s) + 1; - char *p = (char *)malloc (len); + char *p = (char *) g_malloc (len); memcpy (p, s, len); return p; } @@ -817,7 +817,7 @@ init_thread (MonoProfiler *prof, gboolean add_to_lls) if (thread) return thread; - thread = malloc (sizeof (MonoProfilerThread)); + thread = g_malloc (sizeof (MonoProfilerThread)); thread->node.key = thread_id (); thread->profiler = prof; thread->attached = add_to_lls; @@ -848,7 +848,7 @@ deinit_thread (MonoProfilerThread *thread) { g_assert (!thread->attached && "Why are we manually freeing an attached thread?"); - free (thread); + g_free (thread); PROF_TLS_SET (NULL); } @@ -1019,7 +1019,7 @@ register_method_local (MonoMethod *method, MonoJitInfo *ji) MonoProfilerThread *thread = PROF_TLS_GET (); if (!mono_conc_hashtable_lookup (thread->profiler->method_table, method)) { - MethodInfo *info = (MethodInfo *) malloc (sizeof (MethodInfo)); + MethodInfo *info = (MethodInfo *) g_malloc (sizeof (MethodInfo)); info->method = method; info->ji = ji; @@ -1127,7 +1127,7 @@ dump_header (MonoProfiler *profiler) const char *arch = mono_config_get_cpu (); const char *os = mono_config_get_os (); - char *hbuf = malloc ( + char *hbuf = g_malloc ( sizeof (gint32) /* header id */ + sizeof (gint8) /* major version */ + sizeof (gint8) /* minor version */ + @@ -1168,7 +1168,7 @@ dump_header (MonoProfiler *profiler) fflush (profiler->file); } - free (hbuf); + g_free (hbuf); } /* @@ -1217,7 +1217,7 @@ free_thread (gpointer p) send_buffer (thread); - free (thread); + g_free (thread); } static void @@ -1767,7 +1767,7 @@ type_name (MonoClass *klass) char buf [1024]; char *p; push_nesting (buf, klass); - p = (char *)malloc (strlen (buf) + 1); + p = (char *) g_malloc (strlen (buf) + 1); strcpy (p, buf); return p; } @@ -2423,7 +2423,7 @@ add_code_pointer (uintptr_t ip) size_code_pages *= 2; if (size_code_pages == 0) size_code_pages = 16; - n = (uintptr_t *)calloc (sizeof (uintptr_t) * size_code_pages, 1); + n = (uintptr_t *) g_calloc (sizeof (uintptr_t) * size_code_pages, 1); for (i = 0; i < old_size; ++i) { if (code_pages [i]) add_code_page (n, size_code_pages, code_pages [i]); @@ -2839,7 +2839,7 @@ counters_add_agent (MonoCounter *counter) } } - agent = (MonoCounterAgent *)malloc (sizeof (MonoCounterAgent)); + agent = (MonoCounterAgent *) g_malloc (sizeof (MonoCounterAgent)); agent->counter = counter; agent->value = NULL; agent->value_size = 0; @@ -3294,7 +3294,7 @@ parse_generic_type_names(char *name) if (name == NULL || *name == '\0') return g_strdup (""); - if (!(ret = new_name = (char *)calloc (strlen (name) * 4 + 1, sizeof (char)))) + if (!(ret = new_name = (char *) g_calloc (strlen (name) * 4 + 1, sizeof (char)))) return NULL; do { @@ -3432,7 +3432,7 @@ count_queue (MonoLockFreeQueue *queue) while ((node = mono_lock_free_queue_dequeue (queue))) { count++; - mono_thread_hazardous_try_free (node, free); + mono_thread_hazardous_try_free (node, g_free); } return count; @@ -3576,7 +3576,7 @@ process_method_enter_coverage (MonoProfiler *prof, MonoMethod *method) static MonoLockFreeQueueNode * create_method_node (MonoMethod *method) { - MethodNode *node = (MethodNode *)g_malloc (sizeof (MethodNode)); + MethodNode *node = (MethodNode *) g_malloc (sizeof (MethodNode)); mono_lock_free_queue_node_init ((MonoLockFreeQueueNode *) node, FALSE); node->method = method; @@ -3716,7 +3716,7 @@ coverage_filter (MonoProfiler *prof, MonoMethod *method) image_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (image_to_methods, image); if (image_methods == NULL) { - image_methods = (MonoLockFreeQueue *)g_malloc (sizeof (MonoLockFreeQueue)); + image_methods = (MonoLockFreeQueue *) g_malloc (sizeof (MonoLockFreeQueue)); mono_lock_free_queue_init (image_methods); mono_os_mutex_lock (&coverage_mutex); mono_conc_hashtable_insert (image_to_methods, image, image_methods); @@ -3729,7 +3729,7 @@ coverage_filter (MonoProfiler *prof, MonoMethod *method) class_methods = (MonoLockFreeQueue *)mono_conc_hashtable_lookup (coverage_classes, klass); if (class_methods == NULL) { - class_methods = (MonoLockFreeQueue *)g_malloc (sizeof (MonoLockFreeQueue)); + class_methods = (MonoLockFreeQueue *) g_malloc (sizeof (MonoLockFreeQueue)); mono_lock_free_queue_init (class_methods); mono_os_mutex_lock (&coverage_mutex); mono_conc_hashtable_insert (coverage_classes, klass, class_methods); @@ -3768,7 +3768,7 @@ get_file_content (FILE *stream) if (filesize > MAX_FILE_SIZE) return NULL; - buffer = (char *)g_malloc ((filesize + 1) * sizeof (char)); + buffer = (char *) g_malloc ((filesize + 1) * sizeof (char)); while ((bytes_read = fread (buffer + offset, 1, LINE_BUFFER_SIZE, stream)) > 0) offset += bytes_read; @@ -4013,7 +4013,7 @@ new_filename (const char* filename) 1900 + ts->tm_year, 1 + ts->tm_mon, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec); s_date = strlen (time_buf); s_pid = strlen (pid_buf); - d = res = (char *)malloc (strlen (filename) + s_date * count_dates + s_pid * count_pids); + d = res = (char *) g_malloc (strlen (filename) + s_date * count_dates + s_pid * count_pids); for (p = filename; *p; p++) { if (*p != '%') { *d++ = *p; @@ -4539,7 +4539,7 @@ 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 = (MonoProfiler *) g_calloc (1, sizeof (MonoProfiler)); prof->args = pstrdup (args); prof->command_port = command_port; @@ -4557,7 +4557,7 @@ create_profiler (const char *args, const char *filename, GPtrArray *filters) nf = new_filename (filename); if (do_report) { int s = strlen (nf) + 32; - char *p = (char *)malloc (s); + char *p = (char *) g_malloc (s); snprintf (p, s, "|mprof-report '--out=%s' -", nf); g_free (nf); nf = p; @@ -4667,7 +4667,7 @@ match_option (const char* p, const char *opt, char **rval) } else { l = end - opt; } - val = (char *)malloc (l + 1); + val = (char *) g_malloc (l + 1); memcpy (val, opt, l); val [l] = 0; *rval = val; diff --git a/mono/profiler/mprof-report.c b/mono/profiler/mprof-report.c index 7be6dcb54918..1017d1f8e6d4 100644 --- a/mono/profiler/mprof-report.c +++ b/mono/profiler/mprof-report.c @@ -134,7 +134,7 @@ static char* pstrdup (const char *s) { int len = strlen (s) + 1; - char *p = (char *)malloc (len); + char *p = (char *) g_malloc (len); memcpy (p, s, len); return p; } @@ -197,7 +197,7 @@ add_counter_to_section (Counter *counter) CounterSection *csection, *s; CounterList *clist; - clist = (CounterList *)calloc (1, sizeof (CounterList)); + clist = (CounterList *) g_calloc (1, sizeof (CounterList)); clist->counter = counter; for (csection = counters_sections; csection; csection = csection->next) { @@ -213,7 +213,7 @@ add_counter_to_section (Counter *counter) } /* If section does not exist */ - csection = (CounterSection *)calloc (1, sizeof (CounterSection)); + csection = (CounterSection *) g_calloc (1, sizeof (CounterSection)); csection->value = counter->section; csection->counters = clist; csection->counters_last = clist; @@ -238,7 +238,7 @@ add_counter (const char *section, const char *name, int type, int unit, int vari if (list->counter->index == index) return; - counter = (Counter *)calloc (1, sizeof (Counter)); + counter = (Counter *) g_calloc (1, sizeof (Counter)); counter->section = section; counter->name = name; counter->type = type; @@ -246,7 +246,7 @@ add_counter (const char *section, const char *name, int type, int unit, int vari counter->variance = variance; counter->index = index; - list = (CounterList *)calloc (1, sizeof (CounterList)); + list = (CounterList *) g_calloc (1, sizeof (CounterList)); list->counter = counter; if (!counters) { @@ -269,7 +269,7 @@ add_counter_to_timestamp (uint64_t timestamp, Counter *counter) CounterSection *csection; CounterList *clist; - clist = (CounterList *)calloc (1, sizeof (CounterList)); + clist = (CounterList *) g_calloc (1, sizeof (CounterList)); clist->counter = counter; for (ctimestamp = counters_timestamps; ctimestamp; ctimestamp = ctimestamp->next) { @@ -287,7 +287,7 @@ add_counter_to_timestamp (uint64_t timestamp, Counter *counter) } /* if timestamp exist and section does not exist */ - csection = (CounterSection *)calloc (1, sizeof (CounterSection)); + csection = (CounterSection *) g_calloc (1, sizeof (CounterSection)); csection->value = counter->section; csection->counters = clist; csection->counters_last = clist; @@ -302,12 +302,12 @@ add_counter_to_timestamp (uint64_t timestamp, Counter *counter) } /* If timestamp do not exist and section does not exist */ - csection = (CounterSection *)calloc (1, sizeof (CounterSection)); + csection = (CounterSection *) g_calloc (1, sizeof (CounterSection)); csection->value = counter->section; csection->counters = clist; csection->counters_last = clist; - ctimestamp = (CounterTimestamp *)calloc (1, sizeof (CounterTimestamp)); + ctimestamp = (CounterTimestamp *) g_calloc (1, sizeof (CounterTimestamp)); ctimestamp->value = timestamp; ctimestamp->sections = csection; ctimestamp->sections_last = csection; @@ -566,7 +566,7 @@ static void add_image (intptr_t image, char *name) { int slot = ((image >> 2) & 0xffff) % SMALL_HASH_SIZE; - ImageDesc *cd = (ImageDesc *)malloc (sizeof (ImageDesc)); + ImageDesc *cd = (ImageDesc *) g_malloc (sizeof (ImageDesc)); cd->image = image; cd->filename = pstrdup (name); cd->next = image_hash [slot]; @@ -589,7 +589,7 @@ static void add_assembly (intptr_t assembly, char *name) { int slot = ((assembly >> 2) & 0xffff) % SMALL_HASH_SIZE; - AssemblyDesc *cd = (AssemblyDesc *)malloc (sizeof (AssemblyDesc)); + AssemblyDesc *cd = (AssemblyDesc *) g_malloc (sizeof (AssemblyDesc)); cd->assembly = assembly; cd->asmname = pstrdup (name); cd->next = assembly_hash [slot]; @@ -637,7 +637,7 @@ add_class (intptr_t klass, const char *name) cd->name = pstrdup (name); return cd; } - cd = (ClassDesc *)calloc (sizeof (ClassDesc), 1); + cd = (ClassDesc *) g_calloc (sizeof (ClassDesc), 1); cd->klass = klass; cd->name = pstrdup (name); cd->next = class_hash [slot]; @@ -703,7 +703,7 @@ add_method (intptr_t method, const char *name, intptr_t code, int len) cd->name = pstrdup (name); return cd; } - cd = (MethodDesc *)calloc (sizeof (MethodDesc), 1); + cd = (MethodDesc *) g_calloc (sizeof (MethodDesc), 1); cd->method = method; cd->name = pstrdup (name); cd->code = code; @@ -745,8 +745,8 @@ add_stat_sample (int type, uintptr_t ip) { size_stat_samples *= 2; if (!size_stat_samples) size_stat_samples = 32; - stat_samples = (uintptr_t *)realloc (stat_samples, size_stat_samples * sizeof (uintptr_t)); - stat_sample_desc = (int *)realloc (stat_sample_desc, size_stat_samples * sizeof (int)); + stat_samples = (uintptr_t *) g_realloc (stat_samples, size_stat_samples * sizeof (uintptr_t)); + stat_sample_desc = (int *) g_realloc (stat_sample_desc, size_stat_samples * sizeof (int)); } stat_samples [num_stat_samples] = ip; stat_sample_desc [num_stat_samples++] = type; @@ -829,10 +829,10 @@ add_unmanaged_symbol (uintptr_t addr, char *name, uintptr_t size) int new_size = usymbols_size * 2; if (!new_size) new_size = 16; - usymbols = (UnmanagedSymbol **)realloc (usymbols, sizeof (void*) * new_size); + usymbols = (UnmanagedSymbol **) g_realloc (usymbols, sizeof (void*) * new_size); usymbols_size = new_size; } - sym = (UnmanagedSymbol *)calloc (sizeof (UnmanagedSymbol), 1); + sym = (UnmanagedSymbol *) g_calloc (sizeof (UnmanagedSymbol), 1); sym->addr = addr; sym->name = name; sym->size = size; @@ -877,10 +877,10 @@ add_unmanaged_binary (uintptr_t addr, char *name, uintptr_t size) int new_size = ubinaries_size * 2; if (!new_size) new_size = 16; - ubinaries = (UnmanagedSymbol **)realloc (ubinaries, sizeof (void*) * new_size); + ubinaries = (UnmanagedSymbol **) g_realloc (ubinaries, sizeof (void*) * new_size); ubinaries_size = new_size; } - sym = (UnmanagedSymbol *)calloc (sizeof (UnmanagedSymbol), 1); + sym = (UnmanagedSymbol *) g_calloc (sizeof (UnmanagedSymbol), 1); sym->addr = addr; sym->name = name; sym->size = size; @@ -967,7 +967,7 @@ dump_samples (void) msize *= 2; if (!msize) msize = 4; - cachedm = (MethodDesc **)realloc (cachedm, sizeof (void*) * msize); + cachedm = (MethodDesc **) g_realloc (cachedm, sizeof (void*) * msize); } cachedm [count++] = m; } @@ -985,7 +985,7 @@ dump_samples (void) usize *= 2; if (!usize) usize = 4; - cachedus = (UnmanagedSymbol **)realloc (cachedus, sizeof (void*) * usize); + cachedus = (UnmanagedSymbol **) g_realloc (cachedus, sizeof (void*) * usize); } cachedus [ucount++] = usym; } @@ -1093,7 +1093,7 @@ add_heap_class_rev (HeapClassDesc *from, HeapClassDesc *to) to->rev_hash_size *= 2; if (to->rev_hash_size == 0) to->rev_hash_size = 4; - n = (HeapClassRevRef *)calloc (sizeof (HeapClassRevRef) * to->rev_hash_size, 1); + n = (HeapClassRevRef *) g_calloc (sizeof (HeapClassRevRef) * to->rev_hash_size, 1); for (i = 0; i < old_size; ++i) { if (to->rev_hash [i].klass) add_rev_class_hashed (n, to->rev_hash_size, to->rev_hash [i].klass, to->rev_hash [i].count); @@ -1135,9 +1135,9 @@ static int num_heap_shots = 0; static HeapShot* new_heap_shot (uint64_t timestamp) { - HeapShot *hs = (HeapShot *)calloc (sizeof (HeapShot), 1); + HeapShot *hs = (HeapShot *) g_calloc (sizeof (HeapShot), 1); hs->hash_size = 4; - hs->class_hash = (HeapClassDesc **)calloc (sizeof (void*), hs->hash_size); + hs->class_hash = (HeapClassDesc **) g_calloc (sizeof (void*), hs->hash_size); hs->timestamp = timestamp; num_heap_shots++; hs->next = heap_shots; @@ -1183,7 +1183,7 @@ add_heap_hashed (HeapClassDesc **hash, HeapClassDesc **retv, uintptr_t hsize, Cl hash [i] = *retv; return 1; } - hash [i] = (HeapClassDesc *)calloc (sizeof (HeapClassDesc), 1); + hash [i] = (HeapClassDesc *) g_calloc (sizeof (HeapClassDesc), 1); hash [i]->klass = klass; hash [i]->total_size += size; hash [i]->count += count; @@ -1210,7 +1210,7 @@ add_heap_shot_class (HeapShot *hs, ClassDesc *klass, uint64_t size) hs->hash_size *= 2; if (hs->hash_size == 0) hs->hash_size = 4; - n = (HeapClassDesc **)calloc (sizeof (void*) * hs->hash_size, 1); + n = (HeapClassDesc **) g_calloc (sizeof (void*) * hs->hash_size, 1); for (i = 0; i < old_size; ++i) { res = hs->class_hash [i]; if (hs->class_hash [i]) @@ -1230,7 +1230,7 @@ add_heap_shot_class (HeapShot *hs, ClassDesc *klass, uint64_t size) static HeapObjectDesc* alloc_heap_obj (uintptr_t objaddr, HeapClassDesc *hklass, uintptr_t num_refs) { - HeapObjectDesc* ho = (HeapObjectDesc *)calloc (sizeof (HeapObjectDesc) + num_refs * sizeof (uintptr_t), 1); + HeapObjectDesc* ho = (HeapObjectDesc *) g_calloc (sizeof (HeapObjectDesc) + num_refs * sizeof (uintptr_t), 1); ho->objaddr = objaddr; ho->hklass = hklass; ho->num_refs = num_refs; @@ -1313,7 +1313,7 @@ add_heap_shot_obj (HeapShot *hs, HeapObjectDesc *obj) hs->objects_hash_size *= 2; if (hs->objects_hash_size == 0) hs->objects_hash_size = 4; - n = (HeapObjectDesc **)calloc (sizeof (void*) * hs->objects_hash_size, 1); + n = (HeapObjectDesc **) g_calloc (sizeof (void*) * hs->objects_hash_size, 1); for (i = 0; i < old_size; ++i) { if (hs->objects_hash [i]) add_heap_hashed_obj (n, hs->objects_hash_size, hs->objects_hash [i]); @@ -1367,7 +1367,7 @@ heap_shot_mark_objects (HeapShot *hs) if (!debug) return; /* consistency checks: it seems not all the objects are walked in the heap in some cases */ - marks = (unsigned char *)calloc (hs->objects_hash_size, 1); + marks = (unsigned char *) g_calloc (hs->objects_hash_size, 1); if (!marks) return; for (i = 0; i < hs->num_roots; ++i) { @@ -1480,14 +1480,14 @@ add_backtrace (int count, MethodDesc **methods) return bt; bt = bt->next; } - bt = (BackTrace *)malloc (sizeof (BackTrace) + ((count - 1) * sizeof (void*))); + bt = (BackTrace *) g_malloc (sizeof (BackTrace) + ((count - 1) * sizeof (void*))); bt->next = backtrace_hash [slot]; backtrace_hash [slot] = bt; if (next_backtrace == num_backtraces) { num_backtraces *= 2; if (!num_backtraces) num_backtraces = 16; - backtraces = (BackTrace **)realloc (backtraces, sizeof (void*) * num_backtraces); + backtraces = (BackTrace **) g_realloc (backtraces, sizeof (void*) * num_backtraces); } bt->id = next_backtrace++; backtraces [bt->id] = bt; @@ -1567,7 +1567,7 @@ static void ensure_buffer (ProfContext *ctx, int size) { if (ctx->size < size) { - ctx->buf = (unsigned char *)realloc (ctx->buf, size); + ctx->buf = (unsigned char *) g_realloc (ctx->buf, size); ctx->size = size; } } @@ -1605,16 +1605,16 @@ get_thread (ProfContext *ctx, intptr_t thread_id) } thread = thread->next; } - thread = (ThreadContext *)calloc (sizeof (ThreadContext), 1); + thread = (ThreadContext *) g_calloc (sizeof (ThreadContext), 1); thread->next = ctx->threads; ctx->threads = thread; thread->thread_id = thread_id; thread->last_time = 0; thread->stack_id = 0; thread->stack_size = 32; - thread->stack = (MethodDesc **)malloc (thread->stack_size * sizeof (void*)); - thread->time_stack = (uint64_t *)malloc (thread->stack_size * sizeof (uint64_t)); - thread->callee_time_stack = (uint64_t *)malloc (thread->stack_size * sizeof (uint64_t)); + thread->stack = (MethodDesc **) g_malloc (thread->stack_size * sizeof (void*)); + thread->time_stack = (uint64_t *) g_malloc (thread->stack_size * sizeof (uint64_t)); + thread->callee_time_stack = (uint64_t *) g_malloc (thread->stack_size * sizeof (uint64_t)); return thread; } @@ -1633,7 +1633,7 @@ get_domain (ProfContext *ctx, intptr_t domain_id) domain = domain->next; } - domain = (DomainContext *)calloc (sizeof (DomainContext), 1); + domain = (DomainContext *) g_calloc (sizeof (DomainContext), 1); domain->next = ctx->domains; ctx->domains = domain; domain->domain_id = domain_id; @@ -1656,7 +1656,7 @@ get_remctx (ProfContext *ctx, intptr_t remctx_id) remctx = remctx->next; } - remctx = (RemCtxContext *)calloc (sizeof (RemCtxContext), 1); + remctx = (RemCtxContext *) g_calloc (sizeof (RemCtxContext), 1); remctx->next = ctx->remctxs; ctx->remctxs = remctx; remctx->remctx_id = remctx_id; @@ -1677,9 +1677,9 @@ ensure_thread_stack (ThreadContext *thread) { if (thread->stack_id == thread->stack_size) { thread->stack_size *= 2; - thread->stack = (MethodDesc **)realloc (thread->stack, thread->stack_size * sizeof (void*)); - thread->time_stack = (uint64_t *)realloc (thread->time_stack, thread->stack_size * sizeof (uint64_t)); - thread->callee_time_stack = (uint64_t *)realloc (thread->callee_time_stack, thread->stack_size * sizeof (uint64_t)); + thread->stack = (MethodDesc **) g_realloc (thread->stack, thread->stack_size * sizeof (void*)); + thread->time_stack = (uint64_t *) g_realloc (thread->time_stack, thread->stack_size * sizeof (uint64_t)); + thread->callee_time_stack = (uint64_t *) g_realloc (thread->callee_time_stack, thread->stack_size * sizeof (uint64_t)); } } @@ -1720,7 +1720,7 @@ add_trace_bt (BackTrace *bt, TraceDesc *trace, uint64_t value) trace->size *= 2; if (trace->size == 0) trace->size = 4; - n = (CallContext *)calloc (sizeof (CallContext) * trace->size, 1); + n = (CallContext *) g_calloc (sizeof (CallContext) * trace->size, 1); for (i = 0; i < old_size; ++i) { if (trace->traces [i].bt) add_trace_hashed (n, trace->size, trace->traces [i].bt, trace->traces [i].count); @@ -1766,9 +1766,9 @@ thread_add_root (ThreadContext *ctx, uintptr_t obj, int root_type, uintptr_t ext int new_size = ctx->size_roots * 2; if (!new_size) new_size = 4; - ctx->roots = (uintptr_t *)realloc (ctx->roots, new_size * sizeof (uintptr_t)); - ctx->roots_extra = (uintptr_t *)realloc (ctx->roots_extra, new_size * sizeof (uintptr_t)); - ctx->roots_types = (int *)realloc (ctx->roots_types, new_size * sizeof (int)); + ctx->roots = (uintptr_t *) g_realloc (ctx->roots, new_size * sizeof (uintptr_t)); + ctx->roots_extra = (uintptr_t *) g_realloc (ctx->roots_extra, new_size * sizeof (uintptr_t)); + ctx->roots_types = (int *) g_realloc (ctx->roots_types, new_size * sizeof (int)); ctx->size_roots = new_size; } ctx->roots_types [ctx->num_roots] = root_type; @@ -1927,7 +1927,7 @@ lookup_monitor (uintptr_t objid) while (cd && cd->objid != objid) cd = cd->next; if (!cd) { - cd = (MonitorDesc *)calloc (sizeof (MonitorDesc), 1); + cd = (MonitorDesc *) g_calloc (sizeof (MonitorDesc), 1); cd->objid = objid; cd->next = monitor_hash [slot]; monitor_hash [slot] = cd; @@ -2029,7 +2029,7 @@ decode_bt (ProfContext *ctx, MethodDesc** sframes, int *size, unsigned char *p, decode_uleb128 (p, &p); /* flags */ int count = decode_uleb128 (p, &p); if (count > *size) - frames = (MethodDesc **)malloc (count * sizeof (void*)); + frames = (MethodDesc **) g_malloc (count * sizeof (void*)); else frames = sframes; for (i = 0; i < count; ++i) { @@ -2104,7 +2104,7 @@ static void found_object (uintptr_t obj) { num_tracked_objects ++; - tracked_objects = (uintptr_t *)realloc (tracked_objects, num_tracked_objects * sizeof (tracked_objects [0])); + tracked_objects = (uintptr_t *) g_realloc (tracked_objects, num_tracked_objects * sizeof (tracked_objects [0])); tracked_objects [num_tracked_objects - 1] = obj; } @@ -3019,7 +3019,7 @@ decode_buffer (ProfContext *ctx) else type = decode_uleb128 (p, &p); - value = (CounterValue *)calloc (1, sizeof (CounterValue)); + value = (CounterValue *) g_calloc (1, sizeof (CounterValue)); value->timestamp = timestamp; switch (type) { @@ -3027,11 +3027,11 @@ decode_buffer (ProfContext *ctx) #if SIZEOF_VOID_P == 4 case MONO_COUNTER_WORD: #endif - value->buffer = (unsigned char *)malloc (sizeof (int32_t)); + value->buffer = (unsigned char *)g_malloc (sizeof (int32_t)); *(int32_t*)value->buffer = (int32_t)decode_sleb128 (p, &p) + (previous ? (*(int32_t*)previous->buffer) : 0); break; case MONO_COUNTER_UINT: - value->buffer = (unsigned char *)malloc (sizeof (uint32_t)); + value->buffer = (unsigned char *) g_malloc (sizeof (uint32_t)); *(uint32_t*)value->buffer = (uint32_t)decode_uleb128 (p, &p) + (previous ? (*(uint32_t*)previous->buffer) : 0); break; case MONO_COUNTER_LONG: @@ -3039,15 +3039,15 @@ decode_buffer (ProfContext *ctx) case MONO_COUNTER_WORD: #endif case MONO_COUNTER_TIME_INTERVAL: - value->buffer = (unsigned char *)malloc (sizeof (int64_t)); + value->buffer = (unsigned char *) g_malloc (sizeof (int64_t)); *(int64_t*)value->buffer = (int64_t)decode_sleb128 (p, &p) + (previous ? (*(int64_t*)previous->buffer) : 0); break; case MONO_COUNTER_ULONG: - value->buffer = (unsigned char *)malloc (sizeof (uint64_t)); + value->buffer = (unsigned char *) g_malloc (sizeof (uint64_t)); *(uint64_t*)value->buffer = (uint64_t)decode_uleb128 (p, &p) + (previous ? (*(uint64_t*)previous->buffer) : 0); break; case MONO_COUNTER_DOUBLE: - value->buffer = (unsigned char *)malloc (sizeof (double)); + value->buffer = (unsigned char *) g_malloc (sizeof (double)); #if TARGET_BYTE_ORDER == G_LITTLE_ENDIAN for (i = 0; i < sizeof (double); i++) #else @@ -3243,7 +3243,7 @@ static ProfContext* load_file (char *name) { unsigned char *p; - ProfContext *ctx = (ProfContext *)calloc (sizeof (ProfContext), 1); + ProfContext *ctx = (ProfContext *) g_calloc (sizeof (ProfContext), 1); if (strcmp (name, "-") == 0) ctx->file = stdin; else @@ -3418,7 +3418,7 @@ dump_monitors (void) int i, j; if (!num_monitors) return; - monitors = (MonitorDesc **)malloc (sizeof (void*) * num_monitors); + monitors = (MonitorDesc **) g_malloc (sizeof (void*) * num_monitors); for (i = 0, j = 0; i < SMALL_HASH_SIZE; ++i) { MonitorDesc *mdesc = monitor_hash [i]; while (mdesc) { @@ -3500,7 +3500,7 @@ dump_allocations (void) intptr_t allocs = 0; uint64_t size = 0; int header_done = 0; - ClassDesc **classes = (ClassDesc **)malloc (num_classes * sizeof (void*)); + ClassDesc **classes = (ClassDesc **) g_malloc (num_classes * sizeof (void*)); ClassDesc *cd; c = 0; for (i = 0; i < HASH_SIZE; ++i) { @@ -3599,7 +3599,7 @@ dump_methods (void) int i, c; uint64_t calls = 0; int header_done = 0; - MethodDesc **methods = (MethodDesc **)malloc (num_methods * sizeof (void*)); + MethodDesc **methods = (MethodDesc **) g_malloc (num_methods * sizeof (void*)); MethodDesc *cd; c = 0; for (i = 0; i < HASH_SIZE; ++i) { @@ -3694,7 +3694,7 @@ heap_shot_summary (HeapShot *hs, int hs_num, HeapShot *last_hs) int i; HeapClassDesc *cd; HeapClassDesc **sorted; - sorted = (HeapClassDesc **)malloc (sizeof (void*) * hs->class_count); + sorted = (HeapClassDesc **) g_malloc (sizeof (void*) * hs->class_count); for (i = 0; i < hs->hash_size; ++i) { cd = hs->class_hash [i]; if (!cd) @@ -3735,7 +3735,7 @@ heap_shot_summary (HeapShot *hs, int hs_num, HeapShot *last_hs) } if (!collect_traces) continue; - rev_sorted = (HeapClassRevRef *)malloc (cd->rev_count * sizeof (HeapClassRevRef)); + rev_sorted = (HeapClassRevRef *) g_malloc (cd->rev_count * sizeof (HeapClassRevRef)); k = 0; for (j = 0; j < cd->rev_hash_size; ++j) { if (cd->rev_hash [j].klass) @@ -3772,7 +3772,7 @@ dump_heap_shots (void) int i; if (!heap_shots) return; - hs_sorted = (HeapShot **)malloc (num_heap_shots * sizeof (void*)); + hs_sorted = (HeapShot **) g_malloc (num_heap_shots * sizeof (void*)); fprintf (outfile, "\nHeap shot summary\n"); i = 0; for (hs = heap_shots; hs; hs = hs->next) From cf076ebd1dfc8aa912eb3199ef7c8d9eda0b1876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 21:14:20 +0200 Subject: [PATCH 47/50] [profiler] Address a couple of FIXMEs in the counters sampling code. --- mono/profiler/mono-profiler-log.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 64abb62179af..5b901e28754d 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -2978,17 +2978,15 @@ counters_sample (MonoProfiler *profiler, uint64_t timestamp) counter = agent->counter; size = mono_counter_get_size (counter); - if (size < 0) { - continue; // FIXME error - } else if (size > buffer_size) { + + if (size > buffer_size) { buffer_size = size; buffer = g_realloc (buffer, buffer_size); } memset (buffer, 0, buffer_size); - if (mono_counters_sample (counter, buffer, size) < 0) - continue; // FIXME error + g_assert (mono_counters_sample (counter, buffer, size)); type = mono_counter_get_type (counter); From 61d6684f2782f9ceb61e7ee639cd15c3d2cea1ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 21:26:51 +0200 Subject: [PATCH 48/50] [profiler] Add a nocounters option. --- man/mprof-report.1 | 9 ++------- mono/profiler/mono-profiler-log.c | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/man/mprof-report.1 b/man/mprof-report.1 index 168759897a91..f19a02aa14ea 100644 --- a/man/mprof-report.1 +++ b/man/mprof-report.1 @@ -209,13 +209,8 @@ The following commands are available: \f[I]heapshot\f[]: perform a heapshot as soon as possible .RE .IP \[bu] 2 -\f[I]counters\f[]: sample counters values every 1 second. This allow -a really lightweight way to have insight in some of the runtime key -metrics. Counters displayed in non verbose mode are : Methods from AOT, -Methods JITted using mono JIT, Methods JITted using LLVM, Total time -spent JITting (sec), User Time, System Time, Total Time, Working Set, -Private Bytes, Virtual Bytes, Page Faults and CPU Load Average (1min, -5min and 15min). +\f[I]nocounters\f[]: disables sampling of runtime and performance +counters, which is normally done every 1 second. .IP \[bu] 2 \f[I]coverage\f[]: collect code coverage data. This implies enabling the \f[I]calls\f[] option. diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index 5b901e28754d..a9b8b342f837 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -66,6 +66,7 @@ static volatile gint32 runtime_inited; static volatile gint32 in_shutdown; +static gboolean no_counters; static int nocalls = 0; static int notraces = 0; static int use_zip = 0; @@ -77,7 +78,6 @@ static int heapshot_requested = 0; static int sample_freq = 0; static int do_mono_sample = 0; static int do_debug = 0; -static int do_counters = 0; static int do_coverage = 0; static gboolean debug_coverage = FALSE; static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS; @@ -3870,7 +3870,8 @@ log_shutdown (MonoProfiler *prof) { InterlockedWrite (&in_shutdown, 1); - counters_and_perfcounters_sample (prof); + if (!no_counters) + counters_and_perfcounters_sample (prof); dump_coverage (prof); @@ -4093,7 +4094,8 @@ helper_thread (void *arg) exit (1); } - counters_and_perfcounters_sample (prof); + if (!no_counters) + counters_and_perfcounters_sample (prof); buffer_lock_excl (); @@ -4824,7 +4826,12 @@ mono_profiler_startup (const char *desc) events &= ~MONO_PROFILE_GC_MOVES; continue; } + if ((opt = match_option (p, "nocounters", NULL)) != p) { + no_counters = TRUE; + continue; + } if ((opt = match_option (p, "time", &val)) != p) { + // For backwards compatibility. if (strcmp (val, "fast") && strcmp (val, "null")) usage (1); g_free (val); @@ -4901,7 +4908,7 @@ mono_profiler_startup (const char *desc) continue; } if ((opt = match_option (p, "counters", NULL)) != p) { - do_counters = 1; + // For backwards compatibility. continue; } if ((opt = match_option (p, "coverage", NULL)) != p) { @@ -4968,6 +4975,7 @@ mono_profiler_startup (const char *desc) exit (1); } + no_counters = TRUE; events = MONO_PROFILE_GC | MONO_PROFILE_THREADS | MONO_PROFILE_ENTER_LEAVE | MONO_PROFILE_INS_COVERAGE; } From c42acf8bf26ced87409602612b598347fd61ec2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 21:50:18 +0200 Subject: [PATCH 49/50] [profiler] Don't emit enter/leave events in onlycoverage mode. --- mono/profiler/mono-profiler-log.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mono/profiler/mono-profiler-log.c b/mono/profiler/mono-profiler-log.c index a9b8b342f837..abfd3d70aa40 100644 --- a/mono/profiler/mono-profiler-log.c +++ b/mono/profiler/mono-profiler-log.c @@ -79,6 +79,7 @@ static int sample_freq = 0; static int do_mono_sample = 0; static int do_debug = 0; static int do_coverage = 0; +static gboolean only_coverage; static gboolean debug_coverage = FALSE; static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS; static int max_allocated_sample_hits; @@ -1952,7 +1953,7 @@ method_enter (MonoProfiler *prof, MonoMethod *method) { process_method_enter_coverage (prof, method); - if (PROF_TLS_GET ()->call_depth++ <= max_call_depth) { + if (!only_coverage && PROF_TLS_GET ()->call_depth++ <= max_call_depth) { ENTER_LOG (&method_entries_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* method */ @@ -1968,7 +1969,7 @@ method_enter (MonoProfiler *prof, MonoMethod *method) static void method_leave (MonoProfiler *prof, MonoMethod *method) { - if (--PROF_TLS_GET ()->call_depth <= max_call_depth) { + if (!only_coverage && --PROF_TLS_GET ()->call_depth <= max_call_depth) { ENTER_LOG (&method_exits_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* method */ @@ -1984,7 +1985,7 @@ method_leave (MonoProfiler *prof, MonoMethod *method) static void method_exc_leave (MonoProfiler *prof, MonoMethod *method) { - if (!nocalls && --PROF_TLS_GET ()->call_depth <= max_call_depth) { + if (!only_coverage && !nocalls && --PROF_TLS_GET ()->call_depth <= max_call_depth) { ENTER_LOG (&method_exception_exits_ctr, logbuffer, EVENT_SIZE /* event */ + LEB128_SIZE /* method */ @@ -4782,7 +4783,6 @@ mono_profiler_startup (const char *desc) const char *opt; int calls_enabled = 0; int allocs_enabled = 0; - int only_coverage = 0; int events = MONO_PROFILE_GC|MONO_PROFILE_ALLOCATIONS| MONO_PROFILE_GC_MOVES|MONO_PROFILE_CLASS_EVENTS|MONO_PROFILE_THREADS| MONO_PROFILE_ENTER_LEAVE|MONO_PROFILE_JIT_COMPILATION|MONO_PROFILE_EXCEPTIONS| @@ -4918,7 +4918,7 @@ mono_profiler_startup (const char *desc) continue; } if ((opt = match_option (p, "onlycoverage", NULL)) != p) { - only_coverage = 1; + only_coverage = TRUE; continue; } if ((opt = match_option (p, "covfilter-file", &val)) != p) { From 958919f5687f190cf64bc6ee981fad162914d806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Wed, 14 Sep 2016 14:26:12 +0200 Subject: [PATCH 50/50] [profiler] Bump profiler version to v1.1. --- mono/profiler/mono-profiler-log.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mono/profiler/mono-profiler-log.h b/mono/profiler/mono-profiler-log.h index 5649d8be76ab..99b5782db6d9 100644 --- a/mono/profiler/mono-profiler-log.h +++ b/mono/profiler/mono-profiler-log.h @@ -4,8 +4,9 @@ #define BUF_ID 0x4D504C01 #define LOG_HEADER_ID 0x4D505A01 #define LOG_VERSION_MAJOR 1 -#define LOG_VERSION_MINOR 0 +#define LOG_VERSION_MINOR 1 #define LOG_DATA_VERSION 13 + /* * Changes in major/minor versions: * version 1.0: removed sysid field from header