2 * Licensed to the .NET Foundation under one or more agreements.
3 * The .NET Foundation licenses this file to you under the MIT license.
4 * See the LICENSE file in the project root for more information.
7 #include <mono/metadata/assembly.h>
8 #include <mono/metadata/gc-internals.h>
9 #include <mono/metadata/mono-config-dirs.h>
10 #include <mono/metadata/mono-debug.h>
11 #include <mono/metadata/profiler-private.h>
12 #include <mono/utils/mono-dl.h>
13 #include <mono/utils/mono-error-internals.h>
14 #include <mono/utils/mono-logger-internals.h>
16 MonoProfilerState mono_profiler_state;
18 typedef void (*MonoProfilerInitializer) (const char *);
20 #define OLD_INITIALIZER_NAME "mono_profiler_startup"
21 #define NEW_INITIALIZER_NAME "mono_profiler_init"
24 load_profiler (MonoDl *module, const char *desc, const char *suffix)
32 old_name = g_strdup_printf (OLD_INITIALIZER_NAME "_%s", suffix);
34 old_name = g_strdup_printf (OLD_INITIALIZER_NAME);
36 MonoProfilerInitializer func;
40 if (!(err = mono_dl_symbol (module, old_name, (gpointer) &func))) {
41 mono_profiler_printf_err ("Found old-style startup symbol %s for %s; profiler has not been migrated to the new API.", old_name, desc);
52 new_name = g_strdup_printf (NEW_INITIALIZER_NAME "_%s", suffix);
54 new_name = g_strdup_printf (NEW_INITIALIZER_NAME);
56 if ((err = mono_dl_symbol (module, new_name, (gpointer *) &func))) {
70 load_profiler_from_executable (const char *desc, const char *name)
75 * Some profilers (such as ours) may need to call back into the runtime
76 * from their sampling callback (which is called in async-signal context).
77 * They need to be able to know that all references back to the runtime
78 * have been resolved; otherwise, calling runtime functions may result in
79 * invoking the dynamic linker which is not async-signal-safe. Passing
80 * MONO_DL_EAGER will ask the dynamic linker to resolve everything upfront.
82 MonoDl *module = mono_dl_open (NULL, MONO_DL_EAGER, &err);
85 mono_profiler_printf_err ("Could not open main executable: %s", err);
90 return load_profiler (module, desc, name);
94 load_profiler_from_directory (const char *directory, const char *libname, const char *desc)
99 while ((path = mono_dl_build_path (directory, libname, &iter))) {
100 // See the comment in load_embedded_profiler ().
101 MonoDl *module = mono_dl_open (path, MONO_DL_EAGER, NULL);
106 return load_profiler (module, desc, NULL);
113 load_profiler_from_installation (const char *libname, const char *desc)
116 MonoDl *module = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err);
121 return load_profiler (module, desc, NULL);
127 mono_profiler_load (const char *desc)
129 mono_gc_base_init ();
131 if (!desc || !strcmp ("default", desc))
134 const char *col = strchr (desc, ':');
138 mname = (char *) g_memdup (desc, col - desc + 1);
139 mname [col - desc] = 0;
141 mname = g_strdup (desc);
143 if (!load_profiler_from_executable (desc, mname)) {
144 char *libname = g_strdup_printf ("mono-profiler-%s", mname);
145 gboolean res = load_profiler_from_installation (libname, desc);
147 if (!res && mono_config_get_assemblies_dir ())
148 res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc);
151 res = load_profiler_from_directory (NULL, libname, desc);
154 mono_profiler_printf_err ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
163 mono_profiler_install (MonoProfiler *prof)
165 MonoProfilerHandle handle = g_new0 (struct _MonoProfilerDesc, 1);
168 handle->next = mono_profiler_state.profilers;
170 mono_profiler_state.profilers = handle;
176 mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfilerCoverageFilterCallback cb)
178 InterlockedWritePointer (&handle->coverage_filter, (gpointer) cb);
182 initialize_coverage (void)
184 mono_os_mutex_init (&mono_profiler_state.coverage_mutex);
185 mono_profiler_state.coverage_hash = g_hash_table_new (NULL, NULL);
189 lazy_initialize_coverage (void)
191 mono_lazy_initialize (&mono_profiler_state.coverage_status, initialize_coverage);
197 mono_os_mutex_lock (&mono_profiler_state.coverage_mutex);
201 coverage_unlock (void)
203 mono_os_mutex_unlock (&mono_profiler_state.coverage_mutex);
207 mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb)
209 lazy_initialize_coverage ();
213 MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method);
221 MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
222 mono_error_assert_ok (&error);
226 const unsigned char *start = mono_method_header_get_code (header, &size, NULL);
227 const unsigned char *end = start - size;
228 MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
230 for (guint32 i = 0; i < info->entries; i++) {
231 guchar *cil_code = info->data [i].cil_code;
233 if (cil_code && cil_code >= start && cil_code < end) {
234 guint32 offset = cil_code - start;
236 MonoProfilerCoverageData data = {
239 .counter = info->data [i].count,
245 MonoDebugSourceLocation *loc = mono_debug_method_lookup_location (minfo, offset);
248 data.file_name = g_strdup (loc->source_file);
249 data.line = loc->row;
250 data.column = loc->column;
252 mono_debug_free_source_location (loc);
256 cb (handle->prof, &data);
258 g_free ((char *) data.file_name);
262 mono_metadata_free_mh (header);
265 MonoProfilerCoverageInfo *
266 mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
268 lazy_initialize_coverage ();
270 gboolean cover = FALSE;
272 for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
273 MonoProfilerCoverageFilterCallback cb = handle->coverage_filter;
276 cover |= cb (handle->prof, method);
284 MonoProfilerCoverageInfo *info = g_malloc0 (sizeof (MonoProfilerCoverageInfo) + SIZEOF_VOID_P * 2 * entries);
286 info->entries = entries;
288 g_hash_table_insert (mono_profiler_state.coverage_hash, method, info);
296 mono_profiler_coverage_free (MonoMethod *method)
298 lazy_initialize_coverage ();
302 MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method);
305 g_hash_table_remove (mono_profiler_state.coverage_hash, method);
313 mono_profiler_enable_sampling (MonoProfilerHandle handle)
315 if (mono_profiler_state.startup_done)
318 if (mono_profiler_state.sampling_owner)
321 mono_profiler_state.sampling_owner = handle;
322 mono_profiler_state.sample_mode = MONO_PROFILER_SAMPLE_MODE_NONE;
323 mono_profiler_state.sample_freq = 100;
324 mono_os_sem_init (&mono_profiler_state.sampling_semaphore, 0);
330 mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint64_t freq)
332 if (handle != mono_profiler_state.sampling_owner)
335 mono_profiler_state.sample_mode = mode;
336 mono_profiler_state.sample_freq = freq;
338 mono_os_sem_post (&mono_profiler_state.sampling_semaphore);
344 mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint64_t *freq)
347 *mode = mono_profiler_state.sample_mode;
350 *freq = mono_profiler_state.sample_freq;
352 return handle == mono_profiler_state.sampling_owner;
356 mono_profiler_sampling_enabled (void)
358 return !!mono_profiler_state.sampling_owner;
362 mono_profiler_sampling_thread_sleep (void)
364 mono_os_sem_wait (&mono_profiler_state.sampling_semaphore, MONO_SEM_FLAGS_NONE);
368 mono_profiler_enable_allocations (void)
370 if (mono_profiler_state.startup_done)
373 mono_profiler_state.allocations = TRUE;
379 mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handle, MonoProfilerCallInstrumentationFilterCallback cb)
381 InterlockedWritePointer (&handle->call_instrumentation_filter, (gpointer) cb);
385 mono_profiler_should_instrument_method (MonoMethod *method, gboolean entry)
387 MonoProfilerCallInstrumentationFlags flags = MONO_PROFILER_CALL_INSTRUMENTATION_NONE;
389 for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
390 MonoProfilerCallInstrumentationFilterCallback cb = handle->call_instrumentation_filter;
393 flags |= cb (handle->prof, method);
397 return flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE;
399 return flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE;
403 mono_profiler_started (void)
405 mono_profiler_state.startup_done = TRUE;
409 mono_profiler_cleanup (void)
411 for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
412 #define _MONO_PROFILER_EVENT(name) \
413 mono_profiler_set_ ## name ## _callback (handle, NULL); \
414 g_assert (!handle->name ## _cb);
415 #define MONO_PROFILER_EVENT_0(name, type) \
416 _MONO_PROFILER_EVENT(name)
417 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
418 _MONO_PROFILER_EVENT(name)
419 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
420 _MONO_PROFILER_EVENT(name)
421 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
422 _MONO_PROFILER_EVENT(name)
423 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
424 _MONO_PROFILER_EVENT(name)
425 #include <mono/metadata/profiler-events.h>
426 #undef MONO_PROFILER_EVENT_0
427 #undef MONO_PROFILER_EVENT_1
428 #undef MONO_PROFILER_EVENT_2
429 #undef MONO_PROFILER_EVENT_3
430 #undef MONO_PROFILER_EVENT_4
431 #undef _MONO_PROFILER_EVENT
434 #define _MONO_PROFILER_EVENT(name, type) \
435 g_assert (!mono_profiler_state.name ## _count);
436 #define MONO_PROFILER_EVENT_0(name, type) \
437 _MONO_PROFILER_EVENT(name, type)
438 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
439 _MONO_PROFILER_EVENT(name, type)
440 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
441 _MONO_PROFILER_EVENT(name, type)
442 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
443 _MONO_PROFILER_EVENT(name, type)
444 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
445 _MONO_PROFILER_EVENT(name, type)
446 #include <mono/metadata/profiler-events.h>
447 #undef MONO_PROFILER_EVENT_0
448 #undef MONO_PROFILER_EVENT_1
449 #undef MONO_PROFILER_EVENT_2
450 #undef MONO_PROFILER_EVENT_3
451 #undef MONO_PROFILER_EVENT_4
452 #undef _MONO_PROFILER_EVENT
456 update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *counter)
461 old = InterlockedReadPointer (location);
462 } while (InterlockedCompareExchangePointer (location, new_, old) != old);
465 * At this point, we could have installed a NULL callback while the counter
466 * is still non-zero, i.e. setting the callback and modifying the counter
467 * is not a single atomic operation. This is fine as we make sure callbacks
468 * are non-NULL before invoking them (see the code below that generates the
469 * raise functions), and besides, updating callbacks at runtime is an
470 * inherently racy operation.
474 InterlockedDecrement (counter);
477 InterlockedIncrement (counter);
480 #define _MONO_PROFILER_EVENT(name, type) \
482 mono_profiler_set_ ## name ## _callback (MonoProfilerHandle handle, MonoProfiler ## type ## Callback cb) \
484 update_callback (&handle->name ## _cb, (gpointer) cb, &mono_profiler_state.name ## _count); \
486 #define MONO_PROFILER_EVENT_0(name, type) \
487 _MONO_PROFILER_EVENT(name, type)
488 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
489 _MONO_PROFILER_EVENT(name, type)
490 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
491 _MONO_PROFILER_EVENT(name, type)
492 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
493 _MONO_PROFILER_EVENT(name, type)
494 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
495 _MONO_PROFILER_EVENT(name, type)
496 #include <mono/metadata/profiler-events.h>
497 #undef MONO_PROFILER_EVENT_0
498 #undef MONO_PROFILER_EVENT_1
499 #undef MONO_PROFILER_EVENT_2
500 #undef MONO_PROFILER_EVENT_3
501 #undef MONO_PROFILER_EVENT_4
502 #undef _MONO_PROFILER_EVENT
504 #define _MONO_PROFILER_EVENT(name, type, params, args) \
506 mono_profiler_raise_ ## name params \
508 for (MonoProfilerHandle h = mono_profiler_state.profilers; h; h = h->next) { \
509 MonoProfiler ## type ## Callback cb = h->name ## _cb; \
514 #define MONO_PROFILER_EVENT_0(name, type) \
515 _MONO_PROFILER_EVENT(name, type, (void), (h->prof))
516 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
517 _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name), (h->prof, arg1_name))
518 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
519 _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name), (h->prof, arg1_name, arg2_name))
520 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
521 _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))
522 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
523 _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))
524 #include <mono/metadata/profiler-events.h>
525 #undef MONO_PROFILER_EVENT_0
526 #undef MONO_PROFILER_EVENT_1
527 #undef MONO_PROFILER_EVENT_2
528 #undef MONO_PROFILER_EVENT_3
529 #undef MONO_PROFILER_EVENT_4
530 #undef _MONO_PROFILER_EVENT