2 #include "mono/metadata/profiler-private.h"
3 #include "mono/metadata/debug-helpers.h"
6 static MonoProfiler * current_profiler = NULL;
8 static MonoProfileAppDomainFunc domain_start_load;
9 static MonoProfileAppDomainResult domain_end_load;
10 static MonoProfileAppDomainFunc domain_start_unload;
11 static MonoProfileAppDomainFunc domain_end_unload;
13 static MonoProfileAssemblyFunc assembly_start_load;
14 static MonoProfileAssemblyResult assembly_end_load;
15 static MonoProfileAssemblyFunc assembly_start_unload;
16 static MonoProfileAssemblyFunc assembly_end_unload;
18 static MonoProfileModuleFunc module_start_load;
19 static MonoProfileModuleResult module_end_load;
20 static MonoProfileModuleFunc module_start_unload;
21 static MonoProfileModuleFunc module_end_unload;
23 static MonoProfileClassFunc class_start_load;
24 static MonoProfileClassResult class_end_load;
25 static MonoProfileClassFunc class_start_unload;
26 static MonoProfileClassFunc class_end_unload;
28 static MonoProfileMethodFunc jit_start;
29 static MonoProfileMethodResult jit_end;
30 static MonoProfileMethodResult man_unman_transition;
31 static MonoProfileMethodFunc method_enter;
32 static MonoProfileMethodFunc method_leave;
34 static MonoProfileThreadFunc thread_start;
35 static MonoProfileThreadFunc thread_end;
37 static MonoProfileFunc shutdown_callback;
39 /* this is directly accessible to other mono libs. */
40 MonoProfileFlags mono_profiler_events;
43 mono_profiler_install (MonoProfiler *prof, MonoProfileFunc callback)
46 g_error ("profiler already setup");
47 current_profiler = prof;
48 shutdown_callback = callback;
52 mono_profiler_set_events (MonoProfileFlags events)
54 mono_profiler_events = events;
58 mono_profiler_get_events (void)
60 return mono_profiler_events;
64 mono_profiler_install_enter_leave (MonoProfileMethodFunc enter, MonoProfileMethodFunc leave)
71 mono_profiler_install_jit_compile (MonoProfileMethodFunc start, MonoProfileMethodResult end)
78 mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc end)
85 mono_profiler_install_transition (MonoProfileMethodResult callback)
87 man_unman_transition = callback;
91 mono_profiler_install_appdomain (MonoProfileAppDomainFunc start_load, MonoProfileAppDomainResult end_load,
92 MonoProfileAppDomainFunc start_unload, MonoProfileAppDomainFunc end_unload)
95 domain_start_load = start_load;
96 domain_end_load = end_load;
97 domain_start_unload = start_unload;
98 domain_end_unload = end_unload;
102 mono_profiler_install_assembly (MonoProfileAssemblyFunc start_load, MonoProfileAssemblyResult end_load,
103 MonoProfileAssemblyFunc start_unload, MonoProfileAssemblyFunc end_unload)
105 assembly_start_load = start_load;
106 assembly_end_load = end_load;
107 assembly_start_unload = start_unload;
108 assembly_end_unload = end_unload;
112 mono_profiler_install_module (MonoProfileModuleFunc start_load, MonoProfileModuleResult end_load,
113 MonoProfileModuleFunc start_unload, MonoProfileModuleFunc end_unload)
115 module_start_load = start_load;
116 module_end_load = end_load;
117 module_start_unload = start_unload;
118 module_end_unload = end_unload;
122 mono_profiler_install_class (MonoProfileClassFunc start_load, MonoProfileClassResult end_load,
123 MonoProfileClassFunc start_unload, MonoProfileClassFunc end_unload)
125 class_start_load = start_load;
126 class_end_load = end_load;
127 class_start_unload = start_unload;
128 class_end_unload = end_unload;
132 mono_profiler_method_enter (MonoMethod *method)
134 if ((mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) && method_enter)
135 method_enter (current_profiler, method);
139 mono_profiler_method_leave (MonoMethod *method)
141 if ((mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) && method_leave)
142 method_leave (current_profiler, method);
146 mono_profiler_method_jit (MonoMethod *method)
148 if ((mono_profiler_events & MONO_PROFILE_JIT_COMPILATION) && jit_start)
149 jit_start (current_profiler, method);
153 mono_profiler_method_end_jit (MonoMethod *method, int result)
155 if ((mono_profiler_events & MONO_PROFILE_JIT_COMPILATION) && jit_end)
156 jit_end (current_profiler, method, result);
160 mono_profiler_code_transition (MonoMethod *method, int result)
162 if ((mono_profiler_events & MONO_PROFILE_TRANSITIONS) && man_unman_transition)
163 man_unman_transition (current_profiler, method, result);
167 mono_profiler_thread_start (HANDLE thread)
169 if ((mono_profiler_events & MONO_PROFILE_THREADS) && thread_start)
170 thread_start (current_profiler, thread);
174 mono_profiler_thread_end (HANDLE thread)
176 if ((mono_profiler_events & MONO_PROFILE_THREADS) && thread_end)
177 thread_end (current_profiler, thread);
181 mono_profiler_assembly_event (MonoAssembly *assembly, int code)
183 if (!(mono_profiler_events & MONO_PROFILE_ASSEMBLY_EVENTS))
187 case MONO_PROFILE_START_LOAD:
188 if (assembly_start_load)
189 assembly_start_load (current_profiler, assembly);
191 case MONO_PROFILE_START_UNLOAD:
192 if (assembly_start_unload)
193 assembly_start_unload (current_profiler, assembly);
195 case MONO_PROFILE_END_UNLOAD:
196 if (assembly_end_unload)
197 assembly_end_unload (current_profiler, assembly);
200 g_assert_not_reached ();
205 mono_profiler_assembly_loaded (MonoAssembly *assembly, int result)
207 if ((mono_profiler_events & MONO_PROFILE_ASSEMBLY_EVENTS) && assembly_end_load)
208 assembly_end_load (current_profiler, assembly, result);
212 mono_profiler_module_event (MonoImage *module, int code)
214 if (!(mono_profiler_events & MONO_PROFILE_MODULE_EVENTS))
218 case MONO_PROFILE_START_LOAD:
219 if (module_start_load)
220 module_start_load (current_profiler, module);
222 case MONO_PROFILE_START_UNLOAD:
223 if (module_start_unload)
224 module_start_unload (current_profiler, module);
226 case MONO_PROFILE_END_UNLOAD:
227 if (module_end_unload)
228 module_end_unload (current_profiler, module);
231 g_assert_not_reached ();
236 mono_profiler_module_loaded (MonoImage *module, int result)
238 if ((mono_profiler_events & MONO_PROFILE_MODULE_EVENTS) && module_end_load)
239 module_end_load (current_profiler, module, result);
243 mono_profiler_class_event (MonoClass *klass, int code)
245 if (!(mono_profiler_events & MONO_PROFILE_CLASS_EVENTS))
249 case MONO_PROFILE_START_LOAD:
250 if (class_start_load)
251 class_start_load (current_profiler, klass);
253 case MONO_PROFILE_START_UNLOAD:
254 if (class_start_unload)
255 class_start_unload (current_profiler, klass);
257 case MONO_PROFILE_END_UNLOAD:
258 if (class_end_unload)
259 class_end_unload (current_profiler, klass);
262 g_assert_not_reached ();
267 mono_profiler_class_loaded (MonoClass *klass, int result)
269 if ((mono_profiler_events & MONO_PROFILE_CLASS_EVENTS) && class_end_load)
270 class_end_load (current_profiler, klass, result);
274 mono_profiler_appdomain_event (MonoDomain *domain, int code)
276 if (!(mono_profiler_events & MONO_PROFILE_APPDOMAIN_EVENTS))
280 case MONO_PROFILE_START_LOAD:
281 if (domain_start_load)
282 domain_start_load (current_profiler, domain);
284 case MONO_PROFILE_START_UNLOAD:
285 if (domain_start_unload)
286 domain_start_unload (current_profiler, domain);
288 case MONO_PROFILE_END_UNLOAD:
289 if (domain_end_unload)
290 domain_end_unload (current_profiler, domain);
293 g_assert_not_reached ();
298 mono_profiler_appdomain_loaded (MonoDomain *domain, int result)
300 if ((mono_profiler_events & MONO_PROFILE_APPDOMAIN_EVENTS) && domain_end_load)
301 domain_end_load (current_profiler, domain, result);
305 mono_profiler_shutdown (void)
307 if (current_profiler && shutdown_callback)
308 shutdown_callback (current_profiler);
312 * Small profiler extracted from mint: we should move it in a loadable module
313 * and improve it to do graphs and more accurate timestamping with rdtsc.
317 #define USE_WIN32COUNTER 0
321 unsigned int lows, highs, lowe, highe;
324 #define rdtsc(low,high) \
325 __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
330 rdtsc_elapsed (MonoRdtscTimer *t)
332 unsigned long long diff;
333 unsigned int highe = t->highe;
334 if (t->lowe < t->lows)
336 diff = (((unsigned long long) highe - t->highs) << 32) + (t->lowe - t->lows);
337 return ((double)diff / freq) / 1000000; /* have to return the result in seconds */
348 if (!(cpuinfo = fopen ("/proc/cpuinfo", "r")))
350 while (fgets (buf, sizeof(buf), cpuinfo)) {
351 if (sscanf (buf, "cpu MHz : %f", &val) == 1) {
352 /*printf ("got mh: %f\n", val);*/
355 if (strncmp (buf, "flags", 5) == 0) {
356 if (strstr (buf, "tsc")) {
358 /*printf ("have tsc\n");*/
363 return have_flag? have_freq: 0;
366 #define MONO_TIMER_STARTUP \
367 if (!(freq = have_rdtsc ())) g_error ("Compiled with TSC support, but none found");
368 #define MONO_TIMER_TYPE MonoRdtscTimer
369 #define MONO_TIMER_INIT(t)
370 #define MONO_TIMER_DESTROY(t)
371 #define MONO_TIMER_START(t) rdtsc ((t).lows, (t).highs);
372 #define MONO_TIMER_STOP(t) rdtsc ((t).lowe, (t).highe);
373 #define MONO_TIMER_ELAPSED(t) rdtsc_elapsed (&(t))
375 #elif USE_WIN32COUNTER
379 LARGE_INTEGER start, stop;
385 win32_elapsed (MonoWin32Timer *t)
387 LONGLONG diff = t->stop.QuadPart - t->start.QuadPart;
388 return ((double)diff / freq) / 1000000; /* have to return the result in seconds */
392 have_win32counter (void) {
395 if (!QueryPerformanceFrequency (&f))
400 #define MONO_TIMER_STARTUP \
401 if (!(freq = have_win32counter ())) g_error ("Compiled with Win32 counter support, but none found");
402 #define MONO_TIMER_TYPE MonoWin32Timer
403 #define MONO_TIMER_INIT(t)
404 #define MONO_TIMER_DESTROY(t)
405 #define MONO_TIMER_START(t) QueryPerformanceCounter (&(t).start)
406 #define MONO_TIMER_STOP(t) QueryPerformanceCounter (&(t).stop)
407 #define MONO_TIMER_ELAPSED(t) win32_elapsed (&(t))
412 GTimeVal start, stop;
416 timeval_elapsed (MonoGLibTimer *t)
418 if (t->start.tv_usec > t->stop.tv_usec) {
419 t->stop.tv_usec += G_USEC_PER_SEC;
422 return (t->stop.tv_sec - t->start.tv_sec)
423 + ((double)(t->stop.tv_usec - t->start.tv_usec))/ G_USEC_PER_SEC;
426 #define MONO_TIMER_STARTUP
427 #define MONO_TIMER_TYPE MonoGLibTimer
428 #define MONO_TIMER_INIT(t)
429 #define MONO_TIMER_DESTROY(t)
430 #define MONO_TIMER_START(t) g_get_current_time (&(t).start)
431 #define MONO_TIMER_STOP(t) g_get_current_time (&(t).stop)
432 #define MONO_TIMER_ELAPSED(t) timeval_elapsed (&(t))
435 struct _MonoProfiler {
438 MONO_TIMER_TYPE jit_timer;
445 MONO_TIMER_TYPE timer;
452 typedef struct _MethodCallProfile MethodCallProfile;
454 struct _MethodCallProfile {
455 MethodCallProfile *next;
456 MONO_TIMER_TYPE timer;
461 compare_profile (MethodProfile *profa, MethodProfile *profb)
463 return (gint)((profb->total - profa->total)*1000);
467 build_profile (MonoMethod *m, MethodProfile *prof, GList **funcs)
469 MONO_TIMER_DESTROY (prof->u.timer);
471 *funcs = g_list_insert_sorted (*funcs, prof, (GCompareFunc)compare_profile);
475 output_profile (GList *funcs)
481 guint64 total_calls = 0;
484 g_print ("Method name\t\t\t\t\tTotal (ms) Calls Per call (ms)\n");
485 for (tmp = funcs; tmp; tmp = tmp->next) {
487 total_calls += p->count;
488 if (!(gint)(p->total*1000))
490 sig = mono_signature_get_desc (p->u.method->signature, FALSE);
491 g_snprintf (buf, sizeof (buf), "%s.%s::%s(%s)",
492 p->u.method->klass->name_space, p->u.method->klass->name,
493 p->u.method->name, sig);
495 printf ("%-52s %7d %7llu %7d\n", buf,
496 (gint)(p->total*1000), p->count, (gint)((p->total*1000)/p->count));
498 printf ("Total number of calls: %lld\n", total_calls);
507 compare_newobj_profile (NewobjProfile *profa, NewobjProfile *profb)
509 return (gint)profb->count - (gint)profa->count;
513 build_newobj_profile (MonoClass *class, gpointer count, GList **funcs)
515 NewobjProfile *prof = g_new (NewobjProfile, 1);
517 prof->count = GPOINTER_TO_UINT (count);
518 *funcs = g_list_insert_sorted (*funcs, prof, (GCompareFunc)compare_newobj_profile);
522 output_newobj_profile (GList *proflist)
531 g_print ("\n%-52s %9s\n", "Objects created:", "count");
532 for (tmp = proflist; tmp; tmp = tmp->next) {
537 klass = klass->element_class;
541 g_snprintf (buf, sizeof (buf), "%s.%s%s",
542 klass->name_space, klass->name, isarray);
543 g_print ("%-52s %9d\n", buf, p->count);
548 simple_method_enter (MonoProfiler *prof, MonoMethod *method)
550 MethodProfile *profile_info;
551 if (!(profile_info = g_hash_table_lookup (prof->methods, method))) {
552 profile_info = g_new0 (MethodProfile, 1);
553 MONO_TIMER_INIT (profile_info->u.timer);
554 g_hash_table_insert (prof->methods, method, profile_info);
556 profile_info->count++;
557 MONO_TIMER_START (profile_info->u.timer);
561 simple_method_leave (MonoProfiler *prof, MonoMethod *method)
563 MethodProfile *profile_info;
564 if (!(profile_info = g_hash_table_lookup (prof->methods, method)))
565 g_assert_not_reached ();
567 MONO_TIMER_STOP (profile_info->u.timer);
568 profile_info->total += MONO_TIMER_ELAPSED (profile_info->u.timer);
572 simple_method_jit (MonoProfiler *prof, MonoMethod *method)
574 prof->methods_jitted++;
575 MONO_TIMER_START (prof->jit_timer);
579 simple_method_end_jit (MonoProfiler *prof, MonoMethod *method, int result)
581 MONO_TIMER_STOP (prof->jit_timer);
582 prof->jit_time += MONO_TIMER_ELAPSED (prof->jit_timer);
586 simple_shutdown (MonoProfiler *prof)
588 GList *profile = NULL;
590 printf("Total time spent compiling %d methods (sec): %.4g\n", prof->methods_jitted, prof->jit_time);
591 g_hash_table_foreach (prof->methods, (GHFunc)build_profile, &profile);
592 output_profile (profile);
593 g_list_free (profile);
596 g_hash_table_foreach (prof->newobjs, (GHFunc)build_newobj_profile, &profile);
597 output_newobj_profile (profile);
598 g_list_free (profile);
602 mono_profiler_install_simple (void)
604 MonoProfiler *prof = g_new0 (MonoProfiler, 1);
608 prof->methods = g_hash_table_new (g_direct_hash, g_direct_equal);
609 prof->newobjs = g_hash_table_new (g_direct_hash, g_direct_equal);
610 MONO_TIMER_INIT (prof->jit_timer);
612 mono_profiler_install (prof, simple_shutdown);
613 /* later do also object creation */
614 mono_profiler_install_enter_leave (simple_method_enter, simple_method_leave);
615 mono_profiler_install_jit_compile (simple_method_jit, simple_method_end_jit);
616 mono_profiler_set_events (MONO_PROFILE_ENTER_LEAVE|MONO_PROFILE_JIT_COMPILATION);