[merp] Remove dead code (#20043)
[mono-project.git] / mono / metadata / profiler.c
blob1435981ea700be309b3b921dcde498fca2e3545c
1 /*
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.
5 */
7 #include <config.h>
8 #include <mono/metadata/assembly.h>
9 #include <mono/metadata/gc-internals.h>
10 #include <mono/metadata/mono-config-dirs.h>
11 #include <mono/metadata/mono-debug.h>
12 #include <mono/metadata/profiler-legacy.h>
13 #include <mono/metadata/profiler-private.h>
14 #include <mono/metadata/debug-internals.h>
15 #include <mono/utils/mono-dl.h>
16 #include <mono/utils/mono-error-internals.h>
17 #include <mono/utils/mono-logger-internals.h>
19 MonoProfilerState mono_profiler_state;
21 typedef void (*MonoProfilerInitializer) (const char *);
23 #define OLD_INITIALIZER_NAME "mono_profiler_startup"
24 #define NEW_INITIALIZER_NAME "mono_profiler_init"
26 static gboolean
27 load_profiler (MonoDl *module, const char *name, const char *desc)
29 g_assert (module);
31 char *err, *old_name = g_strdup_printf (OLD_INITIALIZER_NAME);
32 MonoProfilerInitializer func;
34 if (!(err = mono_dl_symbol (module, old_name, (gpointer*) &func))) {
35 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_PROFILER, "Found old-style startup symbol '%s' for the '%s' profiler; it has not been migrated to the new API.", old_name, name);
36 g_free (old_name);
37 return FALSE;
40 g_free (err);
41 g_free (old_name);
43 char *new_name = g_strdup_printf (NEW_INITIALIZER_NAME "_%s", name);
45 if ((err = mono_dl_symbol (module, new_name, (gpointer *) &func))) {
46 g_free (err);
47 g_free (new_name);
48 return FALSE;
51 g_free (new_name);
53 func (desc);
55 return TRUE;
58 static gboolean
59 load_profiler_from_executable (const char *name, const char *desc)
61 char *err;
64 * Some profilers (such as ours) may need to call back into the runtime
65 * from their sampling callback (which is called in async-signal context).
66 * They need to be able to know that all references back to the runtime
67 * have been resolved; otherwise, calling runtime functions may result in
68 * invoking the dynamic linker which is not async-signal-safe. Passing
69 * MONO_DL_EAGER will ask the dynamic linker to resolve everything upfront.
71 MonoDl *module = mono_dl_open (NULL, MONO_DL_EAGER, &err);
73 if (!module) {
74 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_PROFILER, "Could not open main executable: %s", err);
75 g_free (err);
76 return FALSE;
79 return load_profiler (module, name, desc);
82 static gboolean
83 load_profiler_from_directory (const char *directory, const char *libname, const char *name, const char *desc)
85 char *path, *err;
86 void *iter = NULL;
88 while ((path = mono_dl_build_path (directory, libname, &iter))) {
89 MonoDl *module = mono_dl_open (path, MONO_DL_EAGER, &err);
91 if (!module) {
92 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_PROFILER, "Could not open from directory \"%s\": %s", path, err);
93 g_free (err);
94 g_free (path);
95 continue;
98 g_free (path);
100 return load_profiler (module, name, desc);
103 return FALSE;
106 static gboolean
107 load_profiler_from_installation (const char *libname, const char *name, const char *desc)
109 char *err;
110 MonoDl *module = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err);
112 if (!module) {
113 mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_PROFILER, "Could not open from installation: %s", err);
114 g_free (err);
115 return FALSE;
118 return load_profiler (module, name, desc);
122 * mono_profiler_load:
124 * Loads a profiler module based on the specified description. \p desc can be
125 * of the form \c name:args or just \c name. For example, \c log:sample and
126 * \c log will both load \c libmono-profiler-log.so. The description is passed
127 * to the module after it has been loaded. If the specified module has already
128 * been loaded, this function has no effect.
130 * A module called \c foo should declare an entry point like so:
132 * \code
133 * void mono_profiler_init_foo (const char *desc)
136 * \endcode
138 * This function is \b not async safe.
140 * This function may \b only be called by embedders prior to running managed
141 * code.
143 void
144 mono_profiler_load (const char *desc)
146 const char *col;
147 char *mname, *libname;
149 mname = libname = NULL;
151 if (!desc || !strcmp ("default", desc))
152 desc = "log:report";
154 if ((col = strchr (desc, ':')) != NULL) {
155 mname = (char *) g_memdup (desc, col - desc + 1);
156 mname [col - desc] = 0;
157 } else {
158 mname = g_strdup (desc);
161 if (load_profiler_from_executable (mname, desc))
162 goto done;
164 libname = g_strdup_printf ("mono-profiler-%s", mname);
166 if (load_profiler_from_installation (libname, mname, desc))
167 goto done;
169 if (mono_config_get_assemblies_dir () && load_profiler_from_directory (mono_assembly_getrootdir (), libname, mname, desc))
170 goto done;
172 if (load_profiler_from_directory (NULL, libname, mname, desc))
173 goto done;
175 mono_trace (G_LOG_LEVEL_CRITICAL, MONO_TRACE_PROFILER, "The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
177 done:
178 g_free (mname);
179 g_free (libname);
183 * mono_profiler_create:
185 * Installs a profiler and returns a handle for it. The handle is used with the
186 * other functions in the profiler API (e.g. for setting up callbacks). The
187 * given structure pointer, \p prof, will be passed to all callbacks from the
188 * profiler API. It can be \c NULL.
190 * Example usage:
192 * \code
193 * struct _MonoProfiler {
194 * int my_stuff;
195 * // ...
196 * };
198 * MonoProfiler *prof = malloc (sizeof (MonoProfiler));
199 * prof->my_stuff = 42;
200 * MonoProfilerHandle handle = mono_profiler_create (prof);
201 * mono_profiler_set_shutdown_callback (handle, my_shutdown_cb);
202 * \endcode
204 * This function is \b not async safe.
206 * This function may \b only be called from a profiler's init function or prior
207 * to running managed code.
209 MonoProfilerHandle
210 mono_profiler_create (MonoProfiler *prof)
212 MonoProfilerHandle handle = g_new0 (struct _MonoProfilerDesc, 1);
214 handle->prof = prof;
215 handle->next = mono_profiler_state.profilers;
217 mono_profiler_state.profilers = handle;
219 return handle;
223 * mono_profiler_set_cleanup_callback:
225 * Sets a profiler cleanup function. This function will be invoked at shutdown
226 * when the profiler API is cleaning up its internal structures. It's mainly
227 * intended for a profiler to free the structure pointer that was passed to
228 * \c mono_profiler_create, if necessary.
230 * This function is async safe.
232 void
233 mono_profiler_set_cleanup_callback (MonoProfilerHandle handle, MonoProfilerCleanupCallback cb)
235 mono_atomic_store_ptr (&handle->cleanup_callback, (gpointer) cb);
239 * mono_profiler_enable_coverage:
241 * Enables support for code coverage instrumentation. At the moment, this means
242 * enabling the debug info subsystem. If this function is not called, it will
243 * not be possible to use \c mono_profiler_get_coverage_data. Returns \c TRUE
244 * if code coverage support was enabled, or \c FALSE if the function was called
245 * too late for this to be possible.
247 * This function is \b not async safe.
249 * This function may \b only be called from a profiler's init function or prior
250 * to running managed code.
252 mono_bool
253 mono_profiler_enable_coverage (void)
255 if (mono_profiler_state.startup_done)
256 return FALSE;
258 mono_os_mutex_init (&mono_profiler_state.coverage_mutex);
259 mono_profiler_state.coverage_hash = g_hash_table_new (NULL, NULL);
261 if (!mono_debug_enabled ())
262 mono_debug_init (MONO_DEBUG_FORMAT_MONO);
264 return mono_profiler_state.code_coverage = TRUE;
268 * mono_profiler_set_coverage_filter_callback:
270 * Sets a code coverage filter function. The profiler API will invoke filter
271 * functions from all installed profilers. If any of them return \c TRUE, then
272 * the given method will be instrumented for coverage analysis. All filters are
273 * guaranteed to be called at least once per method, even if an earlier filter
274 * has already returned \c TRUE.
276 * Note that filter functions must be installed before a method is compiled in
277 * order to have any effect, i.e. a filter should be registered in a profiler's
278 * init function or prior to running managed code (if embedding).
280 * This function is async safe.
282 void
283 mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfilerCoverageFilterCallback cb)
285 mono_atomic_store_ptr (&handle->coverage_filter, (gpointer) cb);
288 static void
289 coverage_lock (void)
291 mono_os_mutex_lock (&mono_profiler_state.coverage_mutex);
294 static void
295 coverage_unlock (void)
297 mono_os_mutex_unlock (&mono_profiler_state.coverage_mutex);
301 * mono_profiler_get_coverage_data:
303 * Retrieves all coverage data for \p method and invokes \p cb for each entry.
304 * Source location information will only be filled out if \p method has debug
305 * info available. Returns \c TRUE if \p method was instrumented for code
306 * coverage; otherwise, \c FALSE.
308 * Please note that the structure passed to \p cb is only valid for the
309 * duration of the callback.
311 * This function is \b not async safe.
313 mono_bool
314 mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb)
316 if (!mono_profiler_state.code_coverage)
317 return FALSE;
319 if ((method->flags & METHOD_ATTRIBUTE_ABSTRACT) || (method->iflags & METHOD_IMPL_ATTRIBUTE_RUNTIME) || (method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) || (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL))
320 return FALSE;
322 coverage_lock ();
324 MonoProfilerCoverageInfo *info = (MonoProfilerCoverageInfo*)g_hash_table_lookup (mono_profiler_state.coverage_hash, method);
326 coverage_unlock ();
328 MonoMethodHeaderSummary header;
330 g_assert (mono_method_get_header_summary (method, &header));
332 guint32 size = header.code_size;
333 const unsigned char *start = header.code;
334 const unsigned char *end = start + size;
335 MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
337 if (!info) {
338 int i, n_il_offsets;
339 int *source_files;
340 GPtrArray *source_file_list;
341 MonoSymSeqPoint *sym_seq_points;
343 if (!minfo)
344 return TRUE;
346 /* Return 0 counts for all locations */
348 mono_debug_get_seq_points (minfo, NULL, &source_file_list, &source_files, &sym_seq_points, &n_il_offsets);
349 for (i = 0; i < n_il_offsets; ++i) {
350 MonoSymSeqPoint *sp = &sym_seq_points [i];
351 const char *srcfile = "";
353 if (source_files [i] != -1) {
354 MonoDebugSourceInfo *sinfo = (MonoDebugSourceInfo *)g_ptr_array_index (source_file_list, source_files [i]);
355 srcfile = sinfo->source_file;
358 MonoProfilerCoverageData data;
359 memset (&data, 0, sizeof (data));
360 data.method = method;
361 data.il_offset = sp->il_offset;
362 data.counter = 0;
363 data.file_name = srcfile;
364 data.line = sp->line;
365 data.column = 0;
367 cb (handle->prof, &data);
370 g_free (source_files);
371 g_free (sym_seq_points);
372 g_ptr_array_free (source_file_list, TRUE);
374 return TRUE;
377 for (guint32 i = 0; i < info->entries; i++) {
378 guchar *cil_code = info->data [i].cil_code;
380 if (cil_code && cil_code >= start && cil_code < end) {
381 guint32 offset = cil_code - start;
383 MonoProfilerCoverageData data;
384 memset (&data, 0, sizeof (data));
385 data.method = method;
386 data.il_offset = offset;
387 data.counter = info->data [i].count;
388 data.line = 1;
389 data.column = 1;
391 if (minfo) {
392 MonoDebugSourceLocation *loc = mono_debug_method_lookup_location (minfo, offset);
394 if (loc) {
395 data.file_name = g_strdup (loc->source_file);
396 data.line = loc->row;
397 data.column = loc->column;
399 mono_debug_free_source_location (loc);
403 cb (handle->prof, &data);
405 g_free ((char *) data.file_name);
409 return TRUE;
412 gboolean
413 mono_profiler_coverage_instrumentation_enabled (MonoMethod *method)
415 gboolean cover = FALSE;
417 for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
418 MonoProfilerCoverageFilterCallback cb = (MonoProfilerCoverageFilterCallback)handle->coverage_filter;
420 if (cb)
421 cover |= cb (handle->prof, method);
424 return cover;
427 MonoProfilerCoverageInfo *
428 mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
430 if (!mono_profiler_state.code_coverage)
431 return NULL;
433 if (!mono_profiler_coverage_instrumentation_enabled (method))
434 return NULL;
436 coverage_lock ();
438 MonoProfilerCoverageInfo *info = g_malloc0 (sizeof (MonoProfilerCoverageInfo) + sizeof (MonoProfilerCoverageInfoEntry) * entries);
440 info->entries = entries;
442 g_hash_table_insert (mono_profiler_state.coverage_hash, method, info);
444 coverage_unlock ();
446 return info;
450 * mono_profiler_enable_sampling:
452 * Enables the sampling thread. Users must call this function if they intend
453 * to use statistical sampling; \c mono_profiler_set_sample_mode will have no
454 * effect if this function has not been called. The first profiler to call this
455 * function will get ownership over sampling settings (mode and frequency) so
456 * that no other profiler can change those settings. Returns \c TRUE if the
457 * sampling thread was enabled, or \c FALSE if the function was called too late
458 * for this to be possible.
460 * Note that \c mono_profiler_set_sample_mode must still be called with a mode
461 * other than \c MONO_PROFILER_SAMPLE_MODE_NONE to actually start sampling.
463 * This function is \b not async safe.
465 * This function may \b only be called from a profiler's init function or prior
466 * to running managed code.
468 mono_bool
469 mono_profiler_enable_sampling (MonoProfilerHandle handle)
471 if (mono_profiler_state.startup_done)
472 return FALSE;
474 if (mono_profiler_state.sampling_owner)
475 return TRUE;
477 mono_profiler_state.sampling_owner = handle;
478 mono_profiler_state.sample_mode = MONO_PROFILER_SAMPLE_MODE_NONE;
479 mono_profiler_state.sample_freq = 100;
480 mono_os_sem_init (&mono_profiler_state.sampling_semaphore, 0);
482 return TRUE;
486 * mono_profiler_set_sample_mode:
488 * Sets the sampling mode and frequency (in Hz). \p freq must be a positive
489 * number. If the calling profiler has ownership over sampling settings, the
490 * settings will be changed and this function will return \c TRUE; otherwise,
491 * it returns \c FALSE without changing any settings.
493 * This function is async safe.
495 mono_bool
496 mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint32_t freq)
498 if (handle != mono_profiler_state.sampling_owner)
499 return FALSE;
501 mono_profiler_state.sample_mode = mode;
502 mono_profiler_state.sample_freq = freq;
504 mono_profiler_sampling_thread_post ();
506 return TRUE;
510 * mono_profiler_get_sample_mode:
512 * Retrieves the current sampling mode and/or frequency (in Hz). Returns
513 * \c TRUE if the calling profiler is allowed to change the sampling settings;
514 * otherwise, \c FALSE.
516 * This function is async safe.
518 mono_bool
519 mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint32_t *freq)
521 if (mode)
522 *mode = mono_profiler_state.sample_mode;
524 if (freq)
525 *freq = mono_profiler_state.sample_freq;
527 return handle == mono_profiler_state.sampling_owner;
530 gboolean
531 mono_profiler_sampling_enabled (void)
533 return !!mono_profiler_state.sampling_owner;
536 void
537 mono_profiler_sampling_thread_post (void)
539 mono_os_sem_post (&mono_profiler_state.sampling_semaphore);
542 void
543 mono_profiler_sampling_thread_wait (void)
545 mono_os_sem_wait (&mono_profiler_state.sampling_semaphore, MONO_SEM_FLAGS_NONE);
549 * mono_profiler_enable_allocations:
551 * Enables instrumentation of GC allocations. This is necessary so that managed
552 * allocators can be instrumented with a call into the profiler API.
553 * Allocations will not be reported unless this function is called. Returns
554 * \c TRUE if allocation instrumentation was enabled, or \c FALSE if the
555 * function was called too late for this to be possible.
557 * This function is \b not async safe.
559 * This function may \b only be called from a profiler's init function or prior
560 * to running managed code.
562 mono_bool
563 mono_profiler_enable_allocations (void)
565 if (mono_profiler_state.startup_done)
566 return FALSE;
568 return mono_profiler_state.allocations = TRUE;
572 * mono_profiler_enable_clauses:
574 * Enables instrumentation of exception clauses. This is necessary so that CIL
575 * \c leave instructions can be instrumented with a call into the profiler API.
576 * Exception clauses will not be reported unless this function is called.
577 * Returns \c TRUE if exception clause instrumentation was enabled, or \c FALSE
578 * if the function was called too late for this to be possible.
580 * This function is \b not async safe.
582 * This function may \b only be called from a profiler's init function or prior
583 * to running managed code.
585 mono_bool
586 mono_profiler_enable_clauses (void)
588 if (mono_profiler_state.startup_done)
589 return FALSE;
591 return mono_profiler_state.clauses = TRUE;
595 * mono_profiler_set_call_instrumentation_filter_callback:
597 * Sets a call instrumentation filter function. The profiler API will invoke
598 * filter functions from all installed profilers. If any of them return flags
599 * other than \c MONO_PROFILER_CALL_INSTRUMENTATION_NONE, then the given method
600 * will be instrumented as requested. All filters are guaranteed to be called
601 * at least once per method, even if earlier filters have already specified all
602 * flags.
604 * Note that filter functions must be installed before a method is compiled in
605 * order to have any effect, i.e. a filter should be registered in a profiler's
606 * init function or prior to running managed code (if embedding). Also, to
607 * instrument a method that's going to be AOT-compiled, a filter must be
608 * installed at AOT time. This can be done in exactly the same way as one would
609 * normally, i.e. by passing the \c --profile option on the command line, by
610 * calling \c mono_profiler_load, or simply by using the profiler API as an
611 * embedder.
613 * Indiscriminate method instrumentation is extremely heavy and will slow down
614 * most applications to a crawl. Users should consider sampling as a possible
615 * alternative to such heavy-handed instrumentation.
617 * This function is async safe.
619 void
620 mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handle, MonoProfilerCallInstrumentationFilterCallback cb)
622 mono_atomic_store_ptr (&handle->call_instrumentation_filter, (gpointer) cb);
626 * mono_profiler_enable_call_context_introspection:
628 * Enables support for retrieving stack frame data from a call context. At the
629 * moment, this means enabling the debug info subsystem. If this function is not
630 * called, it will not be possible to use the call context introspection
631 * functions (they will simply return \c NULL). Returns \c TRUE if call context
632 * introspection was enabled, or \c FALSE if the function was called too late for
633 * this to be possible.
635 * This function is \b not async safe.
637 * This function may \b only be called from a profiler's init function or prior
638 * to running managed code.
640 mono_bool
641 mono_profiler_enable_call_context_introspection (void)
643 if (mono_profiler_state.startup_done)
644 return FALSE;
646 mono_profiler_state.context_enable ();
648 return mono_profiler_state.call_contexts = TRUE;
652 * mono_profiler_call_context_get_this:
654 * Given a valid call context from an enter/leave event, retrieves a pointer to
655 * the \c this reference for the method. Returns \c NULL if none exists (i.e.
656 * it's a static method) or if call context introspection was not enabled.
658 * The buffer returned by this function must be freed with
659 * \c mono_profiler_call_context_free_buffer.
661 * Please note that a call context is only valid for the duration of the
662 * enter/leave callback it was passed to.
664 * This function is \b not async safe.
666 void *
667 mono_profiler_call_context_get_this (MonoProfilerCallContext *context)
669 if (!mono_profiler_state.call_contexts)
670 return NULL;
672 return mono_profiler_state.context_get_this (context);
676 * mono_profiler_call_context_get_argument:
678 * Given a valid call context from an enter/leave event, retrieves a pointer to
679 * the method argument at the given position. Returns \c NULL if \p position is
680 * out of bounds or if call context introspection was not enabled.
682 * The buffer returned by this function must be freed with
683 * \c mono_profiler_call_context_free_buffer.
685 * Please note that a call context is only valid for the duration of the
686 * enter/leave callback it was passed to.
688 * This function is \b not async safe.
690 void *
691 mono_profiler_call_context_get_argument (MonoProfilerCallContext *context, uint32_t position)
693 if (!mono_profiler_state.call_contexts)
694 return NULL;
696 return mono_profiler_state.context_get_argument (context, position);
700 * mono_profiler_call_context_get_local:
702 * Given a valid call context from an enter/leave event, retrieves a pointer to
703 * the local variable at the given position. Returns \c NULL if \p position is
704 * out of bounds or if call context introspection was not enabled.
706 * The buffer returned by this function must be freed with
707 * \c mono_profiler_call_context_free_buffer.
709 * Please note that a call context is only valid for the duration of the
710 * enter/leave callback it was passed to.
712 * This function is \b not async safe.
714 void *
715 mono_profiler_call_context_get_local (MonoProfilerCallContext *context, uint32_t position)
717 if (!mono_profiler_state.call_contexts)
718 return NULL;
720 return mono_profiler_state.context_get_local (context, position);
724 * mono_profiler_call_context_get_result:
726 * Given a valid call context from an enter/leave event, retrieves a pointer to
727 * return value of a method. Returns \c NULL if the method has no return value
728 * (i.e. it returns \c void), if the leave event was the result of a tail call,
729 * if the function is called on a context from an enter event, or if call
730 * context introspection was not enabled.
732 * The buffer returned by this function must be freed with
733 * \c mono_profiler_call_context_free_buffer.
735 * Please note that a call context is only valid for the duration of the
736 * enter/leave callback it was passed to.
738 * This function is \b not async safe.
740 void *
741 mono_profiler_call_context_get_result (MonoProfilerCallContext *context)
743 if (!mono_profiler_state.call_contexts)
744 return NULL;
746 return mono_profiler_state.context_get_result (context);
750 * mono_profiler_call_context_free_buffer:
752 * Frees a buffer returned by one of the call context introspection functions.
753 * Passing a \c NULL value for \p buffer is allowed, which makes this function
754 * a no-op.
756 * This function is \b not async safe.
758 void
759 mono_profiler_call_context_free_buffer (void *buffer)
761 mono_profiler_state.context_free_buffer (buffer);
764 G_ENUM_FUNCTIONS (MonoProfilerCallInstrumentationFlags)
766 MonoProfilerCallInstrumentationFlags
767 mono_profiler_get_call_instrumentation_flags (MonoMethod *method)
769 MonoProfilerCallInstrumentationFlags flags = MONO_PROFILER_CALL_INSTRUMENTATION_NONE;
771 for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
772 MonoProfilerCallInstrumentationFilterCallback cb = (MonoProfilerCallInstrumentationFilterCallback)handle->call_instrumentation_filter;
774 if (cb)
775 flags |= cb (handle->prof, method);
778 return flags;
781 void
782 mono_profiler_started (void)
784 mono_profiler_state.startup_done = TRUE;
787 void
788 mono_profiler_cleanup (void)
790 for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
791 #define _MONO_PROFILER_EVENT(name) \
792 mono_profiler_set_ ## name ## _callback (handle, NULL); \
793 g_assert (!handle->name ## _cb);
794 #define MONO_PROFILER_EVENT_0(name, type) \
795 _MONO_PROFILER_EVENT(name)
796 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
797 _MONO_PROFILER_EVENT(name)
798 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
799 _MONO_PROFILER_EVENT(name)
800 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
801 _MONO_PROFILER_EVENT(name)
802 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
803 _MONO_PROFILER_EVENT(name)
804 #define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \
805 _MONO_PROFILER_EVENT(name)
806 #include <mono/metadata/profiler-events.h>
807 #undef MONO_PROFILER_EVENT_0
808 #undef MONO_PROFILER_EVENT_1
809 #undef MONO_PROFILER_EVENT_2
810 #undef MONO_PROFILER_EVENT_3
811 #undef MONO_PROFILER_EVENT_4
812 #undef MONO_PROFILER_EVENT_5
813 #undef _MONO_PROFILER_EVENT
816 #define _MONO_PROFILER_EVENT(name, type) \
817 g_assert (!mono_profiler_state.name ## _count);
818 #define MONO_PROFILER_EVENT_0(name, type) \
819 _MONO_PROFILER_EVENT(name, type)
820 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
821 _MONO_PROFILER_EVENT(name, type)
822 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
823 _MONO_PROFILER_EVENT(name, type)
824 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
825 _MONO_PROFILER_EVENT(name, type)
826 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
827 _MONO_PROFILER_EVENT(name, type)
828 #define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \
829 _MONO_PROFILER_EVENT(name, type)
830 #include <mono/metadata/profiler-events.h>
831 #undef MONO_PROFILER_EVENT_0
832 #undef MONO_PROFILER_EVENT_1
833 #undef MONO_PROFILER_EVENT_2
834 #undef MONO_PROFILER_EVENT_3
835 #undef MONO_PROFILER_EVENT_4
836 #undef MONO_PROFILER_EVENT_5
837 #undef _MONO_PROFILER_EVENT
839 MonoProfilerHandle head = mono_profiler_state.profilers;
841 while (head) {
842 MonoProfilerCleanupCallback cb = (MonoProfilerCleanupCallback)head->cleanup_callback;
844 if (cb)
845 cb (head->prof);
847 MonoProfilerHandle cur = head;
848 head = head->next;
850 g_free (cur);
853 if (mono_profiler_state.code_coverage) {
854 mono_os_mutex_destroy (&mono_profiler_state.coverage_mutex);
856 GHashTableIter iter;
858 g_hash_table_iter_init (&iter, mono_profiler_state.coverage_hash);
860 MonoProfilerCoverageInfo *info;
862 while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &info))
863 g_free (info);
865 g_hash_table_destroy (mono_profiler_state.coverage_hash);
868 if (mono_profiler_state.sampling_owner)
869 mono_os_sem_destroy (&mono_profiler_state.sampling_semaphore);
872 static void
873 update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *counter)
875 gpointer old;
877 do {
878 old = mono_atomic_load_ptr (location);
879 } while (mono_atomic_cas_ptr (location, new_, old) != old);
882 * At this point, we could have installed a NULL callback while the counter
883 * is still non-zero, i.e. setting the callback and modifying the counter
884 * is not a single atomic operation. This is fine as we make sure callbacks
885 * are non-NULL before invoking them (see the code below that generates the
886 * raise functions), and besides, updating callbacks at runtime is an
887 * inherently racy operation.
890 if (old)
891 mono_atomic_dec_i32 (counter);
893 if (new_)
894 mono_atomic_inc_i32 (counter);
897 #define _MONO_PROFILER_EVENT(name, type) \
898 void \
899 mono_profiler_set_ ## name ## _callback (MonoProfilerHandle handle, MonoProfiler ## type ## Callback cb) \
901 update_callback (&handle->name ## _cb, (gpointer) cb, &mono_profiler_state.name ## _count); \
903 #define MONO_PROFILER_EVENT_0(name, type) \
904 _MONO_PROFILER_EVENT(name, type)
905 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
906 _MONO_PROFILER_EVENT(name, type)
907 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
908 _MONO_PROFILER_EVENT(name, type)
909 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
910 _MONO_PROFILER_EVENT(name, type)
911 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
912 _MONO_PROFILER_EVENT(name, type)
913 #define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \
914 _MONO_PROFILER_EVENT(name, type)
915 #include <mono/metadata/profiler-events.h>
916 #undef MONO_PROFILER_EVENT_0
917 #undef MONO_PROFILER_EVENT_1
918 #undef MONO_PROFILER_EVENT_2
919 #undef MONO_PROFILER_EVENT_3
920 #undef MONO_PROFILER_EVENT_4
921 #undef MONO_PROFILER_EVENT_5
922 #undef _MONO_PROFILER_EVENT
924 #define _MONO_PROFILER_EVENT(name, type, params, args) \
925 void \
926 mono_profiler_raise_ ## name params \
928 if (!mono_profiler_state.startup_done) return; \
929 for (MonoProfilerHandle h = mono_profiler_state.profilers; h; h = h->next) { \
930 MonoProfiler ## type ## Callback cb = (MonoProfiler ## type ## Callback)h->name ## _cb; \
931 if (cb) \
932 cb args; \
935 #define MONO_PROFILER_EVENT_0(name, type) \
936 _MONO_PROFILER_EVENT(name, type, (void), (h->prof))
937 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
938 _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name), (h->prof, arg1_name))
939 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
940 _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name), (h->prof, arg1_name, arg2_name))
941 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
942 _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))
943 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
944 _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))
945 #define MONO_PROFILER_EVENT_5(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name, arg5_type, arg5_name) \
946 _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name, arg5_type arg5_name), (h->prof, arg1_name, arg2_name, arg3_name, arg4_name, arg5_name))
947 #include <mono/metadata/profiler-events.h>
948 #undef MONO_PROFILER_EVENT_0
949 #undef MONO_PROFILER_EVENT_1
950 #undef MONO_PROFILER_EVENT_2
951 #undef MONO_PROFILER_EVENT_3
952 #undef MONO_PROFILER_EVENT_4
953 #undef MONO_PROFILER_EVENT_5
954 #undef _MONO_PROFILER_EVENT
957 struct _MonoProfiler {
958 MonoProfilerHandle handle;
959 MonoLegacyProfiler *profiler;
960 MonoLegacyProfileFunc shutdown_callback;
961 MonoLegacyProfileThreadFunc thread_start, thread_end;
962 MonoLegacyProfileGCFunc gc_event;
963 MonoLegacyProfileGCResizeFunc gc_heap_resize;
964 MonoLegacyProfileJitResult jit_end2;
965 MonoLegacyProfileAllocFunc allocation;
966 MonoLegacyProfileMethodFunc enter;
967 MonoLegacyProfileMethodFunc leave;
968 MonoLegacyProfileExceptionFunc throw_callback;
969 MonoLegacyProfileMethodFunc exc_method_leave;
970 MonoLegacyProfileExceptionClauseFunc clause_callback;
973 static MonoProfiler *current;
975 static void
976 shutdown_cb (MonoProfiler *prof)
978 prof->shutdown_callback (prof->profiler);
981 void
982 mono_profiler_install (MonoLegacyProfiler *prof, MonoLegacyProfileFunc callback)
984 current = g_new0 (MonoProfiler, 1);
985 current->handle = mono_profiler_create (current);
986 current->profiler = prof;
987 current->shutdown_callback = callback;
989 if (callback)
990 mono_profiler_set_runtime_shutdown_end_callback (current->handle, shutdown_cb);
993 static void
994 thread_start_cb (MonoProfiler *prof, uintptr_t tid)
996 prof->thread_start (prof->profiler, tid);
999 static void
1000 thread_stop_cb (MonoProfiler *prof, uintptr_t tid)
1002 prof->thread_end (prof->profiler, tid);
1005 void
1006 mono_profiler_install_thread (MonoLegacyProfileThreadFunc start, MonoLegacyProfileThreadFunc end)
1008 current->thread_start = start;
1009 current->thread_end = end;
1011 if (start)
1012 mono_profiler_set_thread_started_callback (current->handle, thread_start_cb);
1014 if (end)
1015 mono_profiler_set_thread_stopped_callback (current->handle, thread_stop_cb);
1018 static void
1019 gc_event_cb (MonoProfiler *prof, MonoProfilerGCEvent event, uint32_t generation, gboolean is_serial)
1021 prof->gc_event (prof->profiler, event, generation);
1024 static void
1025 gc_resize_cb (MonoProfiler *prof, uintptr_t size)
1027 prof->gc_heap_resize (prof->profiler, size);
1030 void
1031 mono_profiler_install_gc (MonoLegacyProfileGCFunc callback, MonoLegacyProfileGCResizeFunc heap_resize_callback)
1033 current->gc_event = callback;
1034 current->gc_heap_resize = heap_resize_callback;
1036 if (callback)
1037 mono_profiler_set_gc_event_callback (current->handle, gc_event_cb);
1039 if (heap_resize_callback)
1040 mono_profiler_set_gc_resize_callback (current->handle, gc_resize_cb);
1043 static void
1044 jit_done_cb (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo)
1046 prof->jit_end2 (prof->profiler, method, jinfo, 0);
1049 static void
1050 jit_failed_cb (MonoProfiler *prof, MonoMethod *method)
1052 prof->jit_end2 (prof->profiler, method, NULL, 1);
1055 void
1056 mono_profiler_install_jit_end (MonoLegacyProfileJitResult end)
1058 current->jit_end2 = end;
1060 if (end) {
1061 mono_profiler_set_jit_done_callback (current->handle, jit_done_cb);
1062 mono_profiler_set_jit_failed_callback (current->handle, jit_failed_cb);
1066 void
1067 mono_profiler_set_events (int flags)
1069 /* Do nothing. */
1072 static void
1073 allocation_cb (MonoProfiler *prof, MonoObject* object)
1075 prof->allocation (prof->profiler, object, object->vtable->klass);
1078 void
1079 mono_profiler_install_allocation (MonoLegacyProfileAllocFunc callback)
1081 current->allocation = callback;
1083 if (callback)
1084 mono_profiler_set_gc_allocation_callback (current->handle, allocation_cb);
1087 static void
1088 enter_cb (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *context)
1090 prof->enter (prof->profiler, method);
1093 static void
1094 leave_cb (MonoProfiler *prof, MonoMethod *method, MonoProfilerCallContext *context)
1096 prof->leave (prof->profiler, method);
1099 static void
1100 tail_call_cb (MonoProfiler *prof, MonoMethod *method, MonoMethod *target)
1102 prof->leave (prof->profiler, method);
1105 void
1106 mono_profiler_install_enter_leave (MonoLegacyProfileMethodFunc enter, MonoLegacyProfileMethodFunc fleave)
1108 current->enter = enter;
1109 current->leave = fleave;
1111 if (enter)
1112 mono_profiler_set_method_enter_callback (current->handle, enter_cb);
1114 if (fleave) {
1115 mono_profiler_set_method_leave_callback (current->handle, leave_cb);
1116 mono_profiler_set_method_tail_call_callback (current->handle, tail_call_cb);
1120 static void
1121 throw_callback_cb (MonoProfiler *prof, MonoObject *exception)
1123 prof->throw_callback (prof->profiler, exception);
1126 static void
1127 exc_method_leave_cb (MonoProfiler *prof, MonoMethod *method, MonoObject *exception)
1129 prof->exc_method_leave (prof->profiler, method);
1132 static void
1133 clause_callback_cb (MonoProfiler *prof, MonoMethod *method, uint32_t index, MonoExceptionEnum type, MonoObject *exception)
1135 prof->clause_callback (prof->profiler, method, type, index);
1138 void
1139 mono_profiler_install_exception (MonoLegacyProfileExceptionFunc throw_callback, MonoLegacyProfileMethodFunc exc_method_leave, MonoLegacyProfileExceptionClauseFunc clause_callback)
1141 current->throw_callback = throw_callback;
1142 current->exc_method_leave = exc_method_leave;
1143 current->clause_callback = clause_callback;
1145 if (throw_callback)
1146 mono_profiler_set_exception_throw_callback (current->handle, throw_callback_cb);
1148 if (exc_method_leave)
1149 mono_profiler_set_method_exception_leave_callback (current->handle, exc_method_leave_cb);
1151 if (clause_callback)
1152 mono_profiler_set_exception_clause_callback (current->handle, clause_callback_cb);