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