2 * profiler.c: Profiler interface for Mono
5 * Paolo Molaro (lupus@ximian.com)
7 * Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
8 * Copyright 2004-2009 Novell, Inc (http://www.novell.com)
9 * Copyright 2011 Xamarin Inc (http://www.xamarin.com).
13 #include "mono/metadata/profiler-private.h"
14 #include "mono/metadata/assembly.h"
15 #include "mono/metadata/debug-helpers.h"
16 #include "mono/metadata/mono-debug.h"
17 #include "mono/metadata/debug-mono-symfile.h"
18 #include "mono/metadata/metadata-internals.h"
19 #include "mono/metadata/class-internals.h"
20 #include "mono/metadata/domain-internals.h"
21 #include "mono/metadata/gc-internal.h"
22 #include "mono/metadata/mono-config-dirs.h"
23 #include "mono/io-layer/io-layer.h"
24 #include "mono/utils/mono-dl.h"
29 #ifdef HAVE_SYS_TIME_H
32 #ifdef HAVE_BACKTRACE_SYMBOLS
36 typedef struct _ProfilerDesc ProfilerDesc;
37 struct _ProfilerDesc {
39 MonoProfiler *profiler;
40 MonoProfileFlags events;
42 MonoProfileAppDomainFunc domain_start_load;
43 MonoProfileAppDomainResult domain_end_load;
44 MonoProfileAppDomainFunc domain_start_unload;
45 MonoProfileAppDomainFunc domain_end_unload;
47 MonoProfileAssemblyFunc assembly_start_load;
48 MonoProfileAssemblyResult assembly_end_load;
49 MonoProfileAssemblyFunc assembly_start_unload;
50 MonoProfileAssemblyFunc assembly_end_unload;
52 MonoProfileModuleFunc module_start_load;
53 MonoProfileModuleResult module_end_load;
54 MonoProfileModuleFunc module_start_unload;
55 MonoProfileModuleFunc module_end_unload;
57 MonoProfileClassFunc class_start_load;
58 MonoProfileClassResult class_end_load;
59 MonoProfileClassFunc class_start_unload;
60 MonoProfileClassFunc class_end_unload;
62 MonoProfileMethodFunc jit_start;
63 MonoProfileMethodResult jit_end;
64 MonoProfileJitResult jit_end2;
65 MonoProfileMethodFunc method_free;
66 MonoProfileMethodFunc method_start_invoke;
67 MonoProfileMethodFunc method_end_invoke;
68 MonoProfileMethodResult man_unman_transition;
69 MonoProfileAllocFunc allocation_cb;
70 MonoProfileMonitorFunc monitor_event_cb;
71 MonoProfileStatFunc statistical_cb;
72 MonoProfileStatCallChainFunc statistical_call_chain_cb;
73 int statistical_call_chain_depth;
74 MonoProfilerCallChainStrategy statistical_call_chain_strategy;
75 MonoProfileMethodFunc method_enter;
76 MonoProfileMethodFunc method_leave;
78 MonoProfileExceptionFunc exception_throw_cb;
79 MonoProfileMethodFunc exception_method_leave_cb;
80 MonoProfileExceptionClauseFunc exception_clause_cb;
82 MonoProfileIomapFunc iomap_cb;
84 MonoProfileThreadFunc thread_start;
85 MonoProfileThreadFunc thread_end;
86 MonoProfileThreadNameFunc thread_name;
88 MonoProfileCoverageFilterFunc coverage_filter_cb;
90 MonoProfileFunc shutdown_callback;
92 MonoProfileGCFunc gc_event;
93 MonoProfileGCResizeFunc gc_heap_resize;
94 MonoProfileGCMoveFunc gc_moves;
95 MonoProfileGCHandleFunc gc_handle;
96 MonoProfileGCRootFunc gc_roots;
98 MonoProfileFunc runtime_initialized_event;
100 MonoProfilerCodeChunkNew code_chunk_new;
101 MonoProfilerCodeChunkDestroy code_chunk_destroy;
102 MonoProfilerCodeBufferNew code_buffer_new;
105 static ProfilerDesc *prof_list = NULL;
107 #define mono_profiler_coverage_lock() mono_mutex_lock (&profiler_coverage_mutex)
108 #define mono_profiler_coverage_unlock() mono_mutex_unlock (&profiler_coverage_mutex)
109 static mono_mutex_t profiler_coverage_mutex;
111 /* this is directly accessible to other mono libs.
112 * It is the ORed value of all the profiler's events.
114 MonoProfileFlags mono_profiler_events;
117 * mono_profiler_install:
118 * @prof: a MonoProfiler structure pointer, or a pointer to a derived structure.
119 * @callback: the function to invoke at shutdown
121 * Use mono_profiler_install to activate profiling in the Mono runtime.
122 * Typically developers of new profilers will create a new structure whose
123 * first field is a MonoProfiler and put any extra information that they need
124 * to access from the various profiling callbacks there.
128 mono_profiler_install (MonoProfiler *prof, MonoProfileFunc callback)
130 ProfilerDesc *desc = g_new0 (ProfilerDesc, 1);
132 mono_mutex_init_recursive (&profiler_coverage_mutex);
133 desc->profiler = prof;
134 desc->shutdown_callback = callback;
135 desc->next = prof_list;
140 * mono_profiler_set_events:
141 * @events: an ORed set of values made up of MONO_PROFILER_ flags
143 * The events descriped in the @events argument is a set of flags
144 * that represent which profiling events must be triggered. For
145 * example if you have registered a set of methods for tracking
146 * JIT compilation start and end with mono_profiler_install_jit_compile,
147 * you will want to pass the MONO_PROFILE_JIT_COMPILATION flag to
150 * You can call mono_profile_set_events more than once and you can
151 * do this at runtime to modify which methods are invoked.
154 mono_profiler_set_events (MonoProfileFlags events)
157 MonoProfileFlags value = 0;
159 prof_list->events = events;
160 for (prof = prof_list; prof; prof = prof->next)
161 value |= prof->events;
162 mono_profiler_events = value;
166 * mono_profiler_get_events:
168 * Returns a list of active events that will be intercepted.
171 mono_profiler_get_events (void)
173 return mono_profiler_events;
177 * mono_profiler_install_enter_leave:
178 * @enter: the routine to be called on each method entry
179 * @fleave: the routine to be called each time a method returns
181 * Use this routine to install routines that will be called everytime
182 * a method enters and leaves. The routines will receive as an argument
183 * the MonoMethod representing the method that is entering or leaving.
186 mono_profiler_install_enter_leave (MonoProfileMethodFunc enter, MonoProfileMethodFunc fleave)
190 prof_list->method_enter = enter;
191 prof_list->method_leave = fleave;
195 * mono_profiler_install_jit_compile:
196 * @start: the routine to be called when the JIT process starts.
197 * @end: the routine to be called when the JIT process ends.
199 * Use this routine to install routines that will be called when JIT
200 * compilation of a method starts and completes.
203 mono_profiler_install_jit_compile (MonoProfileMethodFunc start, MonoProfileMethodResult end)
207 prof_list->jit_start = start;
208 prof_list->jit_end = end;
212 mono_profiler_install_jit_end (MonoProfileJitResult end)
216 prof_list->jit_end2 = end;
220 mono_profiler_install_method_free (MonoProfileMethodFunc callback)
224 prof_list->method_free = callback;
228 mono_profiler_install_method_invoke (MonoProfileMethodFunc start, MonoProfileMethodFunc end)
232 prof_list->method_start_invoke = start;
233 prof_list->method_end_invoke = end;
237 mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc end)
241 prof_list->thread_start = start;
242 prof_list->thread_end = end;
246 mono_profiler_install_thread_name (MonoProfileThreadNameFunc thread_name_cb)
250 prof_list->thread_name = thread_name_cb;
254 mono_profiler_install_transition (MonoProfileMethodResult callback)
258 prof_list->man_unman_transition = callback;
262 mono_profiler_install_allocation (MonoProfileAllocFunc callback)
266 prof_list->allocation_cb = callback;
270 mono_profiler_install_monitor (MonoProfileMonitorFunc callback)
274 prof_list->monitor_event_cb = callback;
277 static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
278 static int64_t sampling_frequency = 1000; //1ms
281 * mono_profiler_set_statistical_mode:
282 * @mode the sampling mode used.
283 * @sample_frequency_is_us the sampling frequency in microseconds.
285 * Set the sampling parameters for the profiler. Sampling mode affects the effective sampling rate as in samples/s you'll witness.
286 * The default sampling mode is process mode, which only reports samples when there's activity in the process.
288 * Sampling frequency should be interpreted as a suggestion that can't always be honored due to how most kernels expose alarms.
290 * Said that, when using statistical sampling, always assume variable rate sampling as all sort of external factors can interfere.
293 mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_is_us)
295 sampling_mode = mode;
296 sampling_frequency = sampling_frequency_is_us;
300 mono_profiler_install_statistical (MonoProfileStatFunc callback)
304 prof_list->statistical_cb = callback;
308 mono_profiler_get_sampling_rate (void)
310 return sampling_frequency;
313 MonoProfileSamplingMode
314 mono_profiler_get_sampling_mode (void)
316 return sampling_mode;
320 mono_profiler_install_statistical_call_chain (MonoProfileStatCallChainFunc callback, int call_chain_depth, MonoProfilerCallChainStrategy call_chain_strategy) {
323 if (call_chain_depth > MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH) {
324 call_chain_depth = MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH;
326 if ((call_chain_strategy >= MONO_PROFILER_CALL_CHAIN_INVALID) || (call_chain_strategy < MONO_PROFILER_CALL_CHAIN_NONE)) {
327 call_chain_strategy = MONO_PROFILER_CALL_CHAIN_NONE;
329 prof_list->statistical_call_chain_cb = callback;
330 prof_list->statistical_call_chain_depth = call_chain_depth;
331 prof_list->statistical_call_chain_strategy = call_chain_strategy;
335 mono_profiler_stat_get_call_chain_depth (void) {
336 if (prof_list && prof_list->statistical_call_chain_cb != NULL) {
337 return prof_list->statistical_call_chain_depth;
343 MonoProfilerCallChainStrategy
344 mono_profiler_stat_get_call_chain_strategy (void) {
345 if (prof_list && prof_list->statistical_call_chain_cb != NULL) {
346 return prof_list->statistical_call_chain_strategy;
348 return MONO_PROFILER_CALL_CHAIN_NONE;
352 void mono_profiler_install_exception (MonoProfileExceptionFunc throw_callback, MonoProfileMethodFunc exc_method_leave, MonoProfileExceptionClauseFunc clause_callback)
356 prof_list->exception_throw_cb = throw_callback;
357 prof_list->exception_method_leave_cb = exc_method_leave;
358 prof_list->exception_clause_cb = clause_callback;
362 mono_profiler_install_coverage_filter (MonoProfileCoverageFilterFunc callback)
366 prof_list->coverage_filter_cb = callback;
370 mono_profiler_install_appdomain (MonoProfileAppDomainFunc start_load, MonoProfileAppDomainResult end_load,
371 MonoProfileAppDomainFunc start_unload, MonoProfileAppDomainFunc end_unload)
376 prof_list->domain_start_load = start_load;
377 prof_list->domain_end_load = end_load;
378 prof_list->domain_start_unload = start_unload;
379 prof_list->domain_end_unload = end_unload;
383 mono_profiler_install_assembly (MonoProfileAssemblyFunc start_load, MonoProfileAssemblyResult end_load,
384 MonoProfileAssemblyFunc start_unload, MonoProfileAssemblyFunc end_unload)
388 prof_list->assembly_start_load = start_load;
389 prof_list->assembly_end_load = end_load;
390 prof_list->assembly_start_unload = start_unload;
391 prof_list->assembly_end_unload = end_unload;
395 mono_profiler_install_module (MonoProfileModuleFunc start_load, MonoProfileModuleResult end_load,
396 MonoProfileModuleFunc start_unload, MonoProfileModuleFunc end_unload)
400 prof_list->module_start_load = start_load;
401 prof_list->module_end_load = end_load;
402 prof_list->module_start_unload = start_unload;
403 prof_list->module_end_unload = end_unload;
407 mono_profiler_install_class (MonoProfileClassFunc start_load, MonoProfileClassResult end_load,
408 MonoProfileClassFunc start_unload, MonoProfileClassFunc end_unload)
412 prof_list->class_start_load = start_load;
413 prof_list->class_end_load = end_load;
414 prof_list->class_start_unload = start_unload;
415 prof_list->class_end_unload = end_unload;
419 mono_profiler_method_enter (MonoMethod *method)
422 for (prof = prof_list; prof; prof = prof->next) {
423 if ((prof->events & MONO_PROFILE_ENTER_LEAVE) && prof->method_enter)
424 prof->method_enter (prof->profiler, method);
429 mono_profiler_method_leave (MonoMethod *method)
432 for (prof = prof_list; prof; prof = prof->next) {
433 if ((prof->events & MONO_PROFILE_ENTER_LEAVE) && prof->method_leave)
434 prof->method_leave (prof->profiler, method);
439 mono_profiler_method_jit (MonoMethod *method)
442 for (prof = prof_list; prof; prof = prof->next) {
443 if ((prof->events & MONO_PROFILE_JIT_COMPILATION) && prof->jit_start)
444 prof->jit_start (prof->profiler, method);
449 mono_profiler_method_end_jit (MonoMethod *method, MonoJitInfo* jinfo, int result)
452 for (prof = prof_list; prof; prof = prof->next) {
453 if ((prof->events & MONO_PROFILE_JIT_COMPILATION)) {
455 prof->jit_end (prof->profiler, method, result);
457 prof->jit_end2 (prof->profiler, method, jinfo, result);
463 mono_profiler_method_free (MonoMethod *method)
466 for (prof = prof_list; prof; prof = prof->next) {
467 if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_free)
468 prof->method_free (prof->profiler, method);
473 mono_profiler_method_start_invoke (MonoMethod *method)
476 for (prof = prof_list; prof; prof = prof->next) {
477 if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_start_invoke)
478 prof->method_start_invoke (prof->profiler, method);
483 mono_profiler_method_end_invoke (MonoMethod *method)
486 for (prof = prof_list; prof; prof = prof->next) {
487 if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_end_invoke)
488 prof->method_end_invoke (prof->profiler, method);
493 mono_profiler_code_transition (MonoMethod *method, int result)
496 for (prof = prof_list; prof; prof = prof->next) {
497 if ((prof->events & MONO_PROFILE_TRANSITIONS) && prof->man_unman_transition)
498 prof->man_unman_transition (prof->profiler, method, result);
503 mono_profiler_allocation (MonoObject *obj, MonoClass *klass)
506 for (prof = prof_list; prof; prof = prof->next) {
507 if ((prof->events & MONO_PROFILE_ALLOCATIONS) && prof->allocation_cb)
508 prof->allocation_cb (prof->profiler, obj, klass);
513 mono_profiler_monitor_event (MonoObject *obj, MonoProfilerMonitorEvent event) {
515 for (prof = prof_list; prof; prof = prof->next) {
516 if ((prof->events & MONO_PROFILE_MONITOR_EVENTS) && prof->monitor_event_cb)
517 prof->monitor_event_cb (prof->profiler, obj, event);
522 mono_profiler_stat_hit (guchar *ip, void *context)
525 for (prof = prof_list; prof; prof = prof->next) {
526 if ((prof->events & MONO_PROFILE_STATISTICAL) && prof->statistical_cb)
527 prof->statistical_cb (prof->profiler, ip, context);
532 mono_profiler_stat_call_chain (int call_chain_depth, guchar **ips, void *context)
535 for (prof = prof_list; prof; prof = prof->next) {
536 if ((prof->events & MONO_PROFILE_STATISTICAL) && prof->statistical_call_chain_cb)
537 prof->statistical_call_chain_cb (prof->profiler, call_chain_depth, ips, context);
542 mono_profiler_exception_thrown (MonoObject *exception)
545 for (prof = prof_list; prof; prof = prof->next) {
546 if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_throw_cb)
547 prof->exception_throw_cb (prof->profiler, exception);
552 mono_profiler_exception_method_leave (MonoMethod *method)
555 for (prof = prof_list; prof; prof = prof->next) {
556 if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_method_leave_cb)
557 prof->exception_method_leave_cb (prof->profiler, method);
562 mono_profiler_exception_clause_handler (MonoMethod *method, int clause_type, int clause_num)
565 for (prof = prof_list; prof; prof = prof->next) {
566 if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_clause_cb)
567 prof->exception_clause_cb (prof->profiler, method, clause_type, clause_num);
572 mono_profiler_thread_start (gsize tid)
575 for (prof = prof_list; prof; prof = prof->next) {
576 if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_start)
577 prof->thread_start (prof->profiler, tid);
582 mono_profiler_thread_end (gsize tid)
585 for (prof = prof_list; prof; prof = prof->next) {
586 if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_end)
587 prof->thread_end (prof->profiler, tid);
592 mono_profiler_thread_name (gsize tid, const char *name)
595 for (prof = prof_list; prof; prof = prof->next) {
596 if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_name)
597 prof->thread_name (prof->profiler, tid, name);
602 mono_profiler_assembly_event (MonoAssembly *assembly, int code)
605 for (prof = prof_list; prof; prof = prof->next) {
606 if (!(prof->events & MONO_PROFILE_ASSEMBLY_EVENTS))
610 case MONO_PROFILE_START_LOAD:
611 if (prof->assembly_start_load)
612 prof->assembly_start_load (prof->profiler, assembly);
614 case MONO_PROFILE_START_UNLOAD:
615 if (prof->assembly_start_unload)
616 prof->assembly_start_unload (prof->profiler, assembly);
618 case MONO_PROFILE_END_UNLOAD:
619 if (prof->assembly_end_unload)
620 prof->assembly_end_unload (prof->profiler, assembly);
623 g_assert_not_reached ();
629 mono_profiler_assembly_loaded (MonoAssembly *assembly, int result)
632 for (prof = prof_list; prof; prof = prof->next) {
633 if ((prof->events & MONO_PROFILE_ASSEMBLY_EVENTS) && prof->assembly_end_load)
634 prof->assembly_end_load (prof->profiler, assembly, result);
638 void mono_profiler_iomap (char *report, const char *pathname, const char *new_pathname)
641 for (prof = prof_list; prof; prof = prof->next) {
642 if ((prof->events & MONO_PROFILE_IOMAP_EVENTS) && prof->iomap_cb)
643 prof->iomap_cb (prof->profiler, report, pathname, new_pathname);
648 mono_profiler_module_event (MonoImage *module, int code)
651 for (prof = prof_list; prof; prof = prof->next) {
652 if (!(prof->events & MONO_PROFILE_MODULE_EVENTS))
656 case MONO_PROFILE_START_LOAD:
657 if (prof->module_start_load)
658 prof->module_start_load (prof->profiler, module);
660 case MONO_PROFILE_START_UNLOAD:
661 if (prof->module_start_unload)
662 prof->module_start_unload (prof->profiler, module);
664 case MONO_PROFILE_END_UNLOAD:
665 if (prof->module_end_unload)
666 prof->module_end_unload (prof->profiler, module);
669 g_assert_not_reached ();
675 mono_profiler_module_loaded (MonoImage *module, int result)
678 for (prof = prof_list; prof; prof = prof->next) {
679 if ((prof->events & MONO_PROFILE_MODULE_EVENTS) && prof->module_end_load)
680 prof->module_end_load (prof->profiler, module, result);
685 mono_profiler_class_event (MonoClass *klass, int code)
688 for (prof = prof_list; prof; prof = prof->next) {
689 if (!(prof->events & MONO_PROFILE_CLASS_EVENTS))
693 case MONO_PROFILE_START_LOAD:
694 if (prof->class_start_load)
695 prof->class_start_load (prof->profiler, klass);
697 case MONO_PROFILE_START_UNLOAD:
698 if (prof->class_start_unload)
699 prof->class_start_unload (prof->profiler, klass);
701 case MONO_PROFILE_END_UNLOAD:
702 if (prof->class_end_unload)
703 prof->class_end_unload (prof->profiler, klass);
706 g_assert_not_reached ();
712 mono_profiler_class_loaded (MonoClass *klass, int result)
715 for (prof = prof_list; prof; prof = prof->next) {
716 if ((prof->events & MONO_PROFILE_CLASS_EVENTS) && prof->class_end_load)
717 prof->class_end_load (prof->profiler, klass, result);
722 mono_profiler_appdomain_event (MonoDomain *domain, int code)
725 for (prof = prof_list; prof; prof = prof->next) {
726 if (!(prof->events & MONO_PROFILE_APPDOMAIN_EVENTS))
730 case MONO_PROFILE_START_LOAD:
731 if (prof->domain_start_load)
732 prof->domain_start_load (prof->profiler, domain);
734 case MONO_PROFILE_START_UNLOAD:
735 if (prof->domain_start_unload)
736 prof->domain_start_unload (prof->profiler, domain);
738 case MONO_PROFILE_END_UNLOAD:
739 if (prof->domain_end_unload)
740 prof->domain_end_unload (prof->profiler, domain);
743 g_assert_not_reached ();
749 mono_profiler_appdomain_loaded (MonoDomain *domain, int result)
752 for (prof = prof_list; prof; prof = prof->next) {
753 if ((prof->events & MONO_PROFILE_APPDOMAIN_EVENTS) && prof->domain_end_load)
754 prof->domain_end_load (prof->profiler, domain, result);
759 mono_profiler_shutdown (void)
762 for (prof = prof_list; prof; prof = prof->next) {
763 if (prof->shutdown_callback)
764 prof->shutdown_callback (prof->profiler);
767 mono_profiler_set_events (0);
771 mono_profiler_gc_heap_resize (gint64 new_size)
774 for (prof = prof_list; prof; prof = prof->next) {
775 if ((prof->events & MONO_PROFILE_GC) && prof->gc_heap_resize)
776 prof->gc_heap_resize (prof->profiler, new_size);
781 mono_profiler_gc_event (MonoGCEvent event, int generation)
784 for (prof = prof_list; prof; prof = prof->next) {
785 if ((prof->events & MONO_PROFILE_GC) && prof->gc_event)
786 prof->gc_event (prof->profiler, event, generation);
791 mono_profiler_gc_moves (void **objects, int num)
794 for (prof = prof_list; prof; prof = prof->next) {
795 if ((prof->events & MONO_PROFILE_GC_MOVES) && prof->gc_moves)
796 prof->gc_moves (prof->profiler, objects, num);
801 mono_profiler_gc_handle (int op, int type, uintptr_t handle, MonoObject *obj)
804 for (prof = prof_list; prof; prof = prof->next) {
805 if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_handle)
806 prof->gc_handle (prof->profiler, op, type, handle, obj);
811 mono_profiler_gc_roots (int num, void **objects, int *root_types, uintptr_t *extra_info)
814 for (prof = prof_list; prof; prof = prof->next) {
815 if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_roots)
816 prof->gc_roots (prof->profiler, num, objects, root_types, extra_info);
821 mono_profiler_install_gc (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback)
823 mono_gc_enable_events ();
826 prof_list->gc_event = callback;
827 prof_list->gc_heap_resize = heap_resize_callback;
831 * mono_profiler_install_gc_moves:
832 * @callback: callback function
834 * Install the @callback function that the GC will call when moving objects.
835 * The callback receives an array of pointers and the number of elements
836 * in the array. Every even element in the array is the original object location
837 * and the following odd element is the new location of the object in memory.
838 * So the number of elements argument will always be a multiple of 2.
839 * Since this callback happens during the GC, it is a restricted environment:
840 * no locks can be taken and the object pointers can be inspected only once
841 * the GC is finished (of course the original location pointers will not
842 * point to valid objects anymore).
845 mono_profiler_install_gc_moves (MonoProfileGCMoveFunc callback)
849 prof_list->gc_moves = callback;
853 * mono_profiler_install_gc_roots:
854 * @handle_callback: callback function
855 * @roots_callback: callback function
857 * Install the @handle_callback function that the GC will call when GC
858 * handles are created or destroyed.
859 * The callback receives an operation, which is either #MONO_PROFILER_GC_HANDLE_CREATED
860 * or #MONO_PROFILER_GC_HANDLE_DESTROYED, the handle type, the handle value and the
861 * object pointer, if present.
862 * Install the @roots_callback function that the GC will call when tracing
863 * the roots for a collection.
864 * The callback receives the number of elements and three arrays: an array
865 * of objects, an array of root types and flags and an array of extra info.
866 * The size of each array is given by the first argument.
869 mono_profiler_install_gc_roots (MonoProfileGCHandleFunc handle_callback, MonoProfileGCRootFunc roots_callback)
873 prof_list->gc_handle = handle_callback;
874 prof_list->gc_roots = roots_callback;
878 mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback)
882 prof_list->runtime_initialized_event = runtime_initialized_callback;
886 mono_profiler_runtime_initialized (void) {
888 for (prof = prof_list; prof; prof = prof->next) {
889 if (prof->runtime_initialized_event)
890 prof->runtime_initialized_event (prof->profiler);
895 mono_profiler_install_code_chunk_new (MonoProfilerCodeChunkNew callback) {
898 prof_list->code_chunk_new = callback;
901 mono_profiler_code_chunk_new (gpointer chunk, int size) {
903 for (prof = prof_list; prof; prof = prof->next) {
904 if (prof->code_chunk_new)
905 prof->code_chunk_new (prof->profiler, chunk, size);
910 mono_profiler_install_code_chunk_destroy (MonoProfilerCodeChunkDestroy callback) {
913 prof_list->code_chunk_destroy = callback;
916 mono_profiler_code_chunk_destroy (gpointer chunk) {
918 for (prof = prof_list; prof; prof = prof->next) {
919 if (prof->code_chunk_destroy)
920 prof->code_chunk_destroy (prof->profiler, chunk);
925 mono_profiler_install_code_buffer_new (MonoProfilerCodeBufferNew callback) {
928 prof_list->code_buffer_new = callback;
932 mono_profiler_install_iomap (MonoProfileIomapFunc callback)
936 prof_list->iomap_cb = callback;
940 mono_profiler_code_buffer_new (gpointer buffer, int size, MonoProfilerCodeBufferType type, gconstpointer data) {
942 for (prof = prof_list; prof; prof = prof->next) {
943 if (prof->code_buffer_new)
944 prof->code_buffer_new (prof->profiler, buffer, size, type, (void*)data);
948 static GHashTable *coverage_hash = NULL;
950 MonoProfileCoverageInfo*
951 mono_profiler_coverage_alloc (MonoMethod *method, int entries)
953 MonoProfileCoverageInfo *res;
954 int instrument = FALSE;
957 for (prof = prof_list; prof; prof = prof->next) {
958 /* note that we call the filter on all the profilers even if just
959 * a single one would be enough to instrument a method
961 if (prof->coverage_filter_cb)
962 if (prof->coverage_filter_cb (prof->profiler, method))
968 mono_profiler_coverage_lock ();
970 coverage_hash = g_hash_table_new (NULL, NULL);
972 res = g_malloc0 (sizeof (MonoProfileCoverageInfo) + sizeof (void*) * 2 * entries);
974 res->entries = entries;
976 g_hash_table_insert (coverage_hash, method, res);
977 mono_profiler_coverage_unlock ();
982 /* safe only when the method antive code has been unloaded */
984 mono_profiler_coverage_free (MonoMethod *method)
986 MonoProfileCoverageInfo* info;
988 mono_profiler_coverage_lock ();
989 if (!coverage_hash) {
990 mono_profiler_coverage_unlock ();
994 info = g_hash_table_lookup (coverage_hash, method);
997 g_hash_table_remove (coverage_hash, method);
999 mono_profiler_coverage_unlock ();
1003 * mono_profiler_coverage_get:
1004 * @prof: The profiler handle, installed with mono_profiler_install
1005 * @method: the method to gather information from.
1006 * @func: A routine that will be called back with the results
1008 * If the MONO_PROFILER_INS_COVERAGE flag was active during JIT compilation
1009 * it is posisble to obtain coverage information about a give method.
1011 * The function @func will be invoked repeatedly with instances of the
1012 * MonoProfileCoverageEntry structure.
1015 mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileCoverageFunc func)
1017 MonoProfileCoverageInfo* info = NULL;
1020 const unsigned char *start, *end, *cil_code;
1021 MonoMethodHeader *header;
1022 MonoProfileCoverageEntry entry;
1023 MonoDebugMethodInfo *debug_minfo;
1025 mono_profiler_coverage_lock ();
1027 info = g_hash_table_lookup (coverage_hash, method);
1028 mono_profiler_coverage_unlock ();
1033 header = mono_method_get_header (method);
1034 start = mono_method_header_get_code (header, &code_size, NULL);
1035 debug_minfo = mono_debug_lookup_method (method);
1037 end = start + code_size;
1038 for (i = 0; i < info->entries; ++i) {
1039 cil_code = info->data [i].cil_code;
1040 if (cil_code && cil_code >= start && cil_code < end) {
1042 offset = cil_code - start;
1043 entry.iloffset = offset;
1044 entry.method = method;
1045 entry.counter = info->data [i].count;
1046 entry.line = entry.col = 1;
1047 entry.filename = NULL;
1049 MonoDebugSourceLocation *location;
1051 location = mono_debug_symfile_lookup_location (debug_minfo, offset);
1053 entry.line = location->row;
1054 entry.col = location->column;
1055 entry.filename = fname = g_strdup (location->source_file);
1056 mono_debug_free_source_location (location);
1060 func (prof, &entry);
1064 mono_metadata_free_mh (header);
1067 typedef void (*ProfilerInitializer) (const char*);
1068 #define INITIALIZER_NAME "mono_profiler_startup"
1072 load_profiler (MonoDl *pmodule, const char *desc, const char *symbol)
1075 ProfilerInitializer func;
1080 if ((err = mono_dl_symbol (pmodule, symbol, (gpointer *) &func))) {
1090 load_embedded_profiler (const char *desc, const char *name)
1094 MonoDl *pmodule = NULL;
1097 pmodule = mono_dl_open (NULL, MONO_DL_LAZY, &err);
1099 g_warning ("Could not open main executable (%s)", err);
1104 symbol = g_strdup_printf (INITIALIZER_NAME "_%s", name);
1105 result = load_profiler (pmodule, desc, symbol);
1112 load_profiler_from_directory (const char *directory, const char *libname, const char *desc)
1114 MonoDl *pmodule = NULL;
1121 while ((path = mono_dl_build_path (directory, libname, &iter))) {
1122 pmodule = mono_dl_open (path, MONO_DL_LAZY, &err);
1126 return load_profiler (pmodule, desc, INITIALIZER_NAME);
1133 load_profiler_from_mono_instalation (const char *libname, const char *desc)
1136 MonoDl *pmodule = mono_dl_open_runtime_lib (libname, MONO_DL_LAZY, &err);
1139 return load_profiler (pmodule, desc, INITIALIZER_NAME);
1144 * mono_profiler_load:
1145 * @desc: arguments to configure the profiler
1147 * Invoke this method to initialize the profiler. This will drive the
1148 * loading of the internal ("default") or any external profilers.
1150 * This routine is invoked by Mono's driver, but must be called manually
1151 * if you embed Mono into your application.
1154 mono_profiler_load (const char *desc)
1157 mono_gc_base_init ();
1159 if (!desc || (strcmp ("default", desc) == 0)) {
1160 desc = "log:report";
1162 /* we keep command-line compat with the old version here */
1163 if (strncmp (desc, "default:", 8) == 0) {
1164 gchar **args, **ptr;
1165 GString *str = g_string_new ("log:report");
1166 args = g_strsplit (desc + 8, ",", -1);
1167 for (ptr = args; ptr && *ptr; ptr++) {
1168 const char *arg = *ptr;
1170 if (!strcmp (arg, "time"))
1171 g_string_append (str, ",calls");
1172 else if (!strcmp (arg, "alloc"))
1173 g_string_append (str, ",alloc");
1174 else if (!strcmp (arg, "stat"))
1175 g_string_append (str, ",sample");
1176 else if (!strcmp (arg, "jit"))
1177 continue; /* accept and do nothing */
1178 else if (strncmp (arg, "file=", 5) == 0) {
1179 g_string_append_printf (str, ",output=%s", arg + 5);
1181 fprintf (stderr, "profiler : Unknown argument '%s'.\n", arg);
1185 desc = cdesc = g_string_free (str, FALSE);
1188 const char* col = strchr (desc, ':');
1191 gboolean res = FALSE;
1194 mname = g_memdup (desc, col - desc + 1);
1195 mname [col - desc] = 0;
1197 mname = g_strdup (desc);
1199 if (!load_embedded_profiler (desc, mname)) {
1200 libname = g_strdup_printf ("mono-profiler-%s", mname);
1201 if (mono_config_get_assemblies_dir ())
1202 res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc);
1204 res = load_profiler_from_directory (NULL, libname, desc);
1206 res = load_profiler_from_mono_instalation (libname, desc);
1208 g_warning ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);