2 #include "mono/metadata/profiler-private.h"
3 #include "mono/metadata/debug-helpers.h"
4 #include "mono/metadata/mono-debug.h"
8 static MonoProfiler * current_profiler = NULL;
10 static MonoProfileAppDomainFunc domain_start_load;
11 static MonoProfileAppDomainResult domain_end_load;
12 static MonoProfileAppDomainFunc domain_start_unload;
13 static MonoProfileAppDomainFunc domain_end_unload;
15 static MonoProfileAssemblyFunc assembly_start_load;
16 static MonoProfileAssemblyResult assembly_end_load;
17 static MonoProfileAssemblyFunc assembly_start_unload;
18 static MonoProfileAssemblyFunc assembly_end_unload;
20 static MonoProfileModuleFunc module_start_load;
21 static MonoProfileModuleResult module_end_load;
22 static MonoProfileModuleFunc module_start_unload;
23 static MonoProfileModuleFunc module_end_unload;
25 static MonoProfileClassFunc class_start_load;
26 static MonoProfileClassResult class_end_load;
27 static MonoProfileClassFunc class_start_unload;
28 static MonoProfileClassFunc class_end_unload;
30 static MonoProfileMethodFunc jit_start;
31 static MonoProfileMethodResult jit_end;
32 static MonoProfileMethodResult man_unman_transition;
33 static MonoProfileAllocFunc allocation_cb;
34 static MonoProfileMethodFunc method_enter;
35 static MonoProfileMethodFunc method_leave;
37 static MonoProfileThreadFunc thread_start;
38 static MonoProfileThreadFunc thread_end;
40 static MonoProfileCoverageFilterFunc coverage_filter_cb;
42 static MonoProfileFunc shutdown_callback;
44 /* this is directly accessible to other mono libs. */
45 MonoProfileFlags mono_profiler_events;
48 mono_profiler_install (MonoProfiler *prof, MonoProfileFunc callback)
51 g_error ("profiler already setup");
52 current_profiler = prof;
53 shutdown_callback = callback;
57 mono_profiler_set_events (MonoProfileFlags events)
59 mono_profiler_events = events;
63 mono_profiler_get_events (void)
65 return mono_profiler_events;
69 mono_profiler_install_enter_leave (MonoProfileMethodFunc enter, MonoProfileMethodFunc fleave)
72 method_leave = fleave;
76 mono_profiler_install_jit_compile (MonoProfileMethodFunc start, MonoProfileMethodResult end)
83 mono_profiler_install_thread (MonoProfileThreadFunc start, MonoProfileThreadFunc end)
90 mono_profiler_install_transition (MonoProfileMethodResult callback)
92 man_unman_transition = callback;
96 mono_profiler_install_allocation (MonoProfileAllocFunc callback)
98 allocation_cb = callback;
102 mono_profiler_install_coverage_filter (MonoProfileCoverageFilterFunc callback)
104 coverage_filter_cb = callback;
108 mono_profiler_install_appdomain (MonoProfileAppDomainFunc start_load, MonoProfileAppDomainResult end_load,
109 MonoProfileAppDomainFunc start_unload, MonoProfileAppDomainFunc end_unload)
112 domain_start_load = start_load;
113 domain_end_load = end_load;
114 domain_start_unload = start_unload;
115 domain_end_unload = end_unload;
119 mono_profiler_install_assembly (MonoProfileAssemblyFunc start_load, MonoProfileAssemblyResult end_load,
120 MonoProfileAssemblyFunc start_unload, MonoProfileAssemblyFunc end_unload)
122 assembly_start_load = start_load;
123 assembly_end_load = end_load;
124 assembly_start_unload = start_unload;
125 assembly_end_unload = end_unload;
129 mono_profiler_install_module (MonoProfileModuleFunc start_load, MonoProfileModuleResult end_load,
130 MonoProfileModuleFunc start_unload, MonoProfileModuleFunc end_unload)
132 module_start_load = start_load;
133 module_end_load = end_load;
134 module_start_unload = start_unload;
135 module_end_unload = end_unload;
139 mono_profiler_install_class (MonoProfileClassFunc start_load, MonoProfileClassResult end_load,
140 MonoProfileClassFunc start_unload, MonoProfileClassFunc end_unload)
142 class_start_load = start_load;
143 class_end_load = end_load;
144 class_start_unload = start_unload;
145 class_end_unload = end_unload;
149 mono_profiler_method_enter (MonoMethod *method)
151 if ((mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) && method_enter)
152 method_enter (current_profiler, method);
156 mono_profiler_method_leave (MonoMethod *method)
158 if ((mono_profiler_events & MONO_PROFILE_ENTER_LEAVE) && method_leave)
159 method_leave (current_profiler, method);
163 mono_profiler_method_jit (MonoMethod *method)
165 if ((mono_profiler_events & MONO_PROFILE_JIT_COMPILATION) && jit_start)
166 jit_start (current_profiler, method);
170 mono_profiler_method_end_jit (MonoMethod *method, int result)
172 if ((mono_profiler_events & MONO_PROFILE_JIT_COMPILATION) && jit_end)
173 jit_end (current_profiler, method, result);
177 mono_profiler_code_transition (MonoMethod *method, int result)
179 if ((mono_profiler_events & MONO_PROFILE_TRANSITIONS) && man_unman_transition)
180 man_unman_transition (current_profiler, method, result);
184 mono_profiler_allocation (MonoObject *obj, MonoClass *klass)
186 if ((mono_profiler_events & MONO_PROFILE_ALLOCATIONS) && allocation_cb)
187 allocation_cb (current_profiler, obj, klass);
191 mono_profiler_thread_start (guint32 tid)
193 if ((mono_profiler_events & MONO_PROFILE_THREADS) && thread_start)
194 thread_start (current_profiler, tid);
198 mono_profiler_thread_end (guint32 tid)
200 if ((mono_profiler_events & MONO_PROFILE_THREADS) && thread_end)
201 thread_end (current_profiler, tid);
205 mono_profiler_assembly_event (MonoAssembly *assembly, int code)
207 if (!(mono_profiler_events & MONO_PROFILE_ASSEMBLY_EVENTS))
211 case MONO_PROFILE_START_LOAD:
212 if (assembly_start_load)
213 assembly_start_load (current_profiler, assembly);
215 case MONO_PROFILE_START_UNLOAD:
216 if (assembly_start_unload)
217 assembly_start_unload (current_profiler, assembly);
219 case MONO_PROFILE_END_UNLOAD:
220 if (assembly_end_unload)
221 assembly_end_unload (current_profiler, assembly);
224 g_assert_not_reached ();
229 mono_profiler_assembly_loaded (MonoAssembly *assembly, int result)
231 if ((mono_profiler_events & MONO_PROFILE_ASSEMBLY_EVENTS) && assembly_end_load)
232 assembly_end_load (current_profiler, assembly, result);
236 mono_profiler_module_event (MonoImage *module, int code)
238 if (!(mono_profiler_events & MONO_PROFILE_MODULE_EVENTS))
242 case MONO_PROFILE_START_LOAD:
243 if (module_start_load)
244 module_start_load (current_profiler, module);
246 case MONO_PROFILE_START_UNLOAD:
247 if (module_start_unload)
248 module_start_unload (current_profiler, module);
250 case MONO_PROFILE_END_UNLOAD:
251 if (module_end_unload)
252 module_end_unload (current_profiler, module);
255 g_assert_not_reached ();
260 mono_profiler_module_loaded (MonoImage *module, int result)
262 if ((mono_profiler_events & MONO_PROFILE_MODULE_EVENTS) && module_end_load)
263 module_end_load (current_profiler, module, result);
267 mono_profiler_class_event (MonoClass *klass, int code)
269 if (!(mono_profiler_events & MONO_PROFILE_CLASS_EVENTS))
273 case MONO_PROFILE_START_LOAD:
274 if (class_start_load)
275 class_start_load (current_profiler, klass);
277 case MONO_PROFILE_START_UNLOAD:
278 if (class_start_unload)
279 class_start_unload (current_profiler, klass);
281 case MONO_PROFILE_END_UNLOAD:
282 if (class_end_unload)
283 class_end_unload (current_profiler, klass);
286 g_assert_not_reached ();
291 mono_profiler_class_loaded (MonoClass *klass, int result)
293 if ((mono_profiler_events & MONO_PROFILE_CLASS_EVENTS) && class_end_load)
294 class_end_load (current_profiler, klass, result);
298 mono_profiler_appdomain_event (MonoDomain *domain, int code)
300 if (!(mono_profiler_events & MONO_PROFILE_APPDOMAIN_EVENTS))
304 case MONO_PROFILE_START_LOAD:
305 if (domain_start_load)
306 domain_start_load (current_profiler, domain);
308 case MONO_PROFILE_START_UNLOAD:
309 if (domain_start_unload)
310 domain_start_unload (current_profiler, domain);
312 case MONO_PROFILE_END_UNLOAD:
313 if (domain_end_unload)
314 domain_end_unload (current_profiler, domain);
317 g_assert_not_reached ();
322 mono_profiler_appdomain_loaded (MonoDomain *domain, int result)
324 if ((mono_profiler_events & MONO_PROFILE_APPDOMAIN_EVENTS) && domain_end_load)
325 domain_end_load (current_profiler, domain, result);
329 mono_profiler_shutdown (void)
331 if (current_profiler && shutdown_callback)
332 shutdown_callback (current_profiler);
335 static GHashTable *coverage_hash = NULL;
337 MonoProfileCoverageInfo*
338 mono_profiler_coverage_alloc (MonoMethod *method, int entries)
340 MonoProfileCoverageInfo *res;
342 if (coverage_filter_cb)
343 if (! (*coverage_filter_cb) (current_profiler, method))
347 coverage_hash = g_hash_table_new (NULL, NULL);
349 res = g_malloc0 (sizeof (MonoProfileCoverageInfo) + sizeof (void*) * 2 * entries);
351 res->entries = entries;
353 g_hash_table_insert (coverage_hash, method, res);
358 /* safe only when the method antive code has been unloaded */
360 mono_profiler_coverage_free (MonoMethod *method)
362 MonoProfileCoverageInfo* info;
365 info = g_hash_table_lookup (coverage_hash, method);
369 g_hash_table_remove (coverage_hash, method);
373 mono_profiler_coverage_get (MonoProfiler *prof, MonoMethod *method, MonoProfileCoverageFunc func)
375 MonoProfileCoverageInfo* info;
378 unsigned char *start, *end, *cil_code;
379 MonoMethodHeader *header;
380 MonoProfileCoverageEntry entry;
382 info = g_hash_table_lookup (coverage_hash, method);
386 header = ((MonoMethodNormal *)method)->header;
387 start = (unsigned char*)header->code;
388 end = start + header->code_size;
389 for (i = 0; i < info->entries; ++i) {
390 cil_code = info->data [i].cil_code;
391 if (cil_code && cil_code >= start && cil_code < end) {
392 offset = cil_code - start;
393 entry.iloffset = offset;
394 entry.method = method;
395 entry.counter = info->data [i].count;
396 /* the debug interface doesn't support column info, sigh */
398 entry.filename = mono_debug_source_location_from_il_offset (method, offset, &line);
407 * Small profiler extracted from mint: we should move it in a loadable module
408 * and improve it to do graphs and more accurate timestamping with rdtsc.
412 #define USE_WIN32COUNTER 0
416 unsigned int lows, highs, lowe, highe;
419 #define rdtsc(low,high) \
420 __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high))
425 rdtsc_elapsed (MonoRdtscTimer *t)
427 unsigned long long diff;
428 unsigned int highe = t->highe;
429 if (t->lowe < t->lows)
431 diff = (((unsigned long long) highe - t->highs) << 32) + (t->lowe - t->lows);
432 return ((double)diff / freq) / 1000000; /* have to return the result in seconds */
443 if (!(cpuinfo = fopen ("/proc/cpuinfo", "r")))
445 while (fgets (buf, sizeof(buf), cpuinfo)) {
446 if (sscanf (buf, "cpu MHz : %f", &val) == 1) {
447 /*printf ("got mh: %f\n", val);*/
450 if (strncmp (buf, "flags", 5) == 0) {
451 if (strstr (buf, "tsc")) {
453 /*printf ("have tsc\n");*/
458 return have_flag? have_freq: 0;
461 #define MONO_TIMER_STARTUP \
462 if (!(freq = have_rdtsc ())) g_error ("Compiled with TSC support, but none found");
463 #define MONO_TIMER_TYPE MonoRdtscTimer
464 #define MONO_TIMER_INIT(t)
465 #define MONO_TIMER_DESTROY(t)
466 #define MONO_TIMER_START(t) rdtsc ((t).lows, (t).highs);
467 #define MONO_TIMER_STOP(t) rdtsc ((t).lowe, (t).highe);
468 #define MONO_TIMER_ELAPSED(t) rdtsc_elapsed (&(t))
470 #elif USE_WIN32COUNTER
474 LARGE_INTEGER start, stop;
480 win32_elapsed (MonoWin32Timer *t)
482 LONGLONG diff = t->stop.QuadPart - t->start.QuadPart;
483 return ((double)diff / freq) / 1000000; /* have to return the result in seconds */
487 have_win32counter (void) {
490 if (!QueryPerformanceFrequency (&f))
495 #define MONO_TIMER_STARTUP \
496 if (!(freq = have_win32counter ())) g_error ("Compiled with Win32 counter support, but none found");
497 #define MONO_TIMER_TYPE MonoWin32Timer
498 #define MONO_TIMER_INIT(t)
499 #define MONO_TIMER_DESTROY(t)
500 #define MONO_TIMER_START(t) QueryPerformanceCounter (&(t).start)
501 #define MONO_TIMER_STOP(t) QueryPerformanceCounter (&(t).stop)
502 #define MONO_TIMER_ELAPSED(t) win32_elapsed (&(t))
507 GTimeVal start, stop;
511 timeval_elapsed (MonoGLibTimer *t)
513 if (t->start.tv_usec > t->stop.tv_usec) {
514 t->stop.tv_usec += G_USEC_PER_SEC;
517 return (t->stop.tv_sec - t->start.tv_sec)
518 + ((double)(t->stop.tv_usec - t->start.tv_usec))/ G_USEC_PER_SEC;
521 #define MONO_TIMER_STARTUP
522 #define MONO_TIMER_TYPE MonoGLibTimer
523 #define MONO_TIMER_INIT(t)
524 #define MONO_TIMER_DESTROY(t)
525 #define MONO_TIMER_START(t) g_get_current_time (&(t).start)
526 #define MONO_TIMER_STOP(t) g_get_current_time (&(t).stop)
527 #define MONO_TIMER_ELAPSED(t) timeval_elapsed (&(t))
530 typedef struct _AllocInfo AllocInfo;
531 typedef struct _CallerInfo CallerInfo;
532 typedef struct _LastCallerInfo LastCallerInfo;
534 struct _MonoProfiler {
536 MonoMemPool *mempool;
537 /* info about JIT time */
538 MONO_TIMER_TYPE jit_timer;
541 MonoMethod *max_jit_method;
544 /* tls_id is the id for the TLS slot where MonoProfiler is stored */
548 /* chain of callers for the current thread */
549 LastCallerInfo *callers;
550 /* LastCallerInfo nodes for faster allocation */
551 LastCallerInfo *cstorage;
558 AllocInfo *alloc_info;
559 CallerInfo *caller_info;
562 typedef struct _MethodCallProfile MethodCallProfile;
564 struct _MethodCallProfile {
565 MethodCallProfile *next;
566 MONO_TIMER_TYPE timer;
583 struct _LastCallerInfo {
584 LastCallerInfo *next;
586 MONO_TIMER_TYPE timer;
590 create_profiler (void)
592 MonoProfiler *prof = g_new0 (MonoProfiler, 1);
594 prof->methods = g_hash_table_new (NULL, NULL);
595 MONO_TIMER_INIT (prof->jit_timer);
596 prof->mempool = mono_mempool_new ();
600 #define GET_THREAD_PROF(prof) do {\
601 MonoProfiler *_tprofiler = TlsGetValue ((prof)->tls_id); \
603 _tprofiler = create_profiler (); \
604 prof->per_thread = g_slist_prepend (prof->per_thread, _tprofiler); \
605 TlsSetValue ((prof)->tls_id, _tprofiler); \
610 /* thread unsafe but faster variant */
611 #define GET_THREAD_PROF(prof)
615 compare_profile (MethodProfile *profa, MethodProfile *profb)
617 return (gint)((profb->total - profa->total)*1000);
621 build_profile (MonoMethod *m, MethodProfile *prof, GList **funcs)
624 *funcs = g_list_insert_sorted (*funcs, prof, (GCompareFunc)compare_profile);
628 method_get_name (MonoMethod* method)
632 sig = mono_signature_get_desc (method->signature, FALSE);
633 res = g_strdup_printf ("%s.%s::%s(%s)", method->klass->name_space, method->klass->name,
639 static void output_callers (MethodProfile *p);
642 output_profile (GList *funcs)
647 guint64 total_calls = 0;
650 g_print ("Time(ms) Count P/call(ms) Method name\n");
651 for (tmp = funcs; tmp; tmp = tmp->next) {
653 total_calls += p->count;
654 if (!(gint)(p->total*1000))
656 m = method_get_name (p->method);
657 printf ("########################\n");
658 printf ("% 8.3f ", (double) (p->total * 1000));
659 printf ("%7llu ", p->count);
660 printf ("% 8.3f ", (double) (p->total * 1000)/(double)p->count);
667 printf ("Total number of calls: %lld\n", total_calls);
676 compare_newobj_profile (NewobjProfile *profa, NewobjProfile *profb)
678 return (gint)profb->count - (gint)profa->count;
682 build_newobj_profile (MonoClass *class, MethodProfile *mprof, GList **funcs)
684 NewobjProfile *prof = g_new (NewobjProfile, 1);
689 /* we use the total amount of memory to sort */
690 for (tmp = mprof->alloc_info; tmp; tmp = tmp->next)
693 *funcs = g_list_insert_sorted (*funcs, prof, (GCompareFunc)compare_newobj_profile);
697 compare_caller (CallerInfo *a, CallerInfo *b)
699 return b->count - a->count;
703 compare_alloc (AllocInfo *a, AllocInfo *b)
705 return b->mem - a->mem;
709 sort_alloc_list (AllocInfo *ai)
713 for (tmp = ai; tmp; tmp = tmp->next) {
714 l = g_slist_insert_sorted (l, tmp, (GCompareFunc)compare_alloc);
720 sort_caller_list (CallerInfo *ai)
724 for (tmp = ai; tmp; tmp = tmp->next) {
725 l = g_slist_insert_sorted (l, tmp, (GCompareFunc)compare_caller);
731 output_callers (MethodProfile *p) {
732 guint total_callers, percent;
733 GSList *sorted, *tmps;
737 g_print (" Callers (with count) that contribute at least for 1%%:\n");
739 for (cinfo = p->caller_info; cinfo; cinfo = cinfo->next) {
740 total_callers += cinfo->count;
742 sorted = sort_caller_list (p->caller_info);
743 for (tmps = sorted; tmps; tmps = tmps->next) {
745 percent = (cinfo->count * 100)/total_callers;
748 m = method_get_name (cinfo->caller);
749 g_print (" %8d % 3d %% %s\n", cinfo->count, percent, m);
755 output_newobj_profile (GList *proflist)
766 GSList *sorted, *tmps;
768 g_print ("\nAllocation profiler\n");
771 g_print ("%-9s %s\n", "Total mem", "Method");
772 for (tmp = proflist; tmp; tmp = tmp->next) {
775 if (p->count < 50000)
778 m = method_get_name (mp->method);
779 g_print ("########################\n%8d KB %s\n", p->count / 1024, m);
781 sorted = sort_alloc_list (mp->alloc_info);
782 for (tmps = sorted; tmps; tmps = tmps->next) {
784 if (ainfo->mem < 50000)
786 klass = ainfo->klass;
789 klass = klass->element_class;
793 g_snprintf (buf, sizeof (buf), "%s.%s%s",
794 klass->name_space, klass->name, isarray);
795 g_print (" %8d KB %8d %-48s\n", ainfo->mem / 1024, ainfo->count, buf);
800 g_print ("Total memory allocated: %d KB\n", total / 1024);
804 merge_methods (MonoMethod *method, MethodProfile *profile, MonoProfiler *prof)
806 MethodProfile *mprof;
807 AllocInfo *talloc_info, *alloc_info;
808 CallerInfo *tcaller_info, *caller_info;
810 mprof = g_hash_table_lookup (prof->methods, method);
812 /* the master thread didn't see this method, just transfer the info as is */
813 g_hash_table_insert (prof->methods, method, profile);
816 /* merge the info from profile into mprof */
817 mprof->count += profile->count;
818 mprof->total += profile->total;
819 /* merge alloc info */
820 for (talloc_info = profile->alloc_info; talloc_info; talloc_info = talloc_info->next) {
821 for (alloc_info = mprof->alloc_info; alloc_info; alloc_info = alloc_info->next) {
822 if (alloc_info->klass == talloc_info->klass) {
823 /* mprof already has a record for the klass, merge */
824 alloc_info->count += talloc_info->count;
825 alloc_info->mem += talloc_info->mem;
830 /* mprof didn't have the info, just copy it over */
831 alloc_info = mono_mempool_alloc0 (prof->mempool, sizeof (AllocInfo));
832 *alloc_info = *talloc_info;
833 alloc_info->next = mprof->alloc_info;
834 mprof->alloc_info = alloc_info->next;
837 /* merge callers info */
838 for (tcaller_info = profile->caller_info; tcaller_info; tcaller_info = tcaller_info->next) {
839 for (caller_info = mprof->caller_info; caller_info; caller_info = caller_info->next) {
840 if (caller_info->caller == tcaller_info->caller) {
841 /* mprof already has a record for the caller method, merge */
842 caller_info->count += tcaller_info->count;
847 /* mprof didn't have the info, just copy it over */
848 caller_info = mono_mempool_alloc0 (prof->mempool, sizeof (CallerInfo));
849 *caller_info = *tcaller_info;
850 caller_info->next = mprof->caller_info;
851 mprof->caller_info = caller_info;
857 merge_thread_data (MonoProfiler *master, MonoProfiler *tprof)
859 master->jit_time += tprof->jit_time;
860 master->methods_jitted += tprof->methods_jitted;
861 if (master->max_jit_time < tprof->max_jit_time) {
862 master->max_jit_time = tprof->max_jit_time;
863 master->max_jit_method = tprof->max_jit_method;
866 g_hash_table_foreach (tprof->methods, (GHFunc)merge_methods, master);
870 simple_method_enter (MonoProfiler *prof, MonoMethod *method)
872 MethodProfile *profile_info;
873 LastCallerInfo *callinfo;
874 GET_THREAD_PROF (prof);
875 /*g_print ("enter %p %s::%s in %d (%p)\n", method, method->klass->name, method->name, GetCurrentThreadId (), prof);*/
876 if (!(profile_info = g_hash_table_lookup (prof->methods, method))) {
877 profile_info = mono_mempool_alloc0 (prof->mempool, sizeof (MethodProfile));
878 MONO_TIMER_INIT (profile_info->u.timer);
879 g_hash_table_insert (prof->methods, method, profile_info);
881 profile_info->count++;
884 MonoMethod *caller = prof->callers->method;
885 for (cinfo = profile_info->caller_info; cinfo; cinfo = cinfo->next) {
886 if (cinfo->caller == caller)
890 cinfo = mono_mempool_alloc0 (prof->mempool, sizeof (CallerInfo));
891 cinfo->caller = caller;
892 cinfo->next = profile_info->caller_info;
893 profile_info->caller_info = cinfo;
897 if (!(callinfo = prof->cstorage)) {
898 callinfo = mono_mempool_alloc (prof->mempool, sizeof (LastCallerInfo));
899 MONO_TIMER_INIT (callinfo->timer);
901 prof->cstorage = prof->cstorage->next;
903 callinfo->method = method;
904 callinfo->next = prof->callers;
905 prof->callers = callinfo;
906 MONO_TIMER_START (callinfo->timer);
910 simple_method_leave (MonoProfiler *prof, MonoMethod *method)
912 MethodProfile *profile_info;
913 LastCallerInfo *callinfo, *newcallinfo = NULL;
915 GET_THREAD_PROF (prof);
916 /*g_print ("leave %p %s::%s in %d (%p)\n", method, method->klass->name, method->name, GetCurrentThreadId (), prof);*/
917 callinfo = prof->callers;
918 /* should really not happen, but we don't catch exceptions events, yet ... */
920 MONO_TIMER_STOP (callinfo->timer);
921 profile_info = g_hash_table_lookup (prof->methods, callinfo->method);
923 profile_info->total += MONO_TIMER_ELAPSED (callinfo->timer);
924 newcallinfo = callinfo->next;
925 callinfo->next = prof->cstorage;
926 prof->cstorage = callinfo;
927 if (callinfo->method == method)
929 callinfo = newcallinfo;
931 prof->callers = newcallinfo;
935 simple_allocation (MonoProfiler *prof, MonoObject *obj, MonoClass *klass)
937 MethodProfile *profile_info;
940 GET_THREAD_PROF (prof);
942 if (!(profile_info = g_hash_table_lookup (prof->methods, prof->callers->method)))
943 g_assert_not_reached ();
945 return; /* fine for now */
948 for (tmp = profile_info->alloc_info; tmp; tmp = tmp->next) {
949 if (tmp->klass == klass)
953 tmp = mono_mempool_alloc0 (prof->mempool, sizeof (AllocInfo));
955 tmp->next = profile_info->alloc_info;
956 profile_info->alloc_info = tmp;
959 if (klass == mono_defaults.string_class) {
960 tmp->mem += sizeof (MonoString) + 2 * mono_string_length ((MonoString*)obj) + 2;
961 } else if (klass->parent == mono_defaults.array_class) {
962 tmp->mem += sizeof (MonoArray) + mono_array_element_size (klass) * mono_array_length ((MonoArray*)obj);
964 tmp->mem += mono_class_instance_size (klass);
969 simple_method_jit (MonoProfiler *prof, MonoMethod *method)
971 GET_THREAD_PROF (prof);
972 prof->methods_jitted++;
973 MONO_TIMER_START (prof->jit_timer);
977 simple_method_end_jit (MonoProfiler *prof, MonoMethod *method, int result)
980 GET_THREAD_PROF (prof);
981 MONO_TIMER_STOP (prof->jit_timer);
982 jtime = MONO_TIMER_ELAPSED (prof->jit_timer);
983 prof->jit_time += jtime;
984 if (jtime > prof->max_jit_time) {
985 prof->max_jit_time = jtime;
986 prof->max_jit_method = method;
991 simple_shutdown (MonoProfiler *prof)
993 GList *profile = NULL;
998 for (tmp = prof->per_thread; tmp; tmp = tmp->next) {
1000 merge_thread_data (prof, tprof);
1003 printf("Total time spent compiling %d methods (sec): %.4g\n", prof->methods_jitted, prof->jit_time);
1004 if (prof->max_jit_method) {
1005 str = method_get_name (prof->max_jit_method);
1006 printf("Slowest method to compile (sec): %.4g: %s\n", prof->max_jit_time, str);
1009 g_hash_table_foreach (prof->methods, (GHFunc)build_profile, &profile);
1010 output_profile (profile);
1011 g_list_free (profile);
1014 g_hash_table_foreach (prof->methods, (GHFunc)build_newobj_profile, &profile);
1015 output_newobj_profile (profile);
1016 g_list_free (profile);
1020 mono_profiler_install_simple (const char *desc)
1023 gchar **args, **ptr;
1024 MonoProfileFlags flags = MONO_PROFILE_ENTER_LEAVE|MONO_PROFILE_JIT_COMPILATION|MONO_PROFILE_ALLOCATIONS;
1030 if (strstr (desc, ":"))
1031 desc = strstr (desc, ":") + 1;
1034 args = g_strsplit (desc ? desc : "", ",", -1);
1036 for (ptr = args; ptr && *ptr; ptr++) {
1037 const char *arg = *ptr;
1039 if (!strcmp (arg, "-time"))
1040 flags &= ~MONO_PROFILE_ENTER_LEAVE;
1042 if (!strcmp (arg, "-alloc"))
1043 flags &= ~MONO_PROFILE_ALLOCATIONS;
1045 fprintf (stderr, "profiler : Unknown argument '%s'.\n", arg);
1051 prof = create_profiler ();
1052 prof->tls_id = TlsAlloc ();
1053 TlsSetValue (prof->tls_id, prof);
1055 mono_profiler_install (prof, simple_shutdown);
1056 /* later do also object creation */
1057 mono_profiler_install_enter_leave (simple_method_enter, simple_method_leave);
1058 mono_profiler_install_jit_compile (simple_method_jit, simple_method_end_jit);
1059 mono_profiler_install_allocation (simple_allocation);
1060 mono_profiler_set_events (flags);
1063 typedef void (*ProfilerInitializer) (const char*);
1064 #define INITIALIZER_NAME "mono_profiler_startup"
1067 mono_profiler_load (const char *desc)
1069 if (!desc || (strcmp ("default", desc) == 0) || (strncmp (desc, "default:", 8) == 0)) {
1070 mono_profiler_install_simple (desc);
1073 const char* col = strchr (desc, ':');
1078 mname = g_memdup (desc, col - desc);
1079 mname [col - desc] = 0;
1081 mname = g_strdup (desc);
1083 libname = g_strdup_printf ("mono-profiler-%s", mname);
1084 path = g_module_build_path (NULL, libname);
1085 pmodule = g_module_open (path, G_MODULE_BIND_LAZY);
1087 ProfilerInitializer func;
1088 if (!g_module_symbol (pmodule, INITIALIZER_NAME, (gpointer *)&func)) {
1089 g_warning ("Cannot find initializer function %s in profiler module: %s", INITIALIZER_NAME, libname);
1094 g_warning ("Error loading profiler module '%s': %s", libname, g_module_error ());