* 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.
*/
#include "config.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;
static ProfilerDesc *prof_list = NULL;
-#define mono_profiler_coverage_lock() mono_mutex_lock (&profiler_coverage_mutex)
-#define mono_profiler_coverage_unlock() mono_mutex_unlock (&profiler_coverage_mutex)
+#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.
{
ProfilerDesc *desc = g_new0 (ProfilerDesc, 1);
if (!prof_list)
- mono_mutex_init_recursive (&profiler_coverage_mutex);
+ mono_os_mutex_init_recursive (&profiler_coverage_mutex);
desc->profiler = prof;
desc->shutdown_callback = callback;
desc->next = prof_list;
mono_profiler_set_events (MonoProfileFlags events)
{
ProfilerDesc *prof;
- MonoProfileFlags value = 0;
+ MonoProfileFlags value = (MonoProfileFlags)0;
if (prof_list)
prof_list->events = events;
for (prof = prof_list; prof; prof = prof->next)
- value |= prof->events;
+ value = (MonoProfileFlags)(value | prof->events);
mono_profiler_events = value;
}
}
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:
* 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;
}
void
prof->shutdown_callback (prof->profiler);
}
- mono_profiler_set_events (0);
+ mono_profiler_set_events ((MonoProfileFlags)0);
}
void
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_begin = end_obj;
+ prof_list->gc_finalize_end = end;
+}
+
void
mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback)
{
if (!coverage_hash)
coverage_hash = g_hash_table_new (NULL, NULL);
- res = g_malloc0 (sizeof (MonoProfileCoverageInfo) + sizeof (void*) * 2 * entries);
+ res = (MonoProfileCoverageInfo *)g_malloc0 (sizeof (MonoProfileCoverageInfo) + sizeof (void*) * 2 * entries);
res->entries = entries;
return;
}
- info = g_hash_table_lookup (coverage_hash, method);
+ info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method);
if (info) {
g_free (info);
g_hash_table_remove (coverage_hash, method);
void
mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileCoverageFunc func)
{
+ MonoError error;
MonoProfileCoverageInfo* info = NULL;
int i, offset;
guint32 code_size;
mono_profiler_coverage_lock ();
if (coverage_hash)
- info = g_hash_table_lookup (coverage_hash, method);
+ info = (MonoProfileCoverageInfo *)g_hash_table_lookup (coverage_hash, method);
mono_profiler_coverage_unlock ();
if (!info)
return;
- header = mono_method_get_header (method);
+ 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);
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);
gboolean res = FALSE;
if (col != NULL) {
- mname = g_memdup (desc, col - desc + 1);
+ 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);
- 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);