* 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.
BranchMisses = 6,
}
- // mono/metadata/profiler.h : MonoProfileGCRootType
+ // mono/metadata/profiler.h : MonoProfilerGCRootType
[Flags]
public enum LogHeapRootAttributes {
Pinning = 1 << 8,
TypeMask = 0xff,
}
- // mono/metadata/profiler.h : MonoProfilerMonitorEvent
+ // mono/profiler/log.h : MonoProfilerMonitorEvent
public enum LogMonitorEvent {
Contention = 1,
Done = 2,
Fault = 4,
}
- // mono/metadata/profiler.h : MonoGCEvent
+ // mono/metadata/profiler.h : MonoProfilerGCEvent
public enum LogGCEvent {
Begin = 0,
MarkBegin = 1,
PostStartWorldUnlocked = 11,
}
- // mono/sgen/gc-internal-agnostic.h : GCHandleType
+ // mono/metadata/mono-gc.h : MonoGCHandleType
public enum LogGCHandleType {
Weak = 0,
WeakTrackResurrection = 1,
<opcode name="mono_atomic_store_i4" input="PopI+PopI" output="Push0" args="InlineI" o1="0xF0" o2="0x1A" flow="next" />
<opcode name="mono_get_last_error" input="Pop0" output="PushI" args="InlineNone" o1="0xF0" o2="0x1B" flow="next" />
<opcode name="mono_get_rgctx_arg" input="Pop0" output="PushI" args="InlineNone" o1="0xF0" o2="0x1C" flow="next" />
+<opcode name="mono_ldptr_profiler_allocation_count" input="Pop0" output="PushI" args="InlineNone" o1="0xF0" o2="0x1D" flow="next" />
</opdesc>
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)
w32process.h \
w32process-internals.h \
profiler.c \
+ profiler-events.h \
profiler-private.h \
rand.h \
rand.c \
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)) {
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);
mono_assembly_invoke_load_hook (ass);
- mono_profiler_assembly_loaded (ass, MONO_PROFILE_OK);
+ MONO_PROFILER_RAISE (assembly_loaded, (ass));
return ass;
}
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);
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;
}
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:
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;
mono_perfcounters->gc_gen0size = heap_size;
}
#endif
- mono_profiler_gc_heap_resize (new_size);
+
+ MONO_PROFILER_RAISE (gc_resize, (new_size));
}
typedef struct {
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;
}
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;
}
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;
}
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;
}
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;
#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;
}
#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));
}
/**
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;
/*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;
}
}
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_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);
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;
}
mono_loader_unlock ();
- mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+ MONO_PROFILER_RAISE (class_loaded, (klass));
return klass;
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;
}
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);
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);
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;
/* 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;
}
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;
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 {
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;
}
return cached;
}
- mono_profiler_class_event (result, MONO_PROFILE_START_LOAD);
+ MONO_PROFILER_RAISE (class_loading, (result));
classes_size += sizeof (MonoClassPointer);
++class_pointer_count;
mono_loader_unlock ();
- mono_profiler_class_loaded (result, MONO_PROFILE_OK);
+ MONO_PROFILER_RAISE (class_loaded, (result));
return result;
}
return cached;
}
- mono_profiler_class_event (klass, MONO_PROFILE_START_LOAD);
+ MONO_PROFILER_RAISE (class_loading, (klass));
classes_size += sizeof (MonoClassArray);
++class_array_count;
mono_loader_unlock ();
- mono_profiler_class_loaded (klass, MONO_PROFILE_OK);
+ MONO_PROFILER_RAISE (class_loaded, (klass));
return klass;
}
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 ();
if (create_domain_hook)
create_domain_hook (domain);
- mono_profiler_appdomain_loaded (domain, MONO_PROFILE_OK);
+ MONO_PROFILER_RAISE (domain_loaded, (domain));
return domain;
}
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;
}
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);
* 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);
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 */
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 ();
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);
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);
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 ();
GSList *errors = NULL;
GSList *l;
- mono_profiler_module_event (image, MONO_PROFILE_START_LOAD);
+ MONO_PROFILER_RAISE (image_loading, (image));
mono_image_init (image);
load_modules (image);
done:
- mono_profiler_module_loaded (image, MONO_PROFILE_OK);
+ MONO_PROFILER_RAISE (image_loaded, (image));
if (status)
*status = MONO_IMAGE_OK;
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;
}
}
#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);
mono_dynamic_image_free ((MonoDynamicImage*)image);
}
- mono_profiler_module_event (image, MONO_PROFILE_END_UNLOAD);
+ MONO_PROFILER_RAISE (image_unloaded, (image));
return TRUE;
}
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) {
return 0;
}
- mono_profiler_monitor_event (obj, MONO_PROFILER_MONITOR_CONTENTION);
+ MONO_PROFILER_RAISE (monitor_contention, (obj));
/* The slow path begins here. */
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;
}
}
/* 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;
}
/* 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));
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);
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;
--- /dev/null
+/*
+ * 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)
-/**
- * \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 <mono/metadata/profiler.h>
-#include "mono/utils/mono-compiler.h"
-#include <glib.h>
-
-extern MonoProfileFlags mono_profiler_events;
-
-enum {
- MONO_PROFILE_START_LOAD,
- MONO_PROFILE_END_LOAD,
- MONO_PROFILE_START_UNLOAD,
- MONO_PROFILE_END_UNLOAD
+#include <mono/utils/mono-lazy-init.h>
+#include <mono/utils/mono-os-mutex.h>
+#include <mono/utils/mono-os-semaphore.h>
+
+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 <mono/metadata/profiler-events.h>
+#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 <mono/metadata/profiler-events.h>
+#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 <mono/metadata/profiler-events.h>
+#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__
-/**
- * \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 <mono/utils/mono-logger-internals.h>
-#include <string.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_BACKTRACE_SYMBOLS
-#include <execinfo.h>
-#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 <mono/metadata/assembly.h>
+#include <mono/metadata/gc-internals.h>
+#include <mono/metadata/mono-config-dirs.h>
+#include <mono/metadata/mono-debug.h>
+#include <mono/metadata/profiler-private.h>
+#include <mono/utils/mono-dl.h>
+#include <mono/utils/mono-error-internals.h>
-/**
- * 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 <mono/metadata/profiler-events.h>
+#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 <mono/metadata/profiler-events.h>
+#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 <mono/metadata/profiler-events.h>
+#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 <mono/metadata/profiler-events.h>
+#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
-/**
- * \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 <mono/metadata/object.h>
#include <mono/metadata/appdomain.h>
+#include <mono/metadata/mono-gc.h>
+#include <mono/metadata/object.h>
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 <mono/metadata/profiler-events.h>
+#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 <mono/metadata/profiler-events.h>
+#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__
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);
}
{
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)
{
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
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
{
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;
}
{
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;
}
{
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;
}
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
{
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;
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 ();
}
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
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)
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
#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
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;
}
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;
}
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;
}
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;
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;
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;
}
{
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;
}
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);
}
}
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);
}
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
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++;
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;
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;
}
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);
}
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));
}
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
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);
}
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;
}
}
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;
}
}
#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
#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
{
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 ();
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);
/* 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;
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
*/
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;
}
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;
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);
}
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;
/*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 ();
* 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);
}
/* 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;
}
/* 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);
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);
}
mono_threads_unlock ();
- mono_profiler_context_loaded (ctx);
+ MONO_PROFILER_RAISE (context_loaded, (ctx));
}
void
//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
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 */
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;
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");
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);
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;
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) {
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;
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);
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);
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);
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);
}
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;
}
static void
-thread_end (MonoProfiler *prof, uintptr_t tid)
+thread_end (MonoProfiler *prof, uint64_t tid)
{
MonoInternalThread *thread;
DebuggerTlsData *tls = NULL;
}
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);
}
static void
-assembly_load (MonoProfiler *prof, MonoAssembly *assembly, int result)
+assembly_load (MonoProfiler *prof, MonoAssembly *assembly)
{
/* Sent later in jit_end () */
dbg_lock ();
}
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,
send_type_load (method->klass);
- if (!result && jinfo)
+ if (jinfo)
add_pending_breakpoints (method, jinfo);
}
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);
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);
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);
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;
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);
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);
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);
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;
}
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;
}
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;
}
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;
}
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);
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);
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);
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",
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"
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;
}
}
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;
}
}
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;
}
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;
}
}
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;
}
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));
}
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
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);
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;
}
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;
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");
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;
}
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);
}
static void
-emit_instrumentation_call (MonoCompile *cfg, void *func)
+emit_instrumentation_call (MonoCompile *cfg, void *func, gboolean entry)
{
MonoInst *iargs [1];
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);
}
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
{
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;
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);
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;
/* 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;
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);
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]) {
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;
}
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;
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);
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;
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;
}
/* 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);
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);
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;
}
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");
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];
}
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);
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);
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);
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);
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++;
}
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;
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;
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];
}
}
}
-#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;
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);
static clock_serv_t sampling_clock_service;
static void
-clock_init (void)
+clock_init (MonoProfilerSampleMode mode)
{
kern_return_t ret;
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
// 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;
}
}
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);
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. */
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);
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;
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);
}
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);
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 ();
}
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);
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 ();
* 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);
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
mono_threadpool_cleanup ();
- mono_profiler_shutdown ();
+ MONO_PROFILER_RAISE (runtime_shutdown, ());
+
+ mono_profiler_cleanup ();
free_jit_tls_data ((MonoJitTlsData *)mono_tls_get_jit_tls ());
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;
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];
}
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);
}
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);
cpos = bb->max_offset;
- if (cfg->prof_options & MONO_PROFILE_COVERAGE) {
- NOT_IMPLEMENTED;
- }
-
MONO_BB_FOR_EACH_INS (bb, ins) {
guint8* code_start;
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));
}
}
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);
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;
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);
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;
}
/* 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);
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;
} 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);
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);
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;
MonoJitInfo *jinfo, *info;
MonoVTable *vtable;
MonoException *ex = NULL;
- guint32 prof_options;
GTimer *jit_timer;
MonoMethod *prof_method, *shared;
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;
}
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);
jinfo = cfg->jit_info;
- prof_options = cfg->prof_options;
-
/*
* Update global stats while holding a lock, instead of doing many
* InterlockedIncrement operations during JITting.
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 ||
guint epilog_end;
regmask_t used_int_regs;
guint32 opt;
- guint32 prof_options;
guint32 flags;
guint32 comp_done;
guint32 verbose_level;
gpointer debug_info;
guint32 lmf_offset;
guint16 *intvars;
- MonoProfileCoverageInfo *coverage_info;
+ MonoProfilerCoverageInfo *coverage_info;
GHashTable *token_info_hash;
MonoCompileArch arch;
guint32 inline_depth;
* 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")
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);
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);
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);
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));
*(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 */
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);
*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;
}
}
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)));
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)));
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)));
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));
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);
/* 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);
/* 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);
*(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);*/
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);
}
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);
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);
}
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);
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);
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);
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);
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);
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);
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);
/* 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);
/* 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);
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);
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);
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);
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);
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);
}
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);
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;
}
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);
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);
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);
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);
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));
}
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;
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
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)
{
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);
}
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);
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);
}
} 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);
//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;
* 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.
* 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.
*
static MonoProfiler *log_profiler;
struct _MonoProfiler {
+ MonoProfilerHandle handle;
FILE* file;
#if defined (HAVE_SYS_ZLIB)
gzFile gzfile;
}
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;
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;
#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 ();
}
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 */ +
}
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;
);
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);
}
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 */ +
}
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;
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)
{
}
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;
}
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);
}
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))
}
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,
}
}
-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);
}
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;
}
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 */ +
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)
{
}
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 */ +
MonoProfiler *prof;
uint64_t time;
uintptr_t tid;
- void *ip;
+ const void *ip;
int count;
AsyncFrameInfo frames [MONO_ZERO_LEN_ARRAY];
} SampleHit;
}
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
}
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 ();
}
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);
}
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);
* 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;
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);
+ }
}
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 {
//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);
}
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++;
}
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";
}
}
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[])"],
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.";
}
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
/* 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);
}
}
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;
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);
*report = NULL;
}
- mono_profiler_iomap (rep, pathname, new_pathname);
+ MONO_PROFILER_RAISE (iomap_report, (rep, pathname, new_pathname));
g_free (rep);
}
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);
{
}
+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);
}
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;
}
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);
}