X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fprofiler.c;h=9f65059f806699088b673fcf01a1896ae59a7576;hb=baac94e4b7429eb60ec264ef9b974dc148618b64;hp=ccdb022a14fda51e6538da06f85329867d83e6eb;hpb=e0d515ec3235ce7a14eda0174c964a6dcb74bec9;p=mono.git diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c index ccdb022a14f..9f65059f806 100644 --- a/mono/metadata/profiler.c +++ b/mono/metadata/profiler.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -157,23 +158,31 @@ mono_profiler_create (MonoProfiler *prof) return handle; } +void +mono_profiler_set_cleanup_callback (MonoProfilerHandle handle, MonoProfilerCleanupCallback cb) +{ + InterlockedWritePointer (&handle->cleanup_callback, (gpointer) cb); +} + void mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfilerCoverageFilterCallback cb) { InterlockedWritePointer (&handle->coverage_filter, (gpointer) cb); } -static void -initialize_coverage (void) +mono_bool +mono_profiler_enable_coverage (void) { + if (mono_profiler_state.startup_done) + return FALSE; + mono_os_mutex_init (&mono_profiler_state.coverage_mutex); mono_profiler_state.coverage_hash = g_hash_table_new (NULL, NULL); -} -static void -lazy_initialize_coverage (void) -{ - mono_lazy_initialize (&mono_profiler_state.coverage_status, initialize_coverage); + if (!mono_debug_enabled ()) + mono_debug_init (MONO_DEBUG_FORMAT_MONO); + + return mono_profiler_state.code_coverage = TRUE; } static void @@ -188,10 +197,11 @@ coverage_unlock (void) mono_os_mutex_unlock (&mono_profiler_state.coverage_mutex); } -void +mono_bool mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb) { - lazy_initialize_coverage (); + if (!mono_profiler_state.code_coverage) + return FALSE; coverage_lock (); @@ -199,9 +209,6 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, coverage_unlock (); - if (!info) - return; - MonoError error; MonoMethodHeader *header = mono_method_get_header_checked (method, &error); mono_error_assert_ok (&error); @@ -209,9 +216,48 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, guint32 size; const unsigned char *start = mono_method_header_get_code (header, &size, NULL); - const unsigned char *end = start - size; + const unsigned char *end = start + size; MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method); + if (!info) { + char *source_file; + int i, n_il_offsets; + int *source_files; + GPtrArray *source_file_list; + MonoSymSeqPoint *sym_seq_points; + + /* Return 0 counts for all locations */ + + mono_debug_get_seq_points (minfo, &source_file, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets); + for (i = 0; i < n_il_offsets; ++i) { + MonoSymSeqPoint *sp = &sym_seq_points [i]; + const char *srcfile = ""; + + if (source_files [i] != -1) { + MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, source_files [i]); + srcfile = sinfo->source_file; + } + + MonoProfilerCoverageData data = { + .method = method, + .il_offset = sp->il_offset, + .counter = 0, + .file_name = srcfile, + .line = sp->line, + .column = 0, + }; + + cb (handle->prof, &data); + } + + g_free (source_files); + g_free (sym_seq_points); + g_ptr_array_free (source_file_list, TRUE); + + mono_metadata_free_mh (header); + return TRUE; + } + for (guint32 i = 0; i < info->entries; i++) { guchar *cil_code = info->data [i].cil_code; @@ -245,12 +291,18 @@ mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, } mono_metadata_free_mh (header); + + return TRUE; } MonoProfilerCoverageInfo * mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries) { - lazy_initialize_coverage (); + if (!mono_profiler_state.code_coverage) + return FALSE; + + if (method->wrapper_type) + return FALSE; gboolean cover = FALSE; @@ -277,23 +329,6 @@ mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries) return info; } -void -mono_profiler_coverage_free (MonoMethod *method) -{ - lazy_initialize_coverage (); - - coverage_lock (); - - MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method); - - if (info) { - g_hash_table_remove (mono_profiler_state.coverage_hash, method); - g_free (info); - } - - coverage_unlock (); -} - mono_bool mono_profiler_enable_sampling (MonoProfilerHandle handle) { @@ -361,9 +396,7 @@ mono_profiler_enable_allocations (void) if (mono_profiler_state.startup_done) return FALSE; - mono_profiler_state.allocations = TRUE; - - return TRUE; + return mono_profiler_state.allocations = TRUE; } void @@ -372,8 +405,61 @@ mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handl InterlockedWritePointer (&handle->call_instrumentation_filter, (gpointer) cb); } -gboolean -mono_profiler_should_instrument_method (MonoMethod *method, gboolean entry) +mono_bool +mono_profiler_enable_call_context_introspection (void) +{ + if (mono_profiler_state.startup_done) + return FALSE; + + mono_profiler_state.context_enable (); + + return mono_profiler_state.call_contexts = TRUE; +} + +void * +mono_profiler_call_context_get_this (MonoProfilerCallContext *context) +{ + if (!mono_profiler_state.call_contexts) + return NULL; + + return mono_profiler_state.context_get_this (context); +} + +void * +mono_profiler_call_context_get_argument (MonoProfilerCallContext *context, uint32_t position) +{ + if (!mono_profiler_state.call_contexts) + return NULL; + + return mono_profiler_state.context_get_argument (context, position); +} + +void * +mono_profiler_call_context_get_local (MonoProfilerCallContext *context, uint32_t position) +{ + if (!mono_profiler_state.call_contexts) + return NULL; + + return mono_profiler_state.context_get_local (context, position); +} + +void * +mono_profiler_call_context_get_result (MonoProfilerCallContext *context) +{ + if (!mono_profiler_state.call_contexts) + return NULL; + + return mono_profiler_state.context_get_result (context); +} + +void +mono_profiler_call_context_free_buffer (void *buffer) +{ + mono_profiler_state.context_free_buffer (buffer); +} + +MonoProfilerCallInstrumentationFlags +mono_profiler_get_call_instrumentation_flags (MonoMethod *method) { MonoProfilerCallInstrumentationFlags flags = MONO_PROFILER_CALL_INSTRUMENTATION_NONE; @@ -384,10 +470,7 @@ mono_profiler_should_instrument_method (MonoMethod *method, gboolean entry) flags |= cb (handle->prof, method); } - if (entry) - return flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE; - else - return flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE; + return flags; } void @@ -441,6 +524,38 @@ mono_profiler_cleanup (void) #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 #undef _MONO_PROFILER_EVENT + + MonoProfilerHandle head = mono_profiler_state.profilers; + + while (head) { + MonoProfilerCleanupCallback cb = head->cleanup_callback; + + if (cb) + cb (head->prof); + + MonoProfilerHandle cur = head; + head = head->next; + + g_free (cur); + } + + if (mono_profiler_state.code_coverage) { + mono_os_mutex_destroy (&mono_profiler_state.coverage_mutex); + + GHashTableIter iter; + + g_hash_table_iter_init (&iter, mono_profiler_state.coverage_hash); + + MonoProfilerCoverageInfo *info; + + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info)) + g_free (info); + + g_hash_table_destroy (mono_profiler_state.coverage_hash); + } + + if (mono_profiler_state.sampling_owner) + mono_os_sem_destroy (&mono_profiler_state.sampling_semaphore); } static void @@ -519,3 +634,134 @@ update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *co #undef MONO_PROFILER_EVENT_3 #undef MONO_PROFILER_EVENT_4 #undef _MONO_PROFILER_EVENT + +/* + * The following code is here to maintain compatibility with a few profiler API + * functions used by Xamarin.{Android,iOS,Mac} so that they keep working + * regardless of which system Mono version is used. + * + * TODO: Remove this some day if we're OK with breaking compatibility. + */ + +typedef void *MonoLegacyProfiler; + +typedef void (*MonoLegacyProfileFunc) (MonoLegacyProfiler *prof); +typedef void (*MonoLegacyProfileThreadFunc) (MonoLegacyProfiler *prof, uintptr_t tid); +typedef void (*MonoLegacyProfileGCFunc) (MonoLegacyProfiler *prof, MonoProfilerGCEvent event, int generation); +typedef void (*MonoLegacyProfileGCResizeFunc) (MonoLegacyProfiler *prof, int64_t new_size); +typedef void (*MonoLegacyProfileJitResult) (MonoLegacyProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result); + +struct _MonoProfiler { + MonoProfilerHandle handle; + MonoLegacyProfiler *profiler; + MonoLegacyProfileFunc shutdown_callback; + MonoLegacyProfileThreadFunc thread_start, thread_end; + MonoLegacyProfileGCFunc gc_event; + MonoLegacyProfileGCResizeFunc gc_heap_resize; + MonoLegacyProfileJitResult jit_end2; +}; + +static MonoProfiler *current; + +MONO_API void mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback); +MONO_API void mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end); +MONO_API void mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback); +MONO_API void mono_profiler_install_jit_end (MonoLegacyProfileJitResult end); +MONO_API void mono_profiler_set_events (int flags); + +static void +shutdown_cb (MonoProfiler *prof) +{ + prof->shutdown_callback (prof->profiler); +} + +void +mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback) +{ + current = g_new0 (MonoProfiler, 1); + current->handle = mono_profiler_create (current); + current->profiler = prof; + current->shutdown_callback = callback; + + if (callback) + mono_profiler_set_runtime_shutdown_end_callback (current->handle, shutdown_cb); +} + +static void +thread_start_cb (MonoProfiler *prof, uintptr_t tid) +{ + prof->thread_start (prof->profiler, tid); +} + +static void +thread_stop_cb (MonoProfiler *prof, uintptr_t tid) +{ + prof->thread_end (prof->profiler, tid); +} + +void +mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end) +{ + current->thread_start = start; + current->thread_end = end; + + if (start) + mono_profiler_set_thread_started_callback (current->handle, thread_start_cb); + + if (end) + mono_profiler_set_thread_stopped_callback (current->handle, thread_stop_cb); +} + +static void +gc_event_cb (MonoProfiler *prof, MonoProfilerGCEvent event, uint32_t generation) +{ + prof->gc_event (prof->profiler, event, generation); +} + +static void +gc_resize_cb (MonoProfiler *prof, uintptr_t size) +{ + prof->gc_heap_resize (prof->profiler, size); +} + +void +mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback) +{ + current->gc_event = callback; + current->gc_heap_resize = heap_resize_callback; + + if (callback) + mono_profiler_set_gc_event_callback (current->handle, gc_event_cb); + + if (heap_resize_callback) + mono_profiler_set_gc_resize_callback (current->handle, gc_resize_cb); +} + +static void +jit_done_cb (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo) +{ + prof->jit_end2 (prof->profiler, method, jinfo, 0); +} + +static void +jit_failed_cb (MonoProfiler *prof, MonoMethod *method) +{ + prof->jit_end2 (prof->profiler, method, NULL, 1); +} + +void +mono_profiler_install_jit_end (MonoLegacyProfileJitResult end) +{ + current->jit_end2 = end; + + if (end) { + mono_profiler_set_jit_done_callback (current->handle, jit_done_cb); + mono_profiler_set_jit_failed_callback (current->handle, jit_failed_cb); + } +} + +void +mono_profiler_set_events (int flags) +{ + /* Do nothing. */ +}