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