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