From: Alex Rønne Petersen Date: Thu, 22 Jun 2017 15:15:35 +0000 (+0200) Subject: [runtime] New profiler API. X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mono.git;a=commitdiff_plain;h=ea4e4a9ef6fc42570a23026adbe826cf7248290e [runtime] New profiler API. * Profiler callbacks can now be changed and disabled at any point. * API users no longer have to set event flags. The API instead uses a counter internally for each type of callback. * Filter functions for enter/leave instrumentation can be installed, and they can choose whether to instrument the prologue, epilogue, or both. * Managed allocators can now be instrumented for allocation profiling. * A profiler must now declare that it wishes to use allocation profiling and/or sampling in its init function. * Sampling parameters can now be changed at any point, and the sampling thread can be put into an idle mode when no sampling is needed. * Only one profiler can have control over the sampling parameters. Whichever profiler enables sampling first gets control. * Adding new events is now very easy: One line in profiler-events.h and one line wherever the event should be raised. * Lifted the restriction that enter/leave instrumentation would cause an abort in full AOT mode. * Support for call chain sampling has been removed. * Support for the old, platform-specific code coverage mode has been removed. * The new profiler module entry point is mono_profiler_init. If a module has a mono_profiler_startup symbol (the old entry point), a warning will be printed and the module won't be loaded. * Updated the profiler test suite to work with instrumented managed allocators. --- diff --git a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs index 52385963af2..f9a125b5d16 100644 --- a/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs +++ b/mcs/class/Mono.Profiler.Log/Mono.Profiler.Log/LogEnums.cs @@ -148,7 +148,7 @@ namespace Mono.Profiler.Log { BranchMisses = 6, } - // mono/metadata/profiler.h : MonoProfileGCRootType + // mono/metadata/profiler.h : MonoProfilerGCRootType [Flags] public enum LogHeapRootAttributes { Pinning = 1 << 8, @@ -164,7 +164,7 @@ namespace Mono.Profiler.Log { TypeMask = 0xff, } - // mono/metadata/profiler.h : MonoProfilerMonitorEvent + // mono/profiler/log.h : MonoProfilerMonitorEvent public enum LogMonitorEvent { Contention = 1, Done = 2, @@ -179,7 +179,7 @@ namespace Mono.Profiler.Log { Fault = 4, } - // mono/metadata/profiler.h : MonoGCEvent + // mono/metadata/profiler.h : MonoProfilerGCEvent public enum LogGCEvent { Begin = 0, MarkBegin = 1, @@ -195,7 +195,7 @@ namespace Mono.Profiler.Log { PostStartWorldUnlocked = 11, } - // mono/sgen/gc-internal-agnostic.h : GCHandleType + // mono/metadata/mono-gc.h : MonoGCHandleType public enum LogGCHandleType { Weak = 0, WeakTrackResurrection = 1, diff --git a/mono/cil/cil-opcodes.xml b/mono/cil/cil-opcodes.xml index cafb5561891..886cf63af6f 100644 --- a/mono/cil/cil-opcodes.xml +++ b/mono/cil/cil-opcodes.xml @@ -321,4 +321,5 @@ + diff --git a/mono/cil/opcode.def b/mono/cil/opcode.def index 91e8924febc..7cead418fdf 100644 --- a/mono/cil/opcode.def +++ b/mono/cil/opcode.def @@ -321,6 +321,7 @@ OPDEF(CEE_MONO_LDDOMAIN, "mono_lddomain", Pop0, PushI, InlineNone, X, 2, 0xF0, 0 OPDEF(CEE_MONO_ATOMIC_STORE_I4, "mono_atomic_store_i4", PopI+PopI, Push0, InlineI, X, 2, 0xF0, 0x1A, NEXT) OPDEF(CEE_MONO_GET_LAST_ERROR, "mono_get_last_error", Pop0, PushI, InlineNone, X, 2, 0xF0, 0x1B, NEXT) OPDEF(CEE_MONO_GET_RGCTX_ARG, "mono_get_rgctx_arg", Pop0, PushI, InlineNone, X, 2, 0xF0, 0x1C, NEXT) +OPDEF(CEE_MONO_LDPTR_PROFILER_ALLOCATION_COUNT, "mono_ldptr_profiler_allocation_count", Pop0, PushI, InlineNone, X, 2, 0xF0, 0x1D, NEXT) #ifndef OPALIAS #define _MONO_CIL_OPALIAS_DEFINED_ #define OPALIAS(a,s,r) diff --git a/mono/metadata/Makefile.am b/mono/metadata/Makefile.am index 7f4a2bbdc66..3243c12e47b 100644 --- a/mono/metadata/Makefile.am +++ b/mono/metadata/Makefile.am @@ -220,6 +220,7 @@ common_sources = \ w32process.h \ w32process-internals.h \ profiler.c \ + profiler-events.h \ profiler-private.h \ rand.h \ rand.c \ diff --git a/mono/metadata/appdomain.c b/mono/metadata/appdomain.c index 821fd7d8e53..19c44470ec7 100644 --- a/mono/metadata/appdomain.c +++ b/mono/metadata/appdomain.c @@ -636,7 +636,7 @@ mono_domain_create_appdomain_internal (char *friendly_name, MonoAppDomainSetupHa data->domain = MONO_HANDLE_RAW (ad); data->friendly_name = g_strdup (friendly_name); - mono_profiler_appdomain_name (data, data->friendly_name); + MONO_PROFILER_RAISE (domain_name, (data, data->friendly_name)); MonoStringHandle app_base = MONO_HANDLE_NEW_GET (MonoString, setup, application_base); if (MONO_HANDLE_IS_NULL (app_base)) { diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c index 3ecd1478ba2..e5b1cb0c57a 100644 --- a/mono/metadata/assembly.c +++ b/mono/metadata/assembly.c @@ -2222,7 +2222,7 @@ mono_assembly_load_from_predicate (MonoImage *image, const char *fname, ass->ref_only = refonly; ass->image = image; - mono_profiler_assembly_event (ass, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (assembly_loading, (ass)); mono_assembly_fill_assembly_name (image, &ass->aname); @@ -2314,7 +2314,7 @@ mono_assembly_load_from_predicate (MonoImage *image, const char *fname, mono_assembly_invoke_load_hook (ass); - mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (assembly_loaded, (ass)); return ass; } @@ -3804,7 +3804,7 @@ mono_assembly_close_except_image_pools (MonoAssembly *assembly) if (InterlockedDecrement (&assembly->ref_count) > 0) return FALSE; - mono_profiler_assembly_event (assembly, MONO_PROFILE_START_UNLOAD); + MONO_PROFILER_RAISE (assembly_unloading, (assembly)); mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading assembly %s [%p].", assembly->aname.name, assembly); @@ -3827,7 +3827,7 @@ mono_assembly_close_except_image_pools (MonoAssembly *assembly) g_slist_free (assembly->friend_assembly_names); g_free (assembly->basedir); - mono_profiler_assembly_event (assembly, MONO_PROFILE_END_UNLOAD); + MONO_PROFILER_RAISE (assembly_unloaded, (assembly)); return TRUE; } diff --git a/mono/metadata/boehm-gc.c b/mono/metadata/boehm-gc.c index 50ff079d1e2..9439ebfab06 100644 --- a/mono/metadata/boehm-gc.c +++ b/mono/metadata/boehm-gc.c @@ -428,7 +428,7 @@ static gint64 gc_start_time; static void on_gc_notification (GC_EventType event) { - MonoGCEvent e = (MonoGCEvent)event; + MonoProfilerGCEvent e = (MonoProfilerGCEvent)event; switch (e) { case MONO_GC_EVENT_PRE_STOP_WORLD: @@ -483,16 +483,16 @@ on_gc_notification (GC_EventType event) break; } - mono_profiler_gc_event (e, 0); + MONO_PROFILER_RAISE (gc_event, (e, 0)); switch (e) { case MONO_GC_EVENT_PRE_STOP_WORLD: mono_thread_info_suspend_lock (); - mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, 0)); break; case MONO_GC_EVENT_POST_START_WORLD: mono_thread_info_suspend_unlock (); - mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, 0)); break; default: break; @@ -511,7 +511,8 @@ on_gc_heap_resize (size_t new_size) mono_perfcounters->gc_gen0size = heap_size; } #endif - mono_profiler_gc_heap_resize (new_size); + + MONO_PROFILER_RAISE (gc_resize, (new_size)); } typedef struct { @@ -689,8 +690,8 @@ mono_gc_alloc_obj (MonoVTable *vtable, size_t size) obj->vtable = vtable; } - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) - mono_profiler_allocation (obj); + if (G_UNLIKELY (mono_profiler_allocations_enabled ())) + MONO_PROFILER_RAISE (gc_allocation, (obj)); return obj; } @@ -723,8 +724,8 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length) obj->max_length = max_length; - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) - mono_profiler_allocation (&obj->obj); + if (G_UNLIKELY (mono_profiler_allocations_enabled ())) + MONO_PROFILER_RAISE (gc_allocation, (&obj->obj)); return obj; } @@ -760,8 +761,8 @@ 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 (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) - mono_profiler_allocation (&obj->obj); + if (G_UNLIKELY (mono_profiler_allocations_enabled ())) + MONO_PROFILER_RAISE (gc_allocation, (&obj->obj)); return obj; } @@ -778,8 +779,8 @@ mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len) obj->length = len; obj->chars [len] = 0; - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) - mono_profiler_allocation (&obj->object); + if (G_UNLIKELY (mono_profiler_allocations_enabled ())) + MONO_PROFILER_RAISE (gc_allocation, (&obj->object)); return obj; } @@ -1175,7 +1176,7 @@ mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean know return NULL; if (mono_class_has_finalizer (klass) || mono_class_is_marshalbyref (klass)) return NULL; - if (mono_profiler_get_events () & (MONO_PROFILE_ALLOCATIONS | MONO_PROFILE_STATISTICAL)) + if (G_UNLIKELY (mono_profiler_allocations_enabled ())) return NULL; if (klass->rank) return NULL; @@ -1726,7 +1727,7 @@ alloc_handle (HandleData *handles, MonoObject *obj, gboolean track) #endif unlock_handles (handles); res = MONO_GC_HANDLE (slot, handles->type); - mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handles->type, res, obj); + MONO_PROFILER_RAISE (gc_handle_created, (res, handles->type, obj)); return res; } @@ -1924,7 +1925,7 @@ mono_gchandle_free (guint32 gchandle) #endif /*g_print ("freed entry %d of type %d\n", slot, handles->type);*/ unlock_handles (handles); - mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handles->type, gchandle, NULL); + MONO_PROFILER_RAISE (gc_handle_deleted, (gchandle, handles->type)); } /** diff --git a/mono/metadata/class.c b/mono/metadata/class.c index 4ed4f39da3d..cd3f8bf703b 100644 --- a/mono/metadata/class.c +++ b/mono/metadata/class.c @@ -5561,7 +5561,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError klass->name = name; klass->name_space = nspace; - mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (class_loading, (klass)); klass->image = image; klass->type_token = type_token; @@ -5635,7 +5635,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError /*FIXME implement a mono_class_set_failure_from_mono_error */ mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error)); mono_loader_unlock (); - mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED); + MONO_PROFILER_RAISE (class_failed, (klass)); return NULL; } } @@ -5692,7 +5692,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error)); mono_loader_unlock (); - mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED); + MONO_PROFILER_RAISE (class_failed, (klass)); return NULL; } @@ -5742,7 +5742,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError klass->cast_class = klass->element_class = mono_defaults.int32_class; mono_class_set_type_load_failure (klass, "%s", mono_error_get_message (error)); mono_loader_unlock (); - mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED); + MONO_PROFILER_RAISE (class_failed, (klass)); return NULL; } klass->cast_class = klass->element_class = mono_class_from_mono_type (enum_basetype); @@ -5756,7 +5756,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError if (mono_class_is_gtd (klass) && !mono_metadata_load_generic_param_constraints_checked (image, type_token, mono_class_get_generic_container (klass), error)) { mono_class_set_type_load_failure (klass, "Could not load generic parameter constrains due to %s", mono_error_get_message (error)); mono_loader_unlock (); - mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED); + MONO_PROFILER_RAISE (class_failed, (klass)); return NULL; } @@ -5770,7 +5770,7 @@ mono_class_create_from_typedef (MonoImage *image, guint32 type_token, MonoError mono_loader_unlock (); - mono_profiler_class_loaded (klass, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (class_loaded, (klass)); return klass; @@ -5780,7 +5780,7 @@ parent_failure: mono_class_setup_mono_type (klass); mono_loader_unlock (); - mono_profiler_class_loaded (klass, MONO_PROFILE_FAILED); + MONO_PROFILER_RAISE (class_failed, (klass)); return NULL; } @@ -5917,7 +5917,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass) if (mono_class_is_nullable (klass)) klass->cast_class = klass->element_class = mono_class_get_nullable_param (klass); - mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (class_loading, (klass)); mono_generic_class_setup_parent (klass, gklass); @@ -5927,7 +5927,7 @@ mono_generic_class_get_class (MonoGenericClass *gclass) mono_memory_barrier (); gclass->cached_class = klass; - mono_profiler_class_loaded (klass, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (class_loaded, (klass)); ++class_ginst_count; inflated_classes_size += sizeof (MonoClassGenericInst); @@ -6013,7 +6013,7 @@ make_generic_param_class (MonoGenericParam *param, MonoGenericParamInfo *pinfo) CHECKED_METADATA_WRITE_PTR_EXEMPT ( klass->name_space , oklass ? oklass->name_space : "" ); } - mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (class_loading, (klass)); // Count non-NULL items in pinfo->constraints count = 0; @@ -6229,9 +6229,9 @@ mono_class_from_generic_parameter_internal (MonoGenericParam *param) /* FIXME: Should this go inside 'make_generic_param_klass'? */ if (klass2) - mono_profiler_class_loaded (klass2, MONO_PROFILE_FAILED); // Alert profiler about botched class create + MONO_PROFILER_RAISE (class_failed, (klass2)); else - mono_profiler_class_loaded (klass, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (class_loaded, (klass)); return klass; } @@ -6283,7 +6283,7 @@ mono_ptr_class_get (MonoType *type) result->class_kind = MONO_CLASS_POINTER; g_free (name); - mono_profiler_class_event (result, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (class_loading, (result)); result->image = el_class->image; result->inited = TRUE; @@ -6303,7 +6303,7 @@ mono_ptr_class_get (MonoType *type) MonoClass *result2; if ((result2 = (MonoClass *)g_hash_table_lookup (image->ptr_cache, el_class))) { mono_image_unlock (image); - mono_profiler_class_loaded (result, MONO_PROFILE_FAILED); + MONO_PROFILER_RAISE (class_failed, (result)); return result2; } } else { @@ -6312,7 +6312,7 @@ mono_ptr_class_get (MonoType *type) g_hash_table_insert (image->ptr_cache, el_class, result); mono_image_unlock (image); - mono_profiler_class_loaded (result, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (class_loaded, (result)); return result; } @@ -6361,7 +6361,7 @@ mono_fnptr_class_get (MonoMethodSignature *sig) return cached; } - mono_profiler_class_event (result, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (class_loading, (result)); classes_size += sizeof (MonoClassPointer); ++class_pointer_count; @@ -6370,7 +6370,7 @@ mono_fnptr_class_get (MonoMethodSignature *sig) mono_loader_unlock (); - mono_profiler_class_loaded (result, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (class_loaded, (result)); return result; } @@ -6689,7 +6689,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) return cached; } - mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (class_loading, (klass)); classes_size += sizeof (MonoClassArray); ++class_array_count; @@ -6705,7 +6705,7 @@ mono_bounded_array_class_get (MonoClass *eclass, guint32 rank, gboolean bounded) mono_loader_unlock (); - mono_profiler_class_loaded (klass, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (class_loaded, (klass)); return klass; } diff --git a/mono/metadata/domain.c b/mono/metadata/domain.c index 16dc31752dd..2a97148f212 100644 --- a/mono/metadata/domain.c +++ b/mono/metadata/domain.c @@ -398,7 +398,7 @@ mono_domain_create (void) domain->friendly_name = NULL; domain->search_path = NULL; - mono_profiler_appdomain_event (domain, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (domain_loading, (domain)); domain->mp = mono_mempool_new (); domain->code_mp = mono_code_manager_new (); @@ -439,7 +439,7 @@ mono_domain_create (void) if (create_domain_hook) create_domain_hook (domain); - mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (domain_loaded, (domain)); return domain; } @@ -762,7 +762,7 @@ mono_init_internal (const char *filename, const char *exe_filename, const char * domain->friendly_name = g_path_get_basename (filename); - mono_profiler_appdomain_name (domain, domain->friendly_name); + MONO_PROFILER_RAISE (domain_name, (domain, domain->friendly_name)); return domain; } @@ -1033,7 +1033,7 @@ mono_domain_free (MonoDomain *domain, gboolean force) if (mono_dont_free_domains) return; - mono_profiler_appdomain_event (domain, MONO_PROFILE_START_UNLOAD); + MONO_PROFILER_RAISE (domain_unloading, (domain)); mono_debug_domain_unload (domain); @@ -1120,7 +1120,7 @@ mono_domain_free (MonoDomain *domain, gboolean force) * Send this after the assemblies have been unloaded and the domain is still in a * usable state. */ - mono_profiler_appdomain_event (domain, MONO_PROFILE_END_UNLOAD); + MONO_PROFILER_RAISE (domain_unloaded, (domain)); if (free_domain_hook) free_domain_hook (domain); diff --git a/mono/metadata/dynamic-image.c b/mono/metadata/dynamic-image.c index 9ea2bcf0ee5..211ba26266f 100644 --- a/mono/metadata/dynamic-image.c +++ b/mono/metadata/dynamic-image.c @@ -316,7 +316,7 @@ mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, c image = g_new0 (MonoDynamicImage, 1); - mono_profiler_module_event (&image->image, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (image_loading, (&image->image)); /*g_print ("created image %p\n", image);*/ /* keep in sync with image.c */ @@ -375,7 +375,7 @@ mono_dynamic_image_create (MonoDynamicAssembly *assembly, char *assembly_name, c image->pe_kind = 0x1; /* ILOnly */ image->machine = 0x14c; /* I386 */ - mono_profiler_module_loaded (&image->image, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (image_loaded, (&image->image)); dynamic_images_lock (); diff --git a/mono/metadata/gc-internals.h b/mono/metadata/gc-internals.h index 4473b04d60d..76e73073dcc 100644 --- a/mono/metadata/gc-internals.h +++ b/mono/metadata/gc-internals.h @@ -174,8 +174,10 @@ void mono_gc_wbarrier_set_root (gpointer ptr, MonoObject *value); typedef enum { // Regular fast path allocator. MANAGED_ALLOCATOR_REGULAR, - // Managed allocator that just calls into the runtime. Used when allocation profiling w/ AOT. + // Managed allocator that just calls into the runtime. MANAGED_ALLOCATOR_SLOW_PATH, + // Managed allocator that works like the regular one but also calls into the profiler. + MANAGED_ALLOCATOR_PROFILER, } ManagedAllocatorVariant; int mono_gc_get_aligned_size_for_allocator (int size); diff --git a/mono/metadata/gc.c b/mono/metadata/gc.c index f561dc15b4c..4d8075ffd20 100644 --- a/mono/metadata/gc.c +++ b/mono/metadata/gc.c @@ -305,11 +305,11 @@ mono_gc_run_finalize (void *obj, void *data) if (log_finalizers) g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Calling finalizer.", o->vtable->klass->name, o); - mono_profiler_gc_finalize_object_begin (o); + MONO_PROFILER_RAISE (gc_finalizing_object, (o)); runtime_invoke (o, NULL, &exc, NULL); - mono_profiler_gc_finalize_object_end (o); + MONO_PROFILER_RAISE (gc_finalized_object, (o)); if (log_finalizers) g_log ("mono-gc-finalizers", G_LOG_LEVEL_MESSAGE, "<%s at %p> Returned from finalizer.", o->vtable->klass->name, o); @@ -873,14 +873,14 @@ finalizer_thread (gpointer unused) finalize_domain_objects (); - mono_profiler_gc_finalize_begin (); + MONO_PROFILER_RAISE (gc_finalizing, ()); /* If finished == TRUE, mono_gc_cleanup has been called (from mono_runtime_cleanup), * before the domain is unloaded. */ mono_gc_invoke_finalizers (); - mono_profiler_gc_finalize_end (); + MONO_PROFILER_RAISE (gc_finalized, ()); mono_threads_join_threads (); diff --git a/mono/metadata/image.c b/mono/metadata/image.c index f878339b210..827ba841c3d 100644 --- a/mono/metadata/image.c +++ b/mono/metadata/image.c @@ -1272,7 +1272,7 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, GSList *errors = NULL; GSList *l; - mono_profiler_module_event (image, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (image_loading, (image)); mono_image_init (image); @@ -1336,7 +1336,7 @@ do_mono_image_load (MonoImage *image, MonoImageOpenStatus *status, load_modules (image); done: - mono_profiler_module_loaded (image, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (image_loaded, (image)); if (status) *status = MONO_IMAGE_OK; @@ -1348,7 +1348,7 @@ invalid_image: g_warning ("Could not load image %s due to %s", image->name, info->message); mono_free_verify_list (errors); } - mono_profiler_module_loaded (image, MONO_PROFILE_FAILED); + MONO_PROFILER_RAISE (image_failed, (image)); mono_image_close (image); return NULL; } @@ -1978,7 +1978,7 @@ mono_image_close_except_pools (MonoImage *image) } #endif - mono_profiler_module_event (image, MONO_PROFILE_START_UNLOAD); + MONO_PROFILER_RAISE (image_unloading, (image)); mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_ASSEMBLY, "Unloading image %s [%p].", image->name, image); @@ -2139,7 +2139,7 @@ mono_image_close_except_pools (MonoImage *image) mono_dynamic_image_free ((MonoDynamicImage*)image); } - mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD); + MONO_PROFILER_RAISE (image_unloaded, (image)); return TRUE; } diff --git a/mono/metadata/loader.c b/mono/metadata/loader.c index d9781cbdfdd..56c3572e76e 100644 --- a/mono/metadata/loader.c +++ b/mono/metadata/loader.c @@ -1901,11 +1901,10 @@ mono_get_method_constrained_checked (MonoImage *image, guint32 token, MonoClass void mono_free_method (MonoMethod *method) { - if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS) - mono_profiler_method_free (method); + MONO_PROFILER_RAISE (method_free, (method)); /* FIXME: This hack will go away when the profiler will support freeing methods */ - if (mono_profiler_get_events () != MONO_PROFILE_NONE) + if (G_UNLIKELY (mono_profiler_installed ())) return; if (method->signature) { diff --git a/mono/metadata/monitor.c b/mono/metadata/monitor.c index beb96a4dc43..702a47c654f 100644 --- a/mono/metadata/monitor.c +++ b/mono/metadata/monitor.c @@ -801,7 +801,7 @@ retry: return 0; } - mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_CONTENTION); + MONO_PROFILER_RAISE (monitor_contention, (obj)); /* The slow path begins here. */ retry_contended: @@ -824,7 +824,7 @@ retry_contended: if (G_LIKELY (tmp_status == old_status)) { /* Success */ g_assert (mon->nest == 1); - mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_DONE); + MONO_PROFILER_RAISE (monitor_acquired, (obj)); return 1; } } @@ -832,7 +832,7 @@ retry_contended: /* If the object is currently locked by this thread... */ if (mon_status_get_owner (old_status) == id) { mon->nest++; - mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_DONE); + MONO_PROFILER_RAISE (monitor_acquired, (obj)); return 1; } @@ -946,7 +946,7 @@ done_waiting: /* Timed out or interrupted */ mon_decrement_entry_count (mon); - mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_FAIL); + MONO_PROFILER_RAISE (monitor_failed, (obj)); if (wait_ret == MONO_SEM_TIMEDWAIT_RET_ALERTED) { LOCK_DEBUG (g_message ("%s: (%d) interrupted waiting, returning -1", __func__, id)); diff --git a/mono/metadata/mono-gc.h b/mono/metadata/mono-gc.h index d8d5d4435ed..bd1262a67b8 100644 --- a/mono/metadata/mono-gc.h +++ b/mono/metadata/mono-gc.h @@ -45,6 +45,15 @@ typedef enum { MONO_ROOT_SOURCE_HANDLE = 14, } MonoGCRootSource; +typedef enum { + MONO_GC_HANDLE_TYPE_MIN = 0, + MONO_GC_HANDLE_WEAK = MONO_GC_HANDLE_TYPE_MIN, + MONO_GC_HANDLE_WEAK_TRACK_RESURRECTION, + MONO_GC_HANDLE_NORMAL, + MONO_GC_HANDLE_PINNED, + MONO_GC_HANDLE_TYPE_MAX, +} MonoGCHandleType; + MONO_API void mono_gc_collect (int generation); MONO_API int mono_gc_max_generation (void); MONO_API int mono_gc_get_generation (MonoObject *object); diff --git a/mono/metadata/object.c b/mono/metadata/object.c index 3ee786a5d60..5744f45d3c4 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -2822,13 +2822,11 @@ do_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject **ex error_init (error); - if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS) - mono_profiler_method_start_invoke (method); + MONO_PROFILER_RAISE (method_begin_invoke, (method)); result = callbacks.runtime_invoke (method, obj, params, exc, error); - if (mono_profiler_get_events () & MONO_PROFILE_METHOD_EVENTS) - mono_profiler_method_end_invoke (method); + MONO_PROFILER_RAISE (method_end_invoke, (method)); if (!mono_error_ok (error)) return NULL; diff --git a/mono/metadata/profiler-events.h b/mono/metadata/profiler-events.h new file mode 100644 index 00000000000..4f9ce6462c5 --- /dev/null +++ b/mono/metadata/profiler-events.h @@ -0,0 +1,88 @@ +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. + */ + +/* + * To #include this file, #define the following macros first: + * + * MONO_PROFILER_EVENT_0(name, type) + * MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) + * MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) + * MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) + * MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) + * + * To add new callbacks to the API, simply add a line in this file and use + * MONO_PROFILER_RAISE to raise the event wherever. If you need more arguments + * then the current macros provide, add another macro and update all areas + * where the macros are used. + */ + +MONO_PROFILER_EVENT_0(runtime_initialized, RuntimeInitialized) +MONO_PROFILER_EVENT_0(runtime_shutdown, RuntimeShutdown) + +MONO_PROFILER_EVENT_1(context_loaded, ContextLoaded, MonoAppContext *, context) +MONO_PROFILER_EVENT_1(context_unloaded, ContextUnloaded, MonoAppContext *, context) + +MONO_PROFILER_EVENT_1(domain_loading, DomainLoading, MonoDomain *, domain) +MONO_PROFILER_EVENT_1(domain_loaded, DomainLoaded, MonoDomain *, domain) +MONO_PROFILER_EVENT_1(domain_unloading, DomainUnloading, MonoDomain *, domain) +MONO_PROFILER_EVENT_1(domain_unloaded, DomainUnloaded, MonoDomain *, domain) +MONO_PROFILER_EVENT_2(domain_name, DomainName, MonoDomain *, domain, const char *, name) + +MONO_PROFILER_EVENT_1(jit_begin, JitBegin, MonoMethod *, method) +MONO_PROFILER_EVENT_1(jit_failed, JitFailed, MonoMethod *, method) +MONO_PROFILER_EVENT_2(jit_done, JitDone, MonoMethod *, method, MonoJitInfo *, jinfo) +MONO_PROFILER_EVENT_2(jit_chunk_created, JitChunkCreated, const mono_byte *, chunk, uintptr_t, size) +MONO_PROFILER_EVENT_1(jit_chunk_destroyed, JitChunkDestroyed, const mono_byte *, chunk) +MONO_PROFILER_EVENT_4(jit_code_buffer, JitCodeBuffer, const mono_byte *, buffer, uint64_t, size, MonoProfilerCodeBufferType, type, const void *, data) + +MONO_PROFILER_EVENT_1(class_loading, ClassLoading, MonoClass *, klass) +MONO_PROFILER_EVENT_1(class_failed, ClassFailed, MonoClass *, klass) +MONO_PROFILER_EVENT_1(class_loaded, ClassLoaded, MonoClass *, klass) + +MONO_PROFILER_EVENT_1(image_loading, ModuleLoading, MonoImage *, image) +MONO_PROFILER_EVENT_1(image_failed, ModuleFailed, MonoImage *, image) +MONO_PROFILER_EVENT_1(image_loaded, ModuleLoaded, MonoImage *, image) +MONO_PROFILER_EVENT_1(image_unloading, ModuleUnloading, MonoImage *, image) +MONO_PROFILER_EVENT_1(image_unloaded, ModuleUnloaded, MonoImage *, image) + +MONO_PROFILER_EVENT_1(assembly_loading, AssemblyLoading, MonoAssembly *, assembly) +MONO_PROFILER_EVENT_1(assembly_loaded, AssemblyLLoaded, MonoAssembly *, assembly) +MONO_PROFILER_EVENT_1(assembly_unloading, AssemblyLUnloading, MonoAssembly *, assembly) +MONO_PROFILER_EVENT_1(assembly_unloaded, AssemblyLUnloaded, MonoAssembly *, assembly) + +MONO_PROFILER_EVENT_1(method_enter, MethodEnter, MonoMethod *, method) +MONO_PROFILER_EVENT_1(method_leave, MethodLeave, MonoMethod *, method) +MONO_PROFILER_EVENT_2(method_exception_leave, MethodExceptionLeave, MonoMethod *, method, MonoObject *, exception) +MONO_PROFILER_EVENT_1(method_free, MethodFree, MonoMethod *, method) +MONO_PROFILER_EVENT_1(method_begin_invoke, MethodBeginInvoke, MonoMethod *, method) +MONO_PROFILER_EVENT_1(method_end_invoke, MethodEndInvoke, MonoMethod *, method) + +MONO_PROFILER_EVENT_1(exception_throw, ExceptionThrow, MonoObject *, exception) +MONO_PROFILER_EVENT_4(exception_clause, ExceptionClause, MonoMethod *, method, uint32_t, index, MonoExceptionEnum, type, MonoObject *, exception) + +MONO_PROFILER_EVENT_2(gc_event, GCEvent, MonoProfilerGCEvent, event, uint32_t, generation) +MONO_PROFILER_EVENT_1(gc_allocation, GCAllocation, MonoObject *, object) +MONO_PROFILER_EVENT_2(gc_moves, GCMoves, MonoObject *const *, objects, uint64_t, count) +MONO_PROFILER_EVENT_1(gc_resize, GCResize, uintptr_t, size) +MONO_PROFILER_EVENT_3(gc_handle_created, GCHandleCreated, uint32_t, handle, MonoGCHandleType, type, MonoObject *, object) +MONO_PROFILER_EVENT_2(gc_handle_deleted, GCHandleDeleted, uint32_t, handle, MonoGCHandleType, type) +MONO_PROFILER_EVENT_4(gc_roots, GCRoots, MonoObject *const *, roots, const MonoProfilerGCRootType *, types, const uintptr_t *, extra, uint64_t, count) +MONO_PROFILER_EVENT_0(gc_finalizing, GCFinalizing) +MONO_PROFILER_EVENT_0(gc_finalized, GCFinalized) +MONO_PROFILER_EVENT_1(gc_finalizing_object, GCFinalizingObject, MonoObject *, object) +MONO_PROFILER_EVENT_1(gc_finalized_object, GCFinalizedObject, MonoObject *, object) + +MONO_PROFILER_EVENT_1(monitor_contention, MonitorContention, MonoObject *, object) +MONO_PROFILER_EVENT_1(monitor_failed, MonitorFailed, MonoObject *, object) +MONO_PROFILER_EVENT_1(monitor_acquired, MonitorAcquired, MonoObject *, object) + +MONO_PROFILER_EVENT_1(thread_started, ThreadStarted, uintptr_t, tid) +MONO_PROFILER_EVENT_1(thread_stopped, ThreadStopped, uintptr_t, tid) +MONO_PROFILER_EVENT_2(thread_name, ThreadName, uintptr_t, tid, const char *, name) + +MONO_PROFILER_EVENT_2(sample_hit, SampleHit, const mono_byte *, ip, const void *, context) + +MONO_PROFILER_EVENT_3(iomap_report, IOMap, const char *, report, const char *, old_path, const char *, new_path) diff --git a/mono/metadata/profiler-private.h b/mono/metadata/profiler-private.h index 07df86b211f..4d1b93d4a95 100644 --- a/mono/metadata/profiler-private.h +++ b/mono/metadata/profiler-private.h @@ -1,96 +1,139 @@ -/** - * \file +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. */ #ifndef __MONO_PROFILER_PRIVATE_H__ #define __MONO_PROFILER_PRIVATE_H__ #include -#include "mono/utils/mono-compiler.h" -#include - -extern MonoProfileFlags mono_profiler_events; - -enum { - MONO_PROFILE_START_LOAD, - MONO_PROFILE_END_LOAD, - MONO_PROFILE_START_UNLOAD, - MONO_PROFILE_END_UNLOAD +#include +#include +#include + +struct _MonoProfilerDesc { + MonoProfilerHandle next; + MonoProfiler *prof; + volatile gpointer coverage_filter; + volatile gpointer call_instrumentation_filter; + +#define _MONO_PROFILER_EVENT(name) \ + volatile gpointer name ## _cb; +#define MONO_PROFILER_EVENT_0(name, type) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ + _MONO_PROFILER_EVENT(name) +#include +#undef MONO_PROFILER_EVENT_0 +#undef MONO_PROFILER_EVENT_1 +#undef MONO_PROFILER_EVENT_2 +#undef MONO_PROFILER_EVENT_3 +#undef MONO_PROFILER_EVENT_4 +#undef _MONO_PROFILER_EVENT }; typedef struct { - int entries; - struct { - guchar* cil_code; - int count; - } data [1]; -} MonoProfileCoverageInfo; - -void mono_profiler_shutdown (void); - -void mono_profiler_method_enter (MonoMethod *method); -void mono_profiler_method_leave (MonoMethod *method); -void mono_profiler_method_jit (MonoMethod *method); -void mono_profiler_method_end_jit (MonoMethod *method, MonoJitInfo* jinfo, int result); -void mono_profiler_method_free (MonoMethod *method); -void mono_profiler_method_start_invoke (MonoMethod *method); -void mono_profiler_method_end_invoke (MonoMethod *method); - -void mono_profiler_code_transition (MonoMethod *method, int result); -void mono_profiler_allocation (MonoObject *obj); -void mono_profiler_monitor_event (MonoObject *obj, MonoProfilerMonitorEvent event); -void mono_profiler_stat_hit (guchar *ip, void *context); -void mono_profiler_stat_call_chain (int call_chain_depth, guchar **ips, void *context); -int mono_profiler_stat_get_call_chain_depth (void); -MonoProfilerCallChainStrategy mono_profiler_stat_get_call_chain_strategy (void); -void mono_profiler_thread_start (gsize tid); -void mono_profiler_thread_end (gsize tid); -void mono_profiler_thread_name (gsize tid, const char *name); - -void mono_profiler_exception_thrown (MonoObject *exception); -void mono_profiler_exception_method_leave (MonoMethod *method); -void mono_profiler_exception_clause_handler (MonoMethod *method, int clause_type, int clause_num, MonoObject *exc); - -void mono_profiler_assembly_event (MonoAssembly *assembly, int code); -void mono_profiler_assembly_loaded (MonoAssembly *assembly, int result); - -void mono_profiler_module_event (MonoImage *image, int code); -void mono_profiler_module_loaded (MonoImage *image, int result); - -void mono_profiler_class_event (MonoClass *klass, int code); -void mono_profiler_class_loaded (MonoClass *klass, int result); - -void mono_profiler_appdomain_event (MonoDomain *domain, int code); -void mono_profiler_appdomain_loaded (MonoDomain *domain, int result); -void mono_profiler_appdomain_name (MonoDomain *domain, const char *name); - -void mono_profiler_context_loaded (MonoAppContext *context); -void mono_profiler_context_unloaded (MonoAppContext *context); - -void mono_profiler_iomap (char *report, const char *pathname, const char *new_pathname); - -MonoProfileCoverageInfo* mono_profiler_coverage_alloc (MonoMethod *method, int entries); -void mono_profiler_coverage_free (MonoMethod *method); - -void mono_profiler_gc_event (MonoGCEvent e, int generation); -void mono_profiler_gc_heap_resize (gint64 new_size); -void mono_profiler_gc_moves (void **objects, int num); -void mono_profiler_gc_handle (int op, int type, uintptr_t handle, MonoObject *obj); -void mono_profiler_gc_roots (int num, void **objects, int *root_types, uintptr_t *extra_info); - -void mono_profiler_gc_finalize_begin (void); -void mono_profiler_gc_finalize_object_begin (MonoObject *obj); -void mono_profiler_gc_finalize_object_end (MonoObject *obj); -void mono_profiler_gc_finalize_end (void); - -void mono_profiler_code_chunk_new (gpointer chunk, int size); -void mono_profiler_code_chunk_destroy (gpointer chunk); -void mono_profiler_code_buffer_new (gpointer buffer, int size, MonoProfilerCodeBufferType type, gconstpointer data); - -void mono_profiler_runtime_initialized (void); - -int64_t mono_profiler_get_sampling_rate (void); -MonoProfileSamplingMode mono_profiler_get_sampling_mode (void); - -#endif /* __MONO_PROFILER_PRIVATE_H__ */ + gboolean startup_done; + MonoProfilerHandle profilers; + mono_lazy_init_t coverage_status; + mono_mutex_t coverage_mutex; + GHashTable *coverage_hash; + MonoProfilerHandle sampling_owner; + MonoSemType sampling_semaphore; + MonoProfilerSampleMode sample_mode; + uint64_t sample_freq; + gboolean allocations; + +#define _MONO_PROFILER_EVENT(name) \ + volatile gint32 name ## _count; +#define MONO_PROFILER_EVENT_0(name, type) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ + _MONO_PROFILER_EVENT(name) +#include +#undef MONO_PROFILER_EVENT_0 +#undef MONO_PROFILER_EVENT_1 +#undef MONO_PROFILER_EVENT_2 +#undef MONO_PROFILER_EVENT_3 +#undef MONO_PROFILER_EVENT_4 +#undef _MONO_PROFILER_EVENT +} MonoProfilerState; + +extern MonoProfilerState mono_profiler_state; +typedef struct { + guint32 entries; + struct { + guchar *cil_code; + guint32 count; + } data [1]; +} MonoProfilerCoverageInfo; + +void mono_profiler_started (void); +void mono_profiler_cleanup (void); + +static inline gboolean +mono_profiler_installed (void) +{ + return !!mono_profiler_state.profilers; +} + +MonoProfilerCoverageInfo *mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries); +void mono_profiler_coverage_free (MonoMethod *method); + +gboolean mono_profiler_should_instrument_method (MonoMethod *method, gboolean entry); + +gboolean mono_profiler_sampling_enabled (void); +void mono_profiler_sampling_thread_sleep (void); + +static inline gboolean +mono_profiler_allocations_enabled (void) +{ + return mono_profiler_state.allocations; +} + +#define _MONO_PROFILER_EVENT(name, ...) \ + void mono_profiler_raise_ ## name (__VA_ARGS__); +#define MONO_PROFILER_EVENT_0(name, type) \ + _MONO_PROFILER_EVENT(name, void) +#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \ + _MONO_PROFILER_EVENT(name, arg1_type arg1_name) +#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \ + _MONO_PROFILER_EVENT(name, arg1_type arg1_name, arg2_type arg2_name) +#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \ + _MONO_PROFILER_EVENT(name, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name) +#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ + _MONO_PROFILER_EVENT(name, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name) +#include +#undef MONO_PROFILER_EVENT_0 +#undef MONO_PROFILER_EVENT_1 +#undef MONO_PROFILER_EVENT_2 +#undef MONO_PROFILER_EVENT_3 +#undef MONO_PROFILER_EVENT_4 +#undef _MONO_PROFILER_EVENT + +// These are the macros the rest of the runtime should use. + +#define MONO_PROFILER_ENABLED(name) \ + G_UNLIKELY (mono_profiler_state.name ## _count) + +#define MONO_PROFILER_RAISE(name, args) \ + do { \ + if (MONO_PROFILER_ENABLED (name)) \ + mono_profiler_raise_ ## name args; \ + } while (0) + +#endif // __MONO_PROFILER_PRIVATE_H__ diff --git a/mono/metadata/profiler.c b/mono/metadata/profiler.c index c69f55ec6dc..a1e222fc1e6 100644 --- a/mono/metadata/profiler.c +++ b/mono/metadata/profiler.c @@ -1,1428 +1,529 @@ -/** - * \file - * Profiler interface for Mono - * - * Author: - * Paolo Molaro (lupus@ximian.com) - * Alex Rønne Petersen (alexrp@xamarin.com) - * - * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com) - * Copyright 2004-2009 Novell, Inc (http://www.novell.com) - * Copyright 2011 Xamarin Inc (http://www.xamarin.com). - * Licensed under the MIT license. See LICENSE file in the project root for full license information. +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. */ -#include "config.h" -#include "mono/metadata/profiler-private.h" -#include "mono/metadata/assembly.h" -#include "mono/metadata/debug-helpers.h" -#include "mono/metadata/mono-debug.h" -#include "mono/metadata/debug-internals.h" -#include "mono/metadata/metadata-internals.h" -#include "mono/metadata/class-internals.h" -#include "mono/metadata/domain-internals.h" -#include "mono/metadata/gc-internals.h" -#include "mono/metadata/mono-config-dirs.h" -#include "mono/utils/mono-dl.h" -#include -#include -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_BACKTRACE_SYMBOLS -#include -#endif - -typedef struct _ProfilerDesc ProfilerDesc; -struct _ProfilerDesc { - ProfilerDesc *next; - MonoProfiler *profiler; - MonoProfileFlags events; - - MonoProfileAppDomainFunc domain_start_load; - MonoProfileAppDomainResult domain_end_load; - MonoProfileAppDomainFunc domain_start_unload; - MonoProfileAppDomainFunc domain_end_unload; - MonoProfileAppDomainFriendlyNameFunc domain_name; - - MonoProfileContextFunc context_load; - MonoProfileContextFunc context_unload; - - MonoProfileAssemblyFunc assembly_start_load; - MonoProfileAssemblyResult assembly_end_load; - MonoProfileAssemblyFunc assembly_start_unload; - MonoProfileAssemblyFunc assembly_end_unload; - - MonoProfileModuleFunc module_start_load; - MonoProfileModuleResult module_end_load; - MonoProfileModuleFunc module_start_unload; - MonoProfileModuleFunc module_end_unload; - - MonoProfileClassFunc class_start_load; - MonoProfileClassResult class_end_load; - MonoProfileClassFunc class_start_unload; - MonoProfileClassFunc class_end_unload; - - MonoProfileMethodFunc jit_start; - MonoProfileMethodResult jit_end; - MonoProfileJitResult jit_end2; - MonoProfileMethodFunc method_free; - MonoProfileMethodFunc method_start_invoke; - MonoProfileMethodFunc method_end_invoke; - MonoProfileMethodResult man_unman_transition; - MonoProfileAllocFunc allocation_cb; - MonoProfileMonitorFunc monitor_event_cb; - MonoProfileStatFunc statistical_cb; - MonoProfileStatCallChainFunc statistical_call_chain_cb; - int statistical_call_chain_depth; - MonoProfilerCallChainStrategy statistical_call_chain_strategy; - MonoProfileMethodFunc method_enter; - MonoProfileMethodFunc method_leave; - - MonoProfileExceptionFunc exception_throw_cb; - MonoProfileMethodFunc exception_method_leave_cb; - MonoProfileExceptionClauseFunc exception_clause_cb; - MonoProfileExceptionClauseFunc2 exception_clause_cb2; - - MonoProfileIomapFunc iomap_cb; - - MonoProfileThreadFunc thread_start; - MonoProfileThreadFunc thread_end; - MonoProfileThreadNameFunc thread_name; - - MonoProfileCoverageFilterFunc coverage_filter_cb; - - MonoProfileFunc shutdown_callback; - - MonoProfileGCFunc gc_event; - MonoProfileGCResizeFunc gc_heap_resize; - MonoProfileGCMoveFunc gc_moves; - MonoProfileGCHandleFunc gc_handle; - MonoProfileGCRootFunc gc_roots; - - MonoProfileGCFinalizeFunc gc_finalize_begin; - MonoProfileGCFinalizeObjectFunc gc_finalize_object_begin; - MonoProfileGCFinalizeObjectFunc gc_finalize_object_end; - MonoProfileGCFinalizeFunc gc_finalize_end; - - MonoProfileFunc runtime_initialized_event; - - MonoProfilerCodeChunkNew code_chunk_new; - MonoProfilerCodeChunkDestroy code_chunk_destroy; - MonoProfilerCodeBufferNew code_buffer_new; -}; - -static ProfilerDesc *prof_list = NULL; - -#define mono_profiler_coverage_lock() mono_os_mutex_lock (&profiler_coverage_mutex) -#define mono_profiler_coverage_unlock() mono_os_mutex_unlock (&profiler_coverage_mutex) -static mono_mutex_t profiler_coverage_mutex; - -/* this is directly accessible to other mono libs. - * It is the ORed value of all the profiler's events. - */ -MonoProfileFlags mono_profiler_events; - -/** - * mono_profiler_install: - * \param prof a \c MonoProfiler structure pointer, or a pointer to a derived structure. - * \param callback the function to invoke at shutdown - * Use \c mono_profiler_install to activate profiling in the Mono runtime. - * Typically developers of new profilers will create a new structure whose - * first field is a \c MonoProfiler and put any extra information that they need - * to access from the various profiling callbacks there. - */ -void -mono_profiler_install (MonoProfiler *prof, MonoProfileFunc callback) -{ - ProfilerDesc *desc = g_new0 (ProfilerDesc, 1); - if (!prof_list) - mono_os_mutex_init_recursive (&profiler_coverage_mutex); - desc->profiler = prof; - desc->shutdown_callback = callback; - desc->next = prof_list; - prof_list = desc; -} +#include +#include +#include +#include +#include +#include +#include -/** - * mono_profiler_set_events: - * \param events an ORed set of values made up of \c MONO_PROFILER_ flags - * The events described in the \p events argument is a set of flags - * that represent which profiling events must be triggered. For - * example if you have registered a set of methods for tracking - * JIT compilation start and end with \c mono_profiler_install_jit_compile, - * you will want to pass the \c MONO_PROFILE_JIT_COMPILATION flag to - * this routine. - * - * You can call \c mono_profile_set_events more than once and you can - * do this at runtime to modify which methods are invoked. - */ -void -mono_profiler_set_events (MonoProfileFlags events) -{ - ProfilerDesc *prof; - MonoProfileFlags value = (MonoProfileFlags)0; - if (prof_list) - prof_list->events = events; - for (prof = prof_list; prof; prof = prof->next) - value = (MonoProfileFlags)(value | prof->events); - mono_profiler_events = value; -} +MonoProfilerState mono_profiler_state; -/** - * mono_profiler_get_events: - * - * Returns a list of active events that will be intercepted. - */ -MonoProfileFlags -mono_profiler_get_events (void) -{ - return mono_profiler_events; -} +typedef void (*MonoProfilerInitializer) (const char *); -/** - * mono_profiler_install_enter_leave: - * \param enter the routine to be called on each method entry - * \param fleave the routine to be called each time a method returns - * - * Use this routine to install routines that will be called everytime - * a method enters and leaves. The routines will receive as an argument - * the \c MonoMethod representing the method that is entering or leaving. - */ -void -mono_profiler_install_enter_leave (MonoProfileMethodFunc enter, MonoProfileMethodFunc fleave) -{ - if (!prof_list) - return; - prof_list->method_enter = enter; - prof_list->method_leave = fleave; -} +#define OLD_INITIALIZER_NAME "mono_profiler_startup" +#define NEW_INITIALIZER_NAME "mono_profiler_init" -/** - * mono_profiler_install_jit_compile: - * \param start the routine to be called when the JIT process starts. - * \param end the routine to be called when the JIT process ends. - * - * Use this routine to install routines that will be called when JIT - * compilation of a method starts and completes. - */ -void -mono_profiler_install_jit_compile (MonoProfileMethodFunc start, MonoProfileMethodResult end) +static gboolean +load_profiler (MonoDl *module, const char *desc, const char *suffix) { - if (!prof_list) - return; - prof_list->jit_start = start; - prof_list->jit_end = end; -} + if (!module) + return FALSE; -void -mono_profiler_install_jit_end (MonoProfileJitResult end) -{ - if (!prof_list) - return; - prof_list->jit_end2 = end; -} + char *old_name; -void -mono_profiler_install_method_free (MonoProfileMethodFunc callback) -{ - if (!prof_list) - return; - prof_list->method_free = callback; -} + if (suffix) + old_name = g_strdup_printf (OLD_INITIALIZER_NAME "_%s", suffix); + else + old_name = g_strdup_printf (OLD_INITIALIZER_NAME); -void -mono_profiler_install_method_invoke (MonoProfileMethodFunc start, MonoProfileMethodFunc end) -{ - if (!prof_list) - return; - prof_list->method_start_invoke = start; - prof_list->method_end_invoke = end; -} + MonoProfilerInitializer func; -/** - * mono_profiler_install_thread: - */ -void -mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc end) -{ - if (!prof_list) - return; - prof_list->thread_start = start; - prof_list->thread_end = end; -} + char *err; -void -mono_profiler_install_thread_name (MonoProfileThreadNameFunc thread_name_cb) -{ - if (!prof_list) - return; - prof_list->thread_name = thread_name_cb; -} + if (!(err = mono_dl_symbol (module, old_name, (gpointer) &func))) { + g_warning ("Found old-style startup symbol %s; profiler has not been migrated to the new API.", old_name); + g_free (old_name); + return FALSE; + } -/** - * mono_profiler_install_transition: - */ -void -mono_profiler_install_transition (MonoProfileMethodResult callback) -{ - if (!prof_list) - return; - prof_list->man_unman_transition = callback; -} + g_free (err); + g_free (old_name); -/** - * mono_profiler_install_allocation: - */ -void -mono_profiler_install_allocation (MonoProfileAllocFunc callback) -{ - if (!prof_list) - return; - prof_list->allocation_cb = callback; -} + char *new_name; -void -mono_profiler_install_monitor (MonoProfileMonitorFunc callback) -{ - if (!prof_list) - return; - prof_list->monitor_event_cb = callback; -} + if (suffix) + new_name = g_strdup_printf (NEW_INITIALIZER_NAME "_%s", suffix); + else + new_name = g_strdup_printf (NEW_INITIALIZER_NAME); -static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS; -static int64_t sampling_frequency = 100; // Hz - -/** - * mono_profiler_set_statistical_mode: - * \param mode the sampling mode used. - * \param sample_frequency_is_us the sampling frequency in microseconds. - * - * Set the sampling parameters for the profiler. Sampling mode affects the effective sampling rate as in samples/s you'll witness. - * The default sampling mode is process mode, which only reports samples when there's activity in the process. - * - * Sampling frequency should be interpreted as a suggestion that can't always be honored due to how most kernels expose alarms. - * - * Said that, when using statistical sampling, always assume variable rate sampling as all sort of external factors can interfere. - */ -void -mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_hz) -{ - sampling_mode = mode; - sampling_frequency = sampling_frequency_hz; -} + if ((err = mono_dl_symbol (module, new_name, (gpointer *) &func))) { + g_free (err); + g_free (new_name); + return FALSE; + } -/** - * mono_profiler_install_statistical: - */ -void -mono_profiler_install_statistical (MonoProfileStatFunc callback) -{ - if (!prof_list) - return; - prof_list->statistical_cb = callback; -} + g_free (new_name); -int64_t -mono_profiler_get_sampling_rate (void) -{ - return sampling_frequency; -} + func (desc); -MonoProfileSamplingMode -mono_profiler_get_sampling_mode (void) -{ - return sampling_mode; + return TRUE; } -void -mono_profiler_install_statistical_call_chain (MonoProfileStatCallChainFunc callback, int call_chain_depth, MonoProfilerCallChainStrategy call_chain_strategy) { - if (!prof_list) - return; - if (call_chain_depth > MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH) { - call_chain_depth = MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH; - } - if ((call_chain_strategy >= MONO_PROFILER_CALL_CHAIN_INVALID) || (call_chain_strategy < MONO_PROFILER_CALL_CHAIN_NONE)) { - call_chain_strategy = MONO_PROFILER_CALL_CHAIN_NONE; - } - prof_list->statistical_call_chain_cb = callback; - prof_list->statistical_call_chain_depth = call_chain_depth; - prof_list->statistical_call_chain_strategy = call_chain_strategy; -} +static gboolean +load_profiler_from_executable (const char *desc, const char *name) +{ + char *err; -int -mono_profiler_stat_get_call_chain_depth (void) { - if (prof_list && prof_list->statistical_call_chain_cb != NULL) { - return prof_list->statistical_call_chain_depth; - } else { - return 0; - } -} + /* + * Some profilers (such as ours) may need to call back into the runtime + * from their sampling callback (which is called in async-signal context). + * They need to be able to know that all references back to the runtime + * have been resolved; otherwise, calling runtime functions may result in + * invoking the dynamic linker which is not async-signal-safe. Passing + * MONO_DL_EAGER will ask the dynamic linker to resolve everything upfront. + */ + MonoDl *module = mono_dl_open (NULL, MONO_DL_EAGER, &err); -MonoProfilerCallChainStrategy -mono_profiler_stat_get_call_chain_strategy (void) { - if (prof_list && prof_list->statistical_call_chain_cb != NULL) { - return prof_list->statistical_call_chain_strategy; - } else { - return MONO_PROFILER_CALL_CHAIN_NONE; + if (!module) { + g_warning ("Could not open main executable (%s).", err); + g_free (err); + return FALSE; } -} - -void mono_profiler_install_exception (MonoProfileExceptionFunc throw_callback, MonoProfileMethodFunc exc_method_leave, MonoProfileExceptionClauseFunc clause_callback) -{ - if (!prof_list) - return; - prof_list->exception_throw_cb = throw_callback; - prof_list->exception_method_leave_cb = exc_method_leave; - prof_list->exception_clause_cb = clause_callback; -} - -void mono_profiler_install_exception_clause (MonoProfileExceptionClauseFunc2 clause_callback) -{ - if (!prof_list) - return; - prof_list->exception_clause_cb2 = clause_callback; + return load_profiler (module, desc, name); } -/** - * mono_profiler_install_coverage_filter: - */ -void -mono_profiler_install_coverage_filter (MonoProfileCoverageFilterFunc callback) +static gboolean +load_profiler_from_directory (const char *directory, const char *libname, const char *desc) { - if (!prof_list) - return; - prof_list->coverage_filter_cb = callback; -} + char* path; + void *iter = NULL; -/** - * mono_profiler_install_appdomain: - */ -void -mono_profiler_install_appdomain (MonoProfileAppDomainFunc start_load, MonoProfileAppDomainResult end_load, - MonoProfileAppDomainFunc start_unload, MonoProfileAppDomainFunc end_unload) + while ((path = mono_dl_build_path (directory, libname, &iter))) { + // See the comment in load_embedded_profiler (). + MonoDl *module = mono_dl_open (path, MONO_DL_EAGER, NULL); -{ - if (!prof_list) - return; - prof_list->domain_start_load = start_load; - prof_list->domain_end_load = end_load; - prof_list->domain_start_unload = start_unload; - prof_list->domain_end_unload = end_unload; -} + g_free (path); -void -mono_profiler_install_appdomain_name (MonoProfileAppDomainFriendlyNameFunc domain_name_cb) -{ - if (!prof_list) - return; + if (module) + return load_profiler (module, desc, NULL); + } - prof_list->domain_name = domain_name_cb; + return FALSE; } -void -mono_profiler_install_context (MonoProfileContextFunc load, MonoProfileContextFunc unload) +static gboolean +load_profiler_from_installation (const char *libname, const char *desc) { - if (!prof_list) - return; + char *err; + MonoDl *module = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err); - prof_list->context_load = load; - prof_list->context_unload = unload; -} + g_free (err); -/** - * mono_profiler_install_assembly: - */ -void -mono_profiler_install_assembly (MonoProfileAssemblyFunc start_load, MonoProfileAssemblyResult end_load, - MonoProfileAssemblyFunc start_unload, MonoProfileAssemblyFunc end_unload) -{ - if (!prof_list) - return; - prof_list->assembly_start_load = start_load; - prof_list->assembly_end_load = end_load; - prof_list->assembly_start_unload = start_unload; - prof_list->assembly_end_unload = end_unload; -} + if (module) + return load_profiler (module, desc, NULL); -/** - * mono_profiler_install_module: - */ -void -mono_profiler_install_module (MonoProfileModuleFunc start_load, MonoProfileModuleResult end_load, - MonoProfileModuleFunc start_unload, MonoProfileModuleFunc end_unload) -{ - if (!prof_list) - return; - prof_list->module_start_load = start_load; - prof_list->module_end_load = end_load; - prof_list->module_start_unload = start_unload; - prof_list->module_end_unload = end_unload; + return FALSE; } -/** - * mono_profiler_install_class: - */ void -mono_profiler_install_class (MonoProfileClassFunc start_load, MonoProfileClassResult end_load, - MonoProfileClassFunc start_unload, MonoProfileClassFunc end_unload) +mono_profiler_load (const char *desc) { - if (!prof_list) - return; - prof_list->class_start_load = start_load; - prof_list->class_end_load = end_load; - prof_list->class_start_unload = start_unload; - prof_list->class_end_unload = end_unload; -} + mono_gc_base_init (); -/** - * mono_profiler_method_enter: - */ -void -mono_profiler_method_enter (MonoMethod *method) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_ENTER_LEAVE) && prof->method_enter) - prof->method_enter (prof->profiler, method); - } -} + if (!desc || !strcmp ("default", desc)) + desc = "log:report"; -/** - * mono_profiler_method_leave: - */ -void -mono_profiler_method_leave (MonoMethod *method) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_ENTER_LEAVE) && prof->method_leave) - prof->method_leave (prof->profiler, method); - } -} + const char *col = strchr (desc, ':'); + char *mname; -/** - * mono_profiler_method_jit: - */ -void -mono_profiler_method_jit (MonoMethod *method) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_JIT_COMPILATION) && prof->jit_start) - prof->jit_start (prof->profiler, method); - } -} + if (col != NULL) { + mname = (char *) g_memdup (desc, col - desc + 1); + mname [col - desc] = 0; + } else + mname = g_strdup (desc); -/** - * mono_profiler_method_end_jit: - */ -void -mono_profiler_method_end_jit (MonoMethod *method, MonoJitInfo* jinfo, int result) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_JIT_COMPILATION)) { - if (prof->jit_end) - prof->jit_end (prof->profiler, method, result); - if (prof->jit_end2) - prof->jit_end2 (prof->profiler, method, jinfo, result); - } - } -} + if (!load_profiler_from_executable (desc, mname)) { + char *libname = g_strdup_printf ("mono-profiler-%s", mname); + gboolean res = load_profiler_from_installation (libname, desc); -void -mono_profiler_method_free (MonoMethod *method) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_free) - prof->method_free (prof->profiler, method); - } -} + if (!res && mono_config_get_assemblies_dir ()) + res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc); -void -mono_profiler_method_start_invoke (MonoMethod *method) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_start_invoke) - prof->method_start_invoke (prof->profiler, method); - } -} + if (!res) + res = load_profiler_from_directory (NULL, libname, desc); -void -mono_profiler_method_end_invoke (MonoMethod *method) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_end_invoke) - prof->method_end_invoke (prof->profiler, method); - } -} + if (!res) + g_warning ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname); -/** - * mono_profiler_code_transition: - */ -void -mono_profiler_code_transition (MonoMethod *method, int result) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_TRANSITIONS) && prof->man_unman_transition) - prof->man_unman_transition (prof->profiler, method, result); + g_free (libname); } + + g_free (mname); } -/** - * mono_profiler_allocation: - */ -void -mono_profiler_allocation (MonoObject *obj) +MonoProfilerHandle +mono_profiler_install (MonoProfiler *prof) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_ALLOCATIONS) && prof->allocation_cb) - prof->allocation_cb (prof->profiler, obj, obj->vtable->klass); - } -} + MonoProfilerHandle handle = g_new0 (struct _MonoProfilerDesc, 1); -void -mono_profiler_monitor_event (MonoObject *obj, MonoProfilerMonitorEvent event) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_MONITOR_EVENTS) && prof->monitor_event_cb) - prof->monitor_event_cb (prof->profiler, obj, event); - } -} + handle->prof = prof; + handle->next = mono_profiler_state.profilers; -/** - * mono_profiler_stat_hit: - */ -void -mono_profiler_stat_hit (guchar *ip, void *context) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_STATISTICAL) && prof->statistical_cb) - prof->statistical_cb (prof->profiler, ip, context); - } -} + mono_profiler_state.profilers = handle; -void -mono_profiler_stat_call_chain (int call_chain_depth, guchar **ips, void *context) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_STATISTICAL) && prof->statistical_call_chain_cb) - prof->statistical_call_chain_cb (prof->profiler, call_chain_depth, ips, context); - } + return handle; } void -mono_profiler_exception_thrown (MonoObject *exception) +mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfilerCoverageFilterCallback cb) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_throw_cb) - prof->exception_throw_cb (prof->profiler, exception); - } + InterlockedWritePointer (&handle->coverage_filter, (gpointer) cb); } -void -mono_profiler_exception_method_leave (MonoMethod *method) +static void +initialize_coverage (void) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_method_leave_cb) - prof->exception_method_leave_cb (prof->profiler, method); - } + mono_os_mutex_init (&mono_profiler_state.coverage_mutex); + mono_profiler_state.coverage_hash = g_hash_table_new (NULL, NULL); } -void -mono_profiler_exception_clause_handler (MonoMethod *method, int clause_type, int clause_num, MonoObject *exc) +static void +lazy_initialize_coverage (void) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if (prof->events & MONO_PROFILE_EXCEPTIONS) { - if (prof->exception_clause_cb) - prof->exception_clause_cb (prof->profiler, method, clause_type, clause_num); - - if (prof->exception_clause_cb2) - prof->exception_clause_cb2 (prof->profiler, method, clause_type, clause_num, exc); - } - } + mono_lazy_initialize (&mono_profiler_state.coverage_status, initialize_coverage); } -/** - * mono_profiler_thread_start: - */ -void -mono_profiler_thread_start (gsize tid) +static void +coverage_lock (void) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_start) - prof->thread_start (prof->profiler, tid); - } + mono_os_mutex_lock (&mono_profiler_state.coverage_mutex); } -/** - * mono_profiler_thread_end: - */ -void -mono_profiler_thread_end (gsize tid) +static void +coverage_unlock (void) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_end) - prof->thread_end (prof->profiler, tid); - } + mono_os_mutex_unlock (&mono_profiler_state.coverage_mutex); } void -mono_profiler_thread_name (gsize tid, const char *name) +mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_name) - prof->thread_name (prof->profiler, tid, name); - } -} + lazy_initialize_coverage (); -/** - * mono_profiler_assembly_event: - */ -void -mono_profiler_assembly_event (MonoAssembly *assembly, int code) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if (!(prof->events & MONO_PROFILE_ASSEMBLY_EVENTS)) - continue; - - switch (code) { - case MONO_PROFILE_START_LOAD: - if (prof->assembly_start_load) - prof->assembly_start_load (prof->profiler, assembly); - break; - case MONO_PROFILE_START_UNLOAD: - if (prof->assembly_start_unload) - prof->assembly_start_unload (prof->profiler, assembly); - break; - case MONO_PROFILE_END_UNLOAD: - if (prof->assembly_end_unload) - prof->assembly_end_unload (prof->profiler, assembly); - break; - default: - g_assert_not_reached (); - } - } -} + coverage_lock (); -/** - * mono_profiler_assembly_loaded: - */ -void -mono_profiler_assembly_loaded (MonoAssembly *assembly, int result) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_ASSEMBLY_EVENTS) && prof->assembly_end_load) - prof->assembly_end_load (prof->profiler, assembly, result); - } -} + MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method); -void mono_profiler_iomap (char *report, const char *pathname, const char *new_pathname) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_IOMAP_EVENTS) && prof->iomap_cb) - prof->iomap_cb (prof->profiler, report, pathname, new_pathname); - } -} + coverage_unlock (); -/** - * mono_profiler_module_event: - */ -void -mono_profiler_module_event (MonoImage *module, int code) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if (!(prof->events & MONO_PROFILE_MODULE_EVENTS)) - continue; - - switch (code) { - case MONO_PROFILE_START_LOAD: - if (prof->module_start_load) - prof->module_start_load (prof->profiler, module); - break; - case MONO_PROFILE_START_UNLOAD: - if (prof->module_start_unload) - prof->module_start_unload (prof->profiler, module); - break; - case MONO_PROFILE_END_UNLOAD: - if (prof->module_end_unload) - prof->module_end_unload (prof->profiler, module); - break; - default: - g_assert_not_reached (); - } - } -} + if (!info) + return; -/** - * mono_profiler_module_loaded: - */ -void -mono_profiler_module_loaded (MonoImage *module, int result) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_MODULE_EVENTS) && prof->module_end_load) - prof->module_end_load (prof->profiler, module, result); - } -} + MonoError error; + MonoMethodHeader *header = mono_method_get_header_checked (method, &error); + mono_error_assert_ok (&error); -/** - * mono_profiler_class_event: - */ -void -mono_profiler_class_event (MonoClass *klass, int code) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if (!(prof->events & MONO_PROFILE_CLASS_EVENTS)) - continue; - - switch (code) { - case MONO_PROFILE_START_LOAD: - if (prof->class_start_load) - prof->class_start_load (prof->profiler, klass); - break; - case MONO_PROFILE_START_UNLOAD: - if (prof->class_start_unload) - prof->class_start_unload (prof->profiler, klass); - break; - case MONO_PROFILE_END_UNLOAD: - if (prof->class_end_unload) - prof->class_end_unload (prof->profiler, klass); - break; - default: - g_assert_not_reached (); - } - } -} + guint32 size; -/** - * mono_profiler_class_loaded: - */ -void -mono_profiler_class_loaded (MonoClass *klass, int result) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_CLASS_EVENTS) && prof->class_end_load) - prof->class_end_load (prof->profiler, klass, result); - } -} + const unsigned char *start = mono_method_header_get_code (header, &size, NULL); + const unsigned char *end = start - size; + MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method); -/** - * mono_profiler_appdomain_event: - */ -void -mono_profiler_appdomain_event (MonoDomain *domain, int code) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if (!(prof->events & MONO_PROFILE_APPDOMAIN_EVENTS)) - continue; - - switch (code) { - case MONO_PROFILE_START_LOAD: - if (prof->domain_start_load) - prof->domain_start_load (prof->profiler, domain); - break; - case MONO_PROFILE_START_UNLOAD: - if (prof->domain_start_unload) - prof->domain_start_unload (prof->profiler, domain); - break; - case MONO_PROFILE_END_UNLOAD: - if (prof->domain_end_unload) - prof->domain_end_unload (prof->profiler, domain); - break; - default: - g_assert_not_reached (); - } - } -} + for (guint32 i = 0; i < info->entries; i++) { + guchar *cil_code = info->data [i].cil_code; -/** - * mono_profiler_appdomain_loaded: - */ -void -mono_profiler_appdomain_loaded (MonoDomain *domain, int result) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_APPDOMAIN_EVENTS) && prof->domain_end_load) - prof->domain_end_load (prof->profiler, domain, result); - } -} + if (cil_code && cil_code >= start && cil_code < end) { + guint32 offset = cil_code - start; -void -mono_profiler_appdomain_name (MonoDomain *domain, const char *name) -{ - for (ProfilerDesc *prof = prof_list; prof; prof = prof->next) - if ((prof->events & MONO_PROFILE_APPDOMAIN_EVENTS) && prof->domain_name) - prof->domain_name (prof->profiler, domain, name); -} + MonoProfilerCoverageData data = { + .method = method, + .il_offset = offset, + .counter = info->data [i].count, + .line = 1, + .column = 1, + }; -void -mono_profiler_context_loaded (MonoAppContext *context) -{ - for (ProfilerDesc *prof = prof_list; prof; prof = prof->next) - if ((prof->events & MONO_PROFILE_CONTEXT_EVENTS) && prof->context_load) - prof->context_load (prof->profiler, context); -} + if (minfo) { + MonoDebugSourceLocation *loc = mono_debug_method_lookup_location (minfo, offset); -void -mono_profiler_context_unloaded (MonoAppContext *context) -{ - for (ProfilerDesc *prof = prof_list; prof; prof = prof->next) - if ((prof->events & MONO_PROFILE_CONTEXT_EVENTS) && prof->context_unload) - prof->context_unload (prof->profiler, context); -} + if (loc) { + data.file_name = g_strdup (loc->source_file); + data.line = loc->row; + data.column = loc->column; -/** - * mono_profiler_shutdown: - */ -void -mono_profiler_shutdown (void) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if (prof->shutdown_callback) - prof->shutdown_callback (prof->profiler); - } + mono_debug_free_source_location (loc); + } + } - mono_profiler_set_events ((MonoProfileFlags)0); -} + cb (handle->prof, &data); -/** - * mono_profiler_gc_heap_resize: - */ -void -mono_profiler_gc_heap_resize (gint64 new_size) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_GC) && prof->gc_heap_resize) - prof->gc_heap_resize (prof->profiler, new_size); + g_free ((char *) data.file_name); + } } -} -/** - * mono_profiler_gc_event: - */ -void -mono_profiler_gc_event (MonoGCEvent event, int generation) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_GC) && prof->gc_event) - prof->gc_event (prof->profiler, event, generation); - } + mono_metadata_free_mh (header); } -void -mono_profiler_gc_moves (void **objects, int num) +MonoProfilerCoverageInfo * +mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_GC_MOVES) && prof->gc_moves) - prof->gc_moves (prof->profiler, objects, num); - } -} + lazy_initialize_coverage (); -void -mono_profiler_gc_handle (int op, int type, uintptr_t handle, MonoObject *obj) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_handle) - prof->gc_handle (prof->profiler, op, type, handle, obj); - } -} + gboolean cover = FALSE; -void -mono_profiler_gc_roots (int num, void **objects, int *root_types, uintptr_t *extra_info) -{ - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_roots) - prof->gc_roots (prof->profiler, num, objects, root_types, extra_info); + for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) { + MonoProfilerCoverageFilterCallback cb = handle->coverage_filter; + + if (cb) + cover |= cb (handle->prof, method); } -} -/** - * mono_profiler_install_gc: - */ -void -mono_profiler_install_gc (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback) -{ - if (!prof_list) - return; - prof_list->gc_event = callback; - prof_list->gc_heap_resize = heap_resize_callback; -} + if (!cover) + return NULL; -/** - * mono_profiler_install_gc_moves: - * \param callback callback function - * - * Install the \p callback function that the GC will call when moving objects. - * The callback receives an array of pointers and the number of elements - * in the array. Every even element in the array is the original object location - * and the following odd element is the new location of the object in memory. - * So the number of elements argument will always be a multiple of 2. - * Since this callback happens during the GC, it is a restricted environment: - * no locks can be taken and the object pointers can be inspected only once - * the GC is finished (of course the original location pointers will not - * point to valid objects anymore). - */ -void -mono_profiler_install_gc_moves (MonoProfileGCMoveFunc callback) -{ - if (!prof_list) - return; - prof_list->gc_moves = callback; -} + coverage_lock (); -/** - * mono_profiler_install_gc_roots: - * \param handle_callback callback function - * \param roots_callback callback function - * - * Install the \p handle_callback function that the GC will call when GC - * handles are created or destroyed. - * The callback receives an operation, which is either \c MONO_PROFILER_GC_HANDLE_CREATED - * or \c MONO_PROFILER_GC_HANDLE_DESTROYED, the handle type, the handle value and the - * object pointer, if present. - * Install the \p roots_callback function that the GC will call when tracing - * the roots for a collection. - * The callback receives the number of elements and three arrays: an array - * of objects, an array of root types and flags and an array of extra info. - * The size of each array is given by the first argument. - */ -void -mono_profiler_install_gc_roots (MonoProfileGCHandleFunc handle_callback, MonoProfileGCRootFunc roots_callback) -{ - if (!prof_list) - return; - prof_list->gc_handle = handle_callback; - prof_list->gc_roots = roots_callback; -} + MonoProfilerCoverageInfo *info = g_malloc0 (sizeof (MonoProfilerCoverageInfo) + SIZEOF_VOID_P * 2 * entries); -void -mono_profiler_gc_finalize_begin (void) -{ - for (ProfilerDesc *prof = prof_list; prof; prof = prof->next) - if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_begin) - prof->gc_finalize_begin (prof->profiler); -} + info->entries = entries; -void -mono_profiler_gc_finalize_object_begin (MonoObject *obj) -{ - for (ProfilerDesc *prof = prof_list; prof; prof = prof->next) - if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_object_begin) - prof->gc_finalize_object_begin (prof->profiler, obj); -} + g_hash_table_insert (mono_profiler_state.coverage_hash, method, info); -void -mono_profiler_gc_finalize_object_end (MonoObject *obj) -{ - for (ProfilerDesc *prof = prof_list; prof; prof = prof->next) - if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_object_end) - prof->gc_finalize_object_end (prof->profiler, obj); -} + coverage_unlock (); -void -mono_profiler_gc_finalize_end (void) -{ - for (ProfilerDesc *prof = prof_list; prof; prof = prof->next) - if ((prof->events & MONO_PROFILE_GC_FINALIZATION) && prof->gc_finalize_end) - prof->gc_finalize_end (prof->profiler); + return info; } void -mono_profiler_install_gc_finalize (MonoProfileGCFinalizeFunc begin, MonoProfileGCFinalizeObjectFunc begin_obj, MonoProfileGCFinalizeObjectFunc end_obj, MonoProfileGCFinalizeFunc end) +mono_profiler_coverage_free (MonoMethod *method) { - if (!prof_list) - return; + lazy_initialize_coverage (); - prof_list->gc_finalize_begin = begin; - prof_list->gc_finalize_object_begin = begin_obj; - prof_list->gc_finalize_object_end = end_obj; - prof_list->gc_finalize_end = end; -} + coverage_lock (); -void -mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback) -{ - if (!prof_list) - return; - prof_list->runtime_initialized_event = runtime_initialized_callback; -} + MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method); -void -mono_profiler_runtime_initialized (void) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if (prof->runtime_initialized_event) - prof->runtime_initialized_event (prof->profiler); + if (info) { + g_hash_table_remove (mono_profiler_state.coverage_hash, method); + g_free (info); } -} -void -mono_profiler_install_code_chunk_new (MonoProfilerCodeChunkNew callback) { - if (!prof_list) - return; - prof_list->code_chunk_new = callback; -} -void -mono_profiler_code_chunk_new (gpointer chunk, int size) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if (prof->code_chunk_new) - prof->code_chunk_new (prof->profiler, chunk, size); - } + coverage_unlock (); } -void -mono_profiler_install_code_chunk_destroy (MonoProfilerCodeChunkDestroy callback) { - if (!prof_list) - return; - prof_list->code_chunk_destroy = callback; -} -void -mono_profiler_code_chunk_destroy (gpointer chunk) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if (prof->code_chunk_destroy) - prof->code_chunk_destroy (prof->profiler, chunk); - } -} +mono_bool +mono_profiler_enable_sampling (MonoProfilerHandle handle) +{ + if (mono_profiler_state.startup_done) + return FALSE; -void -mono_profiler_install_code_buffer_new (MonoProfilerCodeBufferNew callback) { - if (!prof_list) - return; - prof_list->code_buffer_new = callback; -} + if (mono_profiler_state.sampling_owner) + return TRUE; -void -mono_profiler_install_iomap (MonoProfileIomapFunc callback) -{ - if (!prof_list) - return; - prof_list->iomap_cb = callback; -} + mono_profiler_state.sampling_owner = handle; + mono_profiler_state.sample_mode = MONO_PROFILER_SAMPLE_MODE_NONE; + mono_profiler_state.sample_freq = 100; + mono_os_sem_init (&mono_profiler_state.sampling_semaphore, 0); -void -mono_profiler_code_buffer_new (gpointer buffer, int size, MonoProfilerCodeBufferType type, gconstpointer data) { - ProfilerDesc *prof; - for (prof = prof_list; prof; prof = prof->next) { - if (prof->code_buffer_new) - prof->code_buffer_new (prof->profiler, buffer, size, type, (void*)data); - } + return TRUE; } -static GHashTable *coverage_hash = NULL; - -MonoProfileCoverageInfo* -mono_profiler_coverage_alloc (MonoMethod *method, int entries) +mono_bool +mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint64_t freq) { - MonoProfileCoverageInfo *res; - int instrument = FALSE; - ProfilerDesc *prof; - - for (prof = prof_list; prof; prof = prof->next) { - /* note that we call the filter on all the profilers even if just - * a single one would be enough to instrument a method - */ - if (prof->coverage_filter_cb) - if (prof->coverage_filter_cb (prof->profiler, method)) - instrument = TRUE; - } - if (!instrument) - return NULL; - - mono_profiler_coverage_lock (); - if (!coverage_hash) - coverage_hash = g_hash_table_new (NULL, NULL); - - res = (MonoProfileCoverageInfo *)g_malloc0 (sizeof (MonoProfileCoverageInfo) + sizeof (void*) * 2 * entries); + if (handle != mono_profiler_state.sampling_owner) + return FALSE; - res->entries = entries; + mono_profiler_state.sample_mode = mode; + mono_profiler_state.sample_freq = freq; - g_hash_table_insert (coverage_hash, method, res); - mono_profiler_coverage_unlock (); + mono_os_sem_post (&mono_profiler_state.sampling_semaphore); - return res; + return TRUE; } -/* safe only when the method antive code has been unloaded */ -void -mono_profiler_coverage_free (MonoMethod *method) +mono_bool +mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint64_t *freq) { - MonoProfileCoverageInfo* info; + if (mode) + *mode = mono_profiler_state.sample_mode; - mono_profiler_coverage_lock (); - if (!coverage_hash) { - mono_profiler_coverage_unlock (); - return; - } + if (freq) + *freq = mono_profiler_state.sample_freq; - info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method); - if (info) { - g_free (info); - g_hash_table_remove (coverage_hash, method); - } - mono_profiler_coverage_unlock (); + return handle == mono_profiler_state.sampling_owner; } -/** - * mono_profiler_coverage_get: - * \param prof The profiler handle, installed with mono_profiler_install - * \param method the method to gather information from. - * \param func A routine that will be called back with the results - * - * If the \c MONO_PROFILER_INS_COVERAGE flag was active during JIT compilation - * it is possible to obtain coverage information about a give method. - * - * The function \p func will be invoked repeatedly with instances of the - * \c MonoProfileCoverageEntry structure. - */ -void -mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileCoverageFunc func) +gboolean +mono_profiler_sampling_enabled (void) { - MonoError error; - MonoProfileCoverageInfo* info = NULL; - int i, offset; - guint32 code_size; - const unsigned char *start, *end, *cil_code; - MonoMethodHeader *header; - MonoProfileCoverageEntry entry; - MonoDebugMethodInfo *debug_minfo; - - mono_profiler_coverage_lock (); - if (coverage_hash) - info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method); - mono_profiler_coverage_unlock (); - - if (!info) - return; - - header = mono_method_get_header_checked (method, &error); - mono_error_assert_ok (&error); - start = mono_method_header_get_code (header, &code_size, NULL); - debug_minfo = mono_debug_lookup_method (method); - - end = start + code_size; - for (i = 0; i < info->entries; ++i) { - cil_code = info->data [i].cil_code; - if (cil_code && cil_code >= start && cil_code < end) { - char *fname = NULL; - offset = cil_code - start; - entry.iloffset = offset; - entry.method = method; - entry.counter = info->data [i].count; - entry.line = entry.col = 1; - entry.filename = NULL; - if (debug_minfo) { - MonoDebugSourceLocation *location; - - location = mono_debug_method_lookup_location (debug_minfo, offset); - if (location) { - entry.line = location->row; - entry.col = location->column; - entry.filename = fname = g_strdup (location->source_file); - mono_debug_free_source_location (location); - } - } - - func (prof, &entry); - g_free (fname); - } - } - mono_metadata_free_mh (header); + return !!mono_profiler_state.sampling_owner; } -typedef void (*ProfilerInitializer) (const char*); -#define INITIALIZER_NAME "mono_profiler_startup" - - -static gboolean -load_profiler (MonoDl *pmodule, const char *desc, const char *symbol) +void +mono_profiler_sampling_thread_sleep (void) { - char *err; - ProfilerInitializer func; + mono_os_sem_wait (&mono_profiler_state.sampling_semaphore, MONO_SEM_FLAGS_NONE); +} - if (!pmodule) +mono_bool +mono_profiler_enable_allocations (void) +{ + if (mono_profiler_state.startup_done) return FALSE; - if ((err = mono_dl_symbol (pmodule, symbol, (gpointer *) &func))) { - g_free (err); - return FALSE; - } else { - func (desc); - } + mono_profiler_state.allocations = TRUE; + return TRUE; } -static gboolean -load_embedded_profiler (const char *desc, const char *name) +void +mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handle, MonoProfilerCallInstrumentationFilterCallback cb) { - char *err = NULL; - char *symbol; - MonoDl *pmodule = NULL; - gboolean result; - - /* - * Some profilers (such as ours) may need to call back into the runtime - * from their sampling callback (which is called in async-signal context). - * They need to be able to know that all references back to the runtime - * have been resolved; otherwise, calling runtime functions may result in - * invoking the dynamic linker which is not async-signal-safe. Passing - * MONO_DL_EAGER will ask the dynamic linker to resolve everything upfront. - */ - pmodule = mono_dl_open (NULL, MONO_DL_EAGER, &err); - if (!pmodule) { - g_warning ("Could not open main executable (%s)", err); - g_free (err); - return FALSE; - } - - symbol = g_strdup_printf (INITIALIZER_NAME "_%s", name); - result = load_profiler (pmodule, desc, symbol); - g_free (symbol); - - return result; + InterlockedWritePointer (&handle->call_instrumentation_filter, (gpointer) cb); } -// TODO: Much of the library loading code here is custom. It would be better to merge this with mono-dl -static gboolean -load_profiler_from_directory (const char *directory, const char *libname, const char *desc) +gboolean +mono_profiler_should_instrument_method (MonoMethod *method, gboolean entry) { - MonoDl *pmodule = NULL; - char* path; - char *err; - void *iter; + MonoProfilerCallInstrumentationFlags flags = MONO_PROFILER_CALL_INSTRUMENTATION_NONE; - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "Attempting to load profiler %s from %s (desc %s)", libname, directory, desc); + for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) { + MonoProfilerCallInstrumentationFilterCallback cb = handle->call_instrumentation_filter; - iter = NULL; - err = NULL; - while ((path = mono_dl_build_path (directory, libname, &iter))) { - pmodule = mono_dl_open (path, MONO_DL_EAGER, &err); - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "Attempting to load profiler: %s, %ssuccessful, err: %s", path, pmodule?"":"not ", err); - g_free (path); - g_free (err); - if (pmodule) - return load_profiler (pmodule, desc, INITIALIZER_NAME); + if (cb) + flags |= cb (handle->prof, method); } - - return FALSE; + + if (entry) + return flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE; + else + return flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE; } -static gboolean -load_profiler_from_mono_installation (const char *libname, const char *desc) +void +mono_profiler_started (void) { - char *err = NULL; - MonoDl *pmodule = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err); - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "Attempting to load profiler from runtime libs: %s, %ssuccessful, err: %s", libname, pmodule?"":"not ", err); - g_free (err); - if (pmodule) - return load_profiler (pmodule, desc, INITIALIZER_NAME); - return FALSE; + mono_profiler_state.startup_done = TRUE; } -/** - * mono_profiler_load: - * \param desc arguments to configure the profiler - * - * Invoke this method to initialize the profiler. This will drive the - * loading of the internal ("default") or any external profilers. - * - * This routine is invoked by Mono's driver, but must be called manually - * if you embed Mono into your application. - */ -void -mono_profiler_load (const char *desc) +void +mono_profiler_cleanup (void) { - char *cdesc = NULL; - mono_gc_base_init (); - - if (!desc || (strcmp ("default", desc) == 0)) { - desc = "log:report"; + for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) { +#define _MONO_PROFILER_EVENT(name) \ + mono_profiler_set_ ## name ## _callback (handle, NULL); \ + g_assert (!handle->name ## _cb); +#define MONO_PROFILER_EVENT_0(name, type) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \ + _MONO_PROFILER_EVENT(name) +#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ + _MONO_PROFILER_EVENT(name) +#include +#undef MONO_PROFILER_EVENT_0 +#undef MONO_PROFILER_EVENT_1 +#undef MONO_PROFILER_EVENT_2 +#undef MONO_PROFILER_EVENT_3 +#undef MONO_PROFILER_EVENT_4 +#undef _MONO_PROFILER_EVENT } - /* we keep command-line compat with the old version here */ - if (strncmp (desc, "default:", 8) == 0) { - gchar **args, **ptr; - GString *str = g_string_new ("log:report"); - args = g_strsplit (desc + 8, ",", -1); - for (ptr = args; ptr && *ptr; ptr++) { - const char *arg = *ptr; - - if (!strcmp (arg, "time")) - g_string_append (str, ",calls"); - else if (!strcmp (arg, "alloc")) - g_string_append (str, ",alloc"); - else if (!strcmp (arg, "stat")) - g_string_append (str, ",sample"); - else if (!strcmp (arg, "jit")) - continue; /* accept and do nothing */ - else if (strncmp (arg, "file=", 5) == 0) { - g_string_append_printf (str, ",output=%s", arg + 5); - } else { - fprintf (stderr, "profiler : Unknown argument '%s'.\n", arg); - return; - } - } - desc = cdesc = g_string_free (str, FALSE); - } - { - const char* col = strchr (desc, ':'); - char* libname; - char *mname; - gboolean res = FALSE; - - if (col != NULL) { - mname = (char *)g_memdup (desc, col - desc + 1); - mname [col - desc] = 0; - } else { - mname = g_strdup (desc); - } - if (!load_embedded_profiler (desc, mname)) { - libname = g_strdup_printf ("mono-profiler-%s", mname); - res = load_profiler_from_mono_installation (libname, desc); - if (!res && mono_config_get_assemblies_dir ()) - res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc); - if (!res) - res = load_profiler_from_directory (NULL, libname, desc); - if (!res) - g_warning ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname); - g_free (libname); - } - g_free (mname); - } - g_free (cdesc); + +#define _MONO_PROFILER_EVENT(name, type) \ + g_assert (!mono_profiler_state.name ## _count); +#define MONO_PROFILER_EVENT_0(name, type) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ + _MONO_PROFILER_EVENT(name, type) +#include +#undef MONO_PROFILER_EVENT_0 +#undef MONO_PROFILER_EVENT_1 +#undef MONO_PROFILER_EVENT_2 +#undef MONO_PROFILER_EVENT_3 +#undef MONO_PROFILER_EVENT_4 +#undef _MONO_PROFILER_EVENT } +static void +update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *counter) +{ + gpointer old; + + do { + old = InterlockedReadPointer (location); + } while (InterlockedCompareExchangePointer (location, new_, old) != old); + + /* + * At this point, we could have installed a NULL callback while the counter + * is still non-zero, i.e. setting the callback and modifying the counter + * is not a single atomic operation. This is fine as we make sure callbacks + * are non-NULL before invoking them (see the code below that generates the + * raise functions), and besides, updating callbacks at runtime is an + * inherently racy operation. + */ + + if (old) + InterlockedDecrement (counter); + + if (new_) + InterlockedIncrement (counter); +} + +#define _MONO_PROFILER_EVENT(name, type) \ + void \ + mono_profiler_set_ ## name ## _callback (MonoProfilerHandle handle, MonoProfiler ## type ## Callback cb) \ + { \ + update_callback (&handle->name ## _cb, (gpointer) cb, &mono_profiler_state.name ## _count); \ + } +#define MONO_PROFILER_EVENT_0(name, type) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ + _MONO_PROFILER_EVENT(name, type) +#include +#undef MONO_PROFILER_EVENT_0 +#undef MONO_PROFILER_EVENT_1 +#undef MONO_PROFILER_EVENT_2 +#undef MONO_PROFILER_EVENT_3 +#undef MONO_PROFILER_EVENT_4 +#undef _MONO_PROFILER_EVENT + +#define _MONO_PROFILER_EVENT(name, type, params, args) \ + void \ + mono_profiler_raise_ ## name params \ + { \ + for (MonoProfilerHandle h = mono_profiler_state.profilers; h; h = h->next) { \ + MonoProfiler ## type ## Callback cb = h->name ## _cb; \ + if (cb) \ + cb args; \ + } \ + } +#define MONO_PROFILER_EVENT_0(name, type) \ + _MONO_PROFILER_EVENT(name, type, (void), (h->prof)) +#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \ + _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name), (h->prof, arg1_name)) +#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \ + _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name), (h->prof, arg1_name, arg2_name)) +#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \ + _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name), (h->prof, arg1_name, arg2_name, arg3_name)) +#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ + _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name), (h->prof, arg1_name, arg2_name, arg3_name, arg4_name)) +#include +#undef MONO_PROFILER_EVENT_0 +#undef MONO_PROFILER_EVENT_1 +#undef MONO_PROFILER_EVENT_2 +#undef MONO_PROFILER_EVENT_3 +#undef MONO_PROFILER_EVENT_4 +#undef _MONO_PROFILER_EVENT diff --git a/mono/metadata/profiler.h b/mono/metadata/profiler.h index 81a98ca124c..74a9e651ba4 100644 --- a/mono/metadata/profiler.h +++ b/mono/metadata/profiler.h @@ -1,250 +1,310 @@ -/** - * \file +/* + * Licensed to the .NET Foundation under one or more agreements. + * The .NET Foundation licenses this file to you under the MIT license. + * See the LICENSE file in the project root for more information. */ #ifndef __MONO_PROFILER_H__ #define __MONO_PROFILER_H__ -#include #include +#include +#include MONO_BEGIN_DECLS -#define MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH 128 +/* + * Loads a profiler module based on the specified description. The description + * can be of the form "name:args" or just "name". For example, "log:sample" and + * "log" will both load "libmono-profiler-log.so". The description is passed to + * the module after it has been loaded. If the specified module has already + * been loaded, this function has no effect. + * + * A module should declare an entry point like so: + * + * void mono_profiler_init (const char *desc) + * { + * } + * + * This function is not async safe. + */ +MONO_API void mono_profiler_load (const char *desc); -typedef enum { - MONO_PROFILE_NONE = 0, - MONO_PROFILE_APPDOMAIN_EVENTS = 1 << 0, - MONO_PROFILE_ASSEMBLY_EVENTS = 1 << 1, - MONO_PROFILE_MODULE_EVENTS = 1 << 2, - MONO_PROFILE_CLASS_EVENTS = 1 << 3, - MONO_PROFILE_JIT_COMPILATION = 1 << 4, - MONO_PROFILE_INLINING = 1 << 5, - MONO_PROFILE_EXCEPTIONS = 1 << 6, - MONO_PROFILE_ALLOCATIONS = 1 << 7, - MONO_PROFILE_GC = 1 << 8, - MONO_PROFILE_THREADS = 1 << 9, - MONO_PROFILE_REMOTING = 1 << 10, - MONO_PROFILE_TRANSITIONS = 1 << 11, - MONO_PROFILE_ENTER_LEAVE = 1 << 12, - MONO_PROFILE_COVERAGE = 1 << 13, - MONO_PROFILE_INS_COVERAGE = 1 << 14, - MONO_PROFILE_STATISTICAL = 1 << 15, - MONO_PROFILE_METHOD_EVENTS = 1 << 16, - MONO_PROFILE_MONITOR_EVENTS = 1 << 17, - MONO_PROFILE_IOMAP_EVENTS = 1 << 18, /* this should likely be removed, too */ - MONO_PROFILE_GC_MOVES = 1 << 19, - MONO_PROFILE_GC_ROOTS = 1 << 20, - MONO_PROFILE_CONTEXT_EVENTS = 1 << 21, - MONO_PROFILE_GC_FINALIZATION = 1 << 22 -} MonoProfileFlags; +typedef struct _MonoProfiler MonoProfiler; +typedef struct _MonoProfilerDesc *MonoProfilerHandle; -typedef enum { - MONO_PROFILE_OK, - MONO_PROFILE_FAILED -} MonoProfileResult; +/* + * Installs a profiler and returns a handle for it. The handle is used with the + * other functions in the profiler API (e.g. for setting up callbacks). + * + * This function may only be called from your profiler's init function. + * + * Example usage: + * + * struct _MonoProfiler { + * int my_stuff; + * // ... + * }; + * + * MonoProfiler *prof = calloc (1, sizeof (MonoProfiler)); + * MonoProfilerHandle handle = mono_profiler_install (prof); + * mono_profiler_set_shutdown_callback (handle, my_shutdown_cb); + * + * This function is not async safe. + */ +MONO_API MonoProfilerHandle mono_profiler_install (MonoProfiler *prof); -// Keep somewhat in sync with libgc/include/gc.h:enum GC_EventType -typedef enum { - MONO_GC_EVENT_START, - MONO_GC_EVENT_MARK_START, - MONO_GC_EVENT_MARK_END, - MONO_GC_EVENT_RECLAIM_START, - MONO_GC_EVENT_RECLAIM_END, - MONO_GC_EVENT_END, - /* - * This is the actual arrival order of the following events: - * - * MONO_GC_EVENT_PRE_STOP_WORLD - * MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED - * MONO_GC_EVENT_POST_STOP_WORLD - * MONO_GC_EVENT_PRE_START_WORLD - * MONO_GC_EVENT_POST_START_WORLD_UNLOCKED - * MONO_GC_EVENT_POST_START_WORLD - * - * The LOCKED and UNLOCKED events guarantee that, by the time they arrive, - * the GC and suspend locks will both have been acquired and released, - * respectively. - */ - MONO_GC_EVENT_PRE_STOP_WORLD, - MONO_GC_EVENT_POST_STOP_WORLD, - MONO_GC_EVENT_PRE_START_WORLD, - MONO_GC_EVENT_POST_START_WORLD, - MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, - MONO_GC_EVENT_POST_START_WORLD_UNLOCKED -} MonoGCEvent; - -/* coverage info */ -typedef struct { - MonoMethod *method; - int iloffset; - int counter; - const char *filename; - int line; - int col; -} MonoProfileCoverageEntry; - -/* executable code buffer info */ -typedef enum { - MONO_PROFILER_CODE_BUFFER_UNKNOWN, - MONO_PROFILER_CODE_BUFFER_METHOD, - MONO_PROFILER_CODE_BUFFER_METHOD_TRAMPOLINE, - MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, - MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, - MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, - MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, - MONO_PROFILER_CODE_BUFFER_HELPER, - MONO_PROFILER_CODE_BUFFER_MONITOR, - MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, - MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, - MONO_PROFILER_CODE_BUFFER_LAST -} MonoProfilerCodeBufferType; +typedef mono_bool (*MonoProfilerCoverageFilterCallback) (MonoProfiler *prof, MonoMethod *method); -typedef struct _MonoProfiler MonoProfiler; +/* + * Sets a code coverage filter function. The profiler API will invoke filter + * functions from all installed profilers. If any of them return TRUE, then the + * given method will be instrumented for coverage analysis. All filters are + * guaranteed to be called exactly once per method, even if an earlier filter + * has already returned TRUE. + * + * Note that filter functions must be installed before a method is compiled in + * order to have any effect, i.e. you should register your filter function in + * your profiler's init function. + * + * This function is async safe. + */ +MONO_API void mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfilerCoverageFilterCallback cb); -typedef enum { - MONO_PROFILER_MONITOR_CONTENTION = 1, - MONO_PROFILER_MONITOR_DONE = 2, - MONO_PROFILER_MONITOR_FAIL = 3 -} MonoProfilerMonitorEvent; +typedef struct { + MonoMethod *method; + uint32_t il_offset; + uint32_t counter; + const char *file_name; + uint32_t line; + uint32_t column; +} MonoProfilerCoverageData; -typedef enum { - MONO_PROFILER_CALL_CHAIN_NONE = 0, - MONO_PROFILER_CALL_CHAIN_NATIVE = 1, - MONO_PROFILER_CALL_CHAIN_GLIBC = 2, - MONO_PROFILER_CALL_CHAIN_MANAGED = 3, - MONO_PROFILER_CALL_CHAIN_INVALID = 4 -} MonoProfilerCallChainStrategy; +typedef void (*MonoProfilerCoverageCallback) (MonoProfiler *prof, const MonoProfilerCoverageData *data); -typedef enum { - MONO_PROFILER_GC_HANDLE_CREATED, - MONO_PROFILER_GC_HANDLE_DESTROYED -} MonoProfileGCHandleEvent; +/* + * Retrieves all coverage data for the specified method and invokes the given + * callback for each entry. + * + * This function is not async safe. + */ +MONO_API void mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb); typedef enum { - MONO_PROFILE_GC_ROOT_PINNING = 1 << 8, - MONO_PROFILE_GC_ROOT_WEAKREF = 2 << 8, - MONO_PROFILE_GC_ROOT_INTERIOR = 4 << 8, - /* the above are flags, the type is in the low 2 bytes */ - MONO_PROFILE_GC_ROOT_STACK = 0, - MONO_PROFILE_GC_ROOT_FINALIZER = 1, - MONO_PROFILE_GC_ROOT_HANDLE = 2, - MONO_PROFILE_GC_ROOT_OTHER = 3, - MONO_PROFILE_GC_ROOT_MISC = 4, /* could be stack, handle, etc. */ - MONO_PROFILE_GC_ROOT_TYPEMASK = 0xff -} MonoProfileGCRootType; + /* + * Do not perform sampling. Will make the sampling thread sleep until the + * sampling mode is changed to one of the below modes. + */ + MONO_PROFILER_SAMPLE_MODE_NONE = 0, + /* + * Try to base sampling frequency on process activity. Falls back to + * MONO_PROFILER_SAMPLE_MODE_REAL if such a clock is not available. + */ + MONO_PROFILER_SAMPLE_MODE_PROCESS = 1, + /* + * Base sampling frequency on wall clock time. Uses a monotonic clock when + * available (all major platforms). + */ + MONO_PROFILER_SAMPLE_MODE_REAL = 2, +} MonoProfilerSampleMode; /* - * Functions that the runtime will call on the profiler. + * Enables the sampling thread. You must call this function if you intend to use + * statistical sampling; mono_profiler_set_sample_mode will have no effect if + * this function has not been called. The first profiler to call this function + * will get ownership over sampling settings (mode and frequency) so that no + * other profiler can change those settings. Returns TRUE if the sampling + * thread was enabled, or FALSE if the function was called too late for this + * to be possible. + * + * Note that you still need to call mono_profiler_set_sample_mode with a mode + * other than MONO_PROFILER_SAMPLE_MODE_NONE to actually start sampling. + * + * This function may only be called from your profiler's init function. + * + * This function is not async safe. */ +MONO_API mono_bool mono_profiler_enable_sampling (MonoProfilerHandle handle); -typedef void (*MonoProfileFunc) (MonoProfiler *prof); +/* + * Sets the sampling mode and frequency (in Hz). If the calling profiler has + * ownership over sampling settings, the settings will be changed and this + * function will return TRUE; otherwise, it returns FALSE without changing any + * settings. + * + * This function is async safe. + */ +MONO_API mono_bool mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint64_t freq); -typedef void (*MonoProfileAppDomainFunc) (MonoProfiler *prof, MonoDomain *domain); -typedef void (*MonoProfileContextFunc) (MonoProfiler *prof, MonoAppContext *context); -typedef void (*MonoProfileMethodFunc) (MonoProfiler *prof, MonoMethod *method); -typedef void (*MonoProfileClassFunc) (MonoProfiler *prof, MonoClass *klass); -typedef void (*MonoProfileModuleFunc) (MonoProfiler *prof, MonoImage *module); -typedef void (*MonoProfileAssemblyFunc) (MonoProfiler *prof, MonoAssembly *assembly); -typedef void (*MonoProfileMonitorFunc) (MonoProfiler *prof, MonoObject *obj, MonoProfilerMonitorEvent event); +/* + * Retrieves the current sampling mode and/or frequency (in Hz). Returns TRUE if + * the calling profiler is allowed to change the sampling settings; otherwise, + * FALSE. + * + * This function is async safe. + */ +MONO_API mono_bool mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint64_t *freq); -typedef void (*MonoProfileExceptionFunc) (MonoProfiler *prof, MonoObject *object); -typedef void (*MonoProfileExceptionClauseFunc) (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_num); -typedef void (*MonoProfileExceptionClauseFunc2) (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_num, MonoObject *exc); +/* + * Enables instrumentation of GC allocations. This is necessary so that managed + * allocators can be instrumented with a call into the profiler API. Allocations + * will not be reported unless this function is called. Returns TRUE if + * allocation instrumentation was enabled, or FALSE if the function was called + * too late for this to be possible. + * + * This function may only be called from your profiler's init function. + * + * This function is not async safe. + */ +MONO_API mono_bool mono_profiler_enable_allocations (void); -typedef void (*MonoProfileAppDomainResult)(MonoProfiler *prof, MonoDomain *domain, int result); -typedef void (*MonoProfileAppDomainFriendlyNameFunc) (MonoProfiler *prof, MonoDomain *domain, const char *name); -typedef void (*MonoProfileMethodResult) (MonoProfiler *prof, MonoMethod *method, int result); -typedef void (*MonoProfileJitResult) (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result); -typedef void (*MonoProfileClassResult) (MonoProfiler *prof, MonoClass *klass, int result); -typedef void (*MonoProfileModuleResult) (MonoProfiler *prof, MonoImage *module, int result); -typedef void (*MonoProfileAssemblyResult) (MonoProfiler *prof, MonoAssembly *assembly, int result); +typedef enum { + /* Do not instrument calls. */ + MONO_PROFILER_CALL_INSTRUMENTATION_NONE = 1 << 0, + /* Instrument method prologues. */ + MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE = 1 << 1, + /* Instrument method epilogues. */ + MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE = 1 << 2, +} MonoProfilerCallInstrumentationFlags; -typedef void (*MonoProfileMethodInline) (MonoProfiler *prof, MonoMethod *parent, MonoMethod *child, int *ok); +typedef MonoProfilerCallInstrumentationFlags (*MonoProfilerCallInstrumentationFilterCallback) (MonoProfiler *prof, MonoMethod *method); -typedef void (*MonoProfileThreadFunc) (MonoProfiler *prof, uintptr_t tid); -typedef void (*MonoProfileThreadNameFunc) (MonoProfiler *prof, uintptr_t tid, const char *name); -typedef void (*MonoProfileAllocFunc) (MonoProfiler *prof, MonoObject *obj, MonoClass *klass); -typedef void (*MonoProfileStatFunc) (MonoProfiler *prof, mono_byte *ip, void *context); -typedef void (*MonoProfileStatCallChainFunc) (MonoProfiler *prof, int call_chain_depth, mono_byte **ip, void *context); -typedef void (*MonoProfileGCFunc) (MonoProfiler *prof, MonoGCEvent event, int generation); -typedef void (*MonoProfileGCMoveFunc) (MonoProfiler *prof, void **objects, int num); -typedef void (*MonoProfileGCResizeFunc) (MonoProfiler *prof, int64_t new_size); -typedef void (*MonoProfileGCHandleFunc) (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *obj); -typedef void (*MonoProfileGCRootFunc) (MonoProfiler *prof, int num_roots, void **objects, int *root_types, uintptr_t *extra_info); +/* + * Sets a call instrumentation filter function. The profiler API will invoke + * filter functions from all installed profilers. If any of them return flags + * other than MONO_PROFILER_CALL_INSTRUMENTATION_NONE, then the given method + * will be instrumented as requested. All filters are guaranteed to be called + * at least once (possibly more) per method entry and exit, even if earlier + * filters have already specified all flags. + * + * Note that filter functions must be installed before a method is compiled in + * order to have any effect, i.e. you should register your filter function in + * your profiler's init function. + * + * Keep in mind that method instrumentation is extremely heavy and will slow + * down most applications to a crawl. Consider using sampling instead if it + * would work for your use case. + * + * This function is async safe. + */ +MONO_API void mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handle, MonoProfilerCallInstrumentationFilterCallback cb); -typedef void (*MonoProfileGCFinalizeFunc) (MonoProfiler *prof); -typedef void (*MonoProfileGCFinalizeObjectFunc) (MonoProfiler *prof, MonoObject *obj); +typedef enum { + /* Upper 2 bytes. */ + MONO_PROFILER_GC_ROOT_PINNING = 1 << 8, + MONO_PROFILER_GC_ROOT_WEAKREF = 2 << 8, + MONO_PROFILER_GC_ROOT_INTERIOR = 4 << 8, -typedef void (*MonoProfileIomapFunc) (MonoProfiler *prof, const char *report, const char *pathname, const char *new_pathname); + /* Lower 2 bytes (flags). */ + MONO_PROFILER_GC_ROOT_STACK = 1 << 0, + MONO_PROFILER_GC_ROOT_FINALIZER = 1 << 1, + MONO_PROFILER_GC_ROOT_HANDLE = 1 << 2, + MONO_PROFILER_GC_ROOT_OTHER = 1 << 3, + MONO_PROFILER_GC_ROOT_MISC = 1 << 4, -typedef mono_bool (*MonoProfileCoverageFilterFunc) (MonoProfiler *prof, MonoMethod *method); + MONO_PROFILER_GC_ROOT_TYPEMASK = 0xff, +} MonoProfilerGCRootType; -typedef void (*MonoProfileCoverageFunc) (MonoProfiler *prof, const MonoProfileCoverageEntry *entry); +typedef enum { + /* data = MonoMethod *method */ + MONO_PROFILER_CODE_BUFFER_METHOD = 0, + MONO_PROFILER_CODE_BUFFER_METHOD_TRAMPOLINE = 1, + MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE = 2, + MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE = 3, + MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE = 4, + /* data = const char *name */ + MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE = 5, + MONO_PROFILER_CODE_BUFFER_HELPER = 6, + MONO_PROFILER_CODE_BUFFER_MONITOR = 7, + MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE = 8, + MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING = 9, +} MonoProfilerCodeBufferType; -typedef void (*MonoProfilerCodeChunkNew) (MonoProfiler *prof, void* chunk, int size); -typedef void (*MonoProfilerCodeChunkDestroy) (MonoProfiler *prof, void* chunk); -typedef void (*MonoProfilerCodeBufferNew) (MonoProfiler *prof, void* buffer, int size, MonoProfilerCodeBufferType type, void *data); +// Keep somewhat in sync with libgc/include/gc.h : GC_EventType. +typedef enum { + MONO_GC_EVENT_START = 0, + MONO_GC_EVENT_MARK_START = 1, + MONO_GC_EVENT_MARK_END = 2, + MONO_GC_EVENT_RECLAIM_START = 3, + MONO_GC_EVENT_RECLAIM_END = 4, + MONO_GC_EVENT_END = 5, + MONO_GC_EVENT_PRE_STOP_WORLD = 6, + /* When this event arrives, the GC and suspend locks are acquired. */ + MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED = 10, + MONO_GC_EVENT_POST_STOP_WORLD = 7, + MONO_GC_EVENT_PRE_START_WORLD = 8, + /* When this event arrives, the GC and suspend locks are released. */ + MONO_GC_EVENT_POST_START_WORLD_UNLOCKED = 11, + MONO_GC_EVENT_POST_START_WORLD = 9, +} MonoProfilerGCEvent; /* - * Function the profiler may call. + * The macros below will generate the majority of the callback API. Refer to + * mono/metadata/profiler-events.h for a list of callbacks. They are expanded + * like so: + * + * typedef void (*MonoProfilerRuntimeInitializedCallback (MonoProfiler *prof); + * MONO_API void mono_profiler_set_runtime_initialized_callback (MonoProfiler *prof, MonoProfilerRuntimeInitializedCallback cb); + * + * typedef void (*MonoProfilerRuntimeShutdownCallback (MonoProfiler *prof); + * MONO_API void mono_profiler_set_runtime_shutdown_callback (MonoProfiler *prof, MonoProfilerRuntimeShutdownCallback cb); + * + * typedef void (*MonoProfilerContextLoadedCallback (MonoProfiler *prof); + * MONO_API void mono_profiler_set_context_loaded_callback (MonoProfiler *prof, MonoProfilerContextLoadedCallback cb); + * + * typedef void (*MonoProfilerContextUnloadedCallback (MonoProfiler *prof); + * MONO_API void mono_profiler_set_context_unloaded_callback (MonoProfiler *prof, MonoProfilerContextUnloadedCallback cb); + * + * Etc. + * + * To remove a callback, pass NULL instead of a valid function pointer. + * Callbacks can be changed at any point, but note that doing so is inherently + * racy with respect to threads that aren't suspended, i.e. you may still see a + * call from another thread right after you change a callback. + * + * These functions are async safe. */ -MONO_API void mono_profiler_install (MonoProfiler *prof, MonoProfileFunc shutdown_callback); -MONO_API void mono_profiler_set_events (MonoProfileFlags events); - -MONO_API MonoProfileFlags mono_profiler_get_events (void); - -MONO_API void mono_profiler_install_appdomain (MonoProfileAppDomainFunc start_load, MonoProfileAppDomainResult end_load, - MonoProfileAppDomainFunc start_unload, MonoProfileAppDomainFunc end_unload); -MONO_API void mono_profiler_install_appdomain_name (MonoProfileAppDomainFriendlyNameFunc domain_name_cb); -MONO_API void mono_profiler_install_context (MonoProfileContextFunc load, MonoProfileContextFunc unload); -MONO_API void mono_profiler_install_assembly (MonoProfileAssemblyFunc start_load, MonoProfileAssemblyResult end_load, - MonoProfileAssemblyFunc start_unload, MonoProfileAssemblyFunc end_unload); -MONO_API void mono_profiler_install_module (MonoProfileModuleFunc start_load, MonoProfileModuleResult end_load, - MonoProfileModuleFunc start_unload, MonoProfileModuleFunc end_unload); -MONO_API void mono_profiler_install_class (MonoProfileClassFunc start_load, MonoProfileClassResult end_load, - MonoProfileClassFunc start_unload, MonoProfileClassFunc end_unload); - -MONO_API void mono_profiler_install_jit_compile (MonoProfileMethodFunc start, MonoProfileMethodResult end); -MONO_API void mono_profiler_install_jit_end (MonoProfileJitResult end); -MONO_API void mono_profiler_install_method_free (MonoProfileMethodFunc callback); -MONO_API void mono_profiler_install_method_invoke (MonoProfileMethodFunc start, MonoProfileMethodFunc end); -MONO_API void mono_profiler_install_enter_leave (MonoProfileMethodFunc enter, MonoProfileMethodFunc fleave); -MONO_API void mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc end); -MONO_API void mono_profiler_install_thread_name (MonoProfileThreadNameFunc thread_name_cb); -MONO_API void mono_profiler_install_transition (MonoProfileMethodResult callback); -MONO_API void mono_profiler_install_allocation (MonoProfileAllocFunc callback); -MONO_API void mono_profiler_install_monitor (MonoProfileMonitorFunc callback); -MONO_API void mono_profiler_install_statistical (MonoProfileStatFunc callback); -MONO_API void mono_profiler_install_statistical_call_chain (MonoProfileStatCallChainFunc callback, int call_chain_depth, MonoProfilerCallChainStrategy call_chain_strategy); -MONO_API void mono_profiler_install_exception (MonoProfileExceptionFunc throw_callback, MonoProfileMethodFunc exc_method_leave, MonoProfileExceptionClauseFunc clause_callback); -MONO_API void mono_profiler_install_exception_clause (MonoProfileExceptionClauseFunc2 clause_callback); -MONO_API void mono_profiler_install_coverage_filter (MonoProfileCoverageFilterFunc callback); -MONO_API void mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileCoverageFunc func); -MONO_API void mono_profiler_install_gc (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback); -MONO_API void mono_profiler_install_gc_moves (MonoProfileGCMoveFunc callback); -MONO_API void mono_profiler_install_gc_roots (MonoProfileGCHandleFunc handle_callback, MonoProfileGCRootFunc roots_callback); -MONO_API void mono_profiler_install_gc_finalize (MonoProfileGCFinalizeFunc begin, MonoProfileGCFinalizeObjectFunc begin_obj, MonoProfileGCFinalizeObjectFunc end_obj, MonoProfileGCFinalizeFunc end); -MONO_API void mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback); - -MONO_API void mono_profiler_install_code_chunk_new (MonoProfilerCodeChunkNew callback); -MONO_API void mono_profiler_install_code_chunk_destroy (MonoProfilerCodeChunkDestroy callback); -MONO_API void mono_profiler_install_code_buffer_new (MonoProfilerCodeBufferNew callback); - -MONO_API void mono_profiler_install_iomap (MonoProfileIomapFunc callback); - -MONO_API void mono_profiler_load (const char *desc); -typedef enum { - /* Elapsed time is tracked by user+kernel time of the process - this is the default*/ - MONO_PROFILER_STAT_MODE_PROCESS = 0, - /* Elapsed time is tracked by wallclock time */ - MONO_PROFILER_STAT_MODE_REAL = 1, -} MonoProfileSamplingMode; - -MONO_API void mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_hz); +#define _MONO_PROFILER_EVENT(type, ...) \ + typedef void (*MonoProfiler ## type ## Callback) (__VA_ARGS__); +#define MONO_PROFILER_EVENT_0(name, type) \ + _MONO_PROFILER_EVENT(type, MonoProfiler *prof) +#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \ + _MONO_PROFILER_EVENT(type, MonoProfiler *prof, arg1_type arg1_name) +#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \ + _MONO_PROFILER_EVENT(type, MonoProfiler *prof, arg1_type arg1_name, arg2_type arg2_name) +#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \ + _MONO_PROFILER_EVENT(type, MonoProfiler *prof, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name) +#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ + _MONO_PROFILER_EVENT(type, MonoProfiler *prof, arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name) +#include +#undef MONO_PROFILER_EVENT_0 +#undef MONO_PROFILER_EVENT_1 +#undef MONO_PROFILER_EVENT_2 +#undef MONO_PROFILER_EVENT_3 +#undef MONO_PROFILER_EVENT_4 +#undef _MONO_PROFILER_EVENT + +#define _MONO_PROFILER_EVENT(name, type) \ + MONO_API void mono_profiler_set_ ## name ## _callback (MonoProfilerHandle handle, MonoProfiler ## type ## Callback cb); +#define MONO_PROFILER_EVENT_0(name, type) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \ + _MONO_PROFILER_EVENT(name, type) +#define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \ + _MONO_PROFILER_EVENT(name, type) +#include +#undef MONO_PROFILER_EVENT_0 +#undef MONO_PROFILER_EVENT_1 +#undef MONO_PROFILER_EVENT_2 +#undef MONO_PROFILER_EVENT_3 +#undef MONO_PROFILER_EVENT_4 +#undef _MONO_PROFILER_EVENT MONO_END_DECLS -#endif /* __MONO_PROFILER_H__ */ - +#endif // __MONO_PROFILER_H__ diff --git a/mono/metadata/sgen-client-mono.h b/mono/metadata/sgen-client-mono.h index 78c0126396c..d9a483898e7 100644 --- a/mono/metadata/sgen-client-mono.h +++ b/mono/metadata/sgen-client-mono.h @@ -198,7 +198,7 @@ sgen_client_update_copied_object (char *destination, GCVTable gc_vtable, void *o SGEN_LOG (9, "Array instance %p: size: %lu, rank: %d, length: %lu", array, (unsigned long)objsize, vt->rank, (unsigned long)mono_array_length (array)); } - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_GC_MOVES)) + if (MONO_PROFILER_ENABLED (gc_moves)) mono_sgen_register_moved_object (obj, destination); } @@ -293,7 +293,7 @@ sgen_client_binary_protocol_collection_begin (int minor_gc_count, int generation { MONO_GC_BEGIN (generation); - mono_profiler_gc_event (MONO_GC_EVENT_START, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_START, generation)); #ifndef DISABLE_PERFCOUNTERS if (generation == GENERATION_NURSERY) @@ -308,7 +308,7 @@ sgen_client_binary_protocol_collection_end (int minor_gc_count, int generation, { MONO_GC_END (generation); - mono_profiler_gc_event (MONO_GC_EVENT_END, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_END, generation)); } static void G_GNUC_UNUSED @@ -383,25 +383,25 @@ sgen_client_binary_protocol_block_set_state (gpointer addr, size_t size, int old static void G_GNUC_UNUSED sgen_client_binary_protocol_mark_start (int generation) { - mono_profiler_gc_event (MONO_GC_EVENT_MARK_START, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_MARK_START, generation)); } static void G_GNUC_UNUSED sgen_client_binary_protocol_mark_end (int generation) { - mono_profiler_gc_event (MONO_GC_EVENT_MARK_END, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_MARK_END, generation)); } static void G_GNUC_UNUSED sgen_client_binary_protocol_reclaim_start (int generation) { - mono_profiler_gc_event (MONO_GC_EVENT_RECLAIM_START, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_RECLAIM_START, generation)); } static void G_GNUC_UNUSED sgen_client_binary_protocol_reclaim_end (int generation) { - mono_profiler_gc_event (MONO_GC_EVENT_RECLAIM_END, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_RECLAIM_END, generation)); } static void diff --git a/mono/metadata/sgen-mono.c b/mono/metadata/sgen-mono.c index 99f6100e36b..93bdb1fb5c7 100644 --- a/mono/metadata/sgen-mono.c +++ b/mono/metadata/sgen-mono.c @@ -946,10 +946,8 @@ mono_gc_alloc_obj (MonoVTable *vtable, size_t size) { MonoObject *obj = sgen_alloc_obj (vtable, size); - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) { - if (obj) - mono_profiler_allocation (obj); - } + if (G_UNLIKELY (mono_profiler_allocations_enabled ()) && obj) + MONO_PROFILER_RAISE (gc_allocation, (obj)); return obj; } @@ -959,10 +957,8 @@ mono_gc_alloc_pinned_obj (MonoVTable *vtable, size_t size) { MonoObject *obj = sgen_alloc_obj_pinned (vtable, size); - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) { - if (obj) - mono_profiler_allocation (obj); - } + if (G_UNLIKELY (mono_profiler_allocations_enabled ()) && obj) + MONO_PROFILER_RAISE (gc_allocation, (obj)); return obj; } @@ -972,10 +968,8 @@ mono_gc_alloc_mature (MonoVTable *vtable, size_t size) { MonoObject *obj = sgen_alloc_obj_mature (vtable, size); - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) { - if (obj) - mono_profiler_allocation (obj); - } + if (G_UNLIKELY (mono_profiler_allocations_enabled ()) && obj) + MONO_PROFILER_RAISE (gc_allocation, (obj)); return obj; } @@ -1013,6 +1007,7 @@ mono_gc_free_fixed (void* addr) static MonoMethod* alloc_method_cache [ATYPE_NUM]; static MonoMethod* slowpath_alloc_method_cache [ATYPE_NUM]; +static MonoMethod* profiler_alloc_method_cache [ATYPE_NUM]; static gboolean use_managed_allocator = TRUE; #ifdef MANAGED_ALLOCATION @@ -1059,6 +1054,7 @@ create_allocator (int atype, ManagedAllocatorVariant variant) { int p_var, size_var, real_size_var, thread_var G_GNUC_UNUSED; gboolean slowpath = variant == MANAGED_ALLOCATOR_SLOW_PATH; + gboolean profiler = variant == MANAGED_ALLOCATOR_PROFILER; guint32 fastpath_branch, max_size_branch, no_oom_branch; MonoMethodBuilder *mb; MonoMethod *res; @@ -1073,17 +1069,18 @@ create_allocator (int atype, ManagedAllocatorVariant variant) mono_register_jit_icall (mono_gc_alloc_obj, "mono_gc_alloc_obj", mono_create_icall_signature ("object ptr int"), FALSE); mono_register_jit_icall (mono_gc_alloc_vector, "mono_gc_alloc_vector", mono_create_icall_signature ("object ptr int int"), FALSE); mono_register_jit_icall (mono_gc_alloc_string, "mono_gc_alloc_string", mono_create_icall_signature ("object ptr int int32"), FALSE); + mono_register_jit_icall (mono_profiler_raise_gc_allocation, "mono_profiler_raise_gc_allocation", mono_create_icall_signature ("void object"), FALSE); registered = TRUE; } if (atype == ATYPE_SMALL) { - name = slowpath ? "SlowAllocSmall" : "AllocSmall"; + name = slowpath ? "SlowAllocSmall" : (profiler ? "ProfilerAllocSmall" : "AllocSmall"); } else if (atype == ATYPE_NORMAL) { - name = slowpath ? "SlowAlloc" : "Alloc"; + name = slowpath ? "SlowAlloc" : (profiler ? "ProfilerAlloc" : "Alloc"); } else if (atype == ATYPE_VECTOR) { - name = slowpath ? "SlowAllocVector" : "AllocVector"; + name = slowpath ? "SlowAllocVector" : (profiler ? "ProfilerAllocVector" : "AllocVector"); } else if (atype == ATYPE_STRING) { - name = slowpath ? "SlowAllocString" : "AllocString"; + name = slowpath ? "SlowAllocString" : (profiler ? "ProfilerAllocString" : "AllocString"); } else { g_assert_not_reached (); } @@ -1434,6 +1431,32 @@ create_allocator (int atype, ManagedAllocatorVariant variant) mono_mb_emit_ldloc (mb, p_var); done: + + /* + * It's important that we do this outside of the critical region as we + * will be invoking arbitrary code. + */ + if (profiler) { + /* + * if (G_UNLIKELY (*&mono_profiler_state.gc_allocation_count)) { + * mono_profiler_raise_gc_allocation (p); + * } + */ + + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_LDPTR_PROFILER_ALLOCATION_COUNT); + mono_mb_emit_byte (mb, CEE_LDIND_U4); + + int prof_br = mono_mb_emit_short_branch (mb, CEE_BRFALSE_S); + + mono_mb_emit_byte (mb, MONO_CUSTOM_PREFIX); + mono_mb_emit_byte (mb, CEE_MONO_NOT_TAKEN); + mono_mb_emit_byte (mb, CEE_DUP); + mono_mb_emit_icall (mb, mono_profiler_raise_gc_allocation); + + mono_mb_patch_short_branch (mb, prof_br); + } + mono_mb_emit_byte (mb, CEE_RET); #endif @@ -1468,6 +1491,9 @@ MonoMethod* mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean known_instance_size) { #ifdef MANAGED_ALLOCATION + ManagedAllocatorVariant variant = mono_profiler_allocations_enabled () ? + MANAGED_ALLOCATOR_PROFILER : MANAGED_ALLOCATOR_REGULAR; + if (collect_before_allocs) return NULL; if (klass->instance_size > tlab_size) @@ -1478,15 +1504,13 @@ mono_gc_get_managed_allocator (MonoClass *klass, gboolean for_box, gboolean know return NULL; if (klass->rank) return NULL; - if (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS) - return NULL; if (klass->byval_arg.type == MONO_TYPE_STRING) - return mono_gc_get_managed_allocator_by_type (ATYPE_STRING, MANAGED_ALLOCATOR_REGULAR); + return mono_gc_get_managed_allocator_by_type (ATYPE_STRING, variant); /* Generic classes have dynamic field and can go above MAX_SMALL_OBJ_SIZE. */ if (known_instance_size) - return mono_gc_get_managed_allocator_by_type (ATYPE_SMALL, MANAGED_ALLOCATOR_REGULAR); + return mono_gc_get_managed_allocator_by_type (ATYPE_SMALL, variant); else - return mono_gc_get_managed_allocator_by_type (ATYPE_NORMAL, MANAGED_ALLOCATOR_REGULAR); + return mono_gc_get_managed_allocator_by_type (ATYPE_NORMAL, variant); #else return NULL; #endif @@ -1498,13 +1522,12 @@ mono_gc_get_managed_array_allocator (MonoClass *klass) #ifdef MANAGED_ALLOCATION if (klass->rank != 1) return NULL; - if (mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS) - return NULL; if (has_per_allocation_action) return NULL; g_assert (!mono_class_has_finalizer (klass) && !mono_class_is_marshalbyref (klass)); - return mono_gc_get_managed_allocator_by_type (ATYPE_VECTOR, MANAGED_ALLOCATOR_REGULAR); + return mono_gc_get_managed_allocator_by_type (ATYPE_VECTOR, mono_profiler_allocations_enabled () ? + MANAGED_ALLOCATOR_PROFILER : MANAGED_ALLOCATOR_REGULAR); #else return NULL; #endif @@ -1523,12 +1546,13 @@ mono_gc_get_managed_allocator_by_type (int atype, ManagedAllocatorVariant varian MonoMethod *res; MonoMethod **cache; - if (variant == MANAGED_ALLOCATOR_REGULAR && !use_managed_allocator) + if (variant != MANAGED_ALLOCATOR_SLOW_PATH && !use_managed_allocator) return NULL; switch (variant) { case MANAGED_ALLOCATOR_REGULAR: cache = alloc_method_cache; break; case MANAGED_ALLOCATOR_SLOW_PATH: cache = slowpath_alloc_method_cache; break; + case MANAGED_ALLOCATOR_PROFILER: cache = profiler_alloc_method_cache; break; default: g_assert_not_reached (); break; } @@ -1565,7 +1589,7 @@ sgen_is_managed_allocator (MonoMethod *method) int i; for (i = 0; i < ATYPE_NUM; ++i) - if (method == alloc_method_cache [i] || method == slowpath_alloc_method_cache [i]) + if (method == alloc_method_cache [i] || method == slowpath_alloc_method_cache [i] || method == profiler_alloc_method_cache [i]) return TRUE; return FALSE; } @@ -1576,7 +1600,7 @@ sgen_has_managed_allocator (void) int i; for (i = 0; i < ATYPE_NUM; ++i) - if (alloc_method_cache [i] || slowpath_alloc_method_cache [i]) + if (alloc_method_cache [i] || slowpath_alloc_method_cache [i] || profiler_alloc_method_cache [i]) return TRUE; return FALSE; } @@ -1727,8 +1751,8 @@ mono_gc_alloc_vector (MonoVTable *vtable, size_t size, uintptr_t max_length) UNLOCK_GC; done: - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) - mono_profiler_allocation (&arr->obj); + if (G_UNLIKELY (mono_profiler_allocations_enabled ())) + MONO_PROFILER_RAISE (gc_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."); return arr; @@ -1775,8 +1799,8 @@ mono_gc_alloc_array (MonoVTable *vtable, size_t size, uintptr_t max_length, uint UNLOCK_GC; done: - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) - mono_profiler_allocation (&arr->obj); + if (G_UNLIKELY (mono_profiler_allocations_enabled ())) + MONO_PROFILER_RAISE (gc_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."); return arr; @@ -1816,8 +1840,8 @@ mono_gc_alloc_string (MonoVTable *vtable, size_t size, gint32 len) UNLOCK_GC; done: - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_ALLOCATIONS)) - mono_profiler_allocation (&str->object); + if (G_UNLIKELY (mono_profiler_allocations_enabled ())) + MONO_PROFILER_RAISE (gc_allocation, (&str->object)); return str; } @@ -1862,7 +1886,7 @@ notify_gc_roots (GCRootReport *report) { if (!report->count) return; - mono_profiler_gc_roots (report->count, report->objects, report->root_types, report->extra_info); + MONO_PROFILER_RAISE (gc_roots, ((MonoObject **) report->objects, (MonoProfilerGCRootType *) report->root_types, report->extra_info, report->count)); report->count = 0; } @@ -1879,12 +1903,12 @@ add_profile_gc_root (GCRootReport *report, void *object, int rtype, uintptr_t ex void sgen_client_nursery_objects_pinned (void **definitely_pinned, int count) { - if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS) { + if (MONO_PROFILER_ENABLED (gc_roots)) { GCRootReport report; int idx; report.count = 0; for (idx = 0; idx < count; ++idx) - add_profile_gc_root (&report, definitely_pinned [idx], MONO_PROFILE_GC_ROOT_PINNING | MONO_PROFILE_GC_ROOT_MISC, 0); + add_profile_gc_root (&report, definitely_pinned [idx], MONO_PROFILER_GC_ROOT_PINNING | MONO_PROFILER_GC_ROOT_MISC, 0); notify_gc_roots (&report); } } @@ -1900,7 +1924,7 @@ report_finalizer_roots_from_queue (SgenPointerQueue *queue) void *obj = queue->data [i]; if (!obj) continue; - add_profile_gc_root (&report, obj, MONO_PROFILE_GC_ROOT_FINALIZER, 0); + add_profile_gc_root (&report, obj, MONO_PROFILER_GC_ROOT_FINALIZER, 0); } notify_gc_roots (&report); } @@ -1918,7 +1942,7 @@ static void single_arg_report_root (MonoObject **obj, void *gc_data) { if (*obj) - add_profile_gc_root (root_report, *obj, MONO_PROFILE_GC_ROOT_OTHER, 0); + add_profile_gc_root (root_report, *obj, MONO_PROFILER_GC_ROOT_OTHER, 0); } static void @@ -1929,7 +1953,7 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end desc >>= ROOT_DESC_TYPE_SHIFT; while (desc) { if ((desc & 1) && *start_root) { - add_profile_gc_root (report, *start_root, MONO_PROFILE_GC_ROOT_OTHER, 0); + add_profile_gc_root (report, *start_root, MONO_PROFILER_GC_ROOT_OTHER, 0); } desc >>= 1; start_root++; @@ -1945,7 +1969,7 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end void **objptr = start_run; while (bmap) { if ((bmap & 1) && *objptr) { - add_profile_gc_root (report, *objptr, MONO_PROFILE_GC_ROOT_OTHER, 0); + add_profile_gc_root (report, *objptr, MONO_PROFILER_GC_ROOT_OTHER, 0); } bmap >>= 1; ++objptr; @@ -1959,7 +1983,7 @@ precisely_report_roots_from (GCRootReport *report, void** start_root, void** end for (p = start_root; p < end_root; p++) { if (*p) - add_profile_gc_root (report, *p, MONO_PROFILE_GC_ROOT_OTHER, 0); + add_profile_gc_root (report, *p, MONO_PROFILER_GC_ROOT_OTHER, 0); } break; } @@ -2000,9 +2024,10 @@ report_registered_roots (void) void sgen_client_collecting_minor (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) { - if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS) + if (MONO_PROFILER_ENABLED (gc_roots)) report_registered_roots (); - if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS) + + if (MONO_PROFILER_ENABLED (gc_roots)) report_finalizer_roots (fin_ready_queue, critical_fin_queue); } @@ -2012,7 +2037,7 @@ static gboolean profile_roots; void sgen_client_collecting_major_1 (void) { - profile_roots = mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS; + profile_roots = MONO_PROFILER_ENABLED (gc_roots); memset (&major_root_report, 0, sizeof (GCRootReport)); } @@ -2020,7 +2045,7 @@ void sgen_client_pinned_los_object (GCObject *obj) { if (profile_roots) - add_profile_gc_root (&major_root_report, (char*)obj, MONO_PROFILE_GC_ROOT_PINNING | MONO_PROFILE_GC_ROOT_MISC, 0); + add_profile_gc_root (&major_root_report, (char*)obj, MONO_PROFILER_GC_ROOT_PINNING | MONO_PROFILER_GC_ROOT_MISC, 0); } void @@ -2029,14 +2054,14 @@ sgen_client_collecting_major_2 (void) if (profile_roots) notify_gc_roots (&major_root_report); - if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS) + if (MONO_PROFILER_ENABLED (gc_roots)) report_registered_roots (); } void sgen_client_collecting_major_3 (SgenPointerQueue *fin_ready_queue, SgenPointerQueue *critical_fin_queue) { - if (mono_profiler_get_events () & MONO_PROFILE_GC_ROOTS) + if (MONO_PROFILER_ENABLED (gc_roots)) report_finalizer_roots (fin_ready_queue, critical_fin_queue); } @@ -2064,7 +2089,7 @@ mono_sgen_register_moved_object (void *obj, void *destination) 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); + MONO_PROFILER_RAISE (gc_moves, ((MonoObject **) moved_objects, moved_objects_idx)); moved_objects_idx = 0; } @@ -2084,7 +2109,7 @@ mono_sgen_gc_event_moves (void) } if (moved_objects_idx) { - mono_profiler_gc_moves (moved_objects, moved_objects_idx); + MONO_PROFILER_RAISE (gc_moves, ((MonoObject **) moved_objects, moved_objects_idx)); moved_objects_idx = 0; } } @@ -2702,7 +2727,8 @@ sgen_client_gchandle_created (int handle_type, GCObject *obj, guint32 handle) #ifndef DISABLE_PERFCOUNTERS mono_perfcounters->gc_num_handles++; #endif - mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_CREATED, handle_type, handle, obj); + + MONO_PROFILER_RAISE (gc_handle_created, (handle, handle_type, obj)); } void @@ -2711,7 +2737,8 @@ sgen_client_gchandle_destroyed (int handle_type, guint32 handle) #ifndef DISABLE_PERFCOUNTERS mono_perfcounters->gc_num_handles--; #endif - mono_profiler_gc_handle (MONO_PROFILER_GC_HANDLE_DESTROYED, handle_type, handle, NULL); + + MONO_PROFILER_RAISE (gc_handle_deleted, (handle, handle_type)); } void diff --git a/mono/metadata/sgen-stw.c b/mono/metadata/sgen-stw.c index b90f8c2789e..48ce7f963ed 100644 --- a/mono/metadata/sgen-stw.c +++ b/mono/metadata/sgen-stw.c @@ -104,11 +104,11 @@ sgen_client_stop_world (int generation) { TV_DECLARE (end_handshake); - mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_PRE_STOP_WORLD, generation)); acquire_gc_locks (); - mono_profiler_gc_event (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED, generation)); /* We start to scan after locks are taking, this ensures we won't be interrupted. */ sgen_process_togglerefs (); @@ -123,7 +123,7 @@ sgen_client_stop_world (int generation) SGEN_LOG (3, "world stopped"); - mono_profiler_gc_event (MONO_GC_EVENT_POST_STOP_WORLD, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_POST_STOP_WORLD, generation)); TV_GETTIME (end_handshake); time_stop_world += TV_ELAPSED (stop_world_time, end_handshake); @@ -143,10 +143,10 @@ sgen_client_restart_world (int generation, gint64 *stw_time) /* notify the profiler of the leftovers */ /* FIXME this is the wrong spot at we can STW for non collection reasons. */ - if (G_UNLIKELY (mono_profiler_events & MONO_PROFILE_GC_MOVES)) + if (MONO_PROFILER_ENABLED (gc_moves)) mono_sgen_gc_event_moves (); - mono_profiler_gc_event (MONO_GC_EVENT_PRE_START_WORLD, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_PRE_START_WORLD, generation)); FOREACH_THREAD (info) { info->client_info.stack_start = NULL; @@ -165,7 +165,7 @@ sgen_client_restart_world (int generation, gint64 *stw_time) SGEN_LOG (2, "restarted (pause time: %d usec, max: %d)", (int)usec, (int)max_pause_usec); - mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_POST_START_WORLD, generation)); /* * We must release the thread info suspend lock after doing @@ -179,7 +179,7 @@ sgen_client_restart_world (int generation, gint64 *stw_time) */ release_gc_locks (); - mono_profiler_gc_event (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, generation); + MONO_PROFILER_RAISE (gc_event, (MONO_GC_EVENT_POST_START_WORLD_UNLOCKED, generation)); *stw_time = usec; } diff --git a/mono/metadata/sre.c b/mono/metadata/sre.c index bb164f44be5..3beb23242fb 100644 --- a/mono/metadata/sre.c +++ b/mono/metadata/sre.c @@ -1243,7 +1243,7 @@ mono_reflection_dynimage_basic_init (MonoReflectionAssemblyBuilder *assemblyb) assembly = assemblyb->dynamic_assembly = g_new0 (MonoDynamicAssembly, 1); - mono_profiler_assembly_event (&assembly->assembly, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (assembly_loading, (&assembly->assembly)); assembly->assembly.ref_count = 1; assembly->assembly.dynamic = TRUE; @@ -1305,7 +1305,7 @@ mono_reflection_dynimage_basic_init (MonoReflectionAssemblyBuilder *assemblyb) register_assembly (mono_object_domain (assemblyb), &assemblyb->assembly, &assembly->assembly); - mono_profiler_assembly_loaded (&assembly->assembly, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (assembly_loaded, (&assembly->assembly)); mono_assembly_invoke_load_hook ((MonoAssembly*)assembly); } @@ -2453,7 +2453,7 @@ reflection_setup_internal_class_internal (MonoReflectionTypeBuilderHandle ref_tb klass->type_token = MONO_TOKEN_TYPE_DEF | table_idx; mono_class_set_flags (klass, MONO_HANDLE_GETVAL (ref_tb, attrs)); - mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD); + MONO_PROFILER_RAISE (class_loading, (klass)); klass->element_class = klass; @@ -2545,7 +2545,7 @@ reflection_setup_internal_class_internal (MonoReflectionTypeBuilderHandle ref_tb /*g_print ("setup %s as %s (%p)\n", klass->name, ((MonoObject*)tb)->vtable->klass->name, tb);*/ - mono_profiler_class_loaded (klass, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (class_loaded, (klass)); leave: mono_loader_unlock (); diff --git a/mono/metadata/threads.c b/mono/metadata/threads.c index e19f7e07351..e0a7aee8edc 100644 --- a/mono/metadata/threads.c +++ b/mono/metadata/threads.c @@ -824,12 +824,12 @@ static guint32 WINAPI start_wrapper_internal(StartInfo *start_info, gsize *stack * to lock the thread, and the lock is held by thread_start () which waits for * start_notify. */ - mono_profiler_thread_start (tid); + MONO_PROFILER_RAISE (thread_started, (tid)); /* if the name was set before starting, we didn't invoke the profiler callback */ if (internal->name) { char *tname = g_utf16_to_utf8 (internal->name, internal->name_len, NULL, NULL, NULL); - mono_profiler_thread_name (internal->tid, tname); + MONO_PROFILER_RAISE (thread_name, (internal->tid, tname)); mono_native_thread_set_name (MONO_UINT_TO_NATIVE_THREAD_ID (internal->tid), tname); g_free (tname); } @@ -1124,8 +1124,7 @@ mono_thread_attach_full (MonoDomain *domain, gboolean force_attach) /* Can happen when we attach the profiler helper thread in order to heapshot. */ if (!mono_thread_info_current ()->tools_thread) - // FIXME: Need a separate callback - mono_profiler_thread_start (MONO_NATIVE_THREAD_ID_TO_UINT (tid)); + MONO_PROFILER_RAISE (thread_started, (MONO_NATIVE_THREAD_ID_TO_UINT (tid))); return thread; } @@ -1236,7 +1235,7 @@ mono_thread_detach_internal (MonoInternalThread *thread) /* Can happen when we attach the profiler helper thread in order to heapshot. */ if (!mono_thread_info_lookup (MONO_UINT_TO_NATIVE_THREAD_ID (thread->tid))->tools_thread) - mono_profiler_thread_end (thread->tid); + MONO_PROFILER_RAISE (thread_stopped, (thread->tid)); mono_hazard_pointer_clear (mono_hazard_pointer_get (), 1); @@ -1625,7 +1624,7 @@ mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, g if (this_obj->name && this_obj->tid) { char *tname = mono_string_to_utf8_checked (name, error); return_if_nok (error); - mono_profiler_thread_name (this_obj->tid, tname); + MONO_PROFILER_RAISE (thread_name, (this_obj->tid, tname)); mono_native_thread_set_name (thread_get_tid (this_obj), tname); mono_free (tname); } @@ -2905,7 +2904,7 @@ mono_threads_register_app_context (MonoAppContext *ctx, MonoError *error) mono_threads_unlock (); - mono_profiler_context_loaded (ctx); + MONO_PROFILER_RAISE (context_loaded, (ctx)); } void @@ -2926,7 +2925,7 @@ mono_threads_release_app_context (MonoAppContext* ctx, MonoError *error) //g_print ("Releasing context %d in domain %d\n", ctx->context_id, ctx->domain_id); - mono_profiler_context_unloaded (ctx); + MONO_PROFILER_RAISE (context_unloaded, (ctx)); } void diff --git a/mono/mini/aot-compiler.c b/mono/mini/aot-compiler.c index e4b2378a3e8..a9a477767b6 100644 --- a/mono/mini/aot-compiler.c +++ b/mono/mini/aot-compiler.c @@ -3978,6 +3978,8 @@ add_wrappers (MonoAotCompile *acfg) add_method (acfg, m); if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_SLOW_PATH))) add_method (acfg, m); + if ((m = mono_gc_get_managed_allocator_by_type (i, MANAGED_ALLOCATOR_PROFILER))) + add_method (acfg, m); } /* write barriers */ @@ -5818,6 +5820,8 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint break; case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG: break; + case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: + break; case MONO_PATCH_INFO_RGCTX_FETCH: case MONO_PATCH_INFO_RGCTX_SLOT_INDEX: { MonoJumpInfoRgctxEntry *entry = patch_info->data.rgctx_entry; diff --git a/mono/mini/aot-runtime.c b/mono/mini/aot-runtime.c index f161e27169a..7b28d8db4a2 100644 --- a/mono/mini/aot-runtime.c +++ b/mono/mini/aot-runtime.c @@ -925,12 +925,12 @@ decode_method_ref_with_target (MonoAotModule *module, MethodRef *ref, MonoMethod case MONO_WRAPPER_ALLOC: { int atype = decode_value (p, &p); ManagedAllocatorVariant variant = - mono_profiler_get_events () & MONO_PROFILE_ALLOCATIONS ? - MANAGED_ALLOCATOR_SLOW_PATH : MANAGED_ALLOCATOR_REGULAR; + mono_profiler_allocations_enabled () ? + MANAGED_ALLOCATOR_PROFILER : MANAGED_ALLOCATOR_REGULAR; ref->method = mono_gc_get_managed_allocator_by_type (atype, variant); /* Try to fallback to the slow path version */ - if (!ref->method && variant == MANAGED_ALLOCATOR_REGULAR) + if (!ref->method) ref->method = mono_gc_get_managed_allocator_by_type (atype, MANAGED_ALLOCATOR_SLOW_PATH); if (!ref->method) { mono_error_set_bad_image_name (error, module->aot_name, "Error: No managed allocator, but we need one for AOT.\nAre you using non-standard GC options?\n"); @@ -3662,6 +3662,7 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin case MONO_PATCH_INFO_GC_CARD_TABLE_ADDR: case MONO_PATCH_INFO_GC_NURSERY_START: case MONO_PATCH_INFO_GC_NURSERY_BITS: + case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: break; case MONO_PATCH_INFO_CASTCLASS_CACHE: ji->data.index = decode_value (p, &p); @@ -3900,13 +3901,6 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM init_amodule_got (amodule); - if (mono_profiler_get_events () & MONO_PROFILE_ENTER_LEAVE) { - if (mono_aot_only) - /* The caller cannot handle this */ - g_assert_not_reached (); - return NULL; - } - if (domain != mono_get_root_domain ()) /* Non shared AOT code can't be used in other appdomains */ return NULL; @@ -4021,7 +4015,7 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM amodule_unlock (amodule); - if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION) { + if (MONO_PROFILER_ENABLED (jit_begin) || MONO_PROFILER_ENABLED (jit_done)) { MonoJitInfo *jinfo; if (!method) { @@ -4029,10 +4023,10 @@ load_method (MonoDomain *domain, MonoAotModule *amodule, MonoImage *image, MonoM if (!method) return NULL; } - mono_profiler_method_jit (method); + MONO_PROFILER_RAISE (jit_begin, (method)); jinfo = mono_jit_info_table_find (domain, (char*)code); g_assert (jinfo); - mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (jit_done, (method, jinfo)); } return code; diff --git a/mono/mini/debugger-agent.c b/mono/mini/debugger-agent.c index 0c1a63db2e7..96ef5e20ab2 100644 --- a/mono/mini/debugger-agent.c +++ b/mono/mini/debugger-agent.c @@ -745,11 +745,11 @@ static void runtime_initialized (MonoProfiler *prof); static void runtime_shutdown (MonoProfiler *prof); -static void thread_startup (MonoProfiler *prof, uintptr_t tid); +static void thread_startup (MonoProfiler *prof, uint64_t tid); -static void thread_end (MonoProfiler *prof, uintptr_t tid); +static void thread_end (MonoProfiler *prof, uint64_t tid); -static void appdomain_load (MonoProfiler *prof, MonoDomain *domain, int result); +static void appdomain_load (MonoProfiler *prof, MonoDomain *domain); static void appdomain_start_unload (MonoProfiler *prof, MonoDomain *domain); @@ -761,7 +761,7 @@ static void emit_thread_start (gpointer key, gpointer value, gpointer user_data) static void invalidate_each_thread (gpointer key, gpointer value, gpointer user_data); -static void assembly_load (MonoProfiler *prof, MonoAssembly *assembly, int result); +static void assembly_load (MonoProfiler *prof, MonoAssembly *assembly); static void assembly_unload (MonoProfiler *prof, MonoAssembly *assembly); @@ -769,7 +769,11 @@ static void emit_assembly_load (gpointer assembly, gpointer user_data); static void emit_type_load (gpointer key, gpointer type, gpointer user_data); -static void jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result); +static void jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo); + +static void jit_failed (MonoProfiler *prof, MonoMethod *method); + +static void jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo); static void add_pending_breakpoints (MonoMethod *method, MonoJitInfo *jinfo); @@ -995,13 +999,18 @@ mono_debugger_agent_init (void) mono_coop_mutex_init (&debugger_thread_exited_mutex); mono_coop_cond_init (&debugger_thread_exited_cond); - mono_profiler_install ((MonoProfiler*)&debugger_profiler, runtime_shutdown); - mono_profiler_set_events ((MonoProfileFlags)(MONO_PROFILE_APPDOMAIN_EVENTS | MONO_PROFILE_THREADS | MONO_PROFILE_ASSEMBLY_EVENTS | MONO_PROFILE_JIT_COMPILATION | MONO_PROFILE_METHOD_EVENTS)); - mono_profiler_install_runtime_initialized (runtime_initialized); - mono_profiler_install_appdomain (NULL, appdomain_load, appdomain_start_unload, appdomain_unload); - mono_profiler_install_thread (thread_startup, thread_end); - mono_profiler_install_assembly (NULL, assembly_load, assembly_unload, NULL); - mono_profiler_install_jit_end (jit_end); + MonoProfilerHandle prof = mono_profiler_install ((MonoProfiler*)&debugger_profiler); + mono_profiler_set_runtime_shutdown_callback (prof, runtime_shutdown); + mono_profiler_set_runtime_initialized_callback (prof, runtime_initialized); + mono_profiler_set_domain_loaded_callback (prof, appdomain_load); + mono_profiler_set_domain_unloading_callback (prof, appdomain_start_unload); + mono_profiler_set_domain_unloaded_callback (prof, appdomain_unload); + mono_profiler_set_thread_started_callback (prof, thread_startup); + mono_profiler_set_thread_stopped_callback (prof, thread_end); + mono_profiler_set_assembly_loaded_callback (prof, assembly_load); + mono_profiler_set_assembly_unloading_callback (prof, assembly_unload); + mono_profiler_set_jit_done_callback (prof, jit_done); + mono_profiler_set_jit_failed_callback (prof, jit_failed); mono_native_tls_alloc (&debugger_tls_id, NULL); @@ -3861,7 +3870,7 @@ runtime_shutdown (MonoProfiler *prof) } static void -thread_startup (MonoProfiler *prof, uintptr_t tid) +thread_startup (MonoProfiler *prof, uint64_t tid) { MonoInternalThread *thread = mono_thread_internal_current (); MonoInternalThread *old_thread; @@ -3922,7 +3931,7 @@ thread_startup (MonoProfiler *prof, uintptr_t tid) } static void -thread_end (MonoProfiler *prof, uintptr_t tid) +thread_end (MonoProfiler *prof, uint64_t tid) { MonoInternalThread *thread; DebuggerTlsData *tls = NULL; @@ -3960,7 +3969,7 @@ thread_end (MonoProfiler *prof, uintptr_t tid) } static void -appdomain_load (MonoProfiler *prof, MonoDomain *domain, int result) +appdomain_load (MonoProfiler *prof, MonoDomain *domain) { mono_loader_lock (); g_hash_table_insert (domains, domain, domain); @@ -4022,7 +4031,7 @@ invalidate_each_thread (gpointer key, gpointer value, gpointer user_data) } static void -assembly_load (MonoProfiler *prof, MonoAssembly *assembly, int result) +assembly_load (MonoProfiler *prof, MonoAssembly *assembly) { /* Sent later in jit_end () */ dbg_lock (); @@ -4110,7 +4119,19 @@ send_assemblies_for_domain (MonoDomain *domain, void *user_data) } static void -jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result) +jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo) +{ + jit_end (prof, method, jinfo); +} + +static void +jit_failed (MonoProfiler *prof, MonoMethod *method) +{ + jit_end (prof, method, NULL); +} + +static void +jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo) { /* * We emit type load events when the first method of the type is JITted, @@ -4138,7 +4159,7 @@ jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result) send_type_load (method->klass); - if (!result && jinfo) + if (jinfo) add_pending_breakpoints (method, jinfo); } diff --git a/mono/mini/exceptions-amd64.c b/mono/mini/exceptions-amd64.c index aeee1d4cbec..2c5f03e1832 100644 --- a/mono/mini/exceptions-amd64.c +++ b/mono/mini/exceptions-amd64.c @@ -203,7 +203,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) amd64_jump_reg (code, AMD64_R11); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops); @@ -291,7 +291,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) g_assert ((code - start) < kMaxCodeSize); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops); @@ -474,7 +474,7 @@ get_throw_trampoline (MonoTrampInfo **info, gboolean rethrow, gboolean corlib, g g_assert ((code - start) < kMaxCodeSize); g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE)); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops); @@ -1825,7 +1825,7 @@ mono_tasklets_arch_restore (void) g_assert ((code - start) <= kMaxCodeSize); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); saved = start; return (MonoContinuationRestore)saved; diff --git a/mono/mini/exceptions-arm64.c b/mono/mini/exceptions-arm64.c index 29dc7709aa0..fb8d1736c10 100644 --- a/mono/mini/exceptions-arm64.c +++ b/mono/mini/exceptions-arm64.c @@ -63,7 +63,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) g_assert ((code - start) < size); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops); @@ -152,7 +152,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) g_assert ((code - start) < size); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops); @@ -249,7 +249,7 @@ get_throw_trampoline (int size, gboolean corlib, gboolean rethrow, gboolean llvm g_assert ((code - start) < size); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create (tramp_name, start, code - start, ji, unwind_ops); diff --git a/mono/mini/exceptions-mips.c b/mono/mini/exceptions-mips.c index 4876fc164cf..69d37cba757 100644 --- a/mono/mini/exceptions-mips.c +++ b/mono/mini/exceptions-mips.c @@ -78,7 +78,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) g_assert ((code - start) < sizeof(start)); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); return start; } @@ -170,7 +170,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) g_assert ((code - start) < sizeof(start)); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); return start; } @@ -288,7 +288,7 @@ mono_arch_get_throw_exception_generic (guint8 *start, int size, int corlib, gboo g_assert ((code - start) < size); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); return start; } @@ -354,7 +354,7 @@ mono_arch_get_throw_exception_by_name (void) start = code = mono_global_codeman_reserve (size); mips_break (code, 0xfd); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); return start; } diff --git a/mono/mini/exceptions-ppc.c b/mono/mini/exceptions-ppc.c index 8a758c43c89..5e22cb967c8 100644 --- a/mono/mini/exceptions-ppc.c +++ b/mono/mini/exceptions-ppc.c @@ -220,7 +220,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) g_assert ((code - start) <= size); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("restore_context", start, code - start, ji, unwind_ops); @@ -311,7 +311,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) g_assert ((code - start) < size); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("call_filter", start, code - start, ji, unwind_ops); @@ -444,7 +444,7 @@ mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, int corli ppc_break (code); g_assert ((code - start) <= size); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create (corlib ? "throw_corlib_exception" : (rethrow ? "rethrow_exception" : "throw_exception"), start, code - start, ji, unwind_ops); diff --git a/mono/mini/exceptions-s390x.c b/mono/mini/exceptions-s390x.c index 77241a6c68a..19204c6ccd6 100644 --- a/mono/mini/exceptions-s390x.c +++ b/mono/mini/exceptions-s390x.c @@ -215,7 +215,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) g_assert ((code - start) < SZ_THROW); mono_arch_flush_icache(start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("call_filter", @@ -362,7 +362,7 @@ mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, g_assert ((code - start) < size); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create (corlib ? "throw_corlib_exception" diff --git a/mono/mini/exceptions-x86.c b/mono/mini/exceptions-x86.c index 30cb4b92d27..5042fa5efd1 100644 --- a/mono/mini/exceptions-x86.c +++ b/mono/mini/exceptions-x86.c @@ -114,7 +114,7 @@ mono_win32_get_handle_stackoverflow (void) x86_ret (code); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); return start; } @@ -360,7 +360,7 @@ mono_arch_get_restore_context (MonoTrampInfo **info, gboolean aot) } mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); return start; } @@ -438,7 +438,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) } mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); g_assert ((code - start) < kMaxCodeSize); return start; @@ -676,7 +676,7 @@ get_throw_trampoline (const char *name, gboolean rethrow, gboolean llvm, gboolea } mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); return start; } @@ -978,7 +978,7 @@ mono_x86_get_signal_exception_trampoline (MonoTrampInfo **info, gboolean aot) } mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); return start; } diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index 3a14d692335..bf3a62195ec 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -173,8 +173,8 @@ debug_enter (MonoInvocation *frame, int *tracing) g_print ("%s)\n", args); g_free (args); } - if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) - mono_profiler_method_enter (frame->runtime_method->method); + if (mono_profiler_should_instrument_method (frame->runtime_method->method, TRUE)) + MONO_PROFILER_RAISE (method_enter, (frame->runtime_method->method)); } @@ -191,8 +191,8 @@ debug_enter (MonoInvocation *frame, int *tracing) debug_indent_level--; \ if (tracing == 3) global_tracing = 0; \ } \ - if (mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) \ - mono_profiler_method_leave (frame->runtime_method->method); + if (mono_profiler_should_instrument_method (frame->runtime_method->method, FALSE)) \ + MONO_PROFILER_RAISE (method_enter, (frame->runtime_method->method)); #else diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index 35592cb05e2..02a92f271c8 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -4012,7 +4012,7 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont context->current_env = old_env; } - mono_profiler_method_jit (method); /* sort of... */ + MONO_PROFILER_RAISE (jit_begin, (method)); if (mono_method_signature (method)->is_inflated) generic_context = mono_method_get_context (method); @@ -4027,7 +4027,7 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont mono_os_mutex_lock(&calc_section); if (runtime_method->transformed) { mono_os_mutex_unlock(&calc_section); - mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (jit_done, (method, runtime_method->jinfo)); return NULL; } @@ -4061,7 +4061,7 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont runtime_method->alloca_size = runtime_method->stack_size; runtime_method->transformed = TRUE; mono_os_mutex_unlock(&calc_section); - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (jit_done, (method, NULL)); return NULL; } method = nm; @@ -4078,7 +4078,7 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont runtime_method->transformed = TRUE; } mono_os_mutex_unlock(&calc_section); - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (jit_done, (method, NULL)); return NULL; } else if (!strcmp (method->name, "UnsafeStore")) { g_error ("TODO"); @@ -4202,7 +4202,7 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont if (runtime_method->transformed) { mono_os_mutex_unlock(&calc_section); g_free (is_bb_start); - mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (jit_done, (method, runtime_method->jinfo)); return NULL; } @@ -4262,7 +4262,7 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont g_free (is_bb_start); // FIXME: Add a different callback ? - mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (jit_done, (method, runtime_method->jinfo)); runtime_method->transformed = TRUE; mono_os_mutex_unlock(&calc_section); diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 2a5f8917d5e..c20c6b2bbbf 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -1765,7 +1765,7 @@ emit_pop_lmf (MonoCompile *cfg) } static void -emit_instrumentation_call (MonoCompile *cfg, void *func) +emit_instrumentation_call (MonoCompile *cfg, void *func, gboolean entry) { MonoInst *iargs [1]; @@ -1776,7 +1776,7 @@ emit_instrumentation_call (MonoCompile *cfg, void *func) if (cfg->method != cfg->current_method) return; - if (cfg->prof_options & MONO_PROFILE_ENTER_LEAVE) { + if (mono_profiler_should_instrument_method (cfg->method, entry)) { EMIT_NEW_METHODCONST (cfg, iargs [0], cfg->method); mono_emit_jit_icall (cfg, func, iargs); } @@ -2247,7 +2247,7 @@ mono_emit_call_args (MonoCompile *cfg, MonoMethodSignature *sig, tail = FALSE; if (tail) { - emit_instrumentation_call (cfg, mono_profiler_method_leave); + emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE); MONO_INST_NEW_CALL (cfg, call, OP_TAILCALL); } else @@ -5867,7 +5867,7 @@ mini_redirect_call (MonoCompile *cfg, MonoMethod *method, { if (method->klass == mono_defaults.string_class) { /* managed string allocation support */ - if (strcmp (method->name, "InternalAllocateStr") == 0 && !(mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && !(cfg->opt & MONO_OPT_SHARED)) { + if (strcmp (method->name, "InternalAllocateStr") == 0 && !(cfg->opt & MONO_OPT_SHARED)) { MonoInst *iargs [2]; MonoVTable *vtable = mono_class_vtable (cfg->domain, method->klass); MonoMethod *managed_alloc = NULL; @@ -7310,8 +7310,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cfg->dont_inline = g_list_prepend (cfg->dont_inline, method); if (cfg->method == method) { - if (cfg->prof_options & MONO_PROFILE_INS_COVERAGE) - cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size); + cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, header->code_size); /* ENTRY BLOCK */ NEW_BBLOCK (cfg, start_bblock); @@ -8044,7 +8043,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b if (cfg->gshared && mono_method_check_context_used (cmethod)) GENERIC_SHARING_FAILURE (CEE_JMP); - emit_instrumentation_call (cfg, mono_profiler_method_leave); + emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE); fsig = mono_method_signature (cmethod); n = fsig->param_count + fsig->hasthis; @@ -8986,7 +8985,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b /* Handle tail calls similarly to normal calls */ tail_call = TRUE; } else { - emit_instrumentation_call (cfg, mono_profiler_method_leave); + emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE); MONO_INST_NEW_CALL (cfg, call, OP_JMP); call->tail_call = TRUE; @@ -9120,7 +9119,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b cfg->ret_var_set = TRUE; } } else { - emit_instrumentation_call (cfg, mono_profiler_method_leave); + emit_instrumentation_call (cfg, mono_profiler_raise_method_leave, FALSE); if (cfg->lmf_var && cfg->cbb->in_count && !cfg->llvm_only) emit_pop_lmf (cfg); @@ -11500,7 +11499,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b case CEE_MONO_LDPTR_CARD_TABLE: case CEE_MONO_LDPTR_NURSERY_START: case CEE_MONO_LDPTR_NURSERY_BITS: - case CEE_MONO_LDPTR_INT_REQ_FLAG: { + case CEE_MONO_LDPTR_INT_REQ_FLAG: + case CEE_MONO_LDPTR_PROFILER_ALLOCATION_COUNT: { CHECK_STACK_OVF (1); switch (ip [1]) { @@ -11516,6 +11516,9 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b case CEE_MONO_LDPTR_INT_REQ_FLAG: ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG, NULL); break; + case CEE_MONO_LDPTR_PROFILER_ALLOCATION_COUNT: + ins = mini_emit_runtime_constant (cfg, MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT, NULL); + break; default: g_assert_not_reached (); break; @@ -12628,7 +12631,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b } cfg->cbb = init_localsbb; - emit_instrumentation_call (cfg, mono_profiler_method_enter); + emit_instrumentation_call (cfg, mono_profiler_raise_method_enter, TRUE); if (seq_points) { MonoBasicBlock *bb; diff --git a/mono/mini/mini-amd64.c b/mono/mini/mini-amd64.c index 515be71f91f..84acd5ce754 100644 --- a/mono/mini/mini-amd64.c +++ b/mono/mini/mini-amd64.c @@ -3631,16 +3631,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (cfg->verbose_level > 2) g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset); - if ((cfg->prof_options & MONO_PROFILE_COVERAGE) && cfg->coverage_info) { - MonoProfileCoverageInfo *cov = cfg->coverage_info; - g_assert (!cfg->compile_aot); - - cov->data [bb->dfn].cil_code = bb->cil_code; - amd64_mov_reg_imm (code, AMD64_R11, (guint64)&cov->data [bb->dfn].count); - /* this is not thread save, but good enough */ - amd64_inc_membase (code, AMD64_R11, 0); - } - offset = code - cfg->native_code; mono_debug_open_block (cfg, bb, offset); @@ -6813,8 +6803,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) MonoInst *ins; int max_length = 0; - if (cfg->prof_options & MONO_PROFILE_COVERAGE) - max_length += 6; /* max alignment for loops */ if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb)) max_length += LOOP_ALIGNMENT; @@ -7684,7 +7672,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par if (!has_target) g_free (buff); } - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); return start; } @@ -7718,7 +7706,7 @@ get_delegate_virtual_invoke_impl (MonoTrampInfo **info, gboolean load_imt_reg, i /* Load the vtable */ amd64_mov_reg_membase (code, AMD64_RAX, AMD64_ARG_REG1, MONO_STRUCT_OFFSET (MonoObject, vtable), 8); amd64_jump_membase (code, AMD64_RAX, offset); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); tramp_name = mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset); *info = mono_tramp_info_create (tramp_name, start, code - start, NULL, unwind_ops); @@ -8018,7 +8006,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTC g_assert (code - start <= size); g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0))); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c index 1328e762a65..9703c1e09de 100644 --- a/mono/mini/mini-arm.c +++ b/mono/mini/mini-arm.c @@ -650,7 +650,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, gboolean pa g_free (name); } - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); return start; } @@ -4192,17 +4192,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) cpos = bb->max_offset; - if (cfg->prof_options & MONO_PROFILE_COVERAGE) { - //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method); - //g_assert (!mono_compile_aot); - //cpos += 6; - //if (bb->cil_code) - // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code; - /* this is not thread save, but good enough */ - /* fixme: howto handle overflows? */ - //x86_inc_mem (code, &cov->data [bb->dfn].count); - } - if (mono_break_at_bb_method && mono_method_desc_full_match (mono_break_at_bb_method, cfg->method) && bb->block_num == mono_break_at_bb_bb_num) { mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, (gpointer)"mono_break"); @@ -6151,9 +6140,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) MonoInst *ins = bb->code; bb->max_offset = max_offset; - if (cfg->prof_options & MONO_PROFILE_COVERAGE) - max_offset += 6; - MONO_BB_FOR_EACH_INS (bb, ins) max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; } @@ -7062,7 +7048,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTC g_free (constant_pool_starts); mono_arch_flush_icache ((guint8*)start, size); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL)); mono_stats.imt_trampolines_size += code - start; g_assert (DISTANCE (start, code) <= size); diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index 2b8374596e0..bd4283bf3f8 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -1937,7 +1937,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu mono_print_thread_dump_from_ctx (ctx); } jit_tls->orig_ex_ctx_set = TRUE; - mono_profiler_exception_thrown (obj); + MONO_PROFILER_RAISE (exception_throw, (obj)); jit_tls->orig_ex_ctx_set = FALSE; res = mono_handle_exception_internal_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception); @@ -2139,7 +2139,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu if (mono_trace_is_enabled () && mono_trace_eval (method)) g_print ("EXCEPTION: catch found at clause %d of %s\n", i, mono_method_full_name (method, TRUE)); jit_tls->orig_ex_ctx_set = TRUE; - mono_profiler_exception_clause_handler (method, ei->flags, i, ex_obj); + MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj)); jit_tls->orig_ex_ctx_set = FALSE; mini_set_abort_threshold (ctx); @@ -2183,7 +2183,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu if (mono_trace_is_enabled () && mono_trace_eval (method)) g_print ("EXCEPTION: fault clause %d of %s\n", i, mono_method_full_name (method, TRUE)); jit_tls->orig_ex_ctx_set = TRUE; - mono_profiler_exception_clause_handler (method, ei->flags, i, ex_obj); + MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj)); jit_tls->orig_ex_ctx_set = FALSE; mini_set_abort_threshold (ctx); call_filter (ctx, ei->handler_start); @@ -2192,7 +2192,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu if (mono_trace_is_enabled () && mono_trace_eval (method)) g_print ("EXCEPTION: finally clause %d of %s\n", i, mono_method_full_name (method, TRUE)); jit_tls->orig_ex_ctx_set = TRUE; - mono_profiler_exception_clause_handler (method, ei->flags, i, ex_obj); + MONO_PROFILER_RAISE (exception_clause, (method, i, ei->flags, ex_obj)); jit_tls->orig_ex_ctx_set = FALSE; #ifndef DISABLE_PERFCOUNTERS mono_perfcounters->exceptions_finallys++; @@ -2230,7 +2230,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu } jit_tls->orig_ex_ctx_set = TRUE; - mono_profiler_exception_method_leave (method); + MONO_PROFILER_RAISE (method_exception_leave, (method, ex_obj)); jit_tls->orig_ex_ctx_set = FALSE; *ctx = new_ctx; diff --git a/mono/mini/mini-mips.c b/mono/mini/mini-mips.c index e18c2bdef1d..bf06aee47bb 100644 --- a/mono/mini/mini-mips.c +++ b/mono/mini/mini-mips.c @@ -3216,21 +3216,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) cpos = bb->max_offset; -#if 0 - if (cfg->prof_options & MONO_PROFILE_COVERAGE) { - MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method); - g_assert (!mono_compile_aot); - cpos += 20; - if (bb->cil_code) - cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code; - /* this is not thread save, but good enough */ - /* fixme: howto handle overflows? */ - mips_load_const (code, mips_at, &cov->data [bb->dfn].count); - mips_lw (code, mips_temp, mips_at, 0); - mips_addiu (code, mips_temp, mips_temp, 1); - mips_sw (code, mips_temp, mips_at, 0); - } -#endif MONO_BB_FOR_EACH_INS (bb, ins) { offset = code - cfg->native_code; @@ -4831,9 +4816,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) MonoInst *ins = bb->code; bb->max_offset = max_offset; - if (cfg->prof_options & MONO_PROFILE_COVERAGE) - max_offset += 6; - MONO_BB_FOR_EACH_INS (bb, ins) max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; } diff --git a/mono/mini/mini-posix.c b/mono/mini/mini-posix.c index ba60bd9934a..a3fd4f0e298 100644 --- a/mono/mini/mini-posix.c +++ b/mono/mini/mini-posix.c @@ -210,101 +210,12 @@ MONO_SIG_HANDLER_FUNC (static, sigabrt_signal_handler) } } -#if defined(__i386__) || defined(__x86_64__) -#define FULL_STAT_PROFILER_BACKTRACE 1 -#define CURRENT_FRAME_GET_BASE_POINTER(f) (* (gpointer*)(f)) -#define CURRENT_FRAME_GET_RETURN_ADDRESS(f) (* (((gpointer*)(f)) + 1)) -#if MONO_ARCH_STACK_GROWS_UP -#define IS_BEFORE_ON_STACK < -#define IS_AFTER_ON_STACK > -#else -#define IS_BEFORE_ON_STACK > -#define IS_AFTER_ON_STACK < -#endif -#else -#define FULL_STAT_PROFILER_BACKTRACE 0 -#endif - #if (defined (USE_POSIX_BACKEND) && defined (SIGRTMIN)) || defined (SIGPROF) #define HAVE_PROFILER_SIGNAL #endif #ifdef HAVE_PROFILER_SIGNAL -static void -per_thread_profiler_hit (void *ctx) -{ - int call_chain_depth = mono_profiler_stat_get_call_chain_depth (); - MonoProfilerCallChainStrategy call_chain_strategy = mono_profiler_stat_get_call_chain_strategy (); - - if (call_chain_depth == 0) { - mono_profiler_stat_hit ((guchar *)mono_arch_ip_from_context (ctx), ctx); - } else { - MonoJitTlsData *jit_tls = (MonoJitTlsData *)mono_tls_get_jit_tls (); - int current_frame_index = 1; - MonoContext mono_context; - guchar *ips [call_chain_depth + 1]; - - mono_sigctx_to_monoctx (ctx, &mono_context); - ips [0] = (guchar *)MONO_CONTEXT_GET_IP (&mono_context); - - if (jit_tls != NULL) { - if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_NATIVE) { -#if FULL_STAT_PROFILER_BACKTRACE - guchar *current_frame; - guchar *stack_bottom; - guchar *stack_top; - - stack_bottom = (guchar *)jit_tls->end_of_stack; - stack_top = (guchar *)MONO_CONTEXT_GET_SP (&mono_context); - current_frame = (guchar *)MONO_CONTEXT_GET_BP (&mono_context); - - while ((current_frame_index <= call_chain_depth) && - (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) && - ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) { - ips [current_frame_index] = (guchar *)CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame); - current_frame_index ++; - stack_top = current_frame; - current_frame = (guchar *)CURRENT_FRAME_GET_BASE_POINTER (current_frame); - } -#else - call_chain_strategy = MONO_PROFILER_CALL_CHAIN_GLIBC; -#endif - } - - if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_GLIBC) { -#if GLIBC_PROFILER_BACKTRACE - current_frame_index = backtrace ((void**) & ips [1], call_chain_depth); -#else - call_chain_strategy = MONO_PROFILER_CALL_CHAIN_MANAGED; -#endif - } - - if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_MANAGED) { - MonoDomain *domain = mono_domain_get (); - if (domain != NULL) { - MonoLMF *lmf = NULL; - MonoJitInfo *ji; - MonoJitInfo res; - MonoContext new_mono_context; - int native_offset; - ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context, - &new_mono_context, NULL, &lmf, &native_offset, NULL); - while ((ji != NULL) && (current_frame_index <= call_chain_depth)) { - ips [current_frame_index] = (guchar *)MONO_CONTEXT_GET_IP (&new_mono_context); - current_frame_index ++; - mono_context = new_mono_context; - ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context, - &new_mono_context, NULL, &lmf, &native_offset, NULL); - } - } - } - } - - mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx); - } -} - static MonoNativeThreadId sampling_thread; static gint32 profiler_signals_sent; @@ -342,7 +253,9 @@ MONO_SIG_HANDLER_FUNC (static, profiler_signal_handler) int hp_save_index = mono_hazard_pointer_save_for_signal_handler (); mono_thread_info_set_is_async_context (TRUE); - per_thread_profiler_hit (ctx); + + MONO_PROFILER_RAISE (sample_hit, (mono_arch_ip_from_context (ctx), ctx)); + mono_thread_info_set_is_async_context (FALSE); mono_hazard_pointer_restore_for_signal_handler (hp_save_index); @@ -521,7 +434,7 @@ static volatile gint32 sampling_thread_running; static clock_serv_t sampling_clock_service; static void -clock_init (void) +clock_init (MonoProfilerSampleMode mode) { kern_return_t ret; @@ -584,10 +497,10 @@ clock_sleep_ns_abs (guint64 ns_abs) clockid_t sampling_posix_clock; static void -clock_init (void) +clock_init (MonoProfilerSampleMode mode) { - switch (mono_profiler_get_sampling_mode ()) { - case MONO_PROFILER_STAT_MODE_PROCESS: { + switch (mode) { + case MONO_PROFILER_SAMPLE_MODE_PROCESS: { /* * If we don't have clock_nanosleep (), measuring the process time * makes very little sense as we can only use nanosleep () to sleep on @@ -609,7 +522,7 @@ clock_init (void) // fallthrough } - case MONO_PROFILER_STAT_MODE_REAL: sampling_posix_clock = CLOCK_MONOTONIC; break; + case MONO_PROFILER_SAMPLE_MODE_REAL: sampling_posix_clock = CLOCK_MONOTONIC; break; default: g_assert_not_reached (); break; } } @@ -701,8 +614,6 @@ sampling_thread_func (void *data) mono_threads_attach_tools_thread (); mono_native_thread_set_name (mono_native_thread_id_get (), "Profiler sampler"); - gint64 rate = 1000000000 / mono_profiler_get_sampling_rate (); - int old_policy; struct sched_param old_sched; pthread_getschedparam (pthread_self (), &old_policy, &old_sched); @@ -724,12 +635,30 @@ sampling_thread_func (void *data) struct sched_param sched = { .sched_priority = sched_get_priority_max (SCHED_FIFO) }; pthread_setschedparam (pthread_self (), SCHED_FIFO, &sched); - clock_init (); + MonoProfilerSampleMode mode; + +init: + mono_profiler_get_sample_mode (NULL, &mode, NULL); - guint64 sleep = clock_get_time_ns (); + if (mode == MONO_PROFILER_SAMPLE_MODE_NONE) { + mono_profiler_sampling_thread_sleep (); + goto init; + } + + clock_init (mode); - while (InterlockedRead (&sampling_thread_running)) { - sleep += rate; + for (guint64 sleep = clock_get_time_ns (); InterlockedRead (&sampling_thread_running); clock_sleep_ns_abs (sleep)) { + uint64_t freq; + MonoProfilerSampleMode new_mode; + + mono_profiler_get_sample_mode (NULL, &new_mode, &freq); + + if (new_mode != mode) { + clock_cleanup (); + goto init; + } + + sleep += 1000000000 / freq; FOREACH_THREAD_SAFE (info) { /* info should never be this thread as we're a tools thread. */ @@ -746,8 +675,6 @@ sampling_thread_func (void *data) mono_threads_pthread_kill (info, profiler_signal); InterlockedIncrement (&profiler_signals_sent); } FOREACH_THREAD_SAFE_END - - clock_sleep_ns_abs (sleep); } InterlockedWrite (&sampling_thread_exiting, 1); diff --git a/mono/mini/mini-ppc.c b/mono/mini/mini-ppc.c index d78ef80dfbb..f36a3fd528a 100644 --- a/mono/mini/mini-ppc.c +++ b/mono/mini/mini-ppc.c @@ -3183,17 +3183,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) cpos = bb->max_offset; - if (cfg->prof_options & MONO_PROFILE_COVERAGE) { - //MonoCoverageInfo *cov = mono_get_coverage_info (cfg->method); - //g_assert (!mono_compile_aot); - //cpos += 6; - //if (bb->cil_code) - // cov->data [bb->dfn].iloffset = bb->cil_code - cfg->cil_code; - /* this is not thread save, but good enough */ - /* fixme: howto handle overflows? */ - //x86_inc_mem (code, &cov->data [bb->dfn].count); - } - MONO_BB_FOR_EACH_INS (bb, ins) { offset = code - cfg->native_code; @@ -4918,9 +4907,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) MonoInst *ins; bb->max_offset = max_offset; - if (cfg->prof_options & MONO_PROFILE_COVERAGE) - max_offset += 6; - MONO_BB_FOR_EACH_INS (bb, ins) max_offset += ins_native_length (cfg, ins); } diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 77c69bb9375..0f3c217c654 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -1218,6 +1218,7 @@ mono_patch_info_hash (gconstpointer data) case MONO_PATCH_INFO_GC_SAFE_POINT_FLAG: case MONO_PATCH_INFO_AOT_MODULE: case MONO_PATCH_INFO_JIT_THREAD_ATTACH: + case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: return (ji->type << 8); case MONO_PATCH_INFO_CASTCLASS_CACHE: return (ji->type << 8) | (ji->data.index); @@ -1648,6 +1649,10 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code, target = mi->func; break; } + case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT: { + target = (gpointer) &mono_profiler_state.gc_allocation_count; + break; + } default: g_assert_not_reached (); } @@ -3938,9 +3943,11 @@ mini_init (const char *filename, const char *runtime_version) if (mini_profiler_enabled ()) { mono_profiler_load (mini_profiler_get_options ()); - mono_profiler_thread_name (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main"); + MONO_PROFILER_RAISE (thread_name, (MONO_NATIVE_THREAD_ID_TO_UINT (mono_native_thread_id_get ()), "Main")); } + mono_profiler_started (); + if (debug_options.collect_pagefault_stats) mono_aot_set_make_unreadable (TRUE); @@ -4018,10 +4025,10 @@ mini_init (const char *filename, const char *runtime_version) mono_thread_attach (domain); #endif - if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL) + if (mono_profiler_sampling_enabled ()) mono_runtime_setup_stat_profiler (); - mono_profiler_runtime_initialized (); + MONO_PROFILER_RAISE (runtime_initialized, ()); MONO_VES_INIT_END (); @@ -4052,8 +4059,8 @@ register_icalls (void) * the wrapper would call the icall which would call the wrapper and * so on. */ - register_icall (mono_profiler_method_enter, "mono_profiler_method_enter", "void ptr", TRUE); - register_icall (mono_profiler_method_leave, "mono_profiler_method_leave", "void ptr", TRUE); + register_icall (mono_profiler_raise_method_enter, "mono_profiler_raise_method_enter", "void ptr", TRUE); + register_icall (mono_profiler_raise_method_leave, "mono_profiler_raise_method_leave", "void ptr", TRUE); register_icall (mono_trace_enter_method, "mono_trace_enter_method", NULL, TRUE); register_icall (mono_trace_leave_method, "mono_trace_leave_method", NULL, TRUE); @@ -4349,7 +4356,7 @@ print_jit_stats (void) void mini_cleanup (MonoDomain *domain) { - if (mono_profiler_get_events () & MONO_PROFILE_STATISTICAL) + if (mono_profiler_sampling_enabled ()) mono_runtime_shutdown_stat_profiler (); #ifndef DISABLE_COM @@ -4373,7 +4380,9 @@ mini_cleanup (MonoDomain *domain) mono_threadpool_cleanup (); - mono_profiler_shutdown (); + MONO_PROFILER_RAISE (runtime_shutdown, ()); + + mono_profiler_cleanup (); free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ()); diff --git a/mono/mini/mini-s390x.c b/mono/mini/mini-s390x.c index 2f3cd3ebca3..bab41317cc6 100644 --- a/mono/mini/mini-s390x.c +++ b/mono/mini/mini-s390x.c @@ -2985,15 +2985,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) if (cfg->verbose_level > 2) g_print ("Basic block %d starting at offset 0x%x\n", bb->block_num, bb->native_offset); - if ((cfg->prof_options & MONO_PROFILE_COVERAGE) && cfg->coverage_info) { - MonoProfileCoverageInfo *cov = cfg->coverage_info; - g_assert (!mono_compile_aot); - cov->data [bb->dfn].cil_code = bb->cil_code; - /* This is not thread save, but good enough */ - S390_SET (code, s390_r1, &cov->data [bb->dfn].count); - s390_alsi (code, 0, s390_r1, 1); - } - MONO_BB_FOR_EACH_INS (bb, ins) { offset = code - cfg->native_code; @@ -5672,9 +5663,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) MonoInst *ins; bb->max_offset = max_offset; - if (cfg->prof_options & MONO_PROFILE_COVERAGE) - max_offset += 6; - MONO_BB_FOR_EACH_INS (bb, ins) max_offset += ((guint8 *)ins_get_spec (ins->opcode))[MONO_INST_LEN]; } @@ -6501,7 +6489,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par mono_arch_flush_icache (start, size); } - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); if (has_target) { *info = mono_tramp_info_create ("delegate_invoke_impl_has_target", start, code - start, NULL, NULL); @@ -6787,7 +6775,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, } mono_arch_flush_icache ((guint8*)start, (code - start)); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL)); if (!fail_tramp) mono_stats.imt_trampolines_size += (code - start); diff --git a/mono/mini/mini-sparc.c b/mono/mini/mini-sparc.c index 29c6f96b5c0..1edddbd139c 100644 --- a/mono/mini/mini-sparc.c +++ b/mono/mini/mini-sparc.c @@ -2407,10 +2407,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) cpos = bb->max_offset; - if (cfg->prof_options & MONO_PROFILE_COVERAGE) { - NOT_IMPLEMENTED; - } - MONO_BB_FOR_EACH_INS (bb, ins) { guint8* code_start; diff --git a/mono/mini/mini-windows.c b/mono/mini/mini-windows.c index 2d3c64f22e6..3852baf81f1 100644 --- a/mono/mini/mini-windows.c +++ b/mono/mini/mini-windows.c @@ -271,11 +271,15 @@ thread_timer_expired (HANDLE thread) context.ContextFlags = CONTEXT_CONTROL; if (GetThreadContext (thread, &context)) { + guchar *ip; + #ifdef _WIN64 - mono_profiler_stat_hit ((guchar *) context.Rip, &context); + ip = (guchar *) context.Rip; #else - mono_profiler_stat_hit ((guchar *) context.Eip, &context); + ip = (guchar *) context.Eip; #endif + + MONO_PROFILER_RAISE (sample_hit, (ip, &context)); } } diff --git a/mono/mini/mini-x86.c b/mono/mini/mini-x86.c index 7f7758c517e..ad1637319c8 100644 --- a/mono/mini/mini-x86.c +++ b/mono/mini/mini-x86.c @@ -2427,16 +2427,6 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb) cpos = bb->max_offset; - if ((cfg->prof_options & MONO_PROFILE_COVERAGE) && cfg->coverage_info) { - MonoProfileCoverageInfo *cov = cfg->coverage_info; - g_assert (!cfg->compile_aot); - cpos += 6; - - cov->data [bb->dfn].cil_code = bb->cil_code; - /* this is not thread save, but good enough */ - x86_inc_mem (code, &cov->data [bb->dfn].count); - } - offset = code - cfg->native_code; mono_debug_open_block (cfg, bb, offset); @@ -5165,8 +5155,6 @@ mono_arch_emit_prolog (MonoCompile *cfg) MonoInst *ins; bb->max_offset = max_offset; - if (cfg->prof_options & MONO_PROFILE_COVERAGE) - max_offset += 6; /* max alignment for loops */ if ((cfg->opt & MONO_OPT_LOOP) && bb_is_loop_start (bb)) max_offset += LOOP_ALIGNMENT; @@ -5666,7 +5654,7 @@ mono_arch_build_imt_trampoline (MonoVTable *vtable, MonoDomain *domain, MonoIMTC g_free (buff); } - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_IMT_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); @@ -5937,7 +5925,7 @@ get_delegate_invoke_impl (MonoTrampInfo **info, gboolean has_target, guint32 par if (!has_target) g_free (buff); } - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); return start; } @@ -5977,7 +5965,7 @@ get_delegate_virtual_invoke_impl (MonoTrampInfo **info, gboolean load_imt_reg, i /* Load the vtable */ x86_mov_reg_membase (code, X86_EAX, X86_ECX, MONO_STRUCT_OFFSET (MonoObject, vtable), 4); x86_jump_membase (code, X86_EAX, offset); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_DELEGATE_INVOKE, NULL)); tramp_name = mono_get_delegate_virtual_invoke_impl_name (load_imt_reg, offset); *info = mono_tramp_info_create (tramp_name, start, code - start, NULL, unwind_ops); diff --git a/mono/mini/mini.c b/mono/mini/mini.c index 10d6eac8b16..d058547fc41 100644 --- a/mono/mini/mini.c +++ b/mono/mini/mini.c @@ -2230,9 +2230,6 @@ mono_codegen (MonoCompile *cfg) mono_bb_deduplicate_op_il_seq_points (cfg, bb); } - if (cfg->prof_options & MONO_PROFILE_COVERAGE) - cfg->coverage_info = mono_profiler_coverage_alloc (cfg->method, cfg->num_bblocks); - code = mono_arch_emit_prolog (cfg); cfg->code_len = code - cfg->native_code; @@ -2378,7 +2375,7 @@ mono_codegen (MonoCompile *cfg) } else { mono_domain_code_commit (code_domain, cfg->native_code, cfg->code_size, cfg->code_len); } - mono_profiler_code_buffer_new (cfg->native_code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method); + MONO_PROFILER_RAISE (jit_code_buffer, (cfg->native_code, cfg->code_len, MONO_PROFILER_CODE_BUFFER_METHOD, cfg->method)); mono_arch_flush_icache (cfg->native_code, cfg->code_len); @@ -3097,8 +3094,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl static char *verbose_method_name; InterlockedIncrement (&mono_jit_stats.methods_compiled); - if (mono_profiler_get_events () & MONO_PROFILE_JIT_COMPILATION) - mono_profiler_method_jit (method); + MONO_PROFILER_RAISE (jit_begin, (method)); if (MONO_METHOD_COMPILE_BEGIN_ENABLED ()) MONO_PROBE_METHOD_COMPILE_BEGIN (method); @@ -3161,7 +3157,6 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, JitFl cfg->method = method_to_compile; cfg->mempool = mono_mempool_new (); cfg->opt = opts; - cfg->prof_options = mono_profiler_get_events (); cfg->run_cctors = run_cctors; cfg->domain = domain; cfg->verbose_level = mini_verbose; @@ -4039,7 +4034,6 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in MonoJitInfo *jinfo, *info; MonoVTable *vtable; MonoException *ex = NULL; - guint32 prof_options; GTimer *jit_timer; MonoMethod *prof_method, *shared; @@ -4070,7 +4064,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in if (!jinfo) jinfo = mono_jit_info_table_find (mono_domain_get (), (char *)code); if (jinfo) - mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK); + MONO_PROFILER_RAISE (jit_done, (method, jinfo)); return code; } else if ((method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME)) { const char *name = method->name; @@ -4211,8 +4205,7 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in } if (ex) { - if (cfg->prof_options & MONO_PROFILE_JIT_COMPILATION) - mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_FAILED); + MONO_PROFILER_RAISE (jit_failed, (method)); mono_destroy_compile (cfg); mono_error_set_exception_instance (error, ex); @@ -4255,8 +4248,6 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in jinfo = cfg->jit_info; - prof_options = cfg->prof_options; - /* * Update global stats while holding a lock, instead of doing many * InterlockedIncrement operations during JITting. @@ -4321,19 +4312,16 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in return NULL; } - if (prof_options & MONO_PROFILE_JIT_COMPILATION) { - if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) { - if (mono_marshal_method_from_wrapper (method)) { - /* Native func wrappers have no method */ - /* The profiler doesn't know about wrappers, so pass the original icall method */ - mono_profiler_method_end_jit (mono_marshal_method_from_wrapper (method), jinfo, MONO_PROFILE_OK); - } - } - mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK); - if (prof_method != method) { - mono_profiler_method_end_jit (prof_method, jinfo, MONO_PROFILE_OK); + if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE) { + if (mono_marshal_method_from_wrapper (method)) { + /* Native func wrappers have no method */ + /* The profiler doesn't know about wrappers, so pass the original icall method */ + MONO_PROFILER_RAISE (jit_done, (mono_marshal_method_from_wrapper (method), jinfo)); } } + MONO_PROFILER_RAISE (jit_done, (method, jinfo)); + if (prof_method != method) + MONO_PROFILER_RAISE (jit_done, (prof_method, jinfo)); if (!(method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE || method->wrapper_type == MONO_WRAPPER_REMOTING_INVOKE_WITH_CHECK || diff --git a/mono/mini/mini.h b/mono/mini/mini.h index 1fcb2f1d892..fea3746e5da 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -1682,7 +1682,6 @@ typedef struct { guint epilog_end; regmask_t used_int_regs; guint32 opt; - guint32 prof_options; guint32 flags; guint32 comp_done; guint32 verbose_level; @@ -1761,7 +1760,7 @@ typedef struct { gpointer debug_info; guint32 lmf_offset; guint16 *intvars; - MonoProfileCoverageInfo *coverage_info; + MonoProfilerCoverageInfo *coverage_info; GHashTable *token_info_hash; MonoCompileArch arch; guint32 inline_depth; diff --git a/mono/mini/patch-info.h b/mono/mini/patch-info.h index 8a4ba056ee0..926020246e2 100644 --- a/mono/mini/patch-info.h +++ b/mono/mini/patch-info.h @@ -63,3 +63,4 @@ PATCH_INFO(SET_TLS_TRAMP, "set_tls_tramp") * Same as JIT_ICALL_ADDR, but not treated as a call. */ PATCH_INFO(JIT_ICALL_ADDR_NOCALL, "jit_icall_addr_nocall") +PATCH_INFO(PROFILER_ALLOCATION_COUNT, "profiler_allocation_count") diff --git a/mono/mini/tramp-amd64-gsharedvt.c b/mono/mini/tramp-amd64-gsharedvt.c index 9cf67dd2825..17a6849ed25 100644 --- a/mono/mini/tramp-amd64-gsharedvt.c +++ b/mono/mini/tramp-amd64-gsharedvt.c @@ -162,7 +162,7 @@ mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpoint g_assert ((code - start) < buf_len); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain); diff --git a/mono/mini/tramp-amd64.c b/mono/mini/tramp-amd64.c index 634203bc2e0..cf519e1c929 100644 --- a/mono/mini/tramp-amd64.c +++ b/mono/mini/tramp-amd64.c @@ -71,7 +71,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0))); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); @@ -112,7 +112,7 @@ mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr) g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0))); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); @@ -162,7 +162,7 @@ mono_arch_patch_callsite (guint8 *method_start, guint8 *orig_code, guint8 *addr) addr = thunk_start; g_assert ((((guint64)(addr)) >> 32) == 0); mono_arch_flush_icache (thunk_start, thunk_code - thunk_start); - mono_profiler_code_buffer_new (thunk_start, thunk_code - thunk_start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (thunk_start, thunk_code - thunk_start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); } if (can_write) { InterlockedExchange ((gint32*)(orig_code - 4), ((gint64)addr - (gint64)orig_code)); @@ -197,7 +197,7 @@ mono_arch_create_llvm_native_thunk (MonoDomain *domain, guint8 *addr) *(guint64*)thunk_code = (guint64)addr; addr = thunk_start; mono_arch_flush_icache (thunk_start, thunk_code - thunk_start); - mono_profiler_code_buffer_new (thunk_start, thunk_code - thunk_start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (thunk_start, thunk_code - thunk_start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); return addr; } #endif /* !DISABLE_JIT */ @@ -574,7 +574,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE)); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); tramp_name = mono_get_generic_trampoline_name (tramp_type); *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops); @@ -631,7 +631,7 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty *code_len = size; mono_arch_flush_icache (buf, size); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type)); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type))); return buf; } @@ -724,7 +724,7 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info } mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); g_assert (code - buf <= tramp_size); g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0))); @@ -761,7 +761,7 @@ mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboo amd64_jump_reg (code, AMD64_R11); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); g_assert (code - buf <= tramp_size); g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0))); @@ -855,7 +855,7 @@ mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot) amd64_jump_reg (code, AMD64_RAX); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); g_assert (code - buf <= tramp_size); g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_TRAMPOLINE_UNWINDINFO_SIZE(0))); @@ -992,7 +992,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo amd64_ret (code); mono_arch_flush_icache (code, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); g_assert (code - buf <= tramp_size); g_assert_checked (mono_arch_unwindinfo_validate_size (unwind_ops, MONO_MAX_TRAMPOLINE_UNWINDINFO_SIZE)); @@ -1151,7 +1151,7 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) g_assert (code - start < buf_len); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("enter_icall_trampoline", start, code - start, ji, unwind_ops); diff --git a/mono/mini/tramp-arm.c b/mono/mini/tramp-arm.c index 13c09ac33a7..82d3e95868c 100644 --- a/mono/mini/tramp-arm.c +++ b/mono/mini/tramp-arm.c @@ -395,7 +395,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); /* Sanity check */ g_assert ((code - buf) <= buf_len); @@ -465,7 +465,7 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type)); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type))); g_assert ((code - buf) <= size); @@ -502,7 +502,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) *(guint32*)code = (guint32)addr; code += 4; mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m)); g_assert ((code - start) <= size); /*g_print ("unbox trampoline at %d for %s:%s\n", this_pos, m->klass->name, m->name); g_print ("unbox code is at %p for method at %p\n", start, addr);*/ @@ -534,7 +534,7 @@ mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr) g_assert ((code - start) <= buf_len); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); @@ -648,7 +648,7 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info } mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); g_assert (code - buf <= tramp_size); @@ -683,7 +683,7 @@ mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboo code = emit_bx (code, ARMREG_R1); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); g_assert (code - buf <= tramp_size); @@ -741,7 +741,7 @@ mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot) } mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); g_assert (code - buf <= tramp_size); *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops); @@ -824,7 +824,7 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo ARM_LDM (code, ARMREG_IP, 0xffff); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); const char *tramp_name = single_step ? "sdb_single_step_trampoline" : "sdb_breakpoint_trampoline"; *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops); @@ -980,7 +980,7 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) g_assert (code - start < buf_len); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("enter_icall_trampoline", start, code - start, ji, unwind_ops); @@ -1156,7 +1156,7 @@ mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpoint g_assert ((code - buf) <= buf_len); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, buf, code - buf, NULL, NULL), domain); diff --git a/mono/mini/tramp-arm64.c b/mono/mini/tramp-arm64.c index cf4057a9434..45e18d880aa 100644 --- a/mono/mini/tramp-arm64.c +++ b/mono/mini/tramp-arm64.c @@ -557,7 +557,7 @@ mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot) arm_brx (code, ARMREG_IP0); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); g_assert (code - buf <= tramp_size); *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops); @@ -806,7 +806,7 @@ mono_arch_get_enter_icall_trampoline (MonoTrampInfo **info) g_assert (code - start < buf_len); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_EXCEPTION_HANDLING, NULL)); if (info) *info = mono_tramp_info_create ("enter_icall_trampoline", start, code - start, ji, unwind_ops); diff --git a/mono/mini/tramp-s390x.c b/mono/mini/tramp-s390x.c index 56f1839ae42..b0333d3cf18 100644 --- a/mono/mini/tramp-s390x.c +++ b/mono/mini/tramp-s390x.c @@ -108,7 +108,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *method, gpointer addr) g_assert ((code - start) <= 28); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, method); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, method)); snprintf(trampName, sizeof(trampName), "%s_unbox_trampoline", method->name); @@ -354,7 +354,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (code, buf - code); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); g_assert (info); tramp_name = mono_get_generic_trampoline_name (tramp_type); @@ -420,8 +420,9 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty /* Flush instruction cache, since we've generated code */ mono_arch_flush_icache (code, buf - code); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, - (void *) mono_get_generic_trampoline_simple_name (tramp_type)); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, + MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, + (void *) mono_get_generic_trampoline_simple_name (tramp_type))); /* Sanity check */ g_assert ((buf - code) <= SPECIFIC_TRAMPOLINE_SIZE); @@ -536,7 +537,7 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info s390_jg (code, displace); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); g_assert (code - buf <= tramp_size); @@ -578,7 +579,7 @@ mono_arch_get_static_rgctx_trampoline (gpointer arg, g_assert ((code - start) < buf_len); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, NULL), domain); @@ -638,7 +639,7 @@ mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot) s390_br (code, s390_r1); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); g_assert (code - buf <= tramp_size); *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops); diff --git a/mono/mini/tramp-x86.c b/mono/mini/tramp-x86.c index 55a6d77191e..6d2ba621ea9 100644 --- a/mono/mini/tramp-x86.c +++ b/mono/mini/tramp-x86.c @@ -54,7 +54,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr) x86_jump_code (code, addr); g_assert ((code - start) < size); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_UNBOX_TRAMPOLINE, m)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); @@ -81,7 +81,7 @@ mono_arch_get_static_rgctx_trampoline (gpointer arg, gpointer addr) g_assert ((code - start) <= buf_len); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); @@ -427,7 +427,7 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf } g_assert ((code - buf) <= 256); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); tramp_name = mono_get_generic_trampoline_name (tramp_type); *info = mono_tramp_info_create (tramp_name, buf, code - buf, ji, unwind_ops); @@ -452,7 +452,7 @@ mono_arch_create_specific_trampoline (gpointer arg1, MonoTrampolineType tramp_ty g_assert ((buf - code) <= TRAMPOLINE_SIZE); mono_arch_flush_icache (code, buf - code); - mono_profiler_code_buffer_new (code, buf - code, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type)); + MONO_PROFILER_RAISE (jit_code_buffer, (code, buf - code, MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE, mono_get_generic_trampoline_simple_name (tramp_type))); if (code_len) *code_len = buf - code; @@ -546,7 +546,7 @@ mono_arch_create_rgctx_lazy_fetch_trampoline (guint32 slot, MonoTrampInfo **info } mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); g_assert (code - buf <= tramp_size); @@ -589,7 +589,7 @@ mono_arch_create_general_rgctx_lazy_fetch_trampoline (MonoTrampInfo **info, gboo x86_jump_reg (code, X86_EAX); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); g_assert (code - buf <= tramp_size); @@ -659,7 +659,7 @@ mono_arch_create_handler_block_trampoline (MonoTrampInfo **info, gboolean aot) x86_jump_code (code, tramp); mono_arch_flush_icache (buf, code - buf); - mono_profiler_code_buffer_new (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (buf, code - buf, MONO_PROFILER_CODE_BUFFER_HELPER, NULL)); g_assert (code - buf <= tramp_size); *info = mono_tramp_info_create ("handler_block_trampoline", buf, code - buf, ji, unwind_ops); @@ -710,7 +710,7 @@ mono_arch_get_gsharedvt_arg_trampoline (MonoDomain *domain, gpointer arg, gpoint g_assert ((code - start) <= buf_len); mono_arch_flush_icache (start, code - start); - mono_profiler_code_buffer_new (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL); + MONO_PROFILER_RAISE (jit_code_buffer, (start, code - start, MONO_PROFILER_CODE_BUFFER_GENERICS_TRAMPOLINE, NULL)); mono_tramp_info_register (mono_tramp_info_create (NULL, start, code - start, NULL, unwind_ops), domain); diff --git a/mono/profiler/aot.c b/mono/profiler/aot.c index b5c2d47fb51..758f86eef14 100644 --- a/mono/profiler/aot.c +++ b/mono/profiler/aot.c @@ -46,12 +46,7 @@ static mono_mutex_t mutex; static gboolean verbose; static void -prof_jit_enter (MonoProfiler *prof, MonoMethod *method) -{ -} - -static void -prof_jit_leave (MonoProfiler *prof, MonoMethod *method, int result) +prof_jit_leave (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo) { MonoImage *image = mono_class_get_image (mono_method_get_class (method)); @@ -117,14 +112,14 @@ match_option (const char* p, const char *opt, char **rval) } void -mono_profiler_startup (const char *desc); +mono_profiler_init (const char *desc); /** - * mono_profiler_startup: + * mono_profiler_init: * the entry point */ void -mono_profiler_startup (const char *desc) +mono_profiler_init (const char *desc) { MonoProfiler *prof; const char *p; @@ -172,11 +167,9 @@ mono_profiler_startup (const char *desc) mono_os_mutex_init (&mutex); - mono_profiler_install (prof, prof_shutdown); - - mono_profiler_install_jit_compile (prof_jit_enter, prof_jit_leave); - - mono_profiler_set_events (MONO_PROFILE_JIT_COMPILATION); + MonoProfilerHandle handle = mono_profiler_install (prof); + mono_profiler_set_runtime_shutdown_callback (handle, prof_shutdown); + mono_profiler_set_jit_done_callback (handle, prof_jit_leave); } static void diff --git a/mono/profiler/iomap.c b/mono/profiler/iomap.c index 15baec017ac..5297df369e3 100644 --- a/mono/profiler/iomap.c +++ b/mono/profiler/iomap.c @@ -92,7 +92,7 @@ static inline gchar *build_hint (SavedString *head); static inline gchar *build_hint_from_stack (MonoDomain *domain, void **stack, gint stack_entries); static inline void store_string_location (MonoProfiler *prof, const gchar *string, guint32 hash, size_t len); static void mono_portability_remember_string (MonoProfiler *prof, MonoDomain *domain, MonoString *str); -void mono_profiler_startup (const char *desc); +void mono_profiler_init (const char *desc); static void mismatched_stats_foreach_func (gpointer key, gpointer value, gpointer user_data) { @@ -477,9 +477,9 @@ static void mono_portability_remember_string (MonoProfiler *prof, MonoDomain *do static MonoClass *string_class = NULL; -static void mono_portability_remember_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass) +static void mono_portability_remember_alloc (MonoProfiler *prof, MonoObject *obj) { - if (klass != string_class) + if (mono_object_get_class (obj) != string_class) return; mono_portability_remember_string (prof, mono_object_get_domain (obj), (MonoString*)obj); } @@ -531,7 +531,7 @@ static void profiler_shutdown (MonoProfiler *prof) mono_os_mutex_destroy (&mismatched_files_section); } -void mono_profiler_startup (const char *desc) +void mono_profiler_init (const char *desc) { MonoProfiler *prof = g_new0 (MonoProfiler, 1); @@ -540,10 +540,10 @@ void mono_profiler_startup (const char *desc) prof->saved_strings_hash = g_hash_table_new (NULL, NULL); prof->string_locations_hash = g_hash_table_new (mismatched_files_guint32_hash, mismatched_files_guint32_equal); - mono_profiler_install (prof, profiler_shutdown); - mono_profiler_install_runtime_initialized (runtime_initialized_cb); - mono_profiler_install_iomap (mono_portability_iomap_event); - mono_profiler_install_allocation (mono_portability_remember_alloc); - - mono_profiler_set_events ((MonoProfileFlags)(MONO_PROFILE_ALLOCATIONS | MONO_PROFILE_IOMAP_EVENTS)); + MonoProfilerHandle handle = mono_profiler_install (prof); + mono_profiler_set_runtime_shutdown_callback (handle, profiler_shutdown); + mono_profiler_set_runtime_initialized_callback (handle, runtime_initialized_cb); + mono_profiler_set_iomap_report_callback (handle, mono_portability_iomap_event); + mono_profiler_enable_allocations (); + mono_profiler_set_gc_allocation_callback (handle, mono_portability_remember_alloc); } diff --git a/mono/profiler/log-args.c b/mono/profiler/log-args.c index 53cf67ba6e7..9aaf05b580f 100644 --- a/mono/profiler/log-args.c +++ b/mono/profiler/log-args.c @@ -97,9 +97,9 @@ parse_arg (const char *arg, ProfilerConfig *config) } else if (match_option (arg, "debug-coverage", NULL)) { config->debug_coverage = TRUE; } else if (match_option (arg, "sampling-real", NULL)) { - config->sampling_mode = MONO_PROFILER_STAT_MODE_REAL; + config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_REAL; } else if (match_option (arg, "sampling-process", NULL)) { - config->sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS; + config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_PROCESS; } else if (match_option (arg, "heapshot", &val)) { config->enable_mask |= PROFLOG_HEAPSHOT_ALIAS; set_hsmode (config, val); @@ -158,6 +158,7 @@ load_args_from_env_or_default (ProfilerConfig *config) //XXX change this to header constants config->max_allocated_sample_hits = mono_cpu_count () * 1000; + config->sampling_mode = MONO_PROFILER_SAMPLE_MODE_PROCESS; config->sample_freq = 100; config->max_call_depth = 100; config->num_frames = MAX_FRAMES; diff --git a/mono/profiler/log.c b/mono/profiler/log.c index d84ee526ca2..2b586159b6f 100644 --- a/mono/profiler/log.c +++ b/mono/profiler/log.c @@ -243,13 +243,13 @@ static MonoLinkedListSet profiler_thread_list; * num is always an even number: the even items are the old * addresses, the odd numbers are the respective new object addresses * if exinfo == TYPE_GC_HANDLE_CREATED[_BT] - * [handle_type: uleb128] GC handle type (System.Runtime.InteropServices.GCHandleType) + * [handle_type: uleb128] MonoGCHandleType enum value * upper bits reserved as flags * [handle: uleb128] GC handle value * [objaddr: sleb128] object pointer differences from obj_base * If exinfo == TYPE_GC_HANDLE_CREATED_BT, a backtrace follows. * if exinfo == TYPE_GC_HANDLE_DESTROYED[_BT] - * [handle_type: uleb128] GC handle type (System.Runtime.InteropServices.GCHandleType) + * [handle_type: uleb128] MonoGCHandleType enum value * upper bits reserved as flags * [handle: uleb128] GC handle value * If exinfo == TYPE_GC_HANDLE_DESTROYED_BT, a backtrace follows. @@ -314,7 +314,7 @@ static MonoLinkedListSet profiler_thread_list; * type monitor format: * type: TYPE_MONITOR * exinfo: zero or TYPE_MONITOR_BT - * [type: byte] MONO_PROFILER_MONITOR_{CONTENTION,FAIL,DONE} + * [type: byte] MonoProfilerMonitorEvent enum value * [object: sleb128] the lock object as a difference from obj_base * If exinfo == TYPE_MONITOR_BT, a backtrace follows. * @@ -640,6 +640,7 @@ struct _BinaryObject { static MonoProfiler *log_profiler; struct _MonoProfiler { + MonoProfilerHandle handle; FILE* file; #if defined (HAVE_SYS_ZLIB) gzFile gzfile; @@ -1057,7 +1058,7 @@ emit_uvalue (LogBuffer *logbuffer, uint64_t value) } static void -emit_ptr (LogBuffer *logbuffer, void *ptr) +emit_ptr (LogBuffer *logbuffer, const void *ptr) { if (!logbuffer->ptr_base) logbuffer->ptr_base = (uintptr_t) ptr; @@ -1449,7 +1450,7 @@ static gboolean do_heap_walk = FALSE; static gboolean ignore_heap_events; static void -gc_roots (MonoProfiler *prof, int num, void **objects, int *root_types, uintptr_t *extra_info) +gc_roots (MonoProfiler *prof, MonoObject *const *objects, const MonoProfilerGCRootType *root_types, const uintptr_t *extra_info, uint64_t num) { if (ignore_heap_events) return; @@ -1489,7 +1490,7 @@ trigger_on_demand_heapshot (void) #define ALL_GC_EVENTS_MASK (PROFLOG_GC_MOVES_EVENTS | PROFLOG_GC_ROOT_EVENTS | PROFLOG_GC_EVENTS | PROFLOG_HEAPSHOT_FEATURE) static void -gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) +gc_event (MonoProfiler *profiler, MonoProfilerGCEvent ev, uint32_t generation) { if (ev == MONO_GC_EVENT_START) { uint64_t now = current_time (); @@ -1607,7 +1608,7 @@ gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) } static void -gc_resize (MonoProfiler *profiler, int64_t new_size) +gc_resize (MonoProfiler *profiler, uintptr_t new_size) { ENTER_LOG (&gc_resizes_ctr, logbuffer, EVENT_SIZE /* event */ + @@ -1667,7 +1668,7 @@ emit_bt (MonoProfiler *prof, LogBuffer *logbuffer, FrameData *data) } static void -gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass) +gc_alloc (MonoProfiler *prof, MonoObject *obj) { int do_bt = (nocalls && InterlockedRead (&runtime_inited) && !notraces) ? TYPE_ALLOC_BT : 0; FrameData data; @@ -1693,7 +1694,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass) ); emit_event (logbuffer, do_bt | TYPE_ALLOC); - emit_ptr (logbuffer, klass); + emit_ptr (logbuffer, mono_object_get_class (obj)); emit_obj (logbuffer, obj); emit_value (logbuffer, len); @@ -1704,7 +1705,7 @@ gc_alloc (MonoProfiler *prof, MonoObject *obj, MonoClass *klass) } static void -gc_moves (MonoProfiler *prof, void **objects, int num) +gc_moves (MonoProfiler *prof, MonoObject *const *objects, uint64_t num) { ENTER_LOG (&gc_moves_ctr, logbuffer, EVENT_SIZE /* event */ + @@ -1724,7 +1725,7 @@ gc_moves (MonoProfiler *prof, void **objects, int num) } static void -gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *obj) +gc_handle (MonoProfiler *prof, int op, MonoGCHandleType type, uint32_t handle, MonoObject *obj) { int do_bt = nocalls && InterlockedRead (&runtime_inited) && !notraces; FrameData data; @@ -1768,6 +1769,18 @@ gc_handle (MonoProfiler *prof, int op, int type, uintptr_t handle, MonoObject *o EXIT_LOG; } +static void +gc_handle_created (MonoProfiler *prof, uint32_t handle, MonoGCHandleType type, MonoObject *obj) +{ + gc_handle (prof, MONO_PROFILER_GC_HANDLE_CREATED, type, handle, obj); +} + +static void +gc_handle_deleted (MonoProfiler *prof, uint32_t handle, MonoGCHandleType type) +{ + gc_handle (prof, MONO_PROFILER_GC_HANDLE_DESTROYED, type, handle, NULL); +} + static void finalize_begin (MonoProfiler *prof) { @@ -1860,11 +1873,8 @@ type_name (MonoClass *klass) } static void -image_loaded (MonoProfiler *prof, MonoImage *image, int result) +image_loaded (MonoProfiler *prof, MonoImage *image) { - if (result != MONO_PROFILE_OK) - return; - const char *name = mono_image_get_filename (image); int nlen = strlen (name) + 1; @@ -1907,11 +1917,8 @@ image_unloaded (MonoProfiler *prof, MonoImage *image) } static void -assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly, int result) +assembly_loaded (MonoProfiler *prof, MonoAssembly *assembly) { - if (result != MONO_PROFILE_OK) - return; - char *name = mono_stringify_assembly_name (mono_assembly_get_name (assembly)); int nlen = strlen (name) + 1; MonoImage *image = mono_assembly_get_image (assembly); @@ -1964,11 +1971,8 @@ assembly_unloaded (MonoProfiler *prof, MonoAssembly *assembly) } static void -class_loaded (MonoProfiler *prof, MonoClass *klass, int result) +class_loaded (MonoProfiler *prof, MonoClass *klass) { - if (result != MONO_PROFILE_OK) - return; - char *name; if (InterlockedRead (&runtime_inited)) @@ -2039,7 +2043,7 @@ method_leave (MonoProfiler *prof, MonoMethod *method) } static void -method_exc_leave (MonoProfiler *prof, MonoMethod *method) +method_exc_leave (MonoProfiler *prof, MonoMethod *method, MonoObject *exc) { if (!only_coverage && !nocalls && --get_thread ()->call_depth <= max_call_depth) { ENTER_LOG (&method_exception_exits_ctr, logbuffer, @@ -2054,12 +2058,15 @@ method_exc_leave (MonoProfiler *prof, MonoMethod *method) } } -static void -method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji, int result) +static MonoProfilerCallInstrumentationFlags +method_filter (MonoProfiler *prof, MonoMethod *method) { - if (result != MONO_PROFILE_OK) - return; + return MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE | MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE; +} +static void +method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji) +{ buffer_lock (); register_method_local (method, ji); @@ -2068,13 +2075,13 @@ method_jitted (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *ji, int resu } static void -code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBufferType type, void *data) +code_buffer_new (MonoProfiler *prof, const mono_byte *buffer, uint64_t size, MonoProfilerCodeBufferType type, const void *data) { - char *name; + const char *name; int nlen; if (type == MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE) { - name = (char *) data; + name = (const char *) data; nlen = strlen (name) + 1; } else { name = NULL; @@ -2134,7 +2141,7 @@ throw_exc (MonoProfiler *prof, MonoObject *object) } static void -clause_exc (MonoProfiler *prof, MonoMethod *method, int clause_type, int clause_num, MonoObject *exc) +clause_exc (MonoProfiler *prof, MonoMethod *method, uint32_t clause_num, MonoExceptionEnum clause_type, MonoObject *exc) { ENTER_LOG (&exception_clauses_ctr, logbuffer, EVENT_SIZE /* event */ + @@ -2183,6 +2190,24 @@ monitor_event (MonoProfiler *profiler, MonoObject *object, MonoProfilerMonitorEv EXIT_LOG; } +static void +monitor_contention (MonoProfiler *prof, MonoObject *object) +{ + monitor_event (prof, object, MONO_PROFILER_MONITOR_CONTENTION); +} + +static void +monitor_acquired (MonoProfiler *prof, MonoObject *object) +{ + monitor_event (prof, object, MONO_PROFILER_MONITOR_DONE); +} + +static void +monitor_failed (MonoProfiler *prof, MonoObject *object) +{ + monitor_event (prof, object, MONO_PROFILER_MONITOR_FAIL); +} + static void thread_start (MonoProfiler *prof, uintptr_t tid) { @@ -2250,11 +2275,8 @@ thread_name (MonoProfiler *prof, uintptr_t tid, const char *name) } static void -domain_loaded (MonoProfiler *prof, MonoDomain *domain, int result) +domain_loaded (MonoProfiler *prof, MonoDomain *domain) { - if (result != MONO_PROFILE_OK) - return; - ENTER_LOG (&domain_loads_ctr, logbuffer, EVENT_SIZE /* event */ + BYTE_SIZE /* type */ + @@ -2353,7 +2375,7 @@ typedef struct { MonoProfiler *prof; uint64_t time; uintptr_t tid; - void *ip; + const void *ip; int count; AsyncFrameInfo frames [MONO_ZERO_LEN_ARRAY]; } SampleHit; @@ -2391,7 +2413,7 @@ enqueue_sample_hit (gpointer p) } static void -mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context) +mono_sample_hit (MonoProfiler *profiler, const mono_byte *ip, const void *context) { /* * Please note: We rely on the runtime loading the profiler with @@ -2422,7 +2444,7 @@ mono_sample_hit (MonoProfiler *profiler, unsigned char *ip, void *context) } sample->count = 0; - mono_stack_walk_async_safe (&async_walk_stack, context, sample); + mono_stack_walk_async_safe (&async_walk_stack, (void *) context, sample); sample->time = current_time (); sample->tid = thread_id (); @@ -3231,18 +3253,18 @@ free_coverage_entry (gpointer data, gpointer userdata) } static void -obtain_coverage_for_method (MonoProfiler *prof, const MonoProfileCoverageEntry *entry) +obtain_coverage_for_method (MonoProfiler *prof, const MonoProfilerCoverageData *entry) { - int offset = entry->iloffset - previous_offset; + int offset = entry->il_offset - previous_offset; CoverageEntry *e = g_new (CoverageEntry, 1); - previous_offset = entry->iloffset; + previous_offset = entry->il_offset; e->offset = offset; e->counter = entry->counter; - e->filename = g_strdup(entry->filename ? entry->filename : ""); + e->filename = g_strdup(entry->file_name ? entry->file_name : ""); e->line = entry->line; - e->column = entry->col; + e->column = entry->column; g_ptr_array_add (coverage_data, e); } @@ -3309,7 +3331,7 @@ build_method_buffer (gpointer key, gpointer value, gpointer userdata) previous_offset = 0; coverage_data = g_ptr_array_new (); - mono_profiler_coverage_get (prof, method, obtain_coverage_for_method); + mono_profiler_get_coverage_data (prof->handle, method, obtain_coverage_for_method); klass = mono_method_get_class (method); image = mono_class_get_image (klass); @@ -4631,23 +4653,23 @@ create_profiler (const char *args, const char *filename, GPtrArray *filters) * mono will load from the shared library and call. */ extern void -mono_profiler_startup (const char *desc); +mono_profiler_init (const char *desc); extern void -mono_profiler_startup_log (const char *desc); +mono_profiler_init_log (const char *desc); /* * this is the entry point that will be used when the profiler * is embedded inside the main executable. */ void -mono_profiler_startup_log (const char *desc) +mono_profiler_init_log (const char *desc) { - mono_profiler_startup (desc); + mono_profiler_init (desc); } void -mono_profiler_startup (const char *desc) +mono_profiler_init (const char *desc) { GPtrArray *filters = NULL; @@ -4690,112 +4712,107 @@ mono_profiler_startup (const char *desc) mono_lls_init (&profiler_thread_list, NULL); - //This two events are required for the profiler to work - int events = MONO_PROFILE_THREADS | MONO_PROFILE_GC; + MonoProfilerHandle handle = log_profiler->handle = mono_profiler_install (log_profiler); //Required callbacks - mono_profiler_install (log_profiler, log_shutdown); - mono_profiler_install_runtime_initialized (runtime_initialized); + mono_profiler_set_runtime_shutdown_callback (handle, log_shutdown); + mono_profiler_set_runtime_initialized_callback (handle, runtime_initialized); - mono_profiler_install_gc (gc_event, gc_resize); - mono_profiler_install_thread (thread_start, thread_end); + mono_profiler_set_gc_event_callback (handle, gc_event); + mono_profiler_set_gc_resize_callback (handle, gc_resize); + mono_profiler_set_thread_started_callback (handle, thread_start); + mono_profiler_set_thread_stopped_callback (handle, thread_end); //It's questionable whether we actually want this to be mandatory, maybe put it behind the actual event? - mono_profiler_install_thread_name (thread_name); - + mono_profiler_set_thread_name_callback (handle, thread_name); if (config.effective_mask & PROFLOG_DOMAIN_EVENTS) { - events |= MONO_PROFILE_APPDOMAIN_EVENTS; - mono_profiler_install_appdomain (NULL, domain_loaded, domain_unloaded, NULL); - mono_profiler_install_appdomain_name (domain_name); + mono_profiler_set_domain_loaded_callback (handle, domain_loaded); + mono_profiler_set_domain_unloading_callback (handle, domain_unloaded); + mono_profiler_set_domain_name_callback (handle, domain_name); } if (config.effective_mask & PROFLOG_ASSEMBLY_EVENTS) { - events |= MONO_PROFILE_ASSEMBLY_EVENTS; - mono_profiler_install_assembly (NULL, assembly_loaded, assembly_unloaded, NULL); + mono_profiler_set_assembly_loaded_callback (handle, assembly_loaded); + mono_profiler_set_assembly_unloading_callback (handle, assembly_unloaded); } if (config.effective_mask & PROFLOG_MODULE_EVENTS) { - events |= MONO_PROFILE_MODULE_EVENTS; - mono_profiler_install_module (NULL, image_loaded, image_unloaded, NULL); + mono_profiler_set_image_loaded_callback (handle, image_loaded); + mono_profiler_set_image_unloading_callback (handle, image_unloaded); } - if (config.effective_mask & PROFLOG_CLASS_EVENTS) { - events |= MONO_PROFILE_CLASS_EVENTS; - mono_profiler_install_class (NULL, class_loaded, NULL, NULL); - } + if (config.effective_mask & PROFLOG_CLASS_EVENTS) + mono_profiler_set_class_loaded_callback (handle, class_loaded); if (config.effective_mask & PROFLOG_JIT_COMPILATION_EVENTS) { - events |= MONO_PROFILE_JIT_COMPILATION; - mono_profiler_install_jit_end (method_jitted); - mono_profiler_install_code_buffer_new (code_buffer_new); + mono_profiler_set_jit_done_callback (handle, method_jitted); + mono_profiler_set_jit_code_buffer_callback (handle, code_buffer_new); } if (config.effective_mask & PROFLOG_EXCEPTION_EVENTS) { - events |= MONO_PROFILE_EXCEPTIONS; - mono_profiler_install_exception (throw_exc, method_exc_leave, NULL); - mono_profiler_install_exception_clause (clause_exc); + mono_profiler_set_exception_throw_callback (handle, throw_exc); + mono_profiler_set_exception_clause_callback (handle, clause_exc); } if (config.effective_mask & PROFLOG_ALLOCATION_EVENTS) { - events |= MONO_PROFILE_ALLOCATIONS; - mono_profiler_install_allocation (gc_alloc); + mono_profiler_enable_allocations (); + mono_profiler_set_gc_allocation_callback (handle, gc_alloc); } //PROFLOG_GC_EVENTS is mandatory //PROFLOG_THREAD_EVENTS is mandatory if (config.effective_mask & PROFLOG_CALL_EVENTS) { - events |= MONO_PROFILE_ENTER_LEAVE; - mono_profiler_install_enter_leave (method_enter, method_leave); + mono_profiler_set_call_instrumentation_filter_callback (handle, method_filter); + mono_profiler_set_method_enter_callback (handle, method_enter); + mono_profiler_set_method_leave_callback (handle, method_leave); + mono_profiler_set_method_exception_leave_callback (handle, method_exc_leave); } - if (config.effective_mask & PROFLOG_INS_COVERAGE_EVENTS) { - events |= MONO_PROFILE_INS_COVERAGE; - mono_profiler_install_coverage_filter (coverage_filter); - } + if (config.effective_mask & PROFLOG_INS_COVERAGE_EVENTS) + mono_profiler_set_coverage_filter_callback (handle, coverage_filter); - //XXX should we check for PROFLOG_SAMPLING_FEATURE instead?? if (config.effective_mask & PROFLOG_SAMPLING_EVENTS) { - events |= MONO_PROFILE_STATISTICAL; - mono_profiler_set_statistical_mode (config.sampling_mode, config.sample_freq); - mono_profiler_install_statistical (mono_sample_hit); + mono_profiler_enable_sampling (handle); + + if (!mono_profiler_set_sample_mode (handle, config.sampling_mode, config.sample_freq)) + g_warning ("Another profiler controls sampling parameters; the log profiler will not be able to modify them"); + + mono_profiler_set_sample_hit_callback (handle, mono_sample_hit); } if (config.effective_mask & PROFLOG_MONITOR_EVENTS) { - events |= MONO_PROFILE_MONITOR_EVENTS; - mono_profiler_install_monitor (monitor_event); + mono_profiler_set_monitor_contention_callback (handle, monitor_contention); + mono_profiler_set_monitor_acquired_callback (handle, monitor_acquired); + mono_profiler_set_monitor_failed_callback (handle, monitor_failed); } - if (config.effective_mask & PROFLOG_GC_MOVES_EVENTS) { - events |= MONO_PROFILE_GC_MOVES; - mono_profiler_install_gc_moves (gc_moves); - } + if (config.effective_mask & PROFLOG_GC_MOVES_EVENTS) + mono_profiler_set_gc_moves_callback (handle, gc_moves); - // TODO split those in two profiler events - if (config.effective_mask & (PROFLOG_GC_ROOT_EVENTS | PROFLOG_GC_HANDLE_EVENTS)) { - events |= MONO_PROFILE_GC_ROOTS; - mono_profiler_install_gc_roots ( - config.effective_mask & (PROFLOG_GC_HANDLE_EVENTS) ? gc_handle : NULL, - (config.effective_mask & PROFLOG_GC_ROOT_EVENTS) ? gc_roots : NULL); - } + if (config.effective_mask & PROFLOG_GC_ROOT_EVENTS) + mono_profiler_set_gc_roots_callback (handle, gc_roots); if (config.effective_mask & PROFLOG_CONTEXT_EVENTS) { - events |= MONO_PROFILE_CONTEXT_EVENTS; - mono_profiler_install_context (context_loaded, context_unloaded); + mono_profiler_set_context_loaded_callback (handle, context_loaded); + mono_profiler_set_context_unloaded_callback (handle, context_unloaded); } if (config.effective_mask & PROFLOG_FINALIZATION_EVENTS) { - events |= MONO_PROFILE_GC_FINALIZATION; - mono_profiler_install_gc_finalize (finalize_begin, finalize_object_begin, finalize_object_end, finalize_end); + mono_profiler_set_gc_finalizing_callback (handle, finalize_begin); + mono_profiler_set_gc_finalized_callback (handle, finalize_end); + mono_profiler_set_gc_finalizing_object_callback (handle, finalize_object_begin); + mono_profiler_set_gc_finalized_object_callback (handle, finalize_object_end); } else if (ENABLED (PROFLOG_HEAPSHOT_FEATURE) && config.hs_mode_ondemand) { //On Demand heapshot uses the finalizer thread to force a collection and thus a heapshot - events |= MONO_PROFILE_GC_FINALIZATION; - mono_profiler_install_gc_finalize (NULL, NULL, NULL, finalize_end); + mono_profiler_set_gc_finalized_callback (handle, finalize_end); } //PROFLOG_COUNTER_EVENTS is a pseudo event controled by the no_counters global var - //PROFLOG_GC_HANDLE_EVENTS is handled together with PROFLOG_GC_ROOT_EVENTS - mono_profiler_set_events ((MonoProfileFlags)events); + if (config.effective_mask & PROFLOG_GC_HANDLE_EVENTS) { + mono_profiler_set_gc_handle_created_callback (handle, gc_handle_created); + mono_profiler_set_gc_handle_deleted_callback (handle, gc_handle_deleted); + } } diff --git a/mono/profiler/log.h b/mono/profiler/log.h index 5029c26c70c..10171a8d05b 100644 --- a/mono/profiler/log.h +++ b/mono/profiler/log.h @@ -150,6 +150,17 @@ typedef enum { SYNC_POINT_WORLD_START } MonoProfilerSyncPointType; +typedef enum { + MONO_PROFILER_MONITOR_CONTENTION = 1, + MONO_PROFILER_MONITOR_DONE = 2, + MONO_PROFILER_MONITOR_FAIL = 3, +} MonoProfilerMonitorEvent; + +enum { + MONO_PROFILER_GC_HANDLE_CREATED, + MONO_PROFILER_GC_HANDLE_DESTROYED, +}; + // Sampling sources // Unless you have compiled with --enable-perf-events, only SAMPLE_CYCLES is available enum { @@ -265,7 +276,7 @@ typedef struct { //Max size of the sample hit buffer, we'll drop frames if it's reached int max_allocated_sample_hits; - MonoProfileSamplingMode sampling_mode; + MonoProfilerSampleMode sampling_mode; } ProfilerConfig; void proflog_parse_args (ProfilerConfig *config, const char *desc); diff --git a/mono/profiler/mprof-report.c b/mono/profiler/mprof-report.c index 00254414925..5d93db97466 100644 --- a/mono/profiler/mprof-report.c +++ b/mono/profiler/mprof-report.c @@ -1357,7 +1357,7 @@ heap_shot_mark_objects (HeapShot *hs) } obj = hs->objects_hash [oi]; cd = obj->hklass; - if (hs->roots_types [i] & MONO_PROFILE_GC_ROOT_PINNING) + if (hs->roots_types [i] & MONO_PROFILER_GC_ROOT_PINNING) cd->pinned_references++; cd->root_references++; } @@ -1959,12 +1959,12 @@ get_handle_name (int htype) static const char* get_root_name (int rtype) { - switch (rtype & MONO_PROFILE_GC_ROOT_TYPEMASK) { - case MONO_PROFILE_GC_ROOT_STACK: return "stack"; - case MONO_PROFILE_GC_ROOT_FINALIZER: return "finalizer"; - case MONO_PROFILE_GC_ROOT_HANDLE: return "handle"; - case MONO_PROFILE_GC_ROOT_OTHER: return "other"; - case MONO_PROFILE_GC_ROOT_MISC: return "misc"; + switch (rtype & MONO_PROFILER_GC_ROOT_TYPEMASK) { + case MONO_PROFILER_GC_ROOT_STACK: return "stack"; + case MONO_PROFILER_GC_ROOT_FINALIZER: return "finalizer"; + case MONO_PROFILER_GC_ROOT_HANDLE: return "handle"; + case MONO_PROFILER_GC_ROOT_OTHER: return "other"; + case MONO_PROFILER_GC_ROOT_MISC: return "misc"; default: return "unknown"; } } diff --git a/mono/profiler/ptestrunner.pl b/mono/profiler/ptestrunner.pl index 687f644e5e0..ab9cb1f663f 100755 --- a/mono/profiler/ptestrunner.pl +++ b/mono/profiler/ptestrunner.pl @@ -76,7 +76,7 @@ if ($report ne "missing binary") { report_errors (); } # test traces -$report = run_test ("test-traces.exe", "legacy,calls,alloc,output=-traces.mlpd", "--traces traces.mlpd"); +$report = run_test ("test-traces.exe", "legacy,calls,alloc,output=-traces.mlpd", "--maxframes=7 --traces traces.mlpd"); check_report_basics ($report); check_call_traces ($report, "T:level3 (int)" => [2020, "T:Main (string[])"], @@ -317,8 +317,10 @@ sub check_alloc_traces while (@desc) { my $dm = pop @desc; my $fm = pop @frames; - $fm = pop @frames if $fm =~ /wrapper/; - push @errors, "Wrong frame $fm for alloc of $type." unless $dm eq $fm; + while ($fm =~ /wrapper/) { + $fm = pop @frames; + } + push @errors, "Wrong frame $fm for alloc of $type (expected $dm)." unless $dm eq $fm; } } else { push @errors, "No alloc frames for $type."; diff --git a/mono/profiler/vtune.c b/mono/profiler/vtune.c index 2ed52c541fd..a1615bfa362 100644 --- a/mono/profiler/vtune.c +++ b/mono/profiler/vtune.c @@ -76,64 +76,63 @@ codeanalyst_shutdown (MonoProfiler *prof) } static void -method_jit_result (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result) { - if (result == MONO_PROFILE_OK) { - int i; - MonoDebugSourceLocation *sourceLoc; - MonoDebugMethodJitInfo *dmji; - MonoClass *klass = mono_method_get_class (method); - char *signature = mono_signature_get_desc (mono_method_signature (method), TRUE); - char *name = g_strdup_printf ("%s(%s)", mono_method_get_name (method), signature); - char *classname = g_strdup_printf ("%s%s%s", mono_class_get_namespace (klass), mono_class_get_namespace (klass)[0] != 0 ? "::" : "", mono_class_get_name (klass)); - gpointer code_start = mono_jit_info_get_code_start (jinfo); - int code_size = mono_jit_info_get_code_size (jinfo); - - iJIT_Method_Load vtuneMethod; - memset(&vtuneMethod, 0, sizeof(vtuneMethod)); - vtuneMethod.method_id = iJIT_GetNewMethodID(); - vtuneMethod.method_name = name; - vtuneMethod.method_load_address = code_start; - vtuneMethod.method_size = code_size; - vtuneMethod.class_file_name = classname; - - dmji = mono_debug_find_method (method, mono_domain_get()); - - if (dmji != NULL) - { - vtuneMethod.line_number_size = dmji->num_line_numbers; - vtuneMethod.line_number_table = (vtuneMethod.line_number_size != 0) ? - (LineNumberInfo*)malloc(sizeof(LineNumberInfo) * vtuneMethod.line_number_size) : NULL; +method_jit_done (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo) +{ + int i; + MonoDebugSourceLocation *sourceLoc; + MonoDebugMethodJitInfo *dmji; + MonoClass *klass = mono_method_get_class (method); + char *signature = mono_signature_get_desc (mono_method_signature (method), TRUE); + char *name = g_strdup_printf ("%s(%s)", mono_method_get_name (method), signature); + char *classname = g_strdup_printf ("%s%s%s", mono_class_get_namespace (klass), mono_class_get_namespace (klass)[0] != 0 ? "::" : "", mono_class_get_name (klass)); + gpointer code_start = mono_jit_info_get_code_start (jinfo); + int code_size = mono_jit_info_get_code_size (jinfo); - for (i = 0; i < dmji->num_line_numbers; ++i) + iJIT_Method_Load vtuneMethod; + memset(&vtuneMethod, 0, sizeof(vtuneMethod)); + vtuneMethod.method_id = iJIT_GetNewMethodID(); + vtuneMethod.method_name = name; + vtuneMethod.method_load_address = code_start; + vtuneMethod.method_size = code_size; + vtuneMethod.class_file_name = classname; + + dmji = mono_debug_find_method (method, mono_domain_get()); + + if (dmji != NULL) + { + vtuneMethod.line_number_size = dmji->num_line_numbers; + vtuneMethod.line_number_table = (vtuneMethod.line_number_size != 0) ? + (LineNumberInfo*)malloc(sizeof(LineNumberInfo) * vtuneMethod.line_number_size) : NULL; + + for (i = 0; i < dmji->num_line_numbers; ++i) + { + sourceLoc = mono_debug_lookup_source_location (method, dmji->line_numbers[i].native_offset, mono_domain_get()); + if (sourceLoc == NULL) { - sourceLoc = mono_debug_lookup_source_location (method, dmji->line_numbers[i].native_offset, mono_domain_get()); - if (sourceLoc == NULL) - { - g_free (vtuneMethod.line_number_table); - vtuneMethod.line_number_table = NULL; - vtuneMethod.line_number_size = 0; - break; - } - if (i == 0) - vtuneMethod.source_file_name = strdup(sourceLoc->source_file); - vtuneMethod.line_number_table[i].Offset = dmji->line_numbers[i].native_offset; - vtuneMethod.line_number_table[i].LineNumber = sourceLoc->row; - mono_debug_free_source_location (sourceLoc); + g_free (vtuneMethod.line_number_table); + vtuneMethod.line_number_table = NULL; + vtuneMethod.line_number_size = 0; + break; } - mono_debug_free_method_jit_info (dmji); + if (i == 0) + vtuneMethod.source_file_name = strdup(sourceLoc->source_file); + vtuneMethod.line_number_table[i].Offset = dmji->line_numbers[i].native_offset; + vtuneMethod.line_number_table[i].LineNumber = sourceLoc->row; + mono_debug_free_source_location (sourceLoc); } + mono_debug_free_method_jit_info (dmji); + } - iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &vtuneMethod); + iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, &vtuneMethod); - if (vtuneMethod.source_file_name != NULL) - g_free (vtuneMethod.source_file_name); - if (vtuneMethod.line_number_table != NULL) - g_free (vtuneMethod.line_number_table); - - g_free (signature); - g_free (name); - g_free (classname); - } + if (vtuneMethod.source_file_name != NULL) + g_free (vtuneMethod.source_file_name); + if (vtuneMethod.line_number_table != NULL) + g_free (vtuneMethod.line_number_table); + + g_free (signature); + g_free (name); + g_free (classname); } static void @@ -162,14 +161,14 @@ code_buffer_new (MonoProfiler *prof, void *buffer, int size, MonoProfilerCodeBuf /* the entry point */ void -mono_profiler_startup (const char *desc) +mono_profiler_init (const char *desc) { iJIT_IsProfilingActiveFlags flags = iJIT_IsProfilingActive(); if (flags == iJIT_SAMPLING_ON) { - mono_profiler_install (NULL, codeanalyst_shutdown); - mono_profiler_install_jit_end (method_jit_result); - mono_profiler_install_code_buffer_new (code_buffer_new); - mono_profiler_set_events (MONO_PROFILE_JIT_COMPILATION); + MonoProfilerHandle handle = mono_profiler_install (NULL); + mono_profiler_set_runtime_shutdown_callback (handle, codeanalyst_shutdown); + mono_profiler_set_jit_done_callback (handle, method_jit_done); + mono_profiler_set_jit_code_buffer_callback (handle, code_buffer_new); } } diff --git a/mono/utils/mono-codeman.c b/mono/utils/mono-codeman.c index 2964229a5b1..4738808880b 100644 --- a/mono/utils/mono-codeman.c +++ b/mono/utils/mono-codeman.c @@ -235,7 +235,7 @@ free_chunklist (CodeChunk *chunk) for (; chunk; ) { dead = chunk; - mono_profiler_code_chunk_destroy ((gpointer) dead->data); + MONO_PROFILER_RAISE (jit_chunk_destroyed, ((mono_byte *) dead->data)); if (code_manager_callbacks.chunk_destroy) code_manager_callbacks.chunk_destroy ((gpointer)dead->data); chunk = chunk->next; @@ -423,7 +423,7 @@ new_codechunk (CodeChunk *last, int dynamic, int size) chunk->bsize = bsize; if (code_manager_callbacks.chunk_new) code_manager_callbacks.chunk_new ((gpointer)chunk->data, chunk->size); - mono_profiler_code_chunk_new((gpointer) chunk->data, chunk->size); + MONO_PROFILER_RAISE (jit_chunk_created, ((mono_byte *) chunk->data, chunk->size)); code_memory_used += chunk_size; mono_runtime_resource_check_limit (MONO_RESOURCE_JIT_CODE, code_memory_used); diff --git a/mono/utils/mono-io-portability.c b/mono/utils/mono-io-portability.c index b164b6b56db..d4763a569b9 100644 --- a/mono/utils/mono-io-portability.c +++ b/mono/utils/mono-io-portability.c @@ -121,7 +121,7 @@ static inline void do_mono_profiler_iomap (GString **report, const char *pathnam *report = NULL; } - mono_profiler_iomap (rep, pathname, new_pathname); + MONO_PROFILER_RAISE (iomap_report, (rep, pathname, new_pathname)); g_free (rep); } @@ -148,7 +148,7 @@ static inline gchar *mono_portability_find_file_internal (GString **report, cons DIR *scanning = NULL; size_t len; gboolean drive_stripped = FALSE; - gboolean do_report = (mono_profiler_get_events () & MONO_PROFILE_IOMAP_EVENTS) != 0; + gboolean do_report = MONO_PROFILER_ENABLED (iomap_report); if (IS_PORTABILITY_NONE) { return(NULL); diff --git a/samples/profiler/sample.c b/samples/profiler/sample.c index 45c46da07d9..75e2f779590 100644 --- a/samples/profiler/sample.c +++ b/samples/profiler/sample.c @@ -35,19 +35,25 @@ sample_method_leave (MonoProfiler *prof, MonoMethod *method) { } +static MonoProfilerCallInstrumentationFlags +sample_instrumentation_filter (MonoProfiler *prof, MonoMethod *method) +{ + return MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE | MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE; +} + /* the entry point */ void -mono_profiler_startup (const char *desc) +mono_profiler_init (const char *desc) { MonoProfiler *prof; prof = g_new0 (MonoProfiler, 1); - mono_profiler_install (prof, sample_shutdown); - - mono_profiler_install_enter_leave (sample_method_enter, sample_method_leave); - - mono_profiler_set_events (MONO_PROFILE_ENTER_LEAVE); + MonoProfilerHandle handle = mono_profiler_install (prof); + mono_profiler_set_runtime_shutdown_callback (handle, sample_shutdown); + mono_profiler_set_call_instrumentation_filter_callback (handle, sample_instrumentation_filter); + mono_profiler_set_method_enter_callback (handle, sample_method_enter); + mono_profiler_set_method_leave_callback (handle, sample_method_leave); } diff --git a/samples/size/size.c b/samples/size/size.c index c24b417d21f..86ec27dfd6d 100644 --- a/samples/size/size.c +++ b/samples/size/size.c @@ -121,7 +121,7 @@ GetMemoryUsage (MonoObject *this) static int installed = 0; -void install_icall (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result) +void install_icall (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo) { if (installed) return; @@ -131,8 +131,8 @@ void install_icall (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, } void -mono_profiler_startup (const char *desc) +mono_profiler_init (const char *desc) { - mono_profiler_install_jit_end (install_icall); - mono_profiler_set_events (MONO_PROFILE_JIT_COMPILATION); + MonoProfilerHandle handle = mono_profiler_install (NULL); + mono_profiler_set_jit_done_callback (handle, install_icall); }