-/*
- * profiler.c: Profiler interface for Mono
+/**
+ * \file
+ * Profiler interface for Mono
*
* Author:
* Paolo Molaro (lupus@ximian.com)
#include "mono/metadata/assembly.h"
#include "mono/metadata/debug-helpers.h"
#include "mono/metadata/mono-debug.h"
-#include "mono/metadata/debug-mono-symfile.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/io-layer/io-layer.h"
#include "mono/utils/mono-dl.h"
+#include <mono/utils/mono-logger-internals.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
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;
/**
* mono_profiler_install:
- * @prof: a MonoProfiler structure pointer, or a pointer to a derived structure.
- * @callback: the function to invoke at shutdown
- *
- * Use mono_profiler_install to activate profiling in the Mono runtime.
+ * \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 MonoProfiler and put any extra information that they need
+ * 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)
/**
* mono_profiler_set_events:
- * @events: an ORed set of values made up of MONO_PROFILER_ flags
- *
- * The events descriped in the @events argument is a set of flags
+ * \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 mono_profiler_install_jit_compile,
- * you will want to pass the MONO_PROFILE_JIT_COMPILATION flag to
+ * 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 mono_profile_set_events more than once and you can
+ * 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_install_enter_leave:
- * @enter: the routine to be called on each method entry
- * @fleave: the routine to be called each time a method returns
+ * \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 MonoMethod representing the method that is entering or leaving.
+ * the \c MonoMethod representing the method that is entering or leaving.
*/
void
mono_profiler_install_enter_leave (MonoProfileMethodFunc enter, MonoProfileMethodFunc fleave)
/**
* mono_profiler_install_jit_compile:
- * @start: the routine to be called when the JIT process starts.
- * @end: the routine to be called when the JIT process ends.
+ * \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.
prof_list->method_end_invoke = end;
}
+/**
+ * mono_profiler_install_thread:
+ */
void
mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc end)
{
prof_list->thread_name = thread_name_cb;
}
+/**
+ * mono_profiler_install_transition:
+ */
void
mono_profiler_install_transition (MonoProfileMethodResult callback)
{
prof_list->man_unman_transition = callback;
}
+/**
+ * mono_profiler_install_allocation:
+ */
void
mono_profiler_install_allocation (MonoProfileAllocFunc callback)
{
- mono_gc_enable_alloc_events ();
if (!prof_list)
return;
prof_list->allocation_cb = callback;
}
static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
-static int64_t sampling_frequency = 1000; //1ms
+static int64_t sampling_frequency = 100; // Hz
/**
* mono_profiler_set_statistical_mode:
- * @mode the sampling mode used.
- * @sample_frequency_is_us the sampling frequency in microseconds.
+ * \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.
* 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_is_us)
+mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_hz)
{
sampling_mode = mode;
- sampling_frequency = sampling_frequency_is_us;
+ sampling_frequency = sampling_frequency_hz;
}
+/**
+ * mono_profiler_install_statistical:
+ */
void
mono_profiler_install_statistical (MonoProfileStatFunc callback)
{
prof_list->exception_clause_cb = clause_callback;
}
+/**
+ * mono_profiler_install_coverage_filter:
+ */
void
mono_profiler_install_coverage_filter (MonoProfileCoverageFilterFunc callback)
{
prof_list->coverage_filter_cb = callback;
}
+/**
+ * mono_profiler_install_appdomain:
+ */
void
mono_profiler_install_appdomain (MonoProfileAppDomainFunc start_load, MonoProfileAppDomainResult end_load,
MonoProfileAppDomainFunc start_unload, MonoProfileAppDomainFunc end_unload)
prof_list->context_unload = unload;
}
+/**
+ * mono_profiler_install_assembly:
+ */
void
mono_profiler_install_assembly (MonoProfileAssemblyFunc start_load, MonoProfileAssemblyResult end_load,
MonoProfileAssemblyFunc start_unload, MonoProfileAssemblyFunc end_unload)
prof_list->assembly_end_unload = end_unload;
}
+/**
+ * mono_profiler_install_module:
+ */
void
mono_profiler_install_module (MonoProfileModuleFunc start_load, MonoProfileModuleResult end_load,
MonoProfileModuleFunc start_unload, MonoProfileModuleFunc end_unload)
prof_list->module_end_unload = end_unload;
}
+/**
+ * mono_profiler_install_class:
+ */
void
mono_profiler_install_class (MonoProfileClassFunc start_load, MonoProfileClassResult end_load,
MonoProfileClassFunc start_unload, MonoProfileClassFunc end_unload)
prof_list->class_end_unload = end_unload;
}
+/**
+ * mono_profiler_method_enter:
+ */
void
mono_profiler_method_enter (MonoMethod *method)
{
}
}
+/**
+ * mono_profiler_method_leave:
+ */
void
mono_profiler_method_leave (MonoMethod *method)
{
}
}
+/**
+ * mono_profiler_method_jit:
+ */
void
mono_profiler_method_jit (MonoMethod *method)
{
}
}
+/**
+ * mono_profiler_method_end_jit:
+ */
void
mono_profiler_method_end_jit (MonoMethod *method, MonoJitInfo* jinfo, int result)
{
}
}
+/**
+ * mono_profiler_code_transition:
+ */
void
mono_profiler_code_transition (MonoMethod *method, int result)
{
}
}
+/**
+ * mono_profiler_allocation:
+ */
void
mono_profiler_allocation (MonoObject *obj)
{
}
}
+/**
+ * mono_profiler_stat_hit:
+ */
void
mono_profiler_stat_hit (guchar *ip, void *context)
{
}
}
+/**
+ * mono_profiler_thread_start:
+ */
void
mono_profiler_thread_start (gsize tid)
{
}
}
+/**
+ * mono_profiler_thread_end:
+ */
void
mono_profiler_thread_end (gsize tid)
{
}
}
+/**
+ * mono_profiler_assembly_event:
+ */
void
mono_profiler_assembly_event (MonoAssembly *assembly, int code)
{
}
}
+/**
+ * mono_profiler_assembly_loaded:
+ */
void
mono_profiler_assembly_loaded (MonoAssembly *assembly, int result)
{
}
}
+/**
+ * mono_profiler_module_event:
+ */
void
mono_profiler_module_event (MonoImage *module, int code)
{
}
}
+/**
+ * mono_profiler_module_loaded:
+ */
void
mono_profiler_module_loaded (MonoImage *module, int result)
{
}
}
+/**
+ * mono_profiler_class_event:
+ */
void
mono_profiler_class_event (MonoClass *klass, int code)
{
}
}
+/**
+ * mono_profiler_class_loaded:
+ */
void
mono_profiler_class_loaded (MonoClass *klass, int result)
{
}
}
+/**
+ * mono_profiler_appdomain_event:
+ */
void
mono_profiler_appdomain_event (MonoDomain *domain, int code)
{
}
}
+/**
+ * mono_profiler_appdomain_loaded:
+ */
void
mono_profiler_appdomain_loaded (MonoDomain *domain, int result)
{
prof->context_unload (prof->profiler, context);
}
+/**
+ * mono_profiler_shutdown:
+ */
void
mono_profiler_shutdown (void)
{
mono_profiler_set_events ((MonoProfileFlags)0);
}
+/**
+ * mono_profiler_gc_heap_resize:
+ */
void
mono_profiler_gc_heap_resize (gint64 new_size)
{
}
}
+/**
+ * mono_profiler_gc_event:
+ */
void
mono_profiler_gc_event (MonoGCEvent event, int generation)
{
}
}
+/**
+ * mono_profiler_install_gc:
+ */
void
mono_profiler_install_gc (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback)
{
- mono_gc_enable_events ();
if (!prof_list)
return;
prof_list->gc_event = callback;
/**
* mono_profiler_install_gc_moves:
- * @callback: callback function
+ * \param callback callback function
*
- * Install the @callback function that the GC will call when moving objects.
+ * 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.
/**
* mono_profiler_install_gc_roots:
- * @handle_callback: callback function
- * @roots_callback: callback function
+ * \param handle_callback callback function
+ * \param roots_callback callback function
*
- * Install the @handle_callback function that the GC will call when GC
+ * 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 #MONO_PROFILER_GC_HANDLE_CREATED
- * or #MONO_PROFILER_GC_HANDLE_DESTROYED, the handle type, the handle value and the
+ * 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 @roots_callback function that the GC will call when tracing
+ * 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.
prof_list->gc_roots = roots_callback;
}
+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);
+}
+
+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);
+}
+
+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);
+}
+
+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);
+}
+
+void
+mono_profiler_install_gc_finalize (MonoProfileGCFinalizeFunc begin, MonoProfileGCFinalizeObjectFunc begin_obj, MonoProfileGCFinalizeObjectFunc end_obj, MonoProfileGCFinalizeFunc end)
+{
+ if (!prof_list)
+ return;
+
+ 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;
+}
+
void
mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback)
{
/**
* mono_profiler_coverage_get:
- * @prof: The profiler handle, installed with mono_profiler_install
- * @method: the method to gather information from.
- * @func: A routine that will be called back with the results
+ * \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 MONO_PROFILER_INS_COVERAGE flag was active during JIT compilation
- * it is posisble to obtain coverage information about a give method.
+ * 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 @func will be invoked repeatedly with instances of the
- * MonoProfileCoverageEntry structure.
+ * 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)
if (debug_minfo) {
MonoDebugSourceLocation *location;
- location = mono_debug_symfile_lookup_location (debug_minfo, offset);
+ location = mono_debug_method_lookup_location (debug_minfo, offset);
if (location) {
entry.line = location->row;
entry.col = location->column;
MonoDl *pmodule = NULL;
gboolean result;
- pmodule = mono_dl_open (NULL, MONO_DL_LAZY, &err);
+ /*
+ * 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 result;
}
+// 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)
{
char *err;
void *iter;
+ mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "Attempting to load profiler %s from %s (desc %s)", libname, directory, desc);
+
iter = NULL;
err = NULL;
while ((path = mono_dl_build_path (directory, libname, &iter))) {
- pmodule = mono_dl_open (path, MONO_DL_LAZY, &err);
+ 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)
}
static gboolean
-load_profiler_from_mono_instalation (const char *libname, const char *desc)
+load_profiler_from_mono_installation (const char *libname, const char *desc)
{
char *err = NULL;
- MonoDl *pmodule = mono_dl_open_runtime_lib (libname, MONO_DL_LAZY, &err);
+ 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);
/**
* mono_profiler_load:
- * @desc: arguments to configure the profiler
+ * \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.
}
if (!load_embedded_profiler (desc, mname)) {
libname = g_strdup_printf ("mono-profiler-%s", mname);
- if (mono_config_get_assemblies_dir ())
+ 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)
- res = load_profiler_from_mono_instalation (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);