Merge pull request #1696 from esdrubal/tzrefactor
[mono.git] / mono / metadata / profiler.c
1 /*
2  * profiler.c: Profiler interface for Mono
3  *
4  * Author:
5  *   Paolo Molaro (lupus@ximian.com)
6  *
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).
10  */
11
12 #include "config.h"
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"
25 #include <string.h>
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29 #ifdef HAVE_SYS_TIME_H
30 #include <sys/time.h>
31 #endif
32 #ifdef HAVE_BACKTRACE_SYMBOLS
33 #include <execinfo.h>
34 #endif
35
36 typedef struct _ProfilerDesc ProfilerDesc;
37 struct _ProfilerDesc {
38         ProfilerDesc *next;
39         MonoProfiler *profiler;
40         MonoProfileFlags events;
41
42         MonoProfileAppDomainFunc   domain_start_load;
43         MonoProfileAppDomainResult domain_end_load;
44         MonoProfileAppDomainFunc   domain_start_unload;
45         MonoProfileAppDomainFunc   domain_end_unload;
46
47         MonoProfileAssemblyFunc   assembly_start_load;
48         MonoProfileAssemblyResult assembly_end_load;
49         MonoProfileAssemblyFunc   assembly_start_unload;
50         MonoProfileAssemblyFunc   assembly_end_unload;
51
52         MonoProfileModuleFunc   module_start_load;
53         MonoProfileModuleResult module_end_load;
54         MonoProfileModuleFunc   module_start_unload;
55         MonoProfileModuleFunc   module_end_unload;
56
57         MonoProfileClassFunc   class_start_load;
58         MonoProfileClassResult class_end_load;
59         MonoProfileClassFunc   class_start_unload;
60         MonoProfileClassFunc   class_end_unload;
61
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;
77
78         MonoProfileExceptionFunc        exception_throw_cb;
79         MonoProfileMethodFunc exception_method_leave_cb;
80         MonoProfileExceptionClauseFunc exception_clause_cb;
81
82         MonoProfileIomapFunc iomap_cb;
83
84         MonoProfileThreadFunc   thread_start;
85         MonoProfileThreadFunc   thread_end;
86         MonoProfileThreadNameFunc   thread_name;
87
88         MonoProfileCoverageFilterFunc coverage_filter_cb;
89
90         MonoProfileFunc shutdown_callback;
91
92         MonoProfileGCFunc        gc_event;
93         MonoProfileGCResizeFunc  gc_heap_resize;
94         MonoProfileGCMoveFunc    gc_moves;
95         MonoProfileGCHandleFunc  gc_handle;
96         MonoProfileGCRootFunc    gc_roots;
97
98         MonoProfileFunc          runtime_initialized_event;
99
100         MonoProfilerCodeChunkNew code_chunk_new;
101         MonoProfilerCodeChunkDestroy code_chunk_destroy;
102         MonoProfilerCodeBufferNew code_buffer_new;
103 };
104
105 static ProfilerDesc *prof_list = NULL;
106
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;
110
111 /* this is directly accessible to other mono libs.
112  * It is the ORed value of all the profiler's events.
113  */
114 MonoProfileFlags mono_profiler_events;
115
116 /**
117  * mono_profiler_install:
118  * @prof: a MonoProfiler structure pointer, or a pointer to a derived structure.
119  * @version: profiler API version (see profiler.h)
120  * @callback: the function to invoke at shutdown
121  *
122  * Use mono_profiler_install to activate profiling in the Mono runtime.
123  * Typically developers of new profilers will create a new structure whose
124  * first field is a MonoProfiler and put any extra information that they need
125  * to access from the various profiling callbacks there.
126  *
127  */
128 void
129 mono_profiler_install (MonoProfiler *prof, int version, MonoProfileFunc callback)
130 {
131         if (version != MONO_PROFILER_VERSION)
132                 g_warning ("Profiler module API version (%i) potentially incompatible with current API version (%i)", version, MONO_PROFILER_VERSION);
133
134         ProfilerDesc *desc = g_new0 (ProfilerDesc, 1);
135         if (!prof_list)
136                 mono_mutex_init_recursive (&profiler_coverage_mutex);
137         desc->profiler = prof;
138         desc->shutdown_callback = callback;
139         desc->next = prof_list;
140         prof_list = desc;
141 }
142
143 /**
144  * mono_profiler_set_events:
145  * @events: an ORed set of values made up of MONO_PROFILER_ flags
146  *
147  * The events descriped in the @events argument is a set of flags
148  * that represent which profiling events must be triggered.  For
149  * example if you have registered a set of methods for tracking
150  * JIT compilation start and end with mono_profiler_install_jit_compile,
151  * you will want to pass the MONO_PROFILE_JIT_COMPILATION flag to
152  * this routine.
153  *
154  * You can call mono_profile_set_events more than once and you can
155  * do this at runtime to modify which methods are invoked.
156  */
157 void
158 mono_profiler_set_events (MonoProfileFlags events)
159 {
160         ProfilerDesc *prof;
161         MonoProfileFlags value = 0;
162         if (prof_list)
163                 prof_list->events = events;
164         for (prof = prof_list; prof; prof = prof->next)
165                 value |= prof->events;
166         mono_profiler_events = value;
167 }
168
169 /**
170  * mono_profiler_get_events:
171  *
172  * Returns a list of active events that will be intercepted. 
173  */
174 MonoProfileFlags
175 mono_profiler_get_events (void)
176 {
177         return mono_profiler_events;
178 }
179
180 /**
181  * mono_profiler_install_enter_leave:
182  * @enter: the routine to be called on each method entry
183  * @fleave: the routine to be called each time a method returns
184  *
185  * Use this routine to install routines that will be called everytime
186  * a method enters and leaves.   The routines will receive as an argument
187  * the MonoMethod representing the method that is entering or leaving.
188  */
189 void
190 mono_profiler_install_enter_leave (MonoProfileMethodFunc enter, MonoProfileMethodFunc fleave)
191 {
192         if (!prof_list)
193                 return;
194         prof_list->method_enter = enter;
195         prof_list->method_leave = fleave;
196 }
197
198 /**
199  * mono_profiler_install_jit_compile:
200  * @start: the routine to be called when the JIT process starts.
201  * @end: the routine to be called when the JIT process ends.
202  *
203  * Use this routine to install routines that will be called when JIT 
204  * compilation of a method starts and completes.
205  */
206 void 
207 mono_profiler_install_jit_compile (MonoProfileMethodFunc start, MonoProfileMethodResult end)
208 {
209         if (!prof_list)
210                 return;
211         prof_list->jit_start = start;
212         prof_list->jit_end = end;
213 }
214
215 void 
216 mono_profiler_install_jit_end (MonoProfileJitResult end)
217 {
218         if (!prof_list)
219                 return;
220         prof_list->jit_end2 = end;
221 }
222
223 void 
224 mono_profiler_install_method_free (MonoProfileMethodFunc callback)
225 {
226         if (!prof_list)
227                 return;
228         prof_list->method_free = callback;
229 }
230
231 void
232 mono_profiler_install_method_invoke (MonoProfileMethodFunc start, MonoProfileMethodFunc end)
233 {
234         if (!prof_list)
235                 return;
236         prof_list->method_start_invoke = start;
237         prof_list->method_end_invoke = end;
238 }
239
240 void 
241 mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc end)
242 {
243         if (!prof_list)
244                 return;
245         prof_list->thread_start = start;
246         prof_list->thread_end = end;
247 }
248
249 void 
250 mono_profiler_install_thread_name (MonoProfileThreadNameFunc thread_name_cb)
251 {
252         if (!prof_list)
253                 return;
254         prof_list->thread_name = thread_name_cb;
255 }
256
257 void 
258 mono_profiler_install_transition (MonoProfileMethodResult callback)
259 {
260         if (!prof_list)
261                 return;
262         prof_list->man_unman_transition = callback;
263 }
264
265 void 
266 mono_profiler_install_allocation (MonoProfileAllocFunc callback)
267 {
268         if (!prof_list)
269                 return;
270         prof_list->allocation_cb = callback;
271 }
272
273 void
274 mono_profiler_install_monitor  (MonoProfileMonitorFunc callback)
275 {
276         if (!prof_list)
277                 return;
278         prof_list->monitor_event_cb = callback;
279 }
280
281 static MonoProfileSamplingMode sampling_mode = MONO_PROFILER_STAT_MODE_PROCESS;
282 static int64_t sampling_frequency = 1000; //1ms
283
284 /**
285  * mono_profiler_set_statistical_mode:
286  * @mode the sampling mode used.
287  * @sample_frequency_is_us the sampling frequency in microseconds.
288  *
289  * Set the sampling parameters for the profiler. Sampling mode affects the effective sampling rate as in samples/s you'll witness.
290  * The default sampling mode is process mode, which only reports samples when there's activity in the process.
291  *
292  * Sampling frequency should be interpreted as a suggestion that can't always be honored due to how most kernels expose alarms.
293  *
294  * Said that, when using statistical sampling, always assume variable rate sampling as all sort of external factors can interfere.
295  */
296 void
297 mono_profiler_set_statistical_mode (MonoProfileSamplingMode mode, int64_t sampling_frequency_is_us)
298 {
299         sampling_mode = mode;
300         sampling_frequency = sampling_frequency_is_us;
301 }
302
303 void 
304 mono_profiler_install_statistical (MonoProfileStatFunc callback)
305 {
306         if (!prof_list)
307                 return;
308         prof_list->statistical_cb = callback;
309 }
310
311 int64_t
312 mono_profiler_get_sampling_rate (void)
313 {
314         return sampling_frequency;
315 }
316
317 MonoProfileSamplingMode
318 mono_profiler_get_sampling_mode (void)
319 {
320         return sampling_mode;
321 }
322
323 void 
324 mono_profiler_install_statistical_call_chain (MonoProfileStatCallChainFunc callback, int call_chain_depth, MonoProfilerCallChainStrategy call_chain_strategy) {
325         if (!prof_list)
326                 return;
327         if (call_chain_depth > MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH) {
328                 call_chain_depth = MONO_PROFILER_MAX_STAT_CALL_CHAIN_DEPTH;
329         }
330         if ((call_chain_strategy >= MONO_PROFILER_CALL_CHAIN_INVALID) || (call_chain_strategy < MONO_PROFILER_CALL_CHAIN_NONE)) {
331                 call_chain_strategy = MONO_PROFILER_CALL_CHAIN_NONE;
332         }
333         prof_list->statistical_call_chain_cb = callback;
334         prof_list->statistical_call_chain_depth = call_chain_depth;
335         prof_list->statistical_call_chain_strategy = call_chain_strategy;
336 }
337
338 int
339 mono_profiler_stat_get_call_chain_depth (void) {
340         if (prof_list && prof_list->statistical_call_chain_cb != NULL) {
341                 return prof_list->statistical_call_chain_depth;
342         } else {
343                 return 0;
344         }
345 }
346
347 MonoProfilerCallChainStrategy
348 mono_profiler_stat_get_call_chain_strategy (void) {
349         if (prof_list && prof_list->statistical_call_chain_cb != NULL) {
350                 return prof_list->statistical_call_chain_strategy;
351         } else {
352                 return MONO_PROFILER_CALL_CHAIN_NONE;
353         }
354 }
355
356 void mono_profiler_install_exception (MonoProfileExceptionFunc throw_callback, MonoProfileMethodFunc exc_method_leave, MonoProfileExceptionClauseFunc clause_callback)
357 {
358         if (!prof_list)
359                 return;
360         prof_list->exception_throw_cb = throw_callback;
361         prof_list->exception_method_leave_cb = exc_method_leave;
362         prof_list->exception_clause_cb = clause_callback;
363 }
364
365 void 
366 mono_profiler_install_coverage_filter (MonoProfileCoverageFilterFunc callback)
367 {
368         if (!prof_list)
369                 return;
370         prof_list->coverage_filter_cb = callback;
371 }
372
373 void 
374 mono_profiler_install_appdomain   (MonoProfileAppDomainFunc start_load, MonoProfileAppDomainResult end_load,
375                                    MonoProfileAppDomainFunc start_unload, MonoProfileAppDomainFunc end_unload)
376
377 {
378         if (!prof_list)
379                 return;
380         prof_list->domain_start_load = start_load;
381         prof_list->domain_end_load = end_load;
382         prof_list->domain_start_unload = start_unload;
383         prof_list->domain_end_unload = end_unload;
384 }
385
386 void 
387 mono_profiler_install_assembly    (MonoProfileAssemblyFunc start_load, MonoProfileAssemblyResult end_load,
388                                    MonoProfileAssemblyFunc start_unload, MonoProfileAssemblyFunc end_unload)
389 {
390         if (!prof_list)
391                 return;
392         prof_list->assembly_start_load = start_load;
393         prof_list->assembly_end_load = end_load;
394         prof_list->assembly_start_unload = start_unload;
395         prof_list->assembly_end_unload = end_unload;
396 }
397
398 void 
399 mono_profiler_install_module      (MonoProfileModuleFunc start_load, MonoProfileModuleResult end_load,
400                                    MonoProfileModuleFunc start_unload, MonoProfileModuleFunc end_unload)
401 {
402         if (!prof_list)
403                 return;
404         prof_list->module_start_load = start_load;
405         prof_list->module_end_load = end_load;
406         prof_list->module_start_unload = start_unload;
407         prof_list->module_end_unload = end_unload;
408 }
409
410 void
411 mono_profiler_install_class       (MonoProfileClassFunc start_load, MonoProfileClassResult end_load,
412                                    MonoProfileClassFunc start_unload, MonoProfileClassFunc end_unload)
413 {
414         if (!prof_list)
415                 return;
416         prof_list->class_start_load = start_load;
417         prof_list->class_end_load = end_load;
418         prof_list->class_start_unload = start_unload;
419         prof_list->class_end_unload = end_unload;
420 }
421
422 void
423 mono_profiler_method_enter (MonoMethod *method)
424 {
425         ProfilerDesc *prof;
426         for (prof = prof_list; prof; prof = prof->next) {
427                 if ((prof->events & MONO_PROFILE_ENTER_LEAVE) && prof->method_enter)
428                         prof->method_enter (prof->profiler, method);
429         }
430 }
431
432 void
433 mono_profiler_method_leave (MonoMethod *method)
434 {
435         ProfilerDesc *prof;
436         for (prof = prof_list; prof; prof = prof->next) {
437                 if ((prof->events & MONO_PROFILE_ENTER_LEAVE) && prof->method_leave)
438                         prof->method_leave (prof->profiler, method);
439         }
440 }
441
442 void 
443 mono_profiler_method_jit (MonoMethod *method)
444 {
445         ProfilerDesc *prof;
446         for (prof = prof_list; prof; prof = prof->next) {
447                 if ((prof->events & MONO_PROFILE_JIT_COMPILATION) && prof->jit_start)
448                         prof->jit_start (prof->profiler, method);
449         }
450 }
451
452 void 
453 mono_profiler_method_end_jit (MonoMethod *method, MonoJitInfo* jinfo, int result)
454 {
455         ProfilerDesc *prof;
456         for (prof = prof_list; prof; prof = prof->next) {
457                 if ((prof->events & MONO_PROFILE_JIT_COMPILATION)) {
458                         if (prof->jit_end)
459                                 prof->jit_end (prof->profiler, method, result);
460                         if (prof->jit_end2)
461                                 prof->jit_end2 (prof->profiler, method, jinfo, result);
462                 }
463         }
464 }
465
466 void 
467 mono_profiler_method_free (MonoMethod *method)
468 {
469         ProfilerDesc *prof;
470         for (prof = prof_list; prof; prof = prof->next) {
471                 if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_free)
472                         prof->method_free (prof->profiler, method);
473         }
474 }
475
476 void
477 mono_profiler_method_start_invoke (MonoMethod *method)
478 {
479         ProfilerDesc *prof;
480         for (prof = prof_list; prof; prof = prof->next) {
481                 if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_start_invoke)
482                         prof->method_start_invoke (prof->profiler, method);
483         }
484 }
485
486 void
487 mono_profiler_method_end_invoke (MonoMethod *method)
488 {
489         ProfilerDesc *prof;
490         for (prof = prof_list; prof; prof = prof->next) {
491                 if ((prof->events & MONO_PROFILE_METHOD_EVENTS) && prof->method_end_invoke)
492                         prof->method_end_invoke (prof->profiler, method);
493         }
494 }
495
496 void 
497 mono_profiler_code_transition (MonoMethod *method, int result)
498 {
499         ProfilerDesc *prof;
500         for (prof = prof_list; prof; prof = prof->next) {
501                 if ((prof->events & MONO_PROFILE_TRANSITIONS) && prof->man_unman_transition)
502                         prof->man_unman_transition (prof->profiler, method, result);
503         }
504 }
505
506 void 
507 mono_profiler_allocation (MonoObject *obj, MonoClass *klass)
508 {
509         ProfilerDesc *prof;
510         for (prof = prof_list; prof; prof = prof->next) {
511                 if ((prof->events & MONO_PROFILE_ALLOCATIONS) && prof->allocation_cb)
512                         prof->allocation_cb (prof->profiler, obj, klass);
513         }
514 }
515
516 void
517 mono_profiler_monitor_event      (MonoObject *obj, MonoProfilerMonitorEvent event) {
518         ProfilerDesc *prof;
519         for (prof = prof_list; prof; prof = prof->next) {
520                 if ((prof->events & MONO_PROFILE_MONITOR_EVENTS) && prof->monitor_event_cb)
521                         prof->monitor_event_cb (prof->profiler, obj, event);
522         }
523 }
524
525 void
526 mono_profiler_stat_hit (guchar *ip, void *context)
527 {
528         ProfilerDesc *prof;
529         for (prof = prof_list; prof; prof = prof->next) {
530                 if ((prof->events & MONO_PROFILE_STATISTICAL) && prof->statistical_cb)
531                         prof->statistical_cb (prof->profiler, ip, context);
532         }
533 }
534
535 void
536 mono_profiler_stat_call_chain (int call_chain_depth, guchar **ips, void *context)
537 {
538         ProfilerDesc *prof;
539         for (prof = prof_list; prof; prof = prof->next) {
540                 if ((prof->events & MONO_PROFILE_STATISTICAL) && prof->statistical_call_chain_cb)
541                         prof->statistical_call_chain_cb (prof->profiler, call_chain_depth, ips, context);
542         }
543 }
544
545 void
546 mono_profiler_exception_thrown (MonoObject *exception)
547 {
548         ProfilerDesc *prof;
549         for (prof = prof_list; prof; prof = prof->next) {
550                 if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_throw_cb)
551                         prof->exception_throw_cb (prof->profiler, exception);
552         }
553 }
554
555 void
556 mono_profiler_exception_method_leave (MonoMethod *method)
557 {
558         ProfilerDesc *prof;
559         for (prof = prof_list; prof; prof = prof->next) {
560                 if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_method_leave_cb)
561                         prof->exception_method_leave_cb (prof->profiler, method);
562         }
563 }
564
565 void
566 mono_profiler_exception_clause_handler (MonoMethod *method, int clause_type, int clause_num)
567 {
568         ProfilerDesc *prof;
569         for (prof = prof_list; prof; prof = prof->next) {
570                 if ((prof->events & MONO_PROFILE_EXCEPTIONS) && prof->exception_clause_cb)
571                         prof->exception_clause_cb (prof->profiler, method, clause_type, clause_num);
572         }
573 }
574
575 void
576 mono_profiler_thread_start (gsize tid)
577 {
578         ProfilerDesc *prof;
579         for (prof = prof_list; prof; prof = prof->next) {
580                 if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_start)
581                         prof->thread_start (prof->profiler, tid);
582         }
583 }
584
585 void 
586 mono_profiler_thread_end (gsize tid)
587 {
588         ProfilerDesc *prof;
589         for (prof = prof_list; prof; prof = prof->next) {
590                 if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_end)
591                         prof->thread_end (prof->profiler, tid);
592         }
593 }
594
595 void
596 mono_profiler_thread_name (gsize tid, const char *name)
597 {
598         ProfilerDesc *prof;
599         for (prof = prof_list; prof; prof = prof->next) {
600                 if ((prof->events & MONO_PROFILE_THREADS) && prof->thread_name)
601                         prof->thread_name (prof->profiler, tid, name);
602         }
603 }
604
605 void 
606 mono_profiler_assembly_event  (MonoAssembly *assembly, int code)
607 {
608         ProfilerDesc *prof;
609         for (prof = prof_list; prof; prof = prof->next) {
610                 if (!(prof->events & MONO_PROFILE_ASSEMBLY_EVENTS))
611                         continue;
612
613                 switch (code) {
614                 case MONO_PROFILE_START_LOAD:
615                         if (prof->assembly_start_load)
616                                 prof->assembly_start_load (prof->profiler, assembly);
617                         break;
618                 case MONO_PROFILE_START_UNLOAD:
619                         if (prof->assembly_start_unload)
620                                 prof->assembly_start_unload (prof->profiler, assembly);
621                         break;
622                 case MONO_PROFILE_END_UNLOAD:
623                         if (prof->assembly_end_unload)
624                                 prof->assembly_end_unload (prof->profiler, assembly);
625                         break;
626                 default:
627                         g_assert_not_reached ();
628                 }
629         }
630 }
631
632 void 
633 mono_profiler_assembly_loaded (MonoAssembly *assembly, int result)
634 {
635         ProfilerDesc *prof;
636         for (prof = prof_list; prof; prof = prof->next) {
637                 if ((prof->events & MONO_PROFILE_ASSEMBLY_EVENTS) && prof->assembly_end_load)
638                         prof->assembly_end_load (prof->profiler, assembly, result);
639         }
640 }
641
642 void mono_profiler_iomap (char *report, const char *pathname, const char *new_pathname)
643 {
644         ProfilerDesc *prof;
645         for (prof = prof_list; prof; prof = prof->next) {
646                 if ((prof->events & MONO_PROFILE_IOMAP_EVENTS) && prof->iomap_cb)
647                         prof->iomap_cb (prof->profiler, report, pathname, new_pathname);
648         }
649 }
650
651 void 
652 mono_profiler_module_event  (MonoImage *module, int code)
653 {
654         ProfilerDesc *prof;
655         for (prof = prof_list; prof; prof = prof->next) {
656                 if (!(prof->events & MONO_PROFILE_MODULE_EVENTS))
657                         continue;
658
659                 switch (code) {
660                 case MONO_PROFILE_START_LOAD:
661                         if (prof->module_start_load)
662                                 prof->module_start_load (prof->profiler, module);
663                         break;
664                 case MONO_PROFILE_START_UNLOAD:
665                         if (prof->module_start_unload)
666                                 prof->module_start_unload (prof->profiler, module);
667                         break;
668                 case MONO_PROFILE_END_UNLOAD:
669                         if (prof->module_end_unload)
670                                 prof->module_end_unload (prof->profiler, module);
671                         break;
672                 default:
673                         g_assert_not_reached ();
674                 }
675         }
676 }
677
678 void 
679 mono_profiler_module_loaded (MonoImage *module, int result)
680 {
681         ProfilerDesc *prof;
682         for (prof = prof_list; prof; prof = prof->next) {
683                 if ((prof->events & MONO_PROFILE_MODULE_EVENTS) && prof->module_end_load)
684                         prof->module_end_load (prof->profiler, module, result);
685         }
686 }
687
688 void 
689 mono_profiler_class_event  (MonoClass *klass, int code)
690 {
691         ProfilerDesc *prof;
692         for (prof = prof_list; prof; prof = prof->next) {
693                 if (!(prof->events & MONO_PROFILE_CLASS_EVENTS))
694                         continue;
695
696                 switch (code) {
697                 case MONO_PROFILE_START_LOAD:
698                         if (prof->class_start_load)
699                                 prof->class_start_load (prof->profiler, klass);
700                         break;
701                 case MONO_PROFILE_START_UNLOAD:
702                         if (prof->class_start_unload)
703                                 prof->class_start_unload (prof->profiler, klass);
704                         break;
705                 case MONO_PROFILE_END_UNLOAD:
706                         if (prof->class_end_unload)
707                                 prof->class_end_unload (prof->profiler, klass);
708                         break;
709                 default:
710                         g_assert_not_reached ();
711                 }
712         }
713 }
714
715 void 
716 mono_profiler_class_loaded (MonoClass *klass, int result)
717 {
718         ProfilerDesc *prof;
719         for (prof = prof_list; prof; prof = prof->next) {
720                 if ((prof->events & MONO_PROFILE_CLASS_EVENTS) && prof->class_end_load)
721                         prof->class_end_load (prof->profiler, klass, result);
722         }
723 }
724
725 void 
726 mono_profiler_appdomain_event  (MonoDomain *domain, int code)
727 {
728         ProfilerDesc *prof;
729         for (prof = prof_list; prof; prof = prof->next) {
730                 if (!(prof->events & MONO_PROFILE_APPDOMAIN_EVENTS))
731                         continue;
732
733                 switch (code) {
734                 case MONO_PROFILE_START_LOAD:
735                         if (prof->domain_start_load)
736                                 prof->domain_start_load (prof->profiler, domain);
737                         break;
738                 case MONO_PROFILE_START_UNLOAD:
739                         if (prof->domain_start_unload)
740                                 prof->domain_start_unload (prof->profiler, domain);
741                         break;
742                 case MONO_PROFILE_END_UNLOAD:
743                         if (prof->domain_end_unload)
744                                 prof->domain_end_unload (prof->profiler, domain);
745                         break;
746                 default:
747                         g_assert_not_reached ();
748                 }
749         }
750 }
751
752 void 
753 mono_profiler_appdomain_loaded (MonoDomain *domain, int result)
754 {
755         ProfilerDesc *prof;
756         for (prof = prof_list; prof; prof = prof->next) {
757                 if ((prof->events & MONO_PROFILE_APPDOMAIN_EVENTS) && prof->domain_end_load)
758                         prof->domain_end_load (prof->profiler, domain, result);
759         }
760 }
761
762 void 
763 mono_profiler_shutdown (void)
764 {
765         ProfilerDesc *prof;
766         for (prof = prof_list; prof; prof = prof->next) {
767                 if (prof->shutdown_callback)
768                         prof->shutdown_callback (prof->profiler);
769         }
770
771         mono_profiler_set_events (0);
772 }
773
774 void
775 mono_profiler_gc_heap_resize (gint64 new_size)
776 {
777         ProfilerDesc *prof;
778         for (prof = prof_list; prof; prof = prof->next) {
779                 if ((prof->events & MONO_PROFILE_GC) && prof->gc_heap_resize)
780                         prof->gc_heap_resize (prof->profiler, new_size);
781         }
782 }
783
784 void
785 mono_profiler_gc_event (MonoGCEvent event, int generation)
786 {
787         ProfilerDesc *prof;
788         for (prof = prof_list; prof; prof = prof->next) {
789                 if ((prof->events & MONO_PROFILE_GC) && prof->gc_event)
790                         prof->gc_event (prof->profiler, event, generation);
791         }
792 }
793
794 void
795 mono_profiler_gc_moves (void **objects, int num)
796 {
797         ProfilerDesc *prof;
798         for (prof = prof_list; prof; prof = prof->next) {
799                 if ((prof->events & MONO_PROFILE_GC_MOVES) && prof->gc_moves)
800                         prof->gc_moves (prof->profiler, objects, num);
801         }
802 }
803
804 void
805 mono_profiler_gc_handle (int op, int type, uintptr_t handle, MonoObject *obj)
806 {
807         ProfilerDesc *prof;
808         for (prof = prof_list; prof; prof = prof->next) {
809                 if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_handle)
810                         prof->gc_handle (prof->profiler, op, type, handle, obj);
811         }
812 }
813
814 void
815 mono_profiler_gc_roots (int num, void **objects, int *root_types, uintptr_t *extra_info)
816 {
817         ProfilerDesc *prof;
818         for (prof = prof_list; prof; prof = prof->next) {
819                 if ((prof->events & MONO_PROFILE_GC_ROOTS) && prof->gc_roots)
820                         prof->gc_roots (prof->profiler, num, objects, root_types, extra_info);
821         }
822 }
823
824 void
825 mono_profiler_install_gc (MonoProfileGCFunc callback, MonoProfileGCResizeFunc heap_resize_callback)
826 {
827         mono_gc_enable_events ();
828         if (!prof_list)
829                 return;
830         prof_list->gc_event = callback;
831         prof_list->gc_heap_resize = heap_resize_callback;
832 }
833
834 /**
835  * mono_profiler_install_gc_moves:
836  * @callback: callback function
837  *
838  * Install the @callback function that the GC will call when moving objects.
839  * The callback receives an array of pointers and the number of elements
840  * in the array. Every even element in the array is the original object location
841  * and the following odd element is the new location of the object in memory.
842  * So the number of elements argument will always be a multiple of 2.
843  * Since this callback happens during the GC, it is a restricted environment:
844  * no locks can be taken and the object pointers can be inspected only once
845  * the GC is finished (of course the original location pointers will not
846  * point to valid objects anymore).
847  */
848 void
849 mono_profiler_install_gc_moves (MonoProfileGCMoveFunc callback)
850 {
851         if (!prof_list)
852                 return;
853         prof_list->gc_moves = callback;
854 }
855
856 /**
857  * mono_profiler_install_gc_roots:
858  * @handle_callback: callback function
859  * @roots_callback: callback function
860  *
861  * Install the @handle_callback function that the GC will call when GC
862  * handles are created or destroyed.
863  * The callback receives an operation, which is either #MONO_PROFILER_GC_HANDLE_CREATED
864  * or #MONO_PROFILER_GC_HANDLE_DESTROYED, the handle type, the handle value and the
865  * object pointer, if present.
866  * Install the @roots_callback function that the GC will call when tracing
867  * the roots for a collection.
868  * The callback receives the number of elements and three arrays: an array
869  * of objects, an array of root types and flags and an array of extra info.
870  * The size of each array is given by the first argument.
871  */
872 void
873 mono_profiler_install_gc_roots (MonoProfileGCHandleFunc handle_callback, MonoProfileGCRootFunc roots_callback)
874 {
875         if (!prof_list)
876                 return;
877         prof_list->gc_handle = handle_callback;
878         prof_list->gc_roots = roots_callback;
879 }
880
881 void
882 mono_profiler_install_runtime_initialized (MonoProfileFunc runtime_initialized_callback)
883 {
884         if (!prof_list)
885                 return;
886         prof_list->runtime_initialized_event = runtime_initialized_callback;
887 }
888
889 void
890 mono_profiler_runtime_initialized (void) {
891         ProfilerDesc *prof;
892         for (prof = prof_list; prof; prof = prof->next) {
893                 if (prof->runtime_initialized_event)
894                         prof->runtime_initialized_event (prof->profiler);
895         }
896 }
897
898 void
899 mono_profiler_install_code_chunk_new (MonoProfilerCodeChunkNew callback) {
900         if (!prof_list)
901                 return;
902         prof_list->code_chunk_new = callback;
903 }
904 void
905 mono_profiler_code_chunk_new (gpointer chunk, int size) {
906         ProfilerDesc *prof;
907         for (prof = prof_list; prof; prof = prof->next) {
908                 if (prof->code_chunk_new)
909                         prof->code_chunk_new (prof->profiler, chunk, size);
910         }
911 }
912
913 void
914 mono_profiler_install_code_chunk_destroy (MonoProfilerCodeChunkDestroy callback) {
915         if (!prof_list)
916                 return;
917         prof_list->code_chunk_destroy = callback;
918 }
919 void
920 mono_profiler_code_chunk_destroy (gpointer chunk) {
921         ProfilerDesc *prof;
922         for (prof = prof_list; prof; prof = prof->next) {
923                 if (prof->code_chunk_destroy)
924                         prof->code_chunk_destroy (prof->profiler, chunk);
925         }
926 }
927
928 void
929 mono_profiler_install_code_buffer_new (MonoProfilerCodeBufferNew callback) {
930         if (!prof_list)
931                 return;
932         prof_list->code_buffer_new = callback;
933 }
934
935 void
936 mono_profiler_install_iomap (MonoProfileIomapFunc callback)
937 {
938         if (!prof_list)
939                 return;
940         prof_list->iomap_cb = callback;
941 }
942
943 void
944 mono_profiler_code_buffer_new (gpointer buffer, int size, MonoProfilerCodeBufferType type, gconstpointer data) {
945         ProfilerDesc *prof;
946         for (prof = prof_list; prof; prof = prof->next) {
947                 if (prof->code_buffer_new)
948                         prof->code_buffer_new (prof->profiler, buffer, size, type, (void*)data);
949         }
950 }
951
952 static GHashTable *coverage_hash = NULL;
953
954 MonoProfileCoverageInfo* 
955 mono_profiler_coverage_alloc (MonoMethod *method, int entries)
956 {
957         MonoProfileCoverageInfo *res;
958         int instrument = FALSE;
959         ProfilerDesc *prof;
960
961         for (prof = prof_list; prof; prof = prof->next) {
962                 /* note that we call the filter on all the profilers even if just
963                  * a single one would be enough to instrument a method
964                  */
965                 if (prof->coverage_filter_cb)
966                         if (prof->coverage_filter_cb (prof->profiler, method))
967                                 instrument = TRUE;
968         }
969         if (!instrument)
970                 return NULL;
971
972         mono_profiler_coverage_lock ();
973         if (!coverage_hash)
974                 coverage_hash = g_hash_table_new (NULL, NULL);
975
976         res = g_malloc0 (sizeof (MonoProfileCoverageInfo) + sizeof (void*) * 2 * entries);
977
978         res->entries = entries;
979
980         g_hash_table_insert (coverage_hash, method, res);
981         mono_profiler_coverage_unlock ();
982
983         return res;
984 }
985
986 /* safe only when the method antive code has been unloaded */
987 void
988 mono_profiler_coverage_free (MonoMethod *method)
989 {
990         MonoProfileCoverageInfo* info;
991
992         mono_profiler_coverage_lock ();
993         if (!coverage_hash) {
994                 mono_profiler_coverage_unlock ();
995                 return;
996         }
997
998         info = g_hash_table_lookup (coverage_hash, method);
999         if (info) {
1000                 g_free (info);
1001                 g_hash_table_remove (coverage_hash, method);
1002         }
1003         mono_profiler_coverage_unlock ();
1004 }
1005
1006 /**
1007  * mono_profiler_coverage_get:
1008  * @prof: The profiler handle, installed with mono_profiler_install
1009  * @method: the method to gather information from.
1010  * @func: A routine that will be called back with the results
1011  *
1012  * If the MONO_PROFILER_INS_COVERAGE flag was active during JIT compilation
1013  * it is posisble to obtain coverage information about a give method.
1014  *
1015  * The function @func will be invoked repeatedly with instances of the
1016  * MonoProfileCoverageEntry structure.
1017  */
1018 void 
1019 mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileCoverageFunc func)
1020 {
1021         MonoProfileCoverageInfo* info = NULL;
1022         int i, offset;
1023         guint32 code_size;
1024         const unsigned char *start, *end, *cil_code;
1025         MonoMethodHeader *header;
1026         MonoProfileCoverageEntry entry;
1027         MonoDebugMethodInfo *debug_minfo;
1028
1029         mono_profiler_coverage_lock ();
1030         if (coverage_hash)
1031                 info = g_hash_table_lookup (coverage_hash, method);
1032         mono_profiler_coverage_unlock ();
1033
1034         if (!info)
1035                 return;
1036
1037         header = mono_method_get_header (method);
1038         start = mono_method_header_get_code (header, &code_size, NULL);
1039         debug_minfo = mono_debug_lookup_method (method);
1040
1041         end = start + code_size;
1042         for (i = 0; i < info->entries; ++i) {
1043                 cil_code = info->data [i].cil_code;
1044                 if (cil_code && cil_code >= start && cil_code < end) {
1045                         char *fname = NULL;
1046                         offset = cil_code - start;
1047                         entry.iloffset = offset;
1048                         entry.method = method;
1049                         entry.counter = info->data [i].count;
1050                         entry.line = entry.col = 1;
1051                         entry.filename = NULL;
1052                         if (debug_minfo) {
1053                                 MonoDebugSourceLocation *location;
1054
1055                                 location = mono_debug_symfile_lookup_location (debug_minfo, offset);
1056                                 if (location) {
1057                                         entry.line = location->row;
1058                                         entry.col = location->column;
1059                                         entry.filename = fname = g_strdup (location->source_file);
1060                                         mono_debug_free_source_location (location);
1061                                 }
1062                         }
1063
1064                         func (prof, &entry);
1065                         g_free (fname);
1066                 }
1067         }
1068         mono_metadata_free_mh (header);
1069 }
1070
1071 typedef void (*ProfilerInitializer) (const char*);
1072 #define INITIALIZER_NAME "mono_profiler_startup"
1073
1074
1075 static gboolean
1076 load_profiler (MonoDl *pmodule, const char *desc, const char *symbol)
1077 {
1078         char *err;
1079         ProfilerInitializer func;
1080
1081         if (!pmodule)
1082                 return FALSE;
1083
1084         if ((err = mono_dl_symbol (pmodule, symbol, (gpointer *) &func))) {
1085                 g_free (err);
1086                 return FALSE;
1087         } else {
1088                 func (desc);
1089         }
1090         return TRUE;
1091 }
1092
1093 static gboolean
1094 load_embedded_profiler (const char *desc, const char *name)
1095 {
1096         char *err = NULL;
1097         char *symbol;
1098         MonoDl *pmodule = NULL;
1099         gboolean result;
1100
1101         pmodule = mono_dl_open (NULL, MONO_DL_LAZY, &err);
1102         if (!pmodule) {
1103                 g_warning ("Could not open main executable (%s)", err);
1104                 g_free (err);
1105                 return FALSE;
1106         }
1107
1108         symbol = g_strdup_printf (INITIALIZER_NAME "_%s", name);
1109         result = load_profiler (pmodule, desc, symbol);
1110         g_free (symbol);
1111
1112         return result;
1113 }
1114
1115 static gboolean
1116 load_profiler_from_directory (const char *directory, const char *libname, const char *desc)
1117 {
1118         MonoDl *pmodule = NULL;
1119         char* path;
1120         char *err;
1121         void *iter;
1122
1123         iter = NULL;
1124         err = NULL;
1125         while ((path = mono_dl_build_path (directory, libname, &iter))) {
1126                 pmodule = mono_dl_open (path, MONO_DL_LAZY, &err);
1127                 g_free (path);
1128                 g_free (err);
1129                 if (pmodule)
1130                         return load_profiler (pmodule, desc, INITIALIZER_NAME);
1131         }
1132                 
1133         return FALSE;
1134 }
1135
1136 static gboolean
1137 load_profiler_from_mono_instalation (const char *libname, const char *desc)
1138 {
1139         char *err = NULL;
1140         MonoDl *pmodule = mono_dl_open_runtime_lib (libname, MONO_DL_LAZY, &err);
1141         g_free (err);
1142         if (pmodule)
1143                 return load_profiler (pmodule, desc, INITIALIZER_NAME);
1144         return FALSE;
1145 }
1146
1147 /**
1148  * mono_profiler_load:
1149  * @desc: arguments to configure the profiler
1150  *
1151  * Invoke this method to initialize the profiler.   This will drive the
1152  * loading of the internal ("default") or any external profilers.
1153  *
1154  * This routine is invoked by Mono's driver, but must be called manually
1155  * if you embed Mono into your application.
1156  */
1157 void 
1158 mono_profiler_load (const char *desc)
1159 {
1160         char *cdesc = NULL;
1161         mono_gc_base_init ();
1162
1163         if (!desc || (strcmp ("default", desc) == 0)) {
1164                 desc = "log:report";
1165         }
1166         /* we keep command-line compat with the old version here */
1167         if (strncmp (desc, "default:", 8) == 0) {
1168                 gchar **args, **ptr;
1169                 GString *str = g_string_new ("log:report");
1170                 args = g_strsplit (desc + 8, ",", -1);
1171                 for (ptr = args; ptr && *ptr; ptr++) {
1172                         const char *arg = *ptr;
1173
1174                         if (!strcmp (arg, "time"))
1175                                 g_string_append (str, ",calls");
1176                         else if (!strcmp (arg, "alloc"))
1177                                 g_string_append (str, ",alloc");
1178                         else if (!strcmp (arg, "stat"))
1179                                 g_string_append (str, ",sample");
1180                         else if (!strcmp (arg, "jit"))
1181                                 continue; /* accept and do nothing */
1182                         else if (strncmp (arg, "file=", 5) == 0) {
1183                                 g_string_append_printf (str, ",output=%s", arg + 5);
1184                         } else {
1185                                 fprintf (stderr, "profiler : Unknown argument '%s'.\n", arg);
1186                                 return;
1187                         }
1188                 }
1189                 desc = cdesc = g_string_free (str, FALSE);
1190         }
1191         {
1192                 const char* col = strchr (desc, ':');
1193                 char* libname;
1194                 char *mname;
1195                 gboolean res = FALSE;
1196
1197                 if (col != NULL) {
1198                         mname = g_memdup (desc, col - desc + 1);
1199                         mname [col - desc] = 0;
1200                 } else {
1201                         mname = g_strdup (desc);
1202                 }
1203                 if (!load_embedded_profiler (desc, mname)) {
1204                         libname = g_strdup_printf ("mono-profiler-%s", mname);
1205                         if (mono_config_get_assemblies_dir ())
1206                                 res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc);
1207                         if (!res)
1208                                 res = load_profiler_from_directory (NULL, libname, desc);
1209                         if (!res)
1210                                 res = load_profiler_from_mono_instalation (libname, desc);
1211                         if (!res)
1212                                 g_warning ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
1213                         g_free (libname);
1214                 }
1215                 g_free (mname);
1216         }
1217         g_free (cdesc);
1218 }
1219