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.
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"
27 load_profiler (MonoDl
*module
, const char *name
, const char *desc
)
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
);
43 char *new_name
= g_strdup_printf (NEW_INITIALIZER_NAME
"_%s", name
);
45 if ((err
= mono_dl_symbol (module
, new_name
, (gpointer
*) &func
))) {
59 load_profiler_from_executable (const char *name
, const char *desc
)
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
);
74 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_PROFILER
, "Could not open main executable: %s", err
);
79 return load_profiler (module
, name
, desc
);
83 load_profiler_from_directory (const char *directory
, const char *libname
, const char *name
, const char *desc
)
88 while ((path
= mono_dl_build_path (directory
, libname
, &iter
))) {
89 MonoDl
*module
= mono_dl_open (path
, MONO_DL_EAGER
, &err
);
92 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_PROFILER
, "Could not open from directory \"%s\": %s", path
, err
);
100 return load_profiler (module
, name
, desc
);
107 load_profiler_from_installation (const char *libname
, const char *name
, const char *desc
)
110 MonoDl
*module
= mono_dl_open_runtime_lib (libname
, MONO_DL_EAGER
, &err
);
113 mono_trace (G_LOG_LEVEL_DEBUG
, MONO_TRACE_PROFILER
, "Could not open from installation: %s", err
);
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:
133 * void mono_profiler_init_foo (const char *desc)
138 * This function is \b not async safe.
140 * This function may \b only be called by embedders prior to running managed
144 mono_profiler_load (const char *desc
)
147 char *mname
, *libname
;
149 mname
= libname
= NULL
;
151 if (!desc
|| !strcmp ("default", desc
))
154 if ((col
= strchr (desc
, ':')) != NULL
) {
155 mname
= (char *) g_memdup (desc
, col
- desc
+ 1);
156 mname
[col
- desc
] = 0;
158 mname
= g_strdup (desc
);
161 if (load_profiler_from_executable (mname
, desc
))
164 libname
= g_strdup_printf ("mono-profiler-%s", mname
);
166 if (load_profiler_from_installation (libname
, mname
, desc
))
169 if (mono_config_get_assemblies_dir () && load_profiler_from_directory (mono_assembly_getrootdir (), libname
, mname
, desc
))
172 if (load_profiler_from_directory (NULL
, libname
, mname
, desc
))
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
);
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.
193 * struct _MonoProfiler {
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);
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.
210 mono_profiler_create (MonoProfiler
*prof
)
212 MonoProfilerHandle handle
= g_new0 (struct _MonoProfilerDesc
, 1);
215 handle
->next
= mono_profiler_state
.profilers
;
217 mono_profiler_state
.profilers
= 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.
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.
253 mono_profiler_enable_coverage (void)
255 if (mono_profiler_state
.startup_done
)
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.
283 mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle
, MonoProfilerCoverageFilterCallback cb
)
285 mono_atomic_store_ptr (&handle
->coverage_filter
, (gpointer
) cb
);
291 mono_os_mutex_lock (&mono_profiler_state
.coverage_mutex
);
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.
314 mono_profiler_get_coverage_data (MonoProfilerHandle handle
, MonoMethod
*method
, MonoProfilerCoverageCallback cb
)
316 if (!mono_profiler_state
.code_coverage
)
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
))
324 MonoProfilerCoverageInfo
*info
= (MonoProfilerCoverageInfo
*)g_hash_table_lookup (mono_profiler_state
.coverage_hash
, method
);
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
);
340 GPtrArray
*source_file_list
;
341 MonoSymSeqPoint
*sym_seq_points
;
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
;
363 data
.file_name
= srcfile
;
364 data
.line
= sp
->line
;
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
);
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
;
392 MonoDebugSourceLocation
*loc
= mono_debug_method_lookup_location (minfo
, offset
);
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
);
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
;
421 cover
|= cb (handle
->prof
, method
);
427 MonoProfilerCoverageInfo
*
428 mono_profiler_coverage_alloc (MonoMethod
*method
, guint32 entries
)
430 if (!mono_profiler_state
.code_coverage
)
433 if (!mono_profiler_coverage_instrumentation_enabled (method
))
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
);
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.
469 mono_profiler_enable_sampling (MonoProfilerHandle handle
)
471 if (mono_profiler_state
.startup_done
)
474 if (mono_profiler_state
.sampling_owner
)
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);
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.
496 mono_profiler_set_sample_mode (MonoProfilerHandle handle
, MonoProfilerSampleMode mode
, uint32_t freq
)
498 if (handle
!= mono_profiler_state
.sampling_owner
)
501 mono_profiler_state
.sample_mode
= mode
;
502 mono_profiler_state
.sample_freq
= freq
;
504 mono_profiler_sampling_thread_post ();
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.
519 mono_profiler_get_sample_mode (MonoProfilerHandle handle
, MonoProfilerSampleMode
*mode
, uint32_t *freq
)
522 *mode
= mono_profiler_state
.sample_mode
;
525 *freq
= mono_profiler_state
.sample_freq
;
527 return handle
== mono_profiler_state
.sampling_owner
;
531 mono_profiler_sampling_enabled (void)
533 return !!mono_profiler_state
.sampling_owner
;
537 mono_profiler_sampling_thread_post (void)
539 mono_os_sem_post (&mono_profiler_state
.sampling_semaphore
);
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.
563 mono_profiler_enable_allocations (void)
565 if (mono_profiler_state
.startup_done
)
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.
586 mono_profiler_enable_clauses (void)
588 if (mono_profiler_state
.startup_done
)
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
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
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.
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.
641 mono_profiler_enable_call_context_introspection (void)
643 if (mono_profiler_state
.startup_done
)
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.
667 mono_profiler_call_context_get_this (MonoProfilerCallContext
*context
)
669 if (!mono_profiler_state
.call_contexts
)
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.
691 mono_profiler_call_context_get_argument (MonoProfilerCallContext
*context
, uint32_t position
)
693 if (!mono_profiler_state
.call_contexts
)
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.
715 mono_profiler_call_context_get_local (MonoProfilerCallContext
*context
, uint32_t position
)
717 if (!mono_profiler_state
.call_contexts
)
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.
741 mono_profiler_call_context_get_result (MonoProfilerCallContext
*context
)
743 if (!mono_profiler_state
.call_contexts
)
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
756 * This function is \b not async safe.
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
;
775 flags
|= cb (handle
->prof
, method
);
782 mono_profiler_started (void)
784 mono_profiler_state
.startup_done
= TRUE
;
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
;
842 MonoProfilerCleanupCallback cb
= (MonoProfilerCleanupCallback
)head
->cleanup_callback
;
847 MonoProfilerHandle cur
= head
;
853 if (mono_profiler_state
.code_coverage
) {
854 mono_os_mutex_destroy (&mono_profiler_state
.coverage_mutex
);
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
))
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
);
873 update_callback (volatile gpointer
*location
, gpointer new_
, volatile gint32
*counter
)
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.
891 mono_atomic_dec_i32 (counter
);
894 mono_atomic_inc_i32 (counter
);
897 #define _MONO_PROFILER_EVENT(name, type) \
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) \
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; \
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
;
976 shutdown_cb (MonoProfiler
*prof
)
978 prof
->shutdown_callback (prof
->profiler
);
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
;
990 mono_profiler_set_runtime_shutdown_end_callback (current
->handle
, shutdown_cb
);
994 thread_start_cb (MonoProfiler
*prof
, uintptr_t tid
)
996 prof
->thread_start (prof
->profiler
, tid
);
1000 thread_stop_cb (MonoProfiler
*prof
, uintptr_t tid
)
1002 prof
->thread_end (prof
->profiler
, tid
);
1006 mono_profiler_install_thread (MonoLegacyProfileThreadFunc start
, MonoLegacyProfileThreadFunc end
)
1008 current
->thread_start
= start
;
1009 current
->thread_end
= end
;
1012 mono_profiler_set_thread_started_callback (current
->handle
, thread_start_cb
);
1015 mono_profiler_set_thread_stopped_callback (current
->handle
, thread_stop_cb
);
1019 gc_event_cb (MonoProfiler
*prof
, MonoProfilerGCEvent event
, uint32_t generation
, gboolean is_serial
)
1021 prof
->gc_event (prof
->profiler
, event
, generation
);
1025 gc_resize_cb (MonoProfiler
*prof
, uintptr_t size
)
1027 prof
->gc_heap_resize (prof
->profiler
, size
);
1031 mono_profiler_install_gc (MonoLegacyProfileGCFunc callback
, MonoLegacyProfileGCResizeFunc heap_resize_callback
)
1033 current
->gc_event
= callback
;
1034 current
->gc_heap_resize
= heap_resize_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
);
1044 jit_done_cb (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*jinfo
)
1046 prof
->jit_end2 (prof
->profiler
, method
, jinfo
, 0);
1050 jit_failed_cb (MonoProfiler
*prof
, MonoMethod
*method
)
1052 prof
->jit_end2 (prof
->profiler
, method
, NULL
, 1);
1056 mono_profiler_install_jit_end (MonoLegacyProfileJitResult end
)
1058 current
->jit_end2
= 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
);
1067 mono_profiler_set_events (int flags
)
1073 allocation_cb (MonoProfiler
*prof
, MonoObject
* object
)
1075 prof
->allocation (prof
->profiler
, object
, object
->vtable
->klass
);
1079 mono_profiler_install_allocation (MonoLegacyProfileAllocFunc callback
)
1081 current
->allocation
= callback
;
1084 mono_profiler_set_gc_allocation_callback (current
->handle
, allocation_cb
);
1088 enter_cb (MonoProfiler
*prof
, MonoMethod
*method
, MonoProfilerCallContext
*context
)
1090 prof
->enter (prof
->profiler
, method
);
1094 leave_cb (MonoProfiler
*prof
, MonoMethod
*method
, MonoProfilerCallContext
*context
)
1096 prof
->leave (prof
->profiler
, method
);
1100 tail_call_cb (MonoProfiler
*prof
, MonoMethod
*method
, MonoMethod
*target
)
1102 prof
->leave (prof
->profiler
, method
);
1106 mono_profiler_install_enter_leave (MonoLegacyProfileMethodFunc enter
, MonoLegacyProfileMethodFunc fleave
)
1108 current
->enter
= enter
;
1109 current
->leave
= fleave
;
1112 mono_profiler_set_method_enter_callback (current
->handle
, enter_cb
);
1115 mono_profiler_set_method_leave_callback (current
->handle
, leave_cb
);
1116 mono_profiler_set_method_tail_call_callback (current
->handle
, tail_call_cb
);
1121 throw_callback_cb (MonoProfiler
*prof
, MonoObject
*exception
)
1123 prof
->throw_callback (prof
->profiler
, exception
);
1127 exc_method_leave_cb (MonoProfiler
*prof
, MonoMethod
*method
, MonoObject
*exception
)
1129 prof
->exc_method_leave (prof
->profiler
, method
);
1133 clause_callback_cb (MonoProfiler
*prof
, MonoMethod
*method
, uint32_t index
, MonoExceptionEnum type
, MonoObject
*exception
)
1135 prof
->clause_callback (prof
->profiler
, method
, type
, index
);
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
;
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
);