[runtime] New profiler API.
[mono.git] / mono / metadata / profiler.c
1 /*
2  * Licensed to the .NET Foundation under one or more agreements.
3  * The .NET Foundation licenses this file to you under the MIT license.
4  * See the LICENSE file in the project root for more information.
5  */
6
7 #include <mono/metadata/assembly.h>
8 #include <mono/metadata/gc-internals.h>
9 #include <mono/metadata/mono-config-dirs.h>
10 #include <mono/metadata/mono-debug.h>
11 #include <mono/metadata/profiler-private.h>
12 #include <mono/utils/mono-dl.h>
13 #include <mono/utils/mono-error-internals.h>
14
15 MonoProfilerState mono_profiler_state;
16
17 typedef void (*MonoProfilerInitializer) (const char *);
18
19 #define OLD_INITIALIZER_NAME "mono_profiler_startup"
20 #define NEW_INITIALIZER_NAME "mono_profiler_init"
21
22 static gboolean
23 load_profiler (MonoDl *module, const char *desc, const char *suffix)
24 {
25         if (!module)
26                 return FALSE;
27
28         char *old_name;
29
30         if (suffix)
31                 old_name = g_strdup_printf (OLD_INITIALIZER_NAME "_%s", suffix);
32         else
33                 old_name = g_strdup_printf (OLD_INITIALIZER_NAME);
34
35         MonoProfilerInitializer func;
36
37         char *err;
38
39         if (!(err = mono_dl_symbol (module, old_name, (gpointer) &func))) {
40                 g_warning ("Found old-style startup symbol %s; profiler has not been migrated to the new API.", old_name);
41                 g_free (old_name);
42                 return FALSE;
43         }
44
45         g_free (err);
46         g_free (old_name);
47
48         char *new_name;
49
50         if (suffix)
51                 new_name = g_strdup_printf (NEW_INITIALIZER_NAME "_%s", suffix);
52         else
53                 new_name = g_strdup_printf (NEW_INITIALIZER_NAME);
54
55         if ((err = mono_dl_symbol (module, new_name, (gpointer *) &func))) {
56                 g_free (err);
57                 g_free (new_name);
58                 return FALSE;
59         }
60
61         g_free (new_name);
62
63         func (desc);
64
65         return TRUE;
66 }
67
68 static gboolean
69 load_profiler_from_executable (const char *desc, const char *name)
70 {
71         char *err;
72
73         /*
74          * Some profilers (such as ours) may need to call back into the runtime
75          * from their sampling callback (which is called in async-signal context).
76          * They need to be able to know that all references back to the runtime
77          * have been resolved; otherwise, calling runtime functions may result in
78          * invoking the dynamic linker which is not async-signal-safe. Passing
79          * MONO_DL_EAGER will ask the dynamic linker to resolve everything upfront.
80          */
81         MonoDl *module = mono_dl_open (NULL, MONO_DL_EAGER, &err);
82
83         if (!module) {
84                 g_warning ("Could not open main executable (%s).", err);
85                 g_free (err);
86                 return FALSE;
87         }
88
89         return load_profiler (module, desc, name);
90 }
91
92 static gboolean
93 load_profiler_from_directory (const char *directory, const char *libname, const char *desc)
94 {
95         char* path;
96         void *iter = NULL;
97
98         while ((path = mono_dl_build_path (directory, libname, &iter))) {
99                 // See the comment in load_embedded_profiler ().
100                 MonoDl *module = mono_dl_open (path, MONO_DL_EAGER, NULL);
101
102                 g_free (path);
103
104                 if (module)
105                         return load_profiler (module, desc, NULL);
106         }
107
108         return FALSE;
109 }
110
111 static gboolean
112 load_profiler_from_installation (const char *libname, const char *desc)
113 {
114         char *err;
115         MonoDl *module = mono_dl_open_runtime_lib (libname, MONO_DL_EAGER, &err);
116
117         g_free (err);
118
119         if (module)
120                 return load_profiler (module, desc, NULL);
121
122         return FALSE;
123 }
124
125 void
126 mono_profiler_load (const char *desc)
127 {
128         mono_gc_base_init ();
129
130         if (!desc || !strcmp ("default", desc))
131                 desc = "log:report";
132
133         const char *col = strchr (desc, ':');
134         char *mname;
135
136         if (col != NULL) {
137                 mname = (char *) g_memdup (desc, col - desc + 1);
138                 mname [col - desc] = 0;
139         } else
140                 mname = g_strdup (desc);
141
142         if (!load_profiler_from_executable (desc, mname)) {
143                 char *libname = g_strdup_printf ("mono-profiler-%s", mname);
144                 gboolean res = load_profiler_from_installation (libname, desc);
145
146                 if (!res && mono_config_get_assemblies_dir ())
147                         res = load_profiler_from_directory (mono_assembly_getrootdir (), libname, desc);
148
149                 if (!res)
150                         res = load_profiler_from_directory (NULL, libname, desc);
151
152                 if (!res)
153                         g_warning ("The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", mname, libname);
154
155                 g_free (libname);
156         }
157
158         g_free (mname);
159 }
160
161 MonoProfilerHandle
162 mono_profiler_install (MonoProfiler *prof)
163 {
164         MonoProfilerHandle handle = g_new0 (struct _MonoProfilerDesc, 1);
165
166         handle->prof = prof;
167         handle->next = mono_profiler_state.profilers;
168
169         mono_profiler_state.profilers = handle;
170
171         return handle;
172 }
173
174 void
175 mono_profiler_set_coverage_filter_callback (MonoProfilerHandle handle, MonoProfilerCoverageFilterCallback cb)
176 {
177         InterlockedWritePointer (&handle->coverage_filter, (gpointer) cb);
178 }
179
180 static void
181 initialize_coverage (void)
182 {
183         mono_os_mutex_init (&mono_profiler_state.coverage_mutex);
184         mono_profiler_state.coverage_hash = g_hash_table_new (NULL, NULL);
185 }
186
187 static void
188 lazy_initialize_coverage (void)
189 {
190         mono_lazy_initialize (&mono_profiler_state.coverage_status, initialize_coverage);
191 }
192
193 static void
194 coverage_lock (void)
195 {
196         mono_os_mutex_lock (&mono_profiler_state.coverage_mutex);
197 }
198
199 static void
200 coverage_unlock (void)
201 {
202         mono_os_mutex_unlock (&mono_profiler_state.coverage_mutex);
203 }
204
205 void
206 mono_profiler_get_coverage_data (MonoProfilerHandle handle, MonoMethod *method, MonoProfilerCoverageCallback cb)
207 {
208         lazy_initialize_coverage ();
209
210         coverage_lock ();
211
212         MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method);
213
214         coverage_unlock ();
215
216         if (!info)
217                 return;
218
219         MonoError error;
220         MonoMethodHeader *header = mono_method_get_header_checked (method, &error);
221         mono_error_assert_ok (&error);
222
223         guint32 size;
224
225         const unsigned char *start = mono_method_header_get_code (header, &size, NULL);
226         const unsigned char *end = start - size;
227         MonoDebugMethodInfo *minfo = mono_debug_lookup_method (method);
228
229         for (guint32 i = 0; i < info->entries; i++) {
230                 guchar *cil_code = info->data [i].cil_code;
231
232                 if (cil_code && cil_code >= start && cil_code < end) {
233                         guint32 offset = cil_code - start;
234
235                         MonoProfilerCoverageData data = {
236                                 .method = method,
237                                 .il_offset = offset,
238                                 .counter = info->data [i].count,
239                                 .line = 1,
240                                 .column = 1,
241                         };
242
243                         if (minfo) {
244                                 MonoDebugSourceLocation *loc = mono_debug_method_lookup_location (minfo, offset);
245
246                                 if (loc) {
247                                         data.file_name = g_strdup (loc->source_file);
248                                         data.line = loc->row;
249                                         data.column = loc->column;
250
251                                         mono_debug_free_source_location (loc);
252                                 }
253                         }
254
255                         cb (handle->prof, &data);
256
257                         g_free ((char *) data.file_name);
258                 }
259         }
260
261         mono_metadata_free_mh (header);
262 }
263
264 MonoProfilerCoverageInfo *
265 mono_profiler_coverage_alloc (MonoMethod *method, guint32 entries)
266 {
267         lazy_initialize_coverage ();
268
269         gboolean cover = FALSE;
270
271         for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
272                 MonoProfilerCoverageFilterCallback cb = handle->coverage_filter;
273
274                 if (cb)
275                         cover |= cb (handle->prof, method);
276         }
277
278         if (!cover)
279                 return NULL;
280
281         coverage_lock ();
282
283         MonoProfilerCoverageInfo *info = g_malloc0 (sizeof (MonoProfilerCoverageInfo) + SIZEOF_VOID_P * 2 * entries);
284
285         info->entries = entries;
286
287         g_hash_table_insert (mono_profiler_state.coverage_hash, method, info);
288
289         coverage_unlock ();
290
291         return info;
292 }
293
294 void
295 mono_profiler_coverage_free (MonoMethod *method)
296 {
297         lazy_initialize_coverage ();
298
299         coverage_lock ();
300
301         MonoProfilerCoverageInfo *info = g_hash_table_lookup (mono_profiler_state.coverage_hash, method);
302
303         if (info) {
304                 g_hash_table_remove (mono_profiler_state.coverage_hash, method);
305                 g_free (info);
306         }
307
308         coverage_unlock ();
309 }
310
311 mono_bool
312 mono_profiler_enable_sampling (MonoProfilerHandle handle)
313 {
314         if (mono_profiler_state.startup_done)
315                 return FALSE;
316
317         if (mono_profiler_state.sampling_owner)
318                 return TRUE;
319
320         mono_profiler_state.sampling_owner = handle;
321         mono_profiler_state.sample_mode = MONO_PROFILER_SAMPLE_MODE_NONE;
322         mono_profiler_state.sample_freq = 100;
323         mono_os_sem_init (&mono_profiler_state.sampling_semaphore, 0);
324
325         return TRUE;
326 }
327
328 mono_bool
329 mono_profiler_set_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode mode, uint64_t freq)
330 {
331         if (handle != mono_profiler_state.sampling_owner)
332                 return FALSE;
333
334         mono_profiler_state.sample_mode = mode;
335         mono_profiler_state.sample_freq = freq;
336
337         mono_os_sem_post (&mono_profiler_state.sampling_semaphore);
338
339         return TRUE;
340 }
341
342 mono_bool
343 mono_profiler_get_sample_mode (MonoProfilerHandle handle, MonoProfilerSampleMode *mode, uint64_t *freq)
344 {
345         if (mode)
346                 *mode = mono_profiler_state.sample_mode;
347
348         if (freq)
349                 *freq = mono_profiler_state.sample_freq;
350
351         return handle == mono_profiler_state.sampling_owner;
352 }
353
354 gboolean
355 mono_profiler_sampling_enabled (void)
356 {
357         return !!mono_profiler_state.sampling_owner;
358 }
359
360 void
361 mono_profiler_sampling_thread_sleep (void)
362 {
363         mono_os_sem_wait (&mono_profiler_state.sampling_semaphore, MONO_SEM_FLAGS_NONE);
364 }
365
366 mono_bool
367 mono_profiler_enable_allocations (void)
368 {
369         if (mono_profiler_state.startup_done)
370                 return FALSE;
371
372         mono_profiler_state.allocations = TRUE;
373
374         return TRUE;
375 }
376
377 void
378 mono_profiler_set_call_instrumentation_filter_callback (MonoProfilerHandle handle, MonoProfilerCallInstrumentationFilterCallback cb)
379 {
380         InterlockedWritePointer (&handle->call_instrumentation_filter, (gpointer) cb);
381 }
382
383 gboolean
384 mono_profiler_should_instrument_method (MonoMethod *method, gboolean entry)
385 {
386         MonoProfilerCallInstrumentationFlags flags = MONO_PROFILER_CALL_INSTRUMENTATION_NONE;
387
388         for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
389                 MonoProfilerCallInstrumentationFilterCallback cb = handle->call_instrumentation_filter;
390
391                 if (cb)
392                         flags |= cb (handle->prof, method);
393         }
394
395         if (entry)
396                 return flags & MONO_PROFILER_CALL_INSTRUMENTATION_PROLOGUE;
397         else
398                 return flags & MONO_PROFILER_CALL_INSTRUMENTATION_EPILOGUE;
399 }
400
401 void
402 mono_profiler_started (void)
403 {
404         mono_profiler_state.startup_done = TRUE;
405 }
406
407 void
408 mono_profiler_cleanup (void)
409 {
410         for (MonoProfilerHandle handle = mono_profiler_state.profilers; handle; handle = handle->next) {
411 #define _MONO_PROFILER_EVENT(name) \
412         mono_profiler_set_ ## name ## _callback (handle, NULL); \
413         g_assert (!handle->name ## _cb);
414 #define MONO_PROFILER_EVENT_0(name, type) \
415         _MONO_PROFILER_EVENT(name)
416 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
417         _MONO_PROFILER_EVENT(name)
418 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
419         _MONO_PROFILER_EVENT(name)
420 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
421         _MONO_PROFILER_EVENT(name)
422 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
423         _MONO_PROFILER_EVENT(name)
424 #include <mono/metadata/profiler-events.h>
425 #undef MONO_PROFILER_EVENT_0
426 #undef MONO_PROFILER_EVENT_1
427 #undef MONO_PROFILER_EVENT_2
428 #undef MONO_PROFILER_EVENT_3
429 #undef MONO_PROFILER_EVENT_4
430 #undef _MONO_PROFILER_EVENT
431         }
432
433 #define _MONO_PROFILER_EVENT(name, type) \
434         g_assert (!mono_profiler_state.name ## _count);
435 #define MONO_PROFILER_EVENT_0(name, type) \
436         _MONO_PROFILER_EVENT(name, type)
437 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
438         _MONO_PROFILER_EVENT(name, type)
439 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
440         _MONO_PROFILER_EVENT(name, type)
441 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
442         _MONO_PROFILER_EVENT(name, type)
443 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
444         _MONO_PROFILER_EVENT(name, type)
445 #include <mono/metadata/profiler-events.h>
446 #undef MONO_PROFILER_EVENT_0
447 #undef MONO_PROFILER_EVENT_1
448 #undef MONO_PROFILER_EVENT_2
449 #undef MONO_PROFILER_EVENT_3
450 #undef MONO_PROFILER_EVENT_4
451 #undef _MONO_PROFILER_EVENT
452 }
453
454 static void
455 update_callback (volatile gpointer *location, gpointer new_, volatile gint32 *counter)
456 {
457         gpointer old;
458
459         do {
460                 old = InterlockedReadPointer (location);
461         } while (InterlockedCompareExchangePointer (location, new_, old) != old);
462
463         /*
464          * At this point, we could have installed a NULL callback while the counter
465          * is still non-zero, i.e. setting the callback and modifying the counter
466          * is not a single atomic operation. This is fine as we make sure callbacks
467          * are non-NULL before invoking them (see the code below that generates the
468          * raise functions), and besides, updating callbacks at runtime is an
469          * inherently racy operation.
470          */
471
472         if (old)
473                 InterlockedDecrement (counter);
474
475         if (new_)
476                 InterlockedIncrement (counter);
477 }
478
479 #define _MONO_PROFILER_EVENT(name, type) \
480         void \
481         mono_profiler_set_ ## name ## _callback (MonoProfilerHandle handle, MonoProfiler ## type ## Callback cb) \
482         { \
483                 update_callback (&handle->name ## _cb, (gpointer) cb, &mono_profiler_state.name ## _count); \
484         }
485 #define MONO_PROFILER_EVENT_0(name, type) \
486         _MONO_PROFILER_EVENT(name, type)
487 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
488         _MONO_PROFILER_EVENT(name, type)
489 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
490         _MONO_PROFILER_EVENT(name, type)
491 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
492         _MONO_PROFILER_EVENT(name, type)
493 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
494         _MONO_PROFILER_EVENT(name, type)
495 #include <mono/metadata/profiler-events.h>
496 #undef MONO_PROFILER_EVENT_0
497 #undef MONO_PROFILER_EVENT_1
498 #undef MONO_PROFILER_EVENT_2
499 #undef MONO_PROFILER_EVENT_3
500 #undef MONO_PROFILER_EVENT_4
501 #undef _MONO_PROFILER_EVENT
502
503 #define _MONO_PROFILER_EVENT(name, type, params, args) \
504         void \
505         mono_profiler_raise_ ## name params \
506         { \
507                 for (MonoProfilerHandle h = mono_profiler_state.profilers; h; h = h->next) { \
508                         MonoProfiler ## type ## Callback cb = h->name ## _cb; \
509                         if (cb) \
510                                 cb args; \
511                 } \
512         }
513 #define MONO_PROFILER_EVENT_0(name, type) \
514         _MONO_PROFILER_EVENT(name, type, (void), (h->prof))
515 #define MONO_PROFILER_EVENT_1(name, type, arg1_type, arg1_name) \
516         _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name), (h->prof, arg1_name))
517 #define MONO_PROFILER_EVENT_2(name, type, arg1_type, arg1_name, arg2_type, arg2_name) \
518         _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name), (h->prof, arg1_name, arg2_name))
519 #define MONO_PROFILER_EVENT_3(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name) \
520         _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name), (h->prof, arg1_name, arg2_name, arg3_name))
521 #define MONO_PROFILER_EVENT_4(name, type, arg1_type, arg1_name, arg2_type, arg2_name, arg3_type, arg3_name, arg4_type, arg4_name) \
522         _MONO_PROFILER_EVENT(name, type, (arg1_type arg1_name, arg2_type arg2_name, arg3_type arg3_name, arg4_type arg4_name), (h->prof, arg1_name, arg2_name, arg3_name, arg4_name))
523 #include <mono/metadata/profiler-events.h>
524 #undef MONO_PROFILER_EVENT_0
525 #undef MONO_PROFILER_EVENT_1
526 #undef MONO_PROFILER_EVENT_2
527 #undef MONO_PROFILER_EVENT_3
528 #undef MONO_PROFILER_EVENT_4
529 #undef _MONO_PROFILER_EVENT