2 * log.c: mono log profiler
5 * Paolo Molaro (lupus@ximian.com)
6 * Alex Rønne Petersen (alexrp@xamarin.com)
7 * Johan Lorensson (lateralusx.github@gmail.com)
9 * Copyright 2010 Novell, Inc (http://www.novell.com)
10 * Copyright 2011 Xamarin Inc (http://www.xamarin.com)
11 * Licensed under the MIT license. See LICENSE file in the project root for full license information.
16 #include <mono/metadata/assembly.h>
17 #include <mono/metadata/assembly-internals.h>
18 #include <mono/metadata/class-internals.h>
19 #include <mono/metadata/debug-helpers.h>
20 #include <mono/metadata/icall-internals.h>
21 #include <mono/metadata/loader.h>
22 #include <mono/metadata/loader-internals.h>
23 #include <mono/metadata/metadata-internals.h>
24 #include <mono/metadata/mono-config.h>
25 #include <mono/metadata/mono-gc.h>
26 #include <mono/metadata/mono-perfcounters.h>
27 #include <mono/metadata/object-internals.h>
28 #include <mono/metadata/runtime.h>
29 #include <mono/metadata/tabledefs.h>
30 #include <mono/metadata/threads.h>
31 #include <mono/metadata/threads-types.h>
32 #include <mono/mini/jit.h>
33 #include <mono/utils/atomic.h>
34 #include <mono/utils/hazard-pointer.h>
35 #include <mono/utils/lock-free-alloc.h>
36 #include <mono/utils/lock-free-queue.h>
37 #include <mono/utils/mono-conc-hashtable.h>
38 #include <mono/utils/mono-coop-mutex.h>
39 #include <mono/utils/mono-counters.h>
40 #include <mono/utils/mono-logger-internals.h>
41 #include <mono/utils/mono-linked-list-set.h>
42 #include <mono/utils/mono-membar.h>
43 #include <mono/utils/mono-mmap.h>
44 #include <mono/utils/mono-os-mutex.h>
45 #include <mono/utils/mono-os-semaphore.h>
46 #include <mono/utils/mono-threads.h>
47 #include <mono/utils/mono-threads-api.h>
48 #include <mono/utils/mono-threads-coop.h>
49 #include <mono/utils/mono-error-internals.h>
50 #include <mono/utils/mono-publib.h>
51 #include <mono/utils/os-event.h>
52 #include <mono/utils/w32subset.h>
63 #if defined(__APPLE__)
64 #include <mach/mach_time.h>
67 #include <netinet/in.h>
69 #ifdef HAVE_SYS_MMAN_H
73 #include <sys/socket.h>
75 #if defined (HAVE_SYS_ZLIB)
85 #define HAVE_COMMAND_PIPES 1
88 // Statistics for internal profiler data structures.
89 static gint32 sample_allocations_ctr
,
90 buffer_allocations_ctr
;
92 // Statistics for profiler events.
93 static gint32 sync_points_ctr
,
99 heap_root_registers_ctr
,
100 heap_root_unregisters_ctr
,
105 gc_handle_creations_ctr
,
106 gc_handle_deletions_ctr
,
109 finalize_object_begins_ctr
,
110 finalize_object_ends_ctr
,
114 assembly_unloads_ctr
,
119 method_exception_exits_ctr
,
122 exception_throws_ctr
,
123 exception_clauses_ctr
,
136 counter_descriptors_ctr
,
138 perfcounter_descriptors_ctr
,
139 perfcounter_samples_ctr
;
141 // Pending data to be written to the log, for a single thread.
142 // Threads periodically flush their own LogBuffers by calling safe_send
143 typedef struct _LogBuffer LogBuffer
;
145 // Next (older) LogBuffer in processing queue
150 gboolean has_ptr_base
;
152 uintptr_t method_base
;
153 uintptr_t last_method
;
157 // Bytes allocated for this LogBuffer
160 // Start of currently unused space in buffer
161 unsigned char* cursor
;
163 // Pointer to start-of-structure-plus-size (for convenience)
164 unsigned char* buf_end
;
166 // Start of data in buffer. Contents follow "buffer format" described above.
167 unsigned char buf
[1];
171 MonoLinkedListSetNode node
;
173 // Was this thread added to the LLS?
176 // Did this thread detach from the runtime? Only used for internal profiler threads.
179 // The current log buffer for this thread.
182 // Methods referenced by events in `buffer`, see `MethodInfo`.
185 // Current call depth for enter/leave events.
188 // Indicates whether this thread is currently writing to its `buffer`.
191 // Has this thread written a thread end event to `buffer`?
194 // Stored in `buffer_lock_state` to take the exclusive lock.
196 } MonoProfilerThread
;
198 // Default value in `profiler_tls` for new threads.
199 #define MONO_PROFILER_THREAD_ZERO ((MonoProfilerThread *) NULL)
201 // This is written to `profiler_tls` to indicate that a thread has stopped.
202 #define MONO_PROFILER_THREAD_DEAD ((MonoProfilerThread *) -1)
204 // Do not use these TLS macros directly unless you know what you're doing.
206 #define PROF_TLS_SET(VAL) mono_thread_info_set_tools_data (VAL)
207 #define PROF_TLS_GET mono_thread_info_get_tools_data
212 return (uintptr_t) mono_native_thread_id_get ();
219 return (uintptr_t) GetCurrentProcessId ();
221 return (uintptr_t) getpid ();
225 #define ENABLED(EVT) (!!(log_config.effective_mask & (EVT)))
226 #define ENABLE(EVT) do { log_config.effective_mask |= (EVT); } while (0)
227 #define DISABLE(EVT) do { log_config.effective_mask &= ~(EVT); } while (0)
230 * These macros should be used when writing an event to a log buffer. They
231 * take care of a bunch of stuff that can be repetitive and error-prone, such
232 * as attaching the current thread, acquiring/releasing the buffer lock,
233 * incrementing the event counter, expanding the log buffer, etc. They also
234 * create a scope so that it's harder to leak the LogBuffer pointer, which can
235 * be problematic as the pointer is unstable when the buffer lock isn't
238 * If the calling thread is already attached, these macros will not alter its
239 * attach mode (i.e. whether it's added to the LLS). If the thread is not
240 * attached, init_thread () will be called with add_to_lls = TRUE.
243 #define ENTER_LOG(COUNTER, BUFFER, SIZE) \
245 MonoProfilerThread *thread__ = get_thread (); \
246 g_assert (!thread__->busy && "Why are we trying to write a new event while already writing one?"); \
247 thread__->busy = TRUE; \
248 mono_atomic_inc_i32 ((COUNTER)); \
249 if (thread__->attached) \
251 LogBuffer *BUFFER = ensure_logbuf_unsafe (thread__, (SIZE))
253 #define EXIT_LOG_EXPLICIT(SEND) \
255 send_log_unsafe (TRUE); \
256 if (thread__->attached) \
258 thread__->busy = FALSE; \
261 // Pass these to EXIT_LOG_EXPLICIT () for easier reading.
263 #define NO_SEND FALSE
265 #define EXIT_LOG EXIT_LOG_EXPLICIT (DO_SEND)
267 typedef struct _BinaryObject BinaryObject
;
268 struct _BinaryObject
{
274 typedef struct MonoCounterAgent
{
275 MonoCounter
*counter
;
276 // MonoCounterAgent specific data :
281 struct MonoCounterAgent
*next
;
284 typedef struct _PerfCounterAgent PerfCounterAgent
;
285 struct _PerfCounterAgent
{
286 PerfCounterAgent
*next
;
296 struct _MonoProfiler
{
297 MonoProfilerHandle handle
;
300 #if defined (HAVE_SYS_ZLIB)
305 uint64_t startup_time
;
309 mach_timebase_info_data_t timebase_info
;
310 #elif defined (HOST_WIN32)
311 LARGE_INTEGER pcounter_freq
;
314 #if HAVE_API_SUPPORT_WIN32_PIPE_OPEN_CLOSE && !defined (HOST_WIN32)
320 #ifdef HAVE_COMMAND_PIPES
326 MonoLinkedListSet profiler_thread_list
;
327 volatile gint32 buffer_lock_state
;
328 volatile gint32 buffer_lock_exclusive_intent
;
330 volatile gint32 runtime_inited
;
331 volatile gint32 detach_threads
;
332 volatile gint32 in_shutdown
;
334 MonoSemType attach_threads_sem
;
335 MonoSemType detach_threads_sem
;
337 MonoNativeThreadId helper_thread
;
338 MonoOSEvent helper_thread_exited
;
340 MonoNativeThreadId writer_thread
;
341 volatile gint32 run_writer_thread
;
342 MonoOSEvent writer_thread_exited
;
343 MonoLockFreeQueue writer_queue
;
344 MonoSemType writer_queue_sem
;
346 MonoLockFreeAllocSizeClass writer_entry_size_class
;
347 MonoLockFreeAllocator writer_entry_allocator
;
349 MonoConcurrentHashTable
*method_table
;
350 mono_mutex_t method_table_mutex
;
352 MonoNativeThreadId dumper_thread
;
353 volatile gint32 run_dumper_thread
;
354 MonoOSEvent dumper_thread_exited
;
355 MonoLockFreeQueue dumper_queue
;
356 MonoSemType dumper_queue_sem
;
358 MonoLockFreeAllocSizeClass sample_size_class
;
359 MonoLockFreeAllocator sample_allocator
;
360 MonoLockFreeQueue sample_reuse_queue
;
362 BinaryObject
*binary_objects
;
364 volatile gint32 heapshot_requested
;
366 guint64 last_hs_time
;
367 gboolean do_heap_walk
;
369 mono_mutex_t counters_mutex
;
370 MonoCounterAgent
*counters
;
371 PerfCounterAgent
*perfcounters
;
372 guint32 counters_index
;
374 MonoCoopMutex api_mutex
;
377 static ProfilerConfig log_config
;
378 static struct _MonoProfiler log_profiler
;
381 MonoLockFreeQueueNode node
;
386 #define WRITER_ENTRY_BLOCK_SIZE (mono_pagesize ())
394 #define TICKS_PER_SEC 1000000000LL
395 #define TICKS_PER_MSEC (TICKS_PER_SEC / 1000)
401 uint64_t time
= mach_absolute_time ();
403 time
*= log_profiler
.timebase_info
.numer
;
404 time
/= log_profiler
.timebase_info
.denom
;
407 #elif defined (HOST_WIN32)
410 QueryPerformanceCounter (&value
);
412 return value
.QuadPart
* TICKS_PER_SEC
/ log_profiler
.pcounter_freq
.QuadPart
;
413 #elif defined (CLOCK_MONOTONIC)
414 struct timespec tspec
;
416 clock_gettime (CLOCK_MONOTONIC
, &tspec
);
418 return ((uint64_t) tspec
.tv_sec
* TICKS_PER_SEC
+ tspec
.tv_nsec
);
422 gettimeofday (&tv
, NULL
);
424 return ((uint64_t) tv
.tv_sec
* TICKS_PER_SEC
+ tv
.tv_usec
* 1000);
432 mach_timebase_info (&log_profiler
.timebase_info
);
433 #elif defined (HOST_WIN32)
434 QueryPerformanceFrequency (&log_profiler
.pcounter_freq
);
437 uint64_t time_start
= current_time ();
439 for (int i
= 0; i
< 256; ++i
)
442 uint64_t time_end
= current_time ();
444 log_profiler
.timer_overhead
= (time_end
- time_start
) / 256;
448 pstrdup (const char *s
)
450 int len
= strlen (s
) + 1;
451 char *p
= (char *) g_malloc (len
);
456 #define BUFFER_SIZE (4096 * 16)
458 /* Worst-case size in bytes of a 64-bit value encoded with LEB128. */
459 #define LEB128_SIZE 10
461 /* Size of a value encoded as a single byte. */
462 #undef BYTE_SIZE // mach/i386/vm_param.h on OS X defines this to 8, but it isn't used for anything.
465 /* Size in bytes of the event prefix (ID + time). */
466 #define EVENT_SIZE (BYTE_SIZE + LEB128_SIZE)
469 alloc_buffer (int size
)
471 return mono_valloc (NULL
, size
, MONO_MMAP_READ
| MONO_MMAP_WRITE
| MONO_MMAP_ANON
| MONO_MMAP_PRIVATE
, MONO_MEM_ACCOUNT_PROFILER
);
475 free_buffer (void *buf
, int size
)
477 mono_vfree (buf
, size
, MONO_MEM_ACCOUNT_PROFILER
);
481 create_buffer (uintptr_t tid
, int bytes
)
483 LogBuffer
* buf
= (LogBuffer
*) alloc_buffer (MAX (BUFFER_SIZE
, bytes
));
485 mono_atomic_inc_i32 (&buffer_allocations_ctr
);
487 buf
->size
= BUFFER_SIZE
;
488 buf
->time_base
= current_time ();
489 buf
->last_time
= buf
->time_base
;
490 buf
->buf_end
= (unsigned char *) buf
+ buf
->size
;
491 buf
->cursor
= buf
->buf
;
492 buf
->thread_id
= tid
;
498 * Must be called with the reader lock held if thread is the current thread, or
499 * the exclusive lock if thread is a different thread. However, if thread is
500 * the current thread, and init_thread () was called with add_to_lls = FALSE,
501 * then no locking is necessary.
504 init_buffer_state (MonoProfilerThread
*thread
)
506 thread
->buffer
= create_buffer (thread
->node
.key
, 0);
507 thread
->methods
= NULL
;
511 clear_hazard_pointers (MonoThreadHazardPointers
*hp
)
513 mono_hazard_pointer_clear (hp
, 0);
514 mono_hazard_pointer_clear (hp
, 1);
515 mono_hazard_pointer_clear (hp
, 2);
518 static MonoProfilerThread
*
519 init_thread (gboolean add_to_lls
)
521 MonoProfilerThread
*thread
= PROF_TLS_GET ();
523 g_assert (thread
!= MONO_PROFILER_THREAD_DEAD
&& "Why are we trying to resurrect a stopped thread?");
526 * Sometimes we may try to initialize a thread twice. One example is the
527 * main thread: We initialize it when setting up the profiler, but we will
528 * also get a thread_start () callback for it. Another example is when
529 * attaching new threads to the runtime: We may get a gc_alloc () callback
530 * for that thread's thread object (where we initialize it), soon followed
531 * by a thread_start () callback.
533 * These cases are harmless anyhow. Just return if we've already done the
534 * initialization work.
536 if (thread
!= MONO_PROFILER_THREAD_ZERO
)
539 thread
= g_malloc (sizeof (MonoProfilerThread
));
540 thread
->node
.key
= thread_id ();
541 thread
->attached
= add_to_lls
;
542 thread
->did_detach
= FALSE
;
543 thread
->call_depth
= 0;
544 thread
->busy
= FALSE
;
545 thread
->ended
= FALSE
;
547 init_buffer_state (thread
);
549 thread
->small_id
= mono_thread_info_register_small_id ();
552 * Some internal profiler threads don't need to be cleaned up
553 * by the main thread on shutdown.
556 MonoThreadHazardPointers
*hp
= mono_hazard_pointer_get ();
557 g_assert (mono_lls_insert (&log_profiler
.profiler_thread_list
, hp
, &thread
->node
) && "Why can't we insert the thread in the LLS?");
558 clear_hazard_pointers (hp
);
561 g_assert (PROF_TLS_SET (thread
));
566 // Only valid if init_thread () was called with add_to_lls = FALSE.
568 deinit_thread (MonoProfilerThread
*thread
)
570 g_assert (!thread
->attached
&& "Why are we manually freeing an attached thread?");
573 PROF_TLS_SET (MONO_PROFILER_THREAD_DEAD
);
576 static MonoProfilerThread
*
579 return init_thread (TRUE
);
582 // Only valid if init_thread () was called with add_to_lls = FALSE.
584 ensure_logbuf_unsafe (MonoProfilerThread
*thread
, int bytes
)
586 LogBuffer
*old
= thread
->buffer
;
588 if (old
->cursor
+ bytes
< old
->buf_end
)
591 LogBuffer
*new_
= create_buffer (thread
->node
.key
, bytes
);
593 thread
->buffer
= new_
;
599 * This is a reader/writer spin lock of sorts used to protect log buffers.
600 * When a thread modifies its own log buffer, it increments the reader
601 * count. When a thread wants to access log buffers of other threads, it
602 * takes the exclusive lock.
604 * `buffer_lock_state` holds the reader count in its lower 16 bits, and
605 * the small ID of the thread currently holding the exclusive (writer)
606 * lock in its upper 16 bits. Both can be zero. It's important that the
607 * whole lock state is a single word that can be read/written atomically
608 * to avoid race conditions where there could end up being readers while
609 * the writer lock is held.
611 * The lock is writer-biased. When a thread wants to take the exclusive
612 * lock, it increments `buffer_lock_exclusive_intent` which will make new
613 * readers spin until it's back to zero, then takes the exclusive lock
614 * once the reader count has reached zero. After releasing the exclusive
615 * lock, it decrements `buffer_lock_exclusive_intent`, which, when it
616 * reaches zero again, allows readers to increment the reader count.
618 * The writer bias is necessary because we take the exclusive lock in
619 * `gc_event ()` during STW. If the writer bias was not there, and a
620 * program had a large number of threads, STW-induced pauses could be
621 * significantly longer than they have to be. Also, we emit periodic
622 * sync points from the helper thread, which requires taking the
623 * exclusive lock, and we need those to arrive with a reasonably
624 * consistent frequency so that readers don't have to queue up too many
625 * events between sync points.
627 * The lock does not support recursion.
630 buffer_lock_helper (void);
636 * If the thread holding the exclusive lock tries to modify the
637 * reader count, just make it a no-op. This way, we also avoid
638 * invoking the GC safe point macros below, which could break if
639 * done from a thread that is currently the initiator of STW.
641 * In other words, we rely on the fact that the GC thread takes
642 * the exclusive lock in the gc_event () callback when the world
645 if (mono_atomic_load_i32 (&log_profiler
.buffer_lock_state
) != get_thread ()->small_id
<< 16) {
646 /* We can get some sgen events (for example gc_handle_deleted)
647 * from threads that are unattached to the runtime (but that
648 * are attached to the profiler). In that case, avoid mono
649 * thread state transition to GC Safe around the loop, since
650 * the thread won't be participating in Mono's suspension
653 MonoThreadInfo
*info
= mono_thread_info_current_unchecked ();
655 /* Why do we enter Unsafe and then Safe? Because we
656 * might be called from a native-to-managed wrapper
657 * from a P/Invoke. In that case the thread is already
658 * in GC Safe, and the state machine doesn't allow
659 * recursive GC Safe transitions. (On the other hand
660 * it's ok to enter GC Unsafe multiple times - the
661 * state machine will tell us it's a noop.).
663 MONO_ENTER_GC_UNSAFE_WITH_INFO (info
);
664 MONO_ENTER_GC_SAFE_WITH_INFO (info
);
666 buffer_lock_helper ();
668 MONO_EXIT_GC_SAFE_WITH_INFO
;
669 MONO_EXIT_GC_UNSAFE_WITH_INFO
;
671 buffer_lock_helper ();
674 mono_memory_barrier ();
678 buffer_lock_helper (void)
684 // Hold off if a thread wants to take the exclusive lock.
685 while (mono_atomic_load_i32 (&log_profiler
.buffer_lock_exclusive_intent
))
686 mono_thread_info_yield ();
688 old
= mono_atomic_load_i32 (&log_profiler
.buffer_lock_state
);
690 // Is a thread holding the exclusive lock?
692 mono_thread_info_yield ();
697 } while (mono_atomic_cas_i32 (&log_profiler
.buffer_lock_state
, new_
, old
) != old
);
703 mono_memory_barrier ();
705 gint32 state
= mono_atomic_load_i32 (&log_profiler
.buffer_lock_state
);
707 // See the comment in buffer_lock ().
708 if (state
== get_thread ()->small_id
<< 16)
711 g_assert (state
&& "Why are we decrementing a zero reader count?");
712 g_assert (!(state
>> 16) && "Why is the exclusive lock held?");
714 mono_atomic_dec_i32 (&log_profiler
.buffer_lock_state
);
718 buffer_lock_excl (void)
720 gint32 new_
= get_thread ()->small_id
<< 16;
722 g_assert (mono_atomic_load_i32 (&log_profiler
.buffer_lock_state
) != new_
&& "Why are we taking the exclusive lock twice?");
724 mono_atomic_inc_i32 (&log_profiler
.buffer_lock_exclusive_intent
);
728 while (mono_atomic_cas_i32 (&log_profiler
.buffer_lock_state
, new_
, 0))
729 mono_thread_info_yield ();
733 mono_memory_barrier ();
737 buffer_unlock_excl (void)
739 mono_memory_barrier ();
741 gint32 state
= mono_atomic_load_i32 (&log_profiler
.buffer_lock_state
);
742 gint32 excl
= state
>> 16;
744 g_assert (excl
&& "Why is the exclusive lock not held?");
745 g_assert (excl
== get_thread ()->small_id
&& "Why does another thread hold the exclusive lock?");
746 g_assert (!(state
& 0xFFFF) && "Why are there readers when the exclusive lock is held?");
748 mono_atomic_store_i32 (&log_profiler
.buffer_lock_state
, 0);
749 mono_atomic_dec_i32 (&log_profiler
.buffer_lock_exclusive_intent
);
753 encode_uleb128 (uint64_t value
, uint8_t *buf
, uint8_t **endbuf
)
758 uint8_t b
= value
& 0x7f;
761 if (value
!= 0) /* more bytes to come */
771 encode_sleb128 (intptr_t value
, uint8_t *buf
, uint8_t **endbuf
)
774 int negative
= (value
< 0);
775 unsigned int size
= sizeof (intptr_t) * 8;
783 /* the following is unnecessary if the
784 * implementation of >>= uses an arithmetic rather
785 * than logical shift for a signed left operand
789 value
|= - ((intptr_t) 1 <<(size
- 7));
791 /* sign bit of byte is second high order bit (0x40) */
792 if ((value
== 0 && !(byte
& 0x40)) ||
793 (value
== -1 && (byte
& 0x40)))
805 emit_byte (LogBuffer
*logbuffer
, int value
)
807 logbuffer
->cursor
[0] = value
;
810 g_assert (logbuffer
->cursor
<= logbuffer
->buf_end
&& "Why are we writing past the buffer end?");
814 emit_value (LogBuffer
*logbuffer
, int value
)
816 encode_uleb128 (value
, logbuffer
->cursor
, &logbuffer
->cursor
);
818 g_assert (logbuffer
->cursor
<= logbuffer
->buf_end
&& "Why are we writing past the buffer end?");
822 emit_time (LogBuffer
*logbuffer
, uint64_t value
)
824 uint64_t tdiff
= value
- logbuffer
->last_time
;
825 encode_uleb128 (tdiff
, logbuffer
->cursor
, &logbuffer
->cursor
);
826 logbuffer
->last_time
= value
;
828 g_assert (logbuffer
->cursor
<= logbuffer
->buf_end
&& "Why are we writing past the buffer end?");
832 emit_event_time (LogBuffer
*logbuffer
, int event
, uint64_t time
)
834 emit_byte (logbuffer
, event
);
835 emit_time (logbuffer
, time
);
839 emit_event (LogBuffer
*logbuffer
, int event
)
841 emit_event_time (logbuffer
, event
, current_time ());
845 emit_svalue (LogBuffer
*logbuffer
, int64_t value
)
847 encode_sleb128 (value
, logbuffer
->cursor
, &logbuffer
->cursor
);
849 g_assert (logbuffer
->cursor
<= logbuffer
->buf_end
&& "Why are we writing past the buffer end?");
853 emit_uvalue (LogBuffer
*logbuffer
, uint64_t value
)
855 encode_uleb128 (value
, logbuffer
->cursor
, &logbuffer
->cursor
);
857 g_assert (logbuffer
->cursor
<= logbuffer
->buf_end
&& "Why are we writing past the buffer end?");
861 emit_ptr (LogBuffer
*logbuffer
, const void *ptr
)
863 if (!logbuffer
->has_ptr_base
) {
864 logbuffer
->ptr_base
= (uintptr_t) ptr
;
865 logbuffer
->has_ptr_base
= TRUE
;
868 emit_svalue (logbuffer
, (intptr_t) ptr
- logbuffer
->ptr_base
);
870 g_assert (logbuffer
->cursor
<= logbuffer
->buf_end
&& "Why are we writing past the buffer end?");
874 emit_method_inner (LogBuffer
*logbuffer
, void *method
)
876 if (!logbuffer
->method_base
) {
877 logbuffer
->method_base
= (intptr_t) method
;
878 logbuffer
->last_method
= (intptr_t) method
;
881 encode_sleb128 ((intptr_t) ((char *) method
- (char *) logbuffer
->last_method
), logbuffer
->cursor
, &logbuffer
->cursor
);
882 logbuffer
->last_method
= (intptr_t) method
;
884 g_assert (logbuffer
->cursor
<= logbuffer
->buf_end
&& "Why are we writing past the buffer end?");
888 inc_method_ref_count (MonoMethod
*method
)
890 mono_image_addref (mono_class_get_image (mono_method_get_class (method
)));
894 dec_method_ref_count (MonoMethod
*method
)
896 mono_image_close (mono_class_get_image (mono_method_get_class (method
)));
899 // The reader lock must be held.
901 register_method_local (MonoMethod
*method
, MonoJitInfo
*ji
)
903 MonoProfilerThread
*thread
= get_thread ();
905 if (!mono_conc_hashtable_lookup (log_profiler
.method_table
, method
)) {
906 MethodInfo
*info
= (MethodInfo
*) g_malloc (sizeof (MethodInfo
));
908 info
->method
= method
;
910 info
->time
= current_time ();
912 GPtrArray
*arr
= thread
->methods
? thread
->methods
: (thread
->methods
= g_ptr_array_new ());
914 g_ptr_array_add (arr
, info
);
915 inc_method_ref_count (method
);
920 emit_method (LogBuffer
*logbuffer
, MonoMethod
*method
)
922 register_method_local (method
, NULL
);
923 emit_method_inner (logbuffer
, method
);
927 emit_obj (LogBuffer
*logbuffer
, void *ptr
)
929 if (!logbuffer
->obj_base
)
930 logbuffer
->obj_base
= (uintptr_t) ptr
>> 3;
932 emit_svalue (logbuffer
, ((uintptr_t) ptr
>> 3) - logbuffer
->obj_base
);
934 g_assert (logbuffer
->cursor
<= logbuffer
->buf_end
&& "Why are we writing past the buffer end?");
938 emit_string (LogBuffer
*logbuffer
, const char *str
, size_t size
)
942 for (; i
< size
; i
++) {
945 emit_byte (logbuffer
, str
[i
]);
948 emit_byte (logbuffer
, '\0');
952 emit_double (LogBuffer
*logbuffer
, double value
)
955 unsigned char buffer
[8];
956 memcpy (buffer
, &value
, 8);
957 #if G_BYTE_ORDER == G_BIG_ENDIAN
958 for (i
= 7; i
>= 0; i
--)
960 for (i
= 0; i
< 8; i
++)
962 emit_byte (logbuffer
, buffer
[i
]);
966 write_int16 (char *buf
, int32_t value
)
969 for (i
= 0; i
< 2; ++i
) {
977 write_int32 (char *buf
, int32_t value
)
980 for (i
= 0; i
< 4; ++i
) {
988 write_int64 (char *buf
, int64_t value
)
991 for (i
= 0; i
< 8; ++i
) {
999 write_header_string (char *p
, const char *str
)
1001 size_t len
= strlen (str
) + 1;
1003 p
= write_int32 (p
, len
);
1012 const char *args
= log_profiler
.args
;
1013 const char *arch
= mono_config_get_cpu ();
1014 const char *os
= mono_config_get_os ();
1016 char *hbuf
= g_malloc (
1017 sizeof (gint32
) /* header id */ +
1018 sizeof (gint8
) /* major version */ +
1019 sizeof (gint8
) /* minor version */ +
1020 sizeof (gint8
) /* data version */ +
1021 sizeof (gint8
) /* word size */ +
1022 sizeof (gint64
) /* startup time */ +
1023 sizeof (gint64
) /* startup time (nanoseconds) */ +
1024 sizeof (gint32
) /* timer overhead */ +
1025 sizeof (gint32
) /* flags */ +
1026 sizeof (gint32
) /* process id */ +
1027 sizeof (gint16
) /* command port */ +
1028 sizeof (gint32
) + strlen (args
) + 1 /* arguments */ +
1029 sizeof (gint32
) + strlen (arch
) + 1 /* architecture */ +
1030 sizeof (gint32
) + strlen (os
) + 1 /* operating system */
1034 p
= write_int32 (p
, LOG_HEADER_ID
);
1035 *p
++ = LOG_VERSION_MAJOR
;
1036 *p
++ = LOG_VERSION_MINOR
;
1037 *p
++ = LOG_DATA_VERSION
;
1038 *p
++ = sizeof (void *);
1039 p
= write_int64 (p
, ((uint64_t) time (NULL
)) * 1000);
1040 p
= write_int64 (p
, current_time ());
1041 p
= write_int32 (p
, log_profiler
.timer_overhead
);
1042 p
= write_int32 (p
, 0); /* flags */
1043 p
= write_int32 (p
, process_id ());
1044 p
= write_int16 (p
, log_profiler
.command_port
);
1045 p
= write_header_string (p
, args
);
1046 p
= write_header_string (p
, arch
);
1047 p
= write_header_string (p
, os
);
1049 #if defined (HAVE_SYS_ZLIB)
1050 if (log_profiler
.gzfile
) {
1051 gzwrite (log_profiler
.gzfile
, hbuf
, p
- hbuf
);
1055 fwrite (hbuf
, p
- hbuf
, 1, log_profiler
.file
);
1056 fflush (log_profiler
.file
);
1063 * Must be called with the reader lock held if thread is the current thread, or
1064 * the exclusive lock if thread is a different thread. However, if thread is
1065 * the current thread, and init_thread () was called with add_to_lls = FALSE,
1066 * then no locking is necessary.
1069 send_buffer (MonoProfilerThread
*thread
)
1071 WriterQueueEntry
*entry
= mono_lock_free_alloc (&log_profiler
.writer_entry_allocator
);
1072 entry
->methods
= thread
->methods
;
1073 entry
->buffer
= thread
->buffer
;
1075 mono_lock_free_queue_node_init (&entry
->node
, FALSE
);
1077 mono_lock_free_queue_enqueue (&log_profiler
.writer_queue
, &entry
->node
);
1078 mono_os_sem_post (&log_profiler
.writer_queue_sem
);
1082 free_thread (gpointer p
)
1084 MonoProfilerThread
*thread
= p
;
1086 if (!thread
->ended
) {
1088 * The thread is being cleaned up by the main thread during
1089 * shutdown. This typically happens for internal runtime
1090 * threads. We need to synthesize a thread end event.
1093 mono_atomic_inc_i32 (&thread_ends_ctr
);
1095 LogBuffer
*buf
= ensure_logbuf_unsafe (thread
,
1096 EVENT_SIZE
/* event */ +
1097 BYTE_SIZE
/* type */ +
1098 LEB128_SIZE
/* tid */
1101 emit_event (buf
, TYPE_END_UNLOAD
| TYPE_METADATA
);
1102 emit_byte (buf
, TYPE_THREAD
);
1103 emit_ptr (buf
, (void *) thread
->node
.key
);
1106 send_buffer (thread
);
1112 remove_thread (MonoProfilerThread
*thread
)
1114 MonoThreadHazardPointers
*hp
= mono_hazard_pointer_get ();
1116 if (mono_lls_remove (&log_profiler
.profiler_thread_list
, hp
, &thread
->node
))
1117 mono_thread_hazardous_try_free (thread
, free_thread
);
1119 clear_hazard_pointers (hp
);
1123 dump_buffer (LogBuffer
*buf
)
1129 dump_buffer (buf
->next
);
1131 if (buf
->cursor
- buf
->buf
) {
1132 p
= write_int32 (p
, BUF_ID
);
1133 p
= write_int32 (p
, buf
->cursor
- buf
->buf
);
1134 p
= write_int64 (p
, buf
->time_base
);
1135 p
= write_int64 (p
, buf
->ptr_base
);
1136 p
= write_int64 (p
, buf
->obj_base
);
1137 p
= write_int64 (p
, buf
->thread_id
);
1138 p
= write_int64 (p
, buf
->method_base
);
1140 #if defined (HAVE_SYS_ZLIB)
1141 if (log_profiler
.gzfile
) {
1142 gzwrite (log_profiler
.gzfile
, hbuf
, p
- hbuf
);
1143 gzwrite (log_profiler
.gzfile
, buf
->buf
, buf
->cursor
- buf
->buf
);
1147 fwrite (hbuf
, p
- hbuf
, 1, log_profiler
.file
);
1148 fwrite (buf
->buf
, buf
->cursor
- buf
->buf
, 1, log_profiler
.file
);
1149 fflush (log_profiler
.file
);
1153 free_buffer (buf
, buf
->size
);
1156 // Only valid if init_thread () was called with add_to_lls = FALSE.
1158 send_log_unsafe (gboolean if_needed
)
1160 MonoProfilerThread
*thread
= get_thread ();
1162 if (!if_needed
|| (if_needed
&& thread
->buffer
->next
)) {
1163 send_buffer (thread
);
1164 init_buffer_state (thread
);
1171 const char *aotid
= mono_runtime_get_aotid ();
1176 int alen
= strlen (aotid
) + 1;
1178 ENTER_LOG (&aot_ids_ctr
, logbuffer
,
1179 EVENT_SIZE
/* event */ +
1183 emit_event (logbuffer
, TYPE_META
| TYPE_AOT_ID
);
1184 memcpy (logbuffer
->cursor
, aotid
, alen
);
1185 logbuffer
->cursor
+= alen
;
1190 // Assumes that the exclusive lock is held.
1192 sync_point_flush (void)
1194 g_assert (mono_atomic_load_i32 (&log_profiler
.buffer_lock_state
) == get_thread ()->small_id
<< 16 && "Why don't we hold the exclusive lock?");
1196 MONO_LLS_FOREACH_SAFE (&log_profiler
.profiler_thread_list
, MonoProfilerThread
, thread
) {
1197 g_assert (thread
->attached
&& "Why is a thread in the LLS not attached?");
1199 send_buffer (thread
);
1200 init_buffer_state (thread
);
1201 } MONO_LLS_FOREACH_SAFE_END
1204 // Assumes that the exclusive lock is held.
1206 sync_point_mark (MonoProfilerSyncPointType type
)
1208 g_assert (mono_atomic_load_i32 (&log_profiler
.buffer_lock_state
) == get_thread ()->small_id
<< 16 && "Why don't we hold the exclusive lock?");
1210 ENTER_LOG (&sync_points_ctr
, logbuffer
,
1211 EVENT_SIZE
/* event */ +
1212 BYTE_SIZE
/* type */
1215 emit_event (logbuffer
, TYPE_META
| TYPE_SYNC_POINT
);
1216 emit_byte (logbuffer
, type
);
1218 EXIT_LOG_EXPLICIT (NO_SEND
);
1220 send_log_unsafe (FALSE
);
1223 // Assumes that the exclusive lock is held.
1225 sync_point (MonoProfilerSyncPointType type
)
1227 sync_point_flush ();
1228 sync_point_mark (type
);
1232 gc_reference (MonoObject
*obj
, MonoClass
*klass
, uintptr_t size
, uintptr_t num
, MonoObject
**refs
, uintptr_t *offsets
, void *data
)
1234 /* account for object alignment in the heap */
1238 ENTER_LOG (&heap_objects_ctr
, logbuffer
,
1239 EVENT_SIZE
/* event */ +
1240 LEB128_SIZE
/* obj */ +
1241 LEB128_SIZE
/* vtable */ +
1242 LEB128_SIZE
/* size */ +
1243 BYTE_SIZE
/* generation */ +
1244 LEB128_SIZE
/* num */ +
1246 LEB128_SIZE
/* offset */ +
1247 LEB128_SIZE
/* ref */
1251 emit_event (logbuffer
, TYPE_HEAP_OBJECT
| TYPE_HEAP
);
1252 emit_obj (logbuffer
, obj
);
1253 emit_ptr (logbuffer
, mono_object_get_vtable_internal (obj
));
1254 emit_value (logbuffer
, size
);
1255 emit_byte (logbuffer
, mono_gc_get_generation (obj
));
1256 emit_value (logbuffer
, num
);
1258 uintptr_t last_offset
= 0;
1260 for (int i
= 0; i
< num
; ++i
) {
1261 emit_value (logbuffer
, offsets
[i
] - last_offset
);
1262 last_offset
= offsets
[i
];
1263 emit_obj (logbuffer
, refs
[i
]);
1272 gc_roots (MonoProfiler
*prof
, uint64_t num
, const mono_byte
*const *addresses
, MonoObject
*const *objects
)
1274 ENTER_LOG (&heap_roots_ctr
, logbuffer
,
1275 EVENT_SIZE
/* event */ +
1276 LEB128_SIZE
/* num */ +
1278 LEB128_SIZE
/* address */ +
1279 LEB128_SIZE
/* object */
1283 emit_event (logbuffer
, TYPE_HEAP_ROOT
| TYPE_HEAP
);
1284 emit_value (logbuffer
, num
);
1286 for (int i
= 0; i
< num
; ++i
) {
1287 emit_ptr (logbuffer
, addresses
[i
]);
1288 emit_obj (logbuffer
, objects
[i
]);
1295 gc_root_register (MonoProfiler
*prof
, const mono_byte
*start
, size_t size
, MonoGCRootSource source
, const void *key
, const char *name
)
1297 // We don't write raw domain/context pointers in metadata events.
1299 case MONO_ROOT_SOURCE_DOMAIN
:
1301 key
= (void *)(uintptr_t) mono_domain_get_id ((MonoDomain
*) key
);
1303 case MONO_ROOT_SOURCE_CONTEXT_STATIC
:
1304 key
= (void *)(uintptr_t) mono_context_get_id ((MonoAppContext
*) key
);
1310 int name_len
= name
? strlen (name
) + 1 : 0;
1312 ENTER_LOG (&heap_root_registers_ctr
, logbuffer
,
1313 EVENT_SIZE
/* event */ +
1314 LEB128_SIZE
/* start */ +
1315 LEB128_SIZE
/* size */ +
1316 BYTE_SIZE
/* source */ +
1317 LEB128_SIZE
/* key */ +
1321 emit_event (logbuffer
, TYPE_HEAP_ROOT_REGISTER
| TYPE_HEAP
);
1322 emit_ptr (logbuffer
, start
);
1323 emit_uvalue (logbuffer
, size
);
1324 emit_byte (logbuffer
, source
);
1325 emit_ptr (logbuffer
, key
);
1326 emit_string (logbuffer
, name
, name_len
);
1332 gc_root_deregister (MonoProfiler
*prof
, const mono_byte
*start
)
1334 ENTER_LOG (&heap_root_unregisters_ctr
, logbuffer
,
1335 EVENT_SIZE
/* event */ +
1336 LEB128_SIZE
/* start */
1339 emit_event (logbuffer
, TYPE_HEAP_ROOT_UNREGISTER
| TYPE_HEAP
);
1340 emit_ptr (logbuffer
, start
);
1346 trigger_heapshot (void)
1348 // Rely on the finalization callback triggering a GC.
1349 mono_atomic_store_i32 (&log_profiler
.heapshot_requested
, 1);
1350 mono_gc_finalize_notify ();
1354 process_heapshot (void)
1356 if (mono_atomic_load_i32 (&log_profiler
.heapshot_requested
))
1357 mono_gc_collect (mono_gc_max_generation ());
1360 #define ALL_GC_EVENTS_MASK (PROFLOG_GC_EVENTS | PROFLOG_GC_MOVE_EVENTS | PROFLOG_GC_ROOT_EVENTS)
1363 gc_event (MonoProfiler
*profiler
, MonoProfilerGCEvent ev
, uint32_t generation
, gboolean is_serial
)
1365 gboolean is_major
= generation
== mono_gc_max_generation ();
1367 if (ENABLED (PROFLOG_GC_EVENTS
)) {
1368 ENTER_LOG (&gc_events_ctr
, logbuffer
,
1369 EVENT_SIZE
/* event */ +
1370 BYTE_SIZE
/* gc event */ +
1371 BYTE_SIZE
/* generation */
1374 emit_event (logbuffer
, TYPE_GC_EVENT
| TYPE_GC
);
1375 emit_byte (logbuffer
, ev
);
1376 emit_byte (logbuffer
, generation
);
1382 case MONO_GC_EVENT_PRE_STOP_WORLD_LOCKED
:
1383 switch (log_config
.hs_mode
) {
1384 case MONO_PROFILER_HEAPSHOT_NONE
:
1385 log_profiler
.do_heap_walk
= FALSE
;
1387 case MONO_PROFILER_HEAPSHOT_MAJOR
:
1388 log_profiler
.do_heap_walk
= is_major
;
1390 case MONO_PROFILER_HEAPSHOT_ON_DEMAND
:
1393 case MONO_PROFILER_HEAPSHOT_X_GC
:
1394 log_profiler
.do_heap_walk
= !(log_profiler
.gc_count
% log_config
.hs_freq_gc
);
1396 case MONO_PROFILER_HEAPSHOT_X_MS
:
1397 log_profiler
.do_heap_walk
= (current_time () - log_profiler
.last_hs_time
) / TICKS_PER_MSEC
>= log_config
.hs_freq_ms
;
1400 g_assert_not_reached ();
1404 * heapshot_requested is set either because a heapshot was triggered
1405 * manually (through the API or command server) or because we're doing
1406 * a shutdown heapshot. Either way, a manually triggered heapshot
1407 * overrides any decision we made in the switch above.
1409 if (is_major
&& is_serial
&& mono_atomic_load_i32 (&log_profiler
.heapshot_requested
)) {
1410 log_profiler
.do_heap_walk
= TRUE
;
1411 } else if (log_profiler
.do_heap_walk
&& (!is_major
|| !is_serial
)) {
1412 /* Do a heap walk later, when we get invoked from the finalizer in serial mode */
1413 trigger_heapshot ();
1414 log_profiler
.do_heap_walk
= FALSE
;
1417 if (ENABLED (PROFLOG_GC_ROOT_EVENTS
) &&
1418 (log_config
.always_do_root_report
|| log_profiler
.do_heap_walk
))
1419 mono_profiler_set_gc_roots_callback (log_profiler
.handle
, gc_roots
);
1422 * Ensure that no thread can be in the middle of writing to
1423 * a buffer when the world stops...
1425 buffer_lock_excl ();
1428 case MONO_GC_EVENT_POST_STOP_WORLD
:
1430 * ... So that we now have a consistent view of all buffers.
1431 * This allows us to flush them. We need to do this because
1432 * they may contain object allocation events that need to be
1433 * committed to the log file before any object move events
1434 * that will be produced during this GC.
1436 if (ENABLED (ALL_GC_EVENTS_MASK
))
1437 sync_point (SYNC_POINT_WORLD_STOP
);
1439 // Surround heapshots with HEAP_START/HEAP_END events.
1440 if (log_profiler
.do_heap_walk
) {
1441 ENTER_LOG (&heap_starts_ctr
, logbuffer
,
1442 EVENT_SIZE
/* event */
1445 emit_event (logbuffer
, TYPE_HEAP_START
| TYPE_HEAP
);
1451 case MONO_GC_EVENT_START
:
1453 log_profiler
.gc_count
++;
1456 case MONO_GC_EVENT_PRE_START_WORLD
:
1457 mono_profiler_set_gc_roots_callback (log_profiler
.handle
, NULL
);
1459 if (log_profiler
.do_heap_walk
) {
1460 g_assert (is_major
&& is_serial
);
1461 mono_gc_walk_heap (0, gc_reference
, NULL
);
1463 ENTER_LOG (&heap_ends_ctr
, logbuffer
,
1464 EVENT_SIZE
/* event */
1467 emit_event (logbuffer
, TYPE_HEAP_END
| TYPE_HEAP
);
1471 log_profiler
.do_heap_walk
= FALSE
;
1472 log_profiler
.last_hs_time
= current_time ();
1474 mono_atomic_store_i32 (&log_profiler
.heapshot_requested
, 0);
1478 * Similarly, we must now make sure that any object moves
1479 * written to the GC thread's buffer are flushed. Otherwise,
1480 * object allocation events for certain addresses could come
1481 * after the move events that made those addresses available.
1483 if (ENABLED (ALL_GC_EVENTS_MASK
))
1484 sync_point_mark (SYNC_POINT_WORLD_START
);
1487 case MONO_GC_EVENT_POST_START_WORLD_UNLOCKED
:
1489 * Finally, it is safe to allow other threads to write to
1490 * their buffers again.
1492 buffer_unlock_excl ();
1501 gc_resize (MonoProfiler
*profiler
, uintptr_t new_size
)
1503 ENTER_LOG (&gc_resizes_ctr
, logbuffer
,
1504 EVENT_SIZE
/* event */ +
1505 LEB128_SIZE
/* new size */
1508 emit_event (logbuffer
, TYPE_GC_RESIZE
| TYPE_GC
);
1509 emit_uvalue (logbuffer
, new_size
);
1516 MonoMethod
* methods
[MAX_FRAMES
];
1517 int32_t il_offsets
[MAX_FRAMES
];
1518 int32_t native_offsets
[MAX_FRAMES
];
1522 walk_stack (MonoMethod
*method
, int32_t native_offset
, int32_t il_offset
, mono_bool managed
, void* data
)
1524 FrameData
*frame
= (FrameData
*)data
;
1525 if (method
&& frame
->count
< log_config
.num_frames
) {
1526 frame
->il_offsets
[frame
->count
] = il_offset
;
1527 frame
->native_offsets
[frame
->count
] = native_offset
;
1528 frame
->methods
[frame
->count
++] = method
;
1530 return frame
->count
== log_config
.num_frames
;
1534 * a note about stack walks: they can cause more profiler events to fire,
1535 * so we need to make sure they don't happen after we started emitting an
1536 * event, hence the collect_bt/emit_bt split.
1539 collect_bt (FrameData
*data
)
1542 mono_stack_walk_no_il (walk_stack
, data
);
1546 emit_bt (LogBuffer
*logbuffer
, FrameData
*data
)
1548 emit_value (logbuffer
, data
->count
);
1551 emit_method (logbuffer
, data
->methods
[--data
->count
]);
1555 gc_alloc (MonoProfiler
*prof
, MonoObject
*obj
)
1557 int do_bt
= (!log_config
.enter_leave
&& mono_atomic_load_i32 (&log_profiler
.runtime_inited
) && log_config
.num_frames
) ? TYPE_ALLOC_BT
: 0;
1559 uintptr_t len
= mono_object_get_size_internal (obj
);
1560 /* account for object alignment in the heap */
1567 ENTER_LOG (&gc_allocs_ctr
, logbuffer
,
1568 EVENT_SIZE
/* event */ +
1569 LEB128_SIZE
/* vtable */ +
1570 LEB128_SIZE
/* obj */ +
1571 LEB128_SIZE
/* size */ +
1573 LEB128_SIZE
/* count */ +
1575 LEB128_SIZE
/* method */
1580 emit_event (logbuffer
, do_bt
| TYPE_ALLOC
);
1581 emit_ptr (logbuffer
, mono_object_get_vtable_internal (obj
));
1582 emit_obj (logbuffer
, obj
);
1583 emit_value (logbuffer
, len
);
1586 emit_bt (logbuffer
, &data
);
1592 gc_moves (MonoProfiler
*prof
, MonoObject
*const *objects
, uint64_t num
)
1594 ENTER_LOG (&gc_moves_ctr
, logbuffer
,
1595 EVENT_SIZE
/* event */ +
1596 LEB128_SIZE
/* num */ +
1598 LEB128_SIZE
/* object */
1602 emit_event (logbuffer
, TYPE_GC_MOVE
| TYPE_GC
);
1603 emit_value (logbuffer
, num
);
1605 for (int i
= 0; i
< num
; ++i
)
1606 emit_obj (logbuffer
, objects
[i
]);
1612 gc_handle (MonoProfiler
*prof
, int op
, MonoGCHandleType type
, uint32_t handle
, MonoObject
*obj
)
1614 int do_bt
= !log_config
.enter_leave
&& mono_atomic_load_i32 (&log_profiler
.runtime_inited
) && log_config
.num_frames
;
1620 gint32
*ctr
= op
== MONO_PROFILER_GC_HANDLE_CREATED
? &gc_handle_creations_ctr
: &gc_handle_deletions_ctr
;
1622 ENTER_LOG (ctr
, logbuffer
,
1623 EVENT_SIZE
/* event */ +
1624 LEB128_SIZE
/* type */ +
1625 LEB128_SIZE
/* handle */ +
1626 (op
== MONO_PROFILER_GC_HANDLE_CREATED
? (
1627 LEB128_SIZE
/* obj */
1630 LEB128_SIZE
/* count */ +
1632 LEB128_SIZE
/* method */
1637 if (op
== MONO_PROFILER_GC_HANDLE_CREATED
)
1638 emit_event (logbuffer
, (do_bt
? TYPE_GC_HANDLE_CREATED_BT
: TYPE_GC_HANDLE_CREATED
) | TYPE_GC
);
1639 else if (op
== MONO_PROFILER_GC_HANDLE_DESTROYED
)
1640 emit_event (logbuffer
, (do_bt
? TYPE_GC_HANDLE_DESTROYED_BT
: TYPE_GC_HANDLE_DESTROYED
) | TYPE_GC
);
1642 g_assert_not_reached ();
1644 emit_value (logbuffer
, type
);
1645 emit_value (logbuffer
, handle
);
1647 if (op
== MONO_PROFILER_GC_HANDLE_CREATED
)
1648 emit_obj (logbuffer
, obj
);
1651 emit_bt (logbuffer
, &data
);
1657 gc_handle_created (MonoProfiler
*prof
, uint32_t handle
, MonoGCHandleType type
, MonoObject
*obj
)
1659 gc_handle (prof
, MONO_PROFILER_GC_HANDLE_CREATED
, type
, handle
, obj
);
1663 gc_handle_deleted (MonoProfiler
*prof
, uint32_t handle
, MonoGCHandleType type
)
1665 gc_handle (prof
, MONO_PROFILER_GC_HANDLE_DESTROYED
, type
, handle
, NULL
);
1669 finalize_begin (MonoProfiler
*prof
)
1671 ENTER_LOG (&finalize_begins_ctr
, buf
,
1672 EVENT_SIZE
/* event */
1675 emit_event (buf
, TYPE_GC_FINALIZE_START
| TYPE_GC
);
1681 finalize_end (MonoProfiler
*prof
)
1683 process_heapshot ();
1685 if (ENABLED (PROFLOG_GC_FINALIZATION_EVENTS
)) {
1686 ENTER_LOG (&finalize_ends_ctr
, buf
,
1687 EVENT_SIZE
/* event */
1690 emit_event (buf
, TYPE_GC_FINALIZE_END
| TYPE_GC
);
1697 finalize_object_begin (MonoProfiler
*prof
, MonoObject
*obj
)
1699 ENTER_LOG (&finalize_object_begins_ctr
, buf
,
1700 EVENT_SIZE
/* event */ +
1701 LEB128_SIZE
/* obj */
1704 emit_event (buf
, TYPE_GC_FINALIZE_OBJECT_START
| TYPE_GC
);
1705 emit_obj (buf
, obj
);
1711 finalize_object_end (MonoProfiler
*prof
, MonoObject
*obj
)
1713 ENTER_LOG (&finalize_object_ends_ctr
, buf
,
1714 EVENT_SIZE
/* event */ +
1715 LEB128_SIZE
/* obj */
1718 emit_event (buf
, TYPE_GC_FINALIZE_OBJECT_END
| TYPE_GC
);
1719 emit_obj (buf
, obj
);
1725 push_nesting (char *p
, MonoClass
*klass
)
1730 nesting
= mono_class_get_nesting_type (klass
);
1732 p
= push_nesting (p
, nesting
);
1736 name
= m_class_get_name (klass
);
1737 nspace
= m_class_get_name_space (klass
);
1740 p
+= strlen (nspace
);
1750 type_name (MonoClass
*klass
)
1754 push_nesting (buf
, klass
);
1755 p
= (char *) g_malloc (strlen (buf
) + 1);
1761 image_loaded (MonoProfiler
*prof
, MonoImage
*image
)
1763 const char *name
= mono_image_get_filename (image
);
1764 int nlen
= strlen (name
) + 1;
1765 const char *guid
= mono_image_get_guid (image
);
1767 // Dynamic images don't have a GUID set.
1771 int glen
= strlen (guid
) + 1;
1773 ENTER_LOG (&image_loads_ctr
, logbuffer
,
1774 EVENT_SIZE
/* event */ +
1775 BYTE_SIZE
/* type */ +
1776 LEB128_SIZE
/* image */ +
1781 emit_event (logbuffer
, TYPE_END_LOAD
| TYPE_METADATA
);
1782 emit_byte (logbuffer
, TYPE_IMAGE
);
1783 emit_ptr (logbuffer
, image
);
1784 memcpy (logbuffer
->cursor
, name
, nlen
);
1785 logbuffer
->cursor
+= nlen
;
1786 memcpy (logbuffer
->cursor
, guid
, glen
);
1787 logbuffer
->cursor
+= glen
;
1793 image_unloaded (MonoProfiler
*prof
, MonoImage
*image
)
1795 const char *name
= mono_image_get_filename (image
);
1796 int nlen
= strlen (name
) + 1;
1798 ENTER_LOG (&image_unloads_ctr
, logbuffer
,
1799 EVENT_SIZE
/* event */ +
1800 BYTE_SIZE
/* type */ +
1801 LEB128_SIZE
/* image */ +
1805 emit_event (logbuffer
, TYPE_END_UNLOAD
| TYPE_METADATA
);
1806 emit_byte (logbuffer
, TYPE_IMAGE
);
1807 emit_ptr (logbuffer
, image
);
1808 memcpy (logbuffer
->cursor
, name
, nlen
);
1809 logbuffer
->cursor
+= nlen
;
1815 assembly_loaded (MonoProfiler
*prof
, MonoAssembly
*assembly
)
1817 char *name
= mono_stringify_assembly_name (mono_assembly_get_name_internal (assembly
));
1818 int nlen
= strlen (name
) + 1;
1819 MonoImage
*image
= mono_assembly_get_image_internal (assembly
);
1821 ENTER_LOG (&assembly_loads_ctr
, logbuffer
,
1822 EVENT_SIZE
/* event */ +
1823 BYTE_SIZE
/* type */ +
1824 LEB128_SIZE
/* assembly */ +
1825 LEB128_SIZE
/* image */ +
1829 emit_event (logbuffer
, TYPE_END_LOAD
| TYPE_METADATA
);
1830 emit_byte (logbuffer
, TYPE_ASSEMBLY
);
1831 emit_ptr (logbuffer
, assembly
);
1832 emit_ptr (logbuffer
, image
);
1833 memcpy (logbuffer
->cursor
, name
, nlen
);
1834 logbuffer
->cursor
+= nlen
;
1842 assembly_unloaded (MonoProfiler
*prof
, MonoAssembly
*assembly
)
1844 char *name
= mono_stringify_assembly_name (mono_assembly_get_name_internal (assembly
));
1845 int nlen
= strlen (name
) + 1;
1846 MonoImage
*image
= mono_assembly_get_image_internal (assembly
);
1848 ENTER_LOG (&assembly_unloads_ctr
, logbuffer
,
1849 EVENT_SIZE
/* event */ +
1850 BYTE_SIZE
/* type */ +
1851 LEB128_SIZE
/* assembly */ +
1852 LEB128_SIZE
/* image */ +
1856 emit_event (logbuffer
, TYPE_END_UNLOAD
| TYPE_METADATA
);
1857 emit_byte (logbuffer
, TYPE_ASSEMBLY
);
1858 emit_ptr (logbuffer
, assembly
);
1859 emit_ptr (logbuffer
, image
);
1860 memcpy (logbuffer
->cursor
, name
, nlen
);
1861 logbuffer
->cursor
+= nlen
;
1869 class_loaded (MonoProfiler
*prof
, MonoClass
*klass
)
1873 if (mono_atomic_load_i32 (&log_profiler
.runtime_inited
))
1874 name
= mono_type_get_name (m_class_get_byval_arg (klass
));
1876 name
= type_name (klass
);
1878 int nlen
= strlen (name
) + 1;
1879 MonoImage
*image
= mono_class_get_image (klass
);
1881 ENTER_LOG (&class_loads_ctr
, logbuffer
,
1882 EVENT_SIZE
/* event */ +
1883 BYTE_SIZE
/* type */ +
1884 LEB128_SIZE
/* klass */ +
1885 LEB128_SIZE
/* image */ +
1889 emit_event (logbuffer
, TYPE_END_LOAD
| TYPE_METADATA
);
1890 emit_byte (logbuffer
, TYPE_CLASS
);
1891 emit_ptr (logbuffer
, klass
);
1892 emit_ptr (logbuffer
, image
);
1893 memcpy (logbuffer
->cursor
, name
, nlen
);
1894 logbuffer
->cursor
+= nlen
;
1898 if (mono_atomic_load_i32 (&log_profiler
.runtime_inited
))
1905 vtable_loaded (MonoProfiler
*prof
, MonoVTable
*vtable
)
1907 MonoClass
*klass
= mono_vtable_class_internal (vtable
);
1908 MonoDomain
*domain
= mono_vtable_domain_internal (vtable
);
1909 uint32_t domain_id
= domain
? mono_domain_get_id (domain
) : 0;
1911 ENTER_LOG (&vtable_loads_ctr
, logbuffer
,
1912 EVENT_SIZE
/* event */ +
1913 BYTE_SIZE
/* type */ +
1914 LEB128_SIZE
/* vtable */ +
1915 LEB128_SIZE
/* domain id */ +
1916 LEB128_SIZE
/* klass */
1919 emit_event (logbuffer
, TYPE_END_LOAD
| TYPE_METADATA
);
1920 emit_byte (logbuffer
, TYPE_VTABLE
);
1921 emit_ptr (logbuffer
, vtable
);
1922 emit_ptr (logbuffer
, (void *)(uintptr_t) domain_id
);
1923 emit_ptr (logbuffer
, klass
);
1929 method_enter (MonoProfiler
*prof
, MonoMethod
*method
, MonoProfilerCallContext
*ctx
)
1931 if (get_thread ()->call_depth
++ <= log_config
.max_call_depth
) {
1932 ENTER_LOG (&method_entries_ctr
, logbuffer
,
1933 EVENT_SIZE
/* event */ +
1934 LEB128_SIZE
/* method */
1937 emit_event (logbuffer
, TYPE_ENTER
| TYPE_METHOD
);
1938 emit_method (logbuffer
, method
);
1945 method_leave (MonoProfiler
*prof
, MonoMethod
*method
, MonoProfilerCallContext
*ctx
)
1947 if (--get_thread ()->call_depth
<= log_config
.max_call_depth
) {
1948 ENTER_LOG (&method_exits_ctr
, logbuffer
,
1949 EVENT_SIZE
/* event */ +
1950 LEB128_SIZE
/* method */
1953 emit_event (logbuffer
, TYPE_LEAVE
| TYPE_METHOD
);
1954 emit_method (logbuffer
, method
);
1961 tailcall (MonoProfiler
*prof
, MonoMethod
*method
, MonoMethod
*target
)
1963 method_leave (prof
, method
, NULL
);
1967 method_exc_leave (MonoProfiler
*prof
, MonoMethod
*method
, MonoObject
*exc
)
1969 if (--get_thread ()->call_depth
<= log_config
.max_call_depth
) {
1970 ENTER_LOG (&method_exception_exits_ctr
, logbuffer
,
1971 EVENT_SIZE
/* event */ +
1972 LEB128_SIZE
/* method */
1975 emit_event (logbuffer
, TYPE_EXC_LEAVE
| TYPE_METHOD
);
1976 emit_method (logbuffer
, method
);
1982 static MonoProfilerCallInstrumentationFlags
1983 method_filter (MonoProfiler
*prof
, MonoMethod
*method
)
1985 if (log_config
.callspec
.len
> 0 &&
1986 !mono_callspec_eval (method
, &log_config
.callspec
))
1987 return MONO_PROFILER_CALL_INSTRUMENTATION_NONE
;
1989 return MONO_PROFILER_CALL_INSTRUMENTATION_ENTER
|
1990 MONO_PROFILER_CALL_INSTRUMENTATION_LEAVE
|
1991 MONO_PROFILER_CALL_INSTRUMENTATION_TAIL_CALL
|
1992 MONO_PROFILER_CALL_INSTRUMENTATION_EXCEPTION_LEAVE
;
1996 method_jitted (MonoProfiler
*prof
, MonoMethod
*method
, MonoJitInfo
*ji
)
2000 register_method_local (method
, ji
);
2006 code_buffer_new (MonoProfiler
*prof
, const mono_byte
*buffer
, uint64_t size
, MonoProfilerCodeBufferType type
, const void *data
)
2011 if (type
== MONO_PROFILER_CODE_BUFFER_SPECIFIC_TRAMPOLINE
) {
2012 name
= (const char *) data
;
2013 nlen
= strlen (name
) + 1;
2019 ENTER_LOG (&code_buffers_ctr
, logbuffer
,
2020 EVENT_SIZE
/* event */ +
2021 BYTE_SIZE
/* type */ +
2022 LEB128_SIZE
/* buffer */ +
2023 LEB128_SIZE
/* size */ +
2029 emit_event (logbuffer
, TYPE_JITHELPER
| TYPE_RUNTIME
);
2030 emit_byte (logbuffer
, type
);
2031 emit_ptr (logbuffer
, buffer
);
2032 emit_value (logbuffer
, size
);
2035 memcpy (logbuffer
->cursor
, name
, nlen
);
2036 logbuffer
->cursor
+= nlen
;
2043 throw_exc (MonoProfiler
*prof
, MonoObject
*object
)
2045 int do_bt
= (!log_config
.enter_leave
&& mono_atomic_load_i32 (&log_profiler
.runtime_inited
) && log_config
.num_frames
) ? TYPE_THROW_BT
: 0;
2051 ENTER_LOG (&exception_throws_ctr
, logbuffer
,
2052 EVENT_SIZE
/* event */ +
2053 LEB128_SIZE
/* object */ +
2055 LEB128_SIZE
/* count */ +
2057 LEB128_SIZE
/* method */
2062 emit_event (logbuffer
, do_bt
| TYPE_EXCEPTION
);
2063 emit_obj (logbuffer
, object
);
2066 emit_bt (logbuffer
, &data
);
2072 clause_exc (MonoProfiler
*prof
, MonoMethod
*method
, uint32_t clause_num
, MonoExceptionEnum clause_type
, MonoObject
*exc
)
2074 ENTER_LOG (&exception_clauses_ctr
, logbuffer
,
2075 EVENT_SIZE
/* event */ +
2076 BYTE_SIZE
/* clause type */ +
2077 LEB128_SIZE
/* clause num */ +
2078 LEB128_SIZE
/* method */ +
2079 LEB128_SIZE
/* exc */
2082 emit_event (logbuffer
, TYPE_EXCEPTION
| TYPE_CLAUSE
);
2083 emit_byte (logbuffer
, clause_type
);
2084 emit_value (logbuffer
, clause_num
);
2085 emit_method (logbuffer
, method
);
2086 emit_obj (logbuffer
, exc
);
2092 monitor_event (MonoProfiler
*profiler
, MonoObject
*object
, MonoProfilerMonitorEvent ev
)
2094 int do_bt
= (!log_config
.enter_leave
&& mono_atomic_load_i32 (&log_profiler
.runtime_inited
) && log_config
.num_frames
) ? TYPE_MONITOR_BT
: 0;
2100 ENTER_LOG (&monitor_events_ctr
, logbuffer
,
2101 EVENT_SIZE
/* event */ +
2102 BYTE_SIZE
/* ev */ +
2103 LEB128_SIZE
/* object */ +
2105 LEB128_SIZE
/* count */ +
2107 LEB128_SIZE
/* method */
2112 emit_event (logbuffer
, do_bt
| TYPE_MONITOR
);
2113 emit_byte (logbuffer
, ev
);
2114 emit_obj (logbuffer
, object
);
2117 emit_bt (logbuffer
, &data
);
2123 monitor_contention (MonoProfiler
*prof
, MonoObject
*object
)
2125 monitor_event (prof
, object
, MONO_PROFILER_MONITOR_CONTENTION
);
2129 monitor_acquired (MonoProfiler
*prof
, MonoObject
*object
)
2131 monitor_event (prof
, object
, MONO_PROFILER_MONITOR_DONE
);
2135 monitor_failed (MonoProfiler
*prof
, MonoObject
*object
)
2137 monitor_event (prof
, object
, MONO_PROFILER_MONITOR_FAIL
);
2141 thread_start (MonoProfiler
*prof
, uintptr_t tid
)
2143 ENTER_LOG (&thread_starts_ctr
, logbuffer
,
2144 EVENT_SIZE
/* event */ +
2145 BYTE_SIZE
/* type */ +
2146 LEB128_SIZE
/* tid */
2149 emit_event (logbuffer
, TYPE_END_LOAD
| TYPE_METADATA
);
2150 emit_byte (logbuffer
, TYPE_THREAD
);
2151 emit_ptr (logbuffer
, (void*) tid
);
2157 thread_end (MonoProfiler
*prof
, uintptr_t tid
)
2159 ENTER_LOG (&thread_ends_ctr
, logbuffer
,
2160 EVENT_SIZE
/* event */ +
2161 BYTE_SIZE
/* type */ +
2162 LEB128_SIZE
/* tid */
2165 emit_event (logbuffer
, TYPE_END_UNLOAD
| TYPE_METADATA
);
2166 emit_byte (logbuffer
, TYPE_THREAD
);
2167 emit_ptr (logbuffer
, (void*) tid
);
2169 EXIT_LOG_EXPLICIT (NO_SEND
);
2171 MonoProfilerThread
*thread
= get_thread ();
2173 // Internal profiler threads will clean up manually.
2174 if (thread
->attached
) {
2175 thread
->ended
= TRUE
;
2176 remove_thread (thread
);
2178 PROF_TLS_SET (MONO_PROFILER_THREAD_DEAD
);
2183 thread_name (MonoProfiler
*prof
, uintptr_t tid
, const char *name
)
2185 int len
= strlen (name
) + 1;
2187 ENTER_LOG (&thread_names_ctr
, logbuffer
,
2188 EVENT_SIZE
/* event */ +
2189 BYTE_SIZE
/* type */ +
2190 LEB128_SIZE
/* tid */ +
2194 emit_event (logbuffer
, TYPE_METADATA
);
2195 emit_byte (logbuffer
, TYPE_THREAD
);
2196 emit_ptr (logbuffer
, (void*)tid
);
2197 memcpy (logbuffer
->cursor
, name
, len
);
2198 logbuffer
->cursor
+= len
;
2204 domain_loaded (MonoProfiler
*prof
, MonoDomain
*domain
)
2206 ENTER_LOG (&domain_loads_ctr
, logbuffer
,
2207 EVENT_SIZE
/* event */ +
2208 BYTE_SIZE
/* type */ +
2209 LEB128_SIZE
/* domain id */
2212 emit_event (logbuffer
, TYPE_END_LOAD
| TYPE_METADATA
);
2213 emit_byte (logbuffer
, TYPE_DOMAIN
);
2214 emit_ptr (logbuffer
, (void*)(uintptr_t) mono_domain_get_id (domain
));
2220 domain_unloaded (MonoProfiler
*prof
, MonoDomain
*domain
)
2222 ENTER_LOG (&domain_unloads_ctr
, logbuffer
,
2223 EVENT_SIZE
/* event */ +
2224 BYTE_SIZE
/* type */ +
2225 LEB128_SIZE
/* domain id */
2228 emit_event (logbuffer
, TYPE_END_UNLOAD
| TYPE_METADATA
);
2229 emit_byte (logbuffer
, TYPE_DOMAIN
);
2230 emit_ptr (logbuffer
, (void*)(uintptr_t) mono_domain_get_id (domain
));
2236 domain_name (MonoProfiler
*prof
, MonoDomain
*domain
, const char *name
)
2238 int nlen
= strlen (name
) + 1;
2240 ENTER_LOG (&domain_names_ctr
, logbuffer
,
2241 EVENT_SIZE
/* event */ +
2242 BYTE_SIZE
/* type */ +
2243 LEB128_SIZE
/* domain id */ +
2247 emit_event (logbuffer
, TYPE_METADATA
);
2248 emit_byte (logbuffer
, TYPE_DOMAIN
);
2249 emit_ptr (logbuffer
, (void*)(uintptr_t) mono_domain_get_id (domain
));
2250 memcpy (logbuffer
->cursor
, name
, nlen
);
2251 logbuffer
->cursor
+= nlen
;
2257 context_loaded (MonoProfiler
*prof
, MonoAppContext
*context
)
2259 ENTER_LOG (&context_loads_ctr
, logbuffer
,
2260 EVENT_SIZE
/* event */ +
2261 BYTE_SIZE
/* type */ +
2262 LEB128_SIZE
/* context id */ +
2263 LEB128_SIZE
/* domain id */
2266 emit_event (logbuffer
, TYPE_END_LOAD
| TYPE_METADATA
);
2267 emit_byte (logbuffer
, TYPE_CONTEXT
);
2268 emit_ptr (logbuffer
, (void*)(uintptr_t) mono_context_get_id (context
));
2269 emit_ptr (logbuffer
, (void*)(uintptr_t) mono_context_get_domain_id (context
));
2275 context_unloaded (MonoProfiler
*prof
, MonoAppContext
*context
)
2277 ENTER_LOG (&context_unloads_ctr
, logbuffer
,
2278 EVENT_SIZE
/* event */ +
2279 BYTE_SIZE
/* type */ +
2280 LEB128_SIZE
/* context id */ +
2281 LEB128_SIZE
/* domain id */
2284 emit_event (logbuffer
, TYPE_END_UNLOAD
| TYPE_METADATA
);
2285 emit_byte (logbuffer
, TYPE_CONTEXT
);
2286 emit_ptr (logbuffer
, (void*)(uintptr_t) mono_context_get_id (context
));
2287 emit_ptr (logbuffer
, (void*)(uintptr_t) mono_context_get_domain_id (context
));
2300 MonoLockFreeQueueNode node
;
2305 AsyncFrameInfo frames
[MONO_ZERO_LEN_ARRAY
];
2309 async_walk_stack (MonoMethod
*method
, MonoDomain
*domain
, void *base_address
, int offset
, void *data
)
2311 SampleHit
*sample
= (SampleHit
*) data
;
2313 if (sample
->count
< log_config
.num_frames
) {
2314 int i
= sample
->count
;
2316 sample
->frames
[i
].method
= method
;
2317 sample
->frames
[i
].domain
= domain
;
2318 sample
->frames
[i
].base_address
= base_address
;
2319 sample
->frames
[i
].offset
= offset
;
2322 inc_method_ref_count (method
);
2327 return sample
->count
== log_config
.num_frames
;
2330 #define SAMPLE_SLOT_SIZE(FRAMES) (sizeof (SampleHit) + sizeof (AsyncFrameInfo) * (FRAMES - MONO_ZERO_LEN_ARRAY))
2331 #define SAMPLE_BLOCK_SIZE (mono_pagesize ())
2334 enqueue_sample_hit (gpointer p
)
2336 SampleHit
*sample
= p
;
2338 mono_lock_free_queue_node_unpoison (&sample
->node
);
2339 mono_lock_free_queue_enqueue (&log_profiler
.dumper_queue
, &sample
->node
);
2340 mono_os_sem_post (&log_profiler
.dumper_queue_sem
);
2344 mono_sample_hit (MonoProfiler
*profiler
, const mono_byte
*ip
, const void *context
)
2347 * Please note: We rely on the runtime loading the profiler with
2348 * MONO_DL_EAGER (RTLD_NOW) so that references to runtime functions within
2349 * this function (and its siblings) are resolved when the profiler is
2350 * loaded. Otherwise, we would potentially invoke the dynamic linker when
2351 * invoking runtime functions, which is not async-signal-safe.
2354 if (mono_atomic_load_i32 (&log_profiler
.in_shutdown
))
2357 SampleHit
*sample
= (SampleHit
*) mono_lock_free_queue_dequeue (&profiler
->sample_reuse_queue
);
2361 * If we're out of reusable sample events and we're not allowed to
2362 * allocate more, we have no choice but to drop the event.
2364 if (mono_atomic_load_i32 (&sample_allocations_ctr
) >= log_config
.max_allocated_sample_hits
)
2367 sample
= mono_lock_free_alloc (&profiler
->sample_allocator
);
2368 mono_lock_free_queue_node_init (&sample
->node
, TRUE
);
2370 mono_atomic_inc_i32 (&sample_allocations_ctr
);
2374 mono_stack_walk_async_safe (&async_walk_stack
, (void *) context
, sample
);
2376 sample
->time
= current_time ();
2377 sample
->tid
= thread_id ();
2380 mono_thread_hazardous_try_free (sample
, enqueue_sample_hit
);
2383 static uintptr_t *code_pages
= 0;
2384 static int num_code_pages
= 0;
2385 static int size_code_pages
= 0;
2386 #define CPAGE_SHIFT (9)
2387 #define CPAGE_SIZE (1 << CPAGE_SHIFT)
2388 #define CPAGE_MASK (~(CPAGE_SIZE - 1))
2389 #define CPAGE_ADDR(p) ((p) & CPAGE_MASK)
2392 add_code_page (uintptr_t *hash
, uintptr_t hsize
, uintptr_t page
)
2395 uintptr_t start_pos
;
2396 start_pos
= (page
>> CPAGE_SHIFT
) % hsize
;
2399 if (hash
[i
] && CPAGE_ADDR (hash
[i
]) == CPAGE_ADDR (page
)) {
2401 } else if (!hash
[i
]) {
2408 } while (i
!= start_pos
);
2409 g_assert_not_reached ();
2414 add_code_pointer (uintptr_t ip
)
2417 if (num_code_pages
* 2 >= size_code_pages
) {
2419 uintptr_t old_size
= size_code_pages
;
2420 size_code_pages
*= 2;
2421 if (size_code_pages
== 0)
2422 size_code_pages
= 16;
2423 n
= (uintptr_t *) g_calloc (sizeof (uintptr_t) * size_code_pages
, 1);
2424 for (i
= 0; i
< old_size
; ++i
) {
2426 add_code_page (n
, size_code_pages
, code_pages
[i
]);
2429 g_free (code_pages
);
2432 num_code_pages
+= add_code_page (code_pages
, size_code_pages
, ip
& CPAGE_MASK
);
2436 dump_usym (char *name
, uintptr_t value
, uintptr_t size
)
2438 int len
= strlen (name
) + 1;
2440 ENTER_LOG (&sample_usyms_ctr
, logbuffer
,
2441 EVENT_SIZE
/* event */ +
2442 LEB128_SIZE
/* value */ +
2443 LEB128_SIZE
/* size */ +
2447 emit_event (logbuffer
, TYPE_SAMPLE
| TYPE_SAMPLE_USYM
);
2448 emit_ptr (logbuffer
, (void *) value
);
2449 emit_value (logbuffer
, size
);
2450 memcpy (logbuffer
->cursor
, name
, len
);
2451 logbuffer
->cursor
+= len
;
2457 symbol_for (uintptr_t code
, char *sname
, size_t slen
)
2459 return g_module_address ((void *) code
, NULL
, 0, NULL
, sname
, slen
, NULL
);
2463 dump_unmanaged_coderefs (void)
2466 char last_symbol
[256];
2467 uintptr_t addr
, page_end
;
2469 for (i
= 0; i
< size_code_pages
; ++i
) {
2471 if (!code_pages
[i
] || code_pages
[i
] & 1)
2473 last_symbol
[0] = '\0';
2474 addr
= CPAGE_ADDR (code_pages
[i
]);
2475 page_end
= addr
+ CPAGE_SIZE
;
2476 code_pages
[i
] |= 1;
2477 /* we dump the symbols for the whole page */
2478 for (; addr
< page_end
; addr
+= 16) {
2479 gboolean symret
= symbol_for (addr
, sym
, 256);
2480 if (symret
&& strncmp (sym
, last_symbol
, 256) == 0)
2482 g_strlcpy (last_symbol
, sym
, 256);
2483 if (sym
[0] == '\0')
2485 dump_usym (sym
, addr
, 0); /* let's not guess the size */
2491 counters_add_agent (MonoCounter
*counter
)
2493 if (mono_atomic_load_i32 (&log_profiler
.in_shutdown
))
2496 MonoCounterAgent
*agent
, *item
;
2498 mono_os_mutex_lock (&log_profiler
.counters_mutex
);
2500 for (agent
= log_profiler
.counters
; agent
; agent
= agent
->next
) {
2501 if (agent
->counter
== counter
) {
2502 agent
->value_size
= 0;
2504 g_free (agent
->value
);
2505 agent
->value
= NULL
;
2511 agent
= (MonoCounterAgent
*) g_malloc (sizeof (MonoCounterAgent
));
2512 agent
->counter
= counter
;
2513 agent
->value
= NULL
;
2514 agent
->value_size
= 0;
2515 agent
->index
= log_profiler
.counters_index
++;
2516 agent
->emitted
= FALSE
;
2519 if (!log_profiler
.counters
) {
2520 log_profiler
.counters
= agent
;
2522 item
= log_profiler
.counters
;
2529 mono_os_mutex_unlock (&log_profiler
.counters_mutex
);
2533 counters_init_foreach_callback (MonoCounter
*counter
, gpointer data
)
2535 counters_add_agent (counter
);
2540 counters_init (void)
2542 mono_os_mutex_init (&log_profiler
.counters_mutex
);
2544 log_profiler
.counters_index
= 1;
2546 mono_counters_on_register (&counters_add_agent
);
2547 mono_counters_foreach (counters_init_foreach_callback
, NULL
);
2551 counters_emit (void)
2553 MonoCounterAgent
*agent
;
2556 EVENT_SIZE
/* event */ +
2557 LEB128_SIZE
/* len */
2560 mono_os_mutex_lock (&log_profiler
.counters_mutex
);
2562 for (agent
= log_profiler
.counters
; agent
; agent
= agent
->next
) {
2567 LEB128_SIZE
/* section */ +
2568 strlen (mono_counter_get_name (agent
->counter
)) + 1 /* name */ +
2569 BYTE_SIZE
/* type */ +
2570 BYTE_SIZE
/* unit */ +
2571 BYTE_SIZE
/* variance */ +
2572 LEB128_SIZE
/* index */
2581 ENTER_LOG (&counter_descriptors_ctr
, logbuffer
, size
);
2583 emit_event (logbuffer
, TYPE_SAMPLE_COUNTERS_DESC
| TYPE_SAMPLE
);
2584 emit_value (logbuffer
, len
);
2586 for (agent
= log_profiler
.counters
; agent
; agent
= agent
->next
) {
2592 name
= mono_counter_get_name (agent
->counter
);
2593 emit_value (logbuffer
, mono_counter_get_section (agent
->counter
));
2594 emit_string (logbuffer
, name
, strlen (name
) + 1);
2595 emit_value (logbuffer
, mono_counter_get_type (agent
->counter
));
2596 emit_value (logbuffer
, mono_counter_get_unit (agent
->counter
));
2597 emit_value (logbuffer
, mono_counter_get_variance (agent
->counter
));
2598 emit_value (logbuffer
, agent
->index
);
2600 agent
->emitted
= TRUE
;
2606 mono_os_mutex_unlock (&log_profiler
.counters_mutex
);
2610 counters_sample (uint64_t timestamp
)
2612 MonoCounterAgent
*agent
;
2613 MonoCounter
*counter
;
2622 buffer
= g_calloc (1, buffer_size
);
2624 mono_os_mutex_lock (&log_profiler
.counters_mutex
);
2627 EVENT_SIZE
/* event */
2630 for (agent
= log_profiler
.counters
; agent
; agent
= agent
->next
) {
2632 * FIXME: This calculation is incorrect for string counters since
2633 * mono_counter_get_size () just returns 0 in that case. We should
2634 * address this if we ever actually add any string counters to Mono.
2638 LEB128_SIZE
/* index */ +
2639 BYTE_SIZE
/* type */ +
2640 mono_counter_get_size (agent
->counter
) /* value */
2645 LEB128_SIZE
/* stop marker */
2648 ENTER_LOG (&counter_samples_ctr
, logbuffer
, size
);
2650 emit_event_time (logbuffer
, TYPE_SAMPLE_COUNTERS
| TYPE_SAMPLE
, timestamp
);
2652 for (agent
= log_profiler
.counters
; agent
; agent
= agent
->next
) {
2655 counter
= agent
->counter
;
2657 size
= mono_counter_get_size (counter
);
2659 if (size
> buffer_size
) {
2661 buffer
= g_realloc (buffer
, buffer_size
);
2664 memset (buffer
, 0, buffer_size
);
2666 g_assert (mono_counters_sample (counter
, buffer
, size
));
2668 type
= mono_counter_get_type (counter
);
2670 if (!agent
->value
) {
2671 agent
->value
= g_calloc (1, size
);
2672 agent
->value_size
= size
;
2674 if (type
== MONO_COUNTER_STRING
) {
2675 if (strcmp (agent
->value
, buffer
) == 0)
2678 if (agent
->value_size
== size
&& memcmp (agent
->value
, buffer
, size
) == 0)
2683 emit_uvalue (logbuffer
, agent
->index
);
2684 emit_value (logbuffer
, type
);
2686 case MONO_COUNTER_INT
:
2687 #if SIZEOF_VOID_P == 4
2688 case MONO_COUNTER_WORD
:
2690 emit_svalue (logbuffer
, *(int*)buffer
- *(int*)agent
->value
);
2692 case MONO_COUNTER_UINT
:
2693 emit_uvalue (logbuffer
, *(guint
*)buffer
- *(guint
*)agent
->value
);
2695 case MONO_COUNTER_TIME_INTERVAL
:
2696 case MONO_COUNTER_LONG
:
2697 #if SIZEOF_VOID_P == 8
2698 case MONO_COUNTER_WORD
:
2700 emit_svalue (logbuffer
, *(gint64
*)buffer
- *(gint64
*)agent
->value
);
2702 case MONO_COUNTER_ULONG
:
2703 emit_uvalue (logbuffer
, *(guint64
*)buffer
- *(guint64
*)agent
->value
);
2705 case MONO_COUNTER_DOUBLE
:
2706 emit_double (logbuffer
, *(double*)buffer
);
2708 case MONO_COUNTER_STRING
:
2710 emit_byte (logbuffer
, 0);
2712 emit_byte (logbuffer
, 1);
2713 emit_string (logbuffer
, (char*)buffer
, size
);
2717 g_assert_not_reached ();
2720 if (type
== MONO_COUNTER_STRING
&& size
> agent
->value_size
) {
2721 agent
->value
= g_realloc (agent
->value
, size
);
2722 agent
->value_size
= size
;
2726 memcpy (agent
->value
, buffer
, size
);
2730 emit_value (logbuffer
, 0);
2734 mono_os_mutex_unlock (&log_profiler
.counters_mutex
);
2738 perfcounters_emit (void)
2740 PerfCounterAgent
*pcagent
;
2743 EVENT_SIZE
/* event */ +
2744 LEB128_SIZE
/* len */
2747 for (pcagent
= log_profiler
.perfcounters
; pcagent
; pcagent
= pcagent
->next
) {
2748 if (pcagent
->emitted
)
2752 LEB128_SIZE
/* section */ +
2753 strlen (pcagent
->category_name
) + 1 /* category name */ +
2754 strlen (pcagent
->name
) + 1 /* name */ +
2755 BYTE_SIZE
/* type */ +
2756 BYTE_SIZE
/* unit */ +
2757 BYTE_SIZE
/* variance */ +
2758 LEB128_SIZE
/* index */
2767 ENTER_LOG (&perfcounter_descriptors_ctr
, logbuffer
, size
);
2769 emit_event (logbuffer
, TYPE_SAMPLE_COUNTERS_DESC
| TYPE_SAMPLE
);
2770 emit_value (logbuffer
, len
);
2772 for (pcagent
= log_profiler
.perfcounters
; pcagent
; pcagent
= pcagent
->next
) {
2773 if (pcagent
->emitted
)
2776 emit_value (logbuffer
, MONO_COUNTER_PERFCOUNTERS
);
2777 emit_string (logbuffer
, pcagent
->category_name
, strlen (pcagent
->category_name
) + 1);
2778 emit_string (logbuffer
, pcagent
->name
, strlen (pcagent
->name
) + 1);
2779 emit_byte (logbuffer
, MONO_COUNTER_LONG
);
2780 emit_byte (logbuffer
, MONO_COUNTER_RAW
);
2781 emit_byte (logbuffer
, MONO_COUNTER_VARIABLE
);
2782 emit_value (logbuffer
, pcagent
->index
);
2784 pcagent
->emitted
= TRUE
;
2791 perfcounters_foreach (char *category_name
, char *name
, unsigned char type
, gint64 value
, gpointer user_data
)
2793 PerfCounterAgent
*pcagent
;
2795 for (pcagent
= log_profiler
.perfcounters
; pcagent
; pcagent
= pcagent
->next
) {
2796 if (strcmp (pcagent
->category_name
, category_name
) != 0 || strcmp (pcagent
->name
, name
) != 0)
2798 if (pcagent
->value
== value
)
2801 pcagent
->value
= value
;
2802 pcagent
->updated
= TRUE
;
2803 pcagent
->deleted
= FALSE
;
2807 pcagent
= g_new0 (PerfCounterAgent
, 1);
2808 pcagent
->next
= log_profiler
.perfcounters
;
2809 pcagent
->index
= log_profiler
.counters_index
++;
2810 pcagent
->category_name
= g_strdup (category_name
);
2811 pcagent
->name
= g_strdup (name
);
2812 pcagent
->value
= value
;
2813 pcagent
->emitted
= FALSE
;
2814 pcagent
->updated
= TRUE
;
2815 pcagent
->deleted
= FALSE
;
2817 log_profiler
.perfcounters
= pcagent
;
2823 perfcounters_sample (uint64_t timestamp
)
2825 PerfCounterAgent
*pcagent
;
2829 mono_os_mutex_lock (&log_profiler
.counters_mutex
);
2831 /* mark all perfcounters as deleted, foreach will unmark them as necessary */
2832 for (pcagent
= log_profiler
.perfcounters
; pcagent
; pcagent
= pcagent
->next
)
2833 pcagent
->deleted
= TRUE
;
2835 mono_perfcounter_foreach (perfcounters_foreach
, NULL
);
2837 perfcounters_emit ();
2840 EVENT_SIZE
/* event */
2843 for (pcagent
= log_profiler
.perfcounters
; pcagent
; pcagent
= pcagent
->next
) {
2844 if (pcagent
->deleted
|| !pcagent
->updated
)
2848 LEB128_SIZE
/* index */ +
2849 BYTE_SIZE
/* type */ +
2850 LEB128_SIZE
/* value */
2860 LEB128_SIZE
/* stop marker */
2863 ENTER_LOG (&perfcounter_samples_ctr
, logbuffer
, size
);
2865 emit_event_time (logbuffer
, TYPE_SAMPLE_COUNTERS
| TYPE_SAMPLE
, timestamp
);
2867 for (pcagent
= log_profiler
.perfcounters
; pcagent
; pcagent
= pcagent
->next
) {
2868 if (pcagent
->deleted
|| !pcagent
->updated
)
2870 emit_uvalue (logbuffer
, pcagent
->index
);
2871 emit_byte (logbuffer
, MONO_COUNTER_LONG
);
2872 emit_svalue (logbuffer
, pcagent
->value
);
2874 pcagent
->updated
= FALSE
;
2877 emit_value (logbuffer
, 0);
2882 mono_os_mutex_unlock (&log_profiler
.counters_mutex
);
2886 counters_and_perfcounters_sample (void)
2888 uint64_t now
= current_time ();
2890 counters_sample (now
);
2891 perfcounters_sample (now
);
2895 free_sample_hit (gpointer p
)
2897 mono_lock_free_free (p
, SAMPLE_BLOCK_SIZE
);
2901 cleanup_reusable_samples (void)
2905 while ((sample
= (SampleHit
*) mono_lock_free_queue_dequeue (&log_profiler
.sample_reuse_queue
)))
2906 mono_thread_hazardous_try_free (sample
, free_sample_hit
);
2910 signal_helper_thread (char c
)
2912 #ifdef HAVE_COMMAND_PIPES
2913 if (write (log_profiler
.pipes
[1], &c
, 1) != 1) {
2914 mono_profiler_printf_err ("Could not write to log profiler pipe: %s", g_strerror (errno
));
2919 * On Windows we can't use pipes together with sockets in select. Instead of
2920 * re-writing the whole logic, the Windows implementation will replace use of command pipe
2921 * with simple command buffer and a dummy connect to localhost, making sure
2922 * helper thread will pick up command and process is. Since the dummy connection will
2923 * be closed right away by client, it will be discarded by helper thread.
2925 mono_atomic_store_i32(&log_profiler
.pipe_command
, c
);
2927 SOCKET client_socket
;
2928 client_socket
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
2929 if (client_socket
!= INVALID_SOCKET
) {
2930 struct sockaddr_in client_addr
;
2931 client_addr
.sin_family
= AF_INET
;
2932 client_addr
.sin_port
= htons(log_profiler
.command_port
);
2933 inet_pton (client_addr
.sin_family
, "127.0.0.1", &client_addr
.sin_addr
);
2935 gulong non_blocking
= 1;
2936 ioctlsocket (client_socket
, FIONBIO
, &non_blocking
);
2937 if (connect (client_socket
, (SOCKADDR
*)&client_addr
, sizeof (client_addr
)) == SOCKET_ERROR
) {
2938 if (WSAGetLastError () == WSAEWOULDBLOCK
) {
2943 FD_SET (client_socket
, &wfds
);
2946 * Include timeout to prevent hanging on connect call.
2948 struct timeval tv
= { .tv_sec
= 1, .tv_usec
= 0 };
2949 select (client_socket
+ 1, NULL
, &wfds
, NULL
, &tv
);
2953 mono_profhelper_close_socket_fd (client_socket
);
2959 log_early_shutdown (MonoProfiler
*prof
)
2963 if (log_config
.hs_on_shutdown
) {
2964 mono_atomic_store_i32 (&log_profiler
.heapshot_requested
, 1);
2965 mono_gc_collect (mono_gc_max_generation ());
2969 * We need to detach the internal threads early on. log_shutdown () is
2970 * called after the threading subsystem has been cleaned up, so detaching
2971 * there would crash.
2973 mono_os_sem_init (&log_profiler
.detach_threads_sem
, 0);
2974 mono_atomic_store_i32 (&log_profiler
.detach_threads
, 1);
2976 signal_helper_thread (2);
2977 mono_os_sem_post (&prof
->dumper_queue_sem
);
2978 mono_os_sem_post (&prof
->writer_queue_sem
);
2980 for (int i
= 0; i
< 3; i
++)
2981 mono_os_sem_wait (&log_profiler
.detach_threads_sem
, MONO_SEM_FLAGS_NONE
);
2983 mono_os_sem_destroy (&log_profiler
.detach_threads_sem
);
2987 log_shutdown (MonoProfiler
*prof
)
2989 mono_atomic_store_i32 (&log_profiler
.in_shutdown
, 1);
2991 if (ENABLED (PROFLOG_COUNTER_EVENTS
))
2992 counters_and_perfcounters_sample ();
2994 signal_helper_thread (1);
2995 mono_os_event_wait_one (&prof
->helper_thread_exited
, MONO_INFINITE_WAIT
, FALSE
);
2996 mono_os_event_destroy (&prof
->helper_thread_exited
);
2998 mono_os_mutex_destroy (&log_profiler
.counters_mutex
);
3000 MonoCounterAgent
*mc_next
;
3002 for (MonoCounterAgent
*cur
= log_profiler
.counters
; cur
; cur
= mc_next
) {
3003 mc_next
= cur
->next
;
3007 PerfCounterAgent
*pc_next
;
3009 for (PerfCounterAgent
*cur
= log_profiler
.perfcounters
; cur
; cur
= pc_next
) {
3010 pc_next
= cur
->next
;
3015 * Ensure that we empty the LLS completely, even if some nodes are
3016 * not immediately removed upon calling mono_lls_remove (), by
3017 * iterating until the head is NULL.
3019 while (log_profiler
.profiler_thread_list
.head
) {
3020 MONO_LLS_FOREACH_SAFE (&log_profiler
.profiler_thread_list
, MonoProfilerThread
, thread
) {
3021 g_assert (thread
->attached
&& "Why is a thread in the LLS not attached?");
3023 remove_thread (thread
);
3024 } MONO_LLS_FOREACH_SAFE_END
3028 * Ensure that all threads have been freed, so that we don't miss any
3029 * buffers when we shut down the writer thread below.
3031 mono_thread_hazardous_try_free_all ();
3033 mono_atomic_store_i32 (&prof
->run_dumper_thread
, 0);
3034 mono_os_sem_post (&prof
->dumper_queue_sem
);
3035 mono_os_event_wait_one (&prof
->dumper_thread_exited
, MONO_INFINITE_WAIT
, FALSE
);
3036 mono_os_event_destroy (&prof
->dumper_thread_exited
);
3037 mono_os_sem_destroy (&prof
->dumper_queue_sem
);
3039 mono_atomic_store_i32 (&prof
->run_writer_thread
, 0);
3040 mono_os_sem_post (&prof
->writer_queue_sem
);
3041 mono_os_event_wait_one (&prof
->writer_thread_exited
, MONO_INFINITE_WAIT
, FALSE
);
3042 mono_os_event_destroy (&prof
->writer_thread_exited
);
3043 mono_os_sem_destroy (&prof
->writer_queue_sem
);
3046 * Free all writer queue entries, and ensure that all sample hits will be
3047 * added to the sample reuse queue.
3049 mono_thread_hazardous_try_free_all ();
3051 cleanup_reusable_samples ();
3054 * Finally, make sure that all sample hits are freed. This should cover all
3055 * hazardous data from the profiler. We can now be sure that the runtime
3056 * won't later invoke free functions in the profiler library after it has
3059 mono_thread_hazardous_try_free_all ();
3061 gint32 state
= mono_atomic_load_i32 (&log_profiler
.buffer_lock_state
);
3063 g_assert (!(state
& 0xFFFF) && "Why is the reader count still non-zero?");
3064 g_assert (!(state
>> 16) && "Why is the exclusive lock still held?");
3066 #if defined (HAVE_SYS_ZLIB)
3068 gzclose (prof
->gzfile
);
3070 #if HAVE_API_SUPPORT_WIN32_PIPE_OPEN_CLOSE && !defined (HOST_WIN32)
3071 if (prof
->pipe_output
)
3072 pclose (prof
->file
);
3075 fclose (prof
->file
);
3077 mono_conc_hashtable_destroy (prof
->method_table
);
3078 mono_os_mutex_destroy (&prof
->method_table_mutex
);
3080 mono_coop_mutex_destroy (&log_profiler
.api_mutex
);
3082 g_free (prof
->args
);
3086 * We depend on socket support in this profiler provider we need to
3087 * make sure we keep a reference on WSA for the lifetime of this provider.
3094 new_filename (const char* filename
)
3096 time_t t
= time (NULL
);
3097 int pid
= process_id ();
3102 int count_dates
= 0;
3106 for (p
= filename
; *p
; p
++) {
3117 if (!count_dates
&& !count_pids
)
3118 return pstrdup (filename
);
3119 snprintf (pid_buf
, sizeof (pid_buf
), "%d", pid
);
3121 snprintf (time_buf
, sizeof (time_buf
), "%d%02d%02d%02d%02d%02d",
3122 1900 + ts
->tm_year
, 1 + ts
->tm_mon
, ts
->tm_mday
, ts
->tm_hour
, ts
->tm_min
, ts
->tm_sec
);
3123 s_date
= strlen (time_buf
);
3124 s_pid
= strlen (pid_buf
);
3125 d
= res
= (char *) g_malloc (strlen (filename
) + s_date
* count_dates
+ s_pid
* count_pids
);
3126 for (p
= filename
; *p
; p
++) {
3133 strcpy (d
, time_buf
);
3136 } else if (*p
== 'p') {
3137 strcpy (d
, pid_buf
);
3140 } else if (*p
== '%') {
3152 static MonoProfilerThread
*
3153 profiler_thread_begin_function (const char *name8
, const gunichar2
* name16
, size_t name_length
, gboolean send
)
3155 mono_thread_info_attach ();
3156 MonoProfilerThread
*thread
= init_thread (FALSE
);
3158 mono_thread_internal_attach (mono_get_root_domain ());
3160 MonoInternalThread
*internal
= mono_thread_internal_current ();
3163 * Don't let other threads try to suspend internal profiler threads during
3164 * shutdown. This can happen if a program calls Environment.Exit () which
3165 * calls mono_thread_suspend_all_other_threads ().
3167 internal
->flags
|= MONO_THREAD_FLAG_DONT_MANAGE
;
3169 mono_thread_set_name (internal
, name8
, name_length
, name16
, MonoSetThreadNameFlag_Constant
, NULL
);
3171 mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NO_GC
| MONO_THREAD_INFO_FLAGS_NO_SAMPLE
);
3174 dump_buffer (thread
->buffer
);
3175 init_buffer_state (thread
);
3177 send_log_unsafe (FALSE
);
3179 mono_os_sem_post (&log_profiler
.attach_threads_sem
);
3184 #define profiler_thread_begin(name, send) \
3185 profiler_thread_begin_function (name, MONO_THREAD_NAME_WINDOWS_CONSTANT (name), G_N_ELEMENTS (name) - 1, (send))
3188 profiler_thread_end (MonoProfilerThread
*thread
, MonoOSEvent
*event
, gboolean send
)
3191 send_log_unsafe (FALSE
);
3193 dump_buffer (thread
->buffer
);
3195 deinit_thread (thread
);
3197 mono_os_event_set (event
);
3201 profiler_thread_check_detach (MonoProfilerThread
*thread
)
3203 if (mono_atomic_load_i32 (&log_profiler
.detach_threads
) && !thread
->did_detach
) {
3204 thread
->did_detach
= TRUE
;
3206 mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NONE
);
3207 mono_thread_internal_detach (mono_thread_current ());
3209 mono_os_sem_post (&log_profiler
.detach_threads_sem
);
3214 helper_thread (void *arg
)
3216 MonoProfilerThread
*thread
= profiler_thread_begin ("Profiler Helper", TRUE
);
3218 GArray
*command_sockets
= g_array_new (FALSE
, FALSE
, sizeof (int));
3226 mono_profhelper_add_to_fd_set (&rfds
, log_profiler
.server_socket
, &max_fd
);
3228 #ifdef HAVE_COMMAND_PIPES
3229 mono_profhelper_add_to_fd_set (&rfds
, log_profiler
.pipes
[0], &max_fd
);
3232 for (gint i
= 0; i
< command_sockets
->len
; i
++)
3233 mono_profhelper_add_to_fd_set (&rfds
, g_array_index (command_sockets
, int, i
), &max_fd
);
3235 struct timeval tv
= { .tv_sec
= 1, .tv_usec
= 0 };
3237 // Sleep for 1sec or until a file descriptor has data.
3238 if (select (max_fd
+ 1, &rfds
, NULL
, NULL
, &tv
) == -1) {
3242 mono_profiler_printf_err ("Could not poll in log profiler helper thread: %s", g_strerror (errno
));
3246 if (ENABLED (PROFLOG_COUNTER_EVENTS
))
3247 counters_and_perfcounters_sample ();
3249 buffer_lock_excl ();
3251 sync_point (SYNC_POINT_PERIODIC
);
3253 buffer_unlock_excl ();
3255 // Did we get a shutdown or detach signal?
3256 #ifdef HAVE_COMMAND_PIPES
3257 if (FD_ISSET (log_profiler
.pipes
[0], &rfds
)) {
3259 read (log_profiler
.pipes
[0], &c
, 1);
3264 int value
= mono_atomic_load_i32(&log_profiler
.pipe_command
);
3266 while (mono_atomic_cas_i32 (&log_profiler
.pipe_command
, 0, value
) != value
)
3267 value
= mono_atomic_load_i32(&log_profiler
.pipe_command
);
3269 char c
= (char)value
;
3275 for (gint i
= 0; i
< command_sockets
->len
; i
++) {
3276 int fd
= g_array_index (command_sockets
, int, i
);
3278 if (!FD_ISSET (fd
, &rfds
))
3283 int len
= recv (fd
, buf
, sizeof (buf
) - 1, 0);
3285 int len
= read (fd
, buf
, sizeof (buf
) - 1);
3291 // The other end disconnected.
3292 g_array_remove_index (command_sockets
, i
);
3293 mono_profhelper_close_socket_fd (fd
);
3300 if (!strcmp (buf
, "heapshot\n"))
3301 trigger_heapshot ();
3304 if (FD_ISSET (log_profiler
.server_socket
, &rfds
)) {
3305 int fd
= accept (log_profiler
.server_socket
, NULL
, NULL
);
3309 if (fd
>= FD_SETSIZE
)
3310 mono_profhelper_close_socket_fd (fd
);
3313 g_array_append_val (command_sockets
, fd
);
3317 profiler_thread_check_detach (thread
);
3320 for (gint i
= 0; i
< command_sockets
->len
; i
++)
3321 mono_profhelper_close_socket_fd (g_array_index (command_sockets
, int, i
));
3323 g_array_free (command_sockets
, TRUE
);
3325 profiler_thread_end (thread
, &log_profiler
.helper_thread_exited
, TRUE
);
3331 start_helper_thread (void)
3333 #ifdef HAVE_COMMAND_PIPES
3334 if (pipe (log_profiler
.pipes
) == -1) {
3335 mono_profiler_printf_err ("Could not create log profiler pipe: %s", g_strerror (errno
));
3340 mono_profhelper_setup_command_server (&log_profiler
.server_socket
, &log_profiler
.command_port
, "log");
3342 if (!mono_native_thread_create (&log_profiler
.helper_thread
, helper_thread
, NULL
)) {
3343 mono_profiler_printf_err ("Could not start log profiler helper thread");
3344 mono_profhelper_close_socket_fd (log_profiler
.server_socket
);
3350 free_writer_entry (gpointer p
)
3352 mono_lock_free_free (p
, WRITER_ENTRY_BLOCK_SIZE
);
3356 handle_writer_queue_entry (void)
3358 WriterQueueEntry
*entry
;
3360 if ((entry
= (WriterQueueEntry
*) mono_lock_free_queue_dequeue (&log_profiler
.writer_queue
))) {
3361 if (!entry
->methods
)
3364 gboolean wrote_methods
= FALSE
;
3367 * Encode the method events in a temporary log buffer that we
3368 * flush to disk before the main buffer, ensuring that all
3369 * methods have metadata emitted before they're referenced.
3371 * We use a 'proper' thread-local buffer for this as opposed
3372 * to allocating and freeing a buffer by hand because the call
3373 * to mono_method_full_name () below may trigger class load
3374 * events when it retrieves the signature of the method. So a
3375 * thread-local buffer needs to exist when such events occur.
3377 for (guint i
= 0; i
< entry
->methods
->len
; i
++) {
3378 MethodInfo
*info
= (MethodInfo
*) g_ptr_array_index (entry
->methods
, i
);
3380 if (mono_conc_hashtable_lookup (log_profiler
.method_table
, info
->method
))
3381 goto free_info
; // This method already has metadata emitted.
3384 * Other threads use this hash table to get a general
3385 * idea of whether a method has already been emitted to
3386 * the stream. Due to the way we add to this table, it
3387 * can easily happen that multiple threads queue up the
3388 * same methods, but that's OK since eventually all
3389 * methods will be in this table and the thread-local
3390 * method lists will just be empty for the rest of the
3393 mono_os_mutex_lock (&log_profiler
.method_table_mutex
);
3394 mono_conc_hashtable_insert (log_profiler
.method_table
, info
->method
, info
->method
);
3395 mono_os_mutex_unlock (&log_profiler
.method_table_mutex
);
3397 char *name
= mono_method_full_name (info
->method
, 1);
3398 int nlen
= strlen (name
) + 1;
3399 void *cstart
= info
->ji
? mono_jit_info_get_code_start (info
->ji
) : NULL
;
3400 int csize
= info
->ji
? mono_jit_info_get_code_size (info
->ji
) : 0;
3402 ENTER_LOG (&method_jits_ctr
, logbuffer
,
3403 EVENT_SIZE
/* event */ +
3404 LEB128_SIZE
/* method */ +
3405 LEB128_SIZE
/* start */ +
3406 LEB128_SIZE
/* size */ +
3410 emit_event_time (logbuffer
, TYPE_JIT
| TYPE_METHOD
, info
->time
);
3411 emit_method_inner (logbuffer
, info
->method
);
3412 emit_ptr (logbuffer
, cstart
);
3413 emit_value (logbuffer
, csize
);
3415 memcpy (logbuffer
->cursor
, name
, nlen
);
3416 logbuffer
->cursor
+= nlen
;
3418 EXIT_LOG_EXPLICIT (NO_SEND
);
3422 wrote_methods
= TRUE
;
3425 dec_method_ref_count (info
->method
);
3429 g_ptr_array_free (entry
->methods
, TRUE
);
3431 if (wrote_methods
) {
3432 MonoProfilerThread
*thread
= get_thread ();
3434 dump_buffer (thread
->buffer
);
3435 init_buffer_state (thread
);
3439 dump_buffer (entry
->buffer
);
3441 mono_thread_hazardous_try_free (entry
, free_writer_entry
);
3450 writer_thread (void *arg
)
3454 MonoProfilerThread
*thread
= profiler_thread_begin ("Profiler Writer", FALSE
);
3456 while (mono_atomic_load_i32 (&log_profiler
.run_writer_thread
)) {
3458 mono_os_sem_wait (&log_profiler
.writer_queue_sem
, MONO_SEM_FLAGS_NONE
);
3460 handle_writer_queue_entry ();
3462 profiler_thread_check_detach (thread
);
3465 /* Drain any remaining entries on shutdown. */
3466 while (handle_writer_queue_entry ());
3468 profiler_thread_end (thread
, &log_profiler
.writer_thread_exited
, FALSE
);
3474 start_writer_thread (void)
3476 mono_atomic_store_i32 (&log_profiler
.run_writer_thread
, 1);
3478 if (!mono_native_thread_create (&log_profiler
.writer_thread
, writer_thread
, NULL
)) {
3479 mono_profiler_printf_err ("Could not start log profiler writer thread");
3485 reuse_sample_hit (gpointer p
)
3487 SampleHit
*sample
= p
;
3489 mono_lock_free_queue_node_unpoison (&sample
->node
);
3490 mono_lock_free_queue_enqueue (&log_profiler
.sample_reuse_queue
, &sample
->node
);
3494 handle_dumper_queue_entry (void)
3498 if ((sample
= (SampleHit
*) mono_lock_free_queue_dequeue (&log_profiler
.dumper_queue
))) {
3499 for (int i
= 0; i
< sample
->count
; ++i
) {
3500 MonoMethod
*method
= sample
->frames
[i
].method
;
3501 MonoDomain
*domain
= sample
->frames
[i
].domain
;
3502 void *address
= sample
->frames
[i
].base_address
;
3505 g_assert (domain
&& "What happened to the domain pointer?");
3506 g_assert (address
&& "What happened to the instruction pointer?");
3508 MonoJitInfo
*ji
= mono_jit_info_table_find (domain
, address
);
3511 method
= mono_jit_info_get_method (ji
);
3514 inc_method_ref_count (method
);
3516 sample
->frames
[i
].method
= method
;
3520 ENTER_LOG (&sample_hits_ctr
, logbuffer
,
3521 EVENT_SIZE
/* event */ +
3522 LEB128_SIZE
/* tid */ +
3523 LEB128_SIZE
/* count */ +
3525 LEB128_SIZE
/* ip */
3527 LEB128_SIZE
/* managed count */ +
3529 LEB128_SIZE
/* method */
3533 emit_event_time (logbuffer
, TYPE_SAMPLE
| TYPE_SAMPLE_HIT
, sample
->time
);
3534 emit_ptr (logbuffer
, (void *) sample
->tid
);
3535 emit_value (logbuffer
, 1);
3537 // TODO: Actual native unwinding.
3538 for (int i
= 0; i
< 1; ++i
) {
3539 emit_ptr (logbuffer
, sample
->ip
);
3540 add_code_pointer ((uintptr_t) sample
->ip
);
3543 /* new in data version 6 */
3544 emit_uvalue (logbuffer
, sample
->count
);
3546 for (int i
= 0; i
< sample
->count
; ++i
)
3547 emit_method (logbuffer
, sample
->frames
[i
].method
);
3551 for (int i
= 0; i
< sample
->count
; ++i
) {
3552 MonoMethod
*method
= sample
->frames
[i
].method
;
3555 dec_method_ref_count (method
);
3558 mono_thread_hazardous_try_free (sample
, reuse_sample_hit
);
3560 dump_unmanaged_coderefs ();
3567 dumper_thread (void *arg
)
3569 MonoProfilerThread
*thread
= profiler_thread_begin ("Profiler Dumper", TRUE
);
3571 while (mono_atomic_load_i32 (&log_profiler
.run_dumper_thread
)) {
3572 gboolean timedout
= FALSE
;
3575 * Flush samples every second so it doesn't seem like the profiler is
3576 * not working if the program is mostly idle.
3578 timedout
= mono_os_sem_timedwait (&log_profiler
.dumper_queue_sem
, 1000, MONO_SEM_FLAGS_NONE
) == MONO_SEM_TIMEDWAIT_RET_TIMEDOUT
;
3581 send_log_unsafe (FALSE
);
3583 handle_dumper_queue_entry ();
3585 profiler_thread_check_detach (thread
);
3588 /* Drain any remaining entries on shutdown. */
3589 while (handle_dumper_queue_entry ());
3591 profiler_thread_end (thread
, &log_profiler
.dumper_thread_exited
, TRUE
);
3597 start_dumper_thread (void)
3599 mono_atomic_store_i32 (&log_profiler
.run_dumper_thread
, 1);
3601 if (!mono_native_thread_create (&log_profiler
.dumper_thread
, dumper_thread
, NULL
)) {
3602 mono_profiler_printf_err ("Could not start log profiler dumper thread");
3608 register_counter (const char *name
, gint32
*counter
)
3610 mono_counters_register (name
, MONO_COUNTER_UINT
| MONO_COUNTER_PROFILER
| MONO_COUNTER_MONOTONIC
, counter
);
3614 #pragma GCC diagnostic push
3615 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
3619 proflog_icall_GetMaxStackTraceFrames (void)
3625 proflog_icall_GetStackTraceFrames (void)
3627 return log_config
.num_frames
;
3631 proflog_icall_SetStackTraceFrames (gint32 value
)
3633 log_config
.num_frames
= value
;
3636 ICALL_EXPORT MonoProfilerHeapshotMode
3637 proflog_icall_GetHeapshotMode (void)
3639 return log_config
.hs_mode
;
3643 proflog_icall_SetHeapshotMode (MonoProfilerHeapshotMode value
)
3645 log_config
.hs_mode
= value
;
3649 proflog_icall_GetHeapshotMillisecondsFrequency (void)
3651 return log_config
.hs_freq_ms
;
3655 proflog_icall_SetHeapshotMillisecondsFrequency (gint32 value
)
3657 log_config
.hs_freq_ms
= value
;
3661 proflog_icall_GetHeapshotCollectionsFrequency (void)
3663 return log_config
.hs_freq_gc
;
3667 proflog_icall_SetHeapshotCollectionsFrequency (gint32 value
)
3669 log_config
.hs_freq_gc
= value
;
3673 proflog_icall_TriggerHeapshot (void)
3675 trigger_heapshot ();
3679 proflog_icall_GetCallDepth (void)
3681 return log_config
.max_call_depth
;
3685 proflog_icall_SetCallDepth (gint32 value
)
3687 log_config
.max_call_depth
= value
;
3691 proflog_icall_GetSampleMode (MonoProfilerSampleMode
*mode
, gint32
*frequency
)
3695 mono_profiler_get_sample_mode (log_profiler
.handle
, mode
, &freq
);
3700 ICALL_EXPORT MonoBoolean
3701 proflog_icall_SetSampleMode (MonoProfilerSampleMode mode
, gint32 frequency
)
3703 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3705 mono_bool result
= mono_profiler_set_sample_mode (log_profiler
.handle
, mode
, frequency
);
3707 if (mode
!= MONO_PROFILER_SAMPLE_MODE_NONE
) {
3708 ENABLE (PROFLOG_SAMPLE_EVENTS
);
3709 mono_profiler_set_sample_hit_callback (log_profiler
.handle
, mono_sample_hit
);
3711 DISABLE (PROFLOG_SAMPLE_EVENTS
);
3712 mono_profiler_set_sample_hit_callback (log_profiler
.handle
, NULL
);
3715 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3720 ICALL_EXPORT MonoBoolean
3721 proflog_icall_GetExceptionEvents (void)
3723 return ENABLED (PROFLOG_EXCEPTION_EVENTS
);
3727 proflog_icall_SetExceptionEvents (MonoBoolean value
)
3729 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3732 ENABLE (PROFLOG_EXCEPTION_EVENTS
);
3733 mono_profiler_set_exception_throw_callback (log_profiler
.handle
, throw_exc
);
3734 mono_profiler_set_exception_clause_callback (log_profiler
.handle
, clause_exc
);
3736 DISABLE (PROFLOG_EXCEPTION_EVENTS
);
3737 mono_profiler_set_exception_throw_callback (log_profiler
.handle
, NULL
);
3738 mono_profiler_set_exception_clause_callback (log_profiler
.handle
, NULL
);
3741 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3744 ICALL_EXPORT MonoBoolean
3745 proflog_icall_GetMonitorEvents (void)
3747 return ENABLED (PROFLOG_MONITOR_EVENTS
);
3751 proflog_icall_SetMonitorEvents (MonoBoolean value
)
3753 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3756 ENABLE (PROFLOG_MONITOR_EVENTS
);
3757 mono_profiler_set_monitor_contention_callback (log_profiler
.handle
, monitor_contention
);
3758 mono_profiler_set_monitor_acquired_callback (log_profiler
.handle
, monitor_acquired
);
3759 mono_profiler_set_monitor_failed_callback (log_profiler
.handle
, monitor_failed
);
3761 DISABLE (PROFLOG_MONITOR_EVENTS
);
3762 mono_profiler_set_monitor_contention_callback (log_profiler
.handle
, NULL
);
3763 mono_profiler_set_monitor_acquired_callback (log_profiler
.handle
, NULL
);
3764 mono_profiler_set_monitor_failed_callback (log_profiler
.handle
, NULL
);
3767 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3770 ICALL_EXPORT MonoBoolean
3771 proflog_icall_GetGCEvents (void)
3773 return ENABLED (PROFLOG_GC_EVENTS
);
3777 proflog_icall_SetGCEvents (MonoBoolean value
)
3779 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3782 ENABLE (PROFLOG_GC_EVENTS
);
3784 DISABLE (PROFLOG_GC_EVENTS
);
3786 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3789 ICALL_EXPORT MonoBoolean
3790 proflog_icall_GetGCAllocationEvents (void)
3792 return ENABLED (PROFLOG_GC_ALLOCATION_EVENTS
);
3796 proflog_icall_SetGCAllocationEvents (MonoBoolean value
)
3798 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3801 ENABLE (PROFLOG_GC_ALLOCATION_EVENTS
);
3802 mono_profiler_set_gc_allocation_callback (log_profiler
.handle
, gc_alloc
);
3804 DISABLE (PROFLOG_GC_ALLOCATION_EVENTS
);
3805 mono_profiler_set_gc_allocation_callback (log_profiler
.handle
, NULL
);
3808 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3811 ICALL_EXPORT MonoBoolean
3812 proflog_icall_GetGCMoveEvents (void)
3814 return ENABLED (PROFLOG_GC_MOVE_EVENTS
);
3818 proflog_icall_SetGCMoveEvents (MonoBoolean value
)
3820 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3823 ENABLE (PROFLOG_GC_MOVE_EVENTS
);
3824 mono_profiler_set_gc_moves_callback (log_profiler
.handle
, gc_moves
);
3826 DISABLE (PROFLOG_GC_MOVE_EVENTS
);
3827 mono_profiler_set_gc_moves_callback (log_profiler
.handle
, NULL
);
3830 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3833 ICALL_EXPORT MonoBoolean
3834 proflog_icall_GetGCRootEvents (void)
3836 return ENABLED (PROFLOG_GC_ROOT_EVENTS
);
3840 proflog_icall_SetGCRootEvents (MonoBoolean value
)
3842 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3845 ENABLE (PROFLOG_GC_ROOT_EVENTS
);
3847 DISABLE (PROFLOG_GC_ROOT_EVENTS
);
3849 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3852 ICALL_EXPORT MonoBoolean
3853 proflog_icall_GetGCHandleEvents (void)
3855 return ENABLED (PROFLOG_GC_HANDLE_EVENTS
);
3859 proflog_icall_SetGCHandleEvents (MonoBoolean value
)
3861 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3864 ENABLE (PROFLOG_GC_HANDLE_EVENTS
);
3865 mono_profiler_set_gc_handle_created_callback (log_profiler
.handle
, gc_handle_created
);
3866 mono_profiler_set_gc_handle_deleted_callback (log_profiler
.handle
, gc_handle_deleted
);
3868 DISABLE (PROFLOG_GC_HANDLE_EVENTS
);
3869 mono_profiler_set_gc_handle_created_callback (log_profiler
.handle
, NULL
);
3870 mono_profiler_set_gc_handle_deleted_callback (log_profiler
.handle
, NULL
);
3873 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3876 ICALL_EXPORT MonoBoolean
3877 proflog_icall_GetGCFinalizationEvents (void)
3879 return ENABLED (PROFLOG_GC_FINALIZATION_EVENTS
);
3883 proflog_icall_SetGCFinalizationEvents (MonoBoolean value
)
3885 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3888 ENABLE (PROFLOG_GC_FINALIZATION_EVENTS
);
3889 mono_profiler_set_gc_finalizing_callback (log_profiler
.handle
, finalize_begin
);
3890 mono_profiler_set_gc_finalizing_object_callback (log_profiler
.handle
, finalize_object_begin
);
3891 mono_profiler_set_gc_finalized_object_callback (log_profiler
.handle
, finalize_object_end
);
3893 DISABLE (PROFLOG_GC_FINALIZATION_EVENTS
);
3894 mono_profiler_set_gc_finalizing_callback (log_profiler
.handle
, NULL
);
3895 mono_profiler_set_gc_finalizing_object_callback (log_profiler
.handle
, NULL
);
3896 mono_profiler_set_gc_finalized_object_callback (log_profiler
.handle
, NULL
);
3899 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3902 ICALL_EXPORT MonoBoolean
3903 proflog_icall_GetCounterEvents (void)
3905 return ENABLED (PROFLOG_COUNTER_EVENTS
);
3909 proflog_icall_SetCounterEvents (MonoBoolean value
)
3911 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3914 ENABLE (PROFLOG_COUNTER_EVENTS
);
3916 DISABLE (PROFLOG_COUNTER_EVENTS
);
3918 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3921 ICALL_EXPORT MonoBoolean
3922 proflog_icall_GetJitEvents (void)
3924 return ENABLED (PROFLOG_JIT_EVENTS
);
3928 proflog_icall_SetJitEvents (MonoBoolean value
)
3930 mono_coop_mutex_lock (&log_profiler
.api_mutex
);
3933 ENABLE (PROFLOG_JIT_EVENTS
);
3934 mono_profiler_set_jit_code_buffer_callback (log_profiler
.handle
, code_buffer_new
);
3936 DISABLE (PROFLOG_JIT_EVENTS
);
3937 mono_profiler_set_jit_code_buffer_callback (log_profiler
.handle
, NULL
);
3940 mono_coop_mutex_unlock (&log_profiler
.api_mutex
);
3944 #pragma GCC diagnostic pop
3948 runtime_initialized (MonoProfiler
*profiler
)
3952 * We depend on socket support in this profiler provider we need to
3953 * make sure we keep a reference on WSA for the lifetime of this provider.
3958 err
= WSAStartup (2 /* 2.0 */, &wsadata
);
3960 mono_profiler_printf_err ("Couldn't initialise networking.");
3964 mono_atomic_store_i32 (&log_profiler
.runtime_inited
, 1);
3966 register_counter ("Sample events allocated", &sample_allocations_ctr
);
3967 register_counter ("Log buffers allocated", &buffer_allocations_ctr
);
3969 register_counter ("Event: Sync points", &sync_points_ctr
);
3970 register_counter ("Event: AOT IDs", &aot_ids_ctr
);
3971 register_counter ("Event: Heap objects", &heap_objects_ctr
);
3972 register_counter ("Event: Heap starts", &heap_starts_ctr
);
3973 register_counter ("Event: Heap ends", &heap_ends_ctr
);
3974 register_counter ("Event: Heap roots", &heap_roots_ctr
);
3975 register_counter ("Event: Heap root registers", &heap_root_registers_ctr
);
3976 register_counter ("Event: Heap root unregisters", &heap_root_unregisters_ctr
);
3977 register_counter ("Event: GC events", &gc_events_ctr
);
3978 register_counter ("Event: GC resizes", &gc_resizes_ctr
);
3979 register_counter ("Event: GC allocations", &gc_allocs_ctr
);
3980 register_counter ("Event: GC moves", &gc_moves_ctr
);
3981 register_counter ("Event: GC handle creations", &gc_handle_creations_ctr
);
3982 register_counter ("Event: GC handle deletions", &gc_handle_deletions_ctr
);
3983 register_counter ("Event: GC finalize starts", &finalize_begins_ctr
);
3984 register_counter ("Event: GC finalize ends", &finalize_ends_ctr
);
3985 register_counter ("Event: GC finalize object starts", &finalize_object_begins_ctr
);
3986 register_counter ("Event: GC finalize object ends", &finalize_object_ends_ctr
);
3987 register_counter ("Event: Image loads", &image_loads_ctr
);
3988 register_counter ("Event: Image unloads", &image_unloads_ctr
);
3989 register_counter ("Event: Assembly loads", &assembly_loads_ctr
);
3990 register_counter ("Event: Assembly unloads", &assembly_unloads_ctr
);
3991 register_counter ("Event: Class loads", &class_loads_ctr
);
3992 register_counter ("Event: VTable loads", &vtable_loads_ctr
);
3993 register_counter ("Event: Method entries", &method_entries_ctr
);
3994 register_counter ("Event: Method exits", &method_exits_ctr
);
3995 register_counter ("Event: Method exception leaves", &method_exception_exits_ctr
);
3996 register_counter ("Event: Method JITs", &method_jits_ctr
);
3997 register_counter ("Event: Code buffers", &code_buffers_ctr
);
3998 register_counter ("Event: Exception throws", &exception_throws_ctr
);
3999 register_counter ("Event: Exception clauses", &exception_clauses_ctr
);
4000 register_counter ("Event: Monitor events", &monitor_events_ctr
);
4001 register_counter ("Event: Thread starts", &thread_starts_ctr
);
4002 register_counter ("Event: Thread ends", &thread_ends_ctr
);
4003 register_counter ("Event: Thread names", &thread_names_ctr
);
4004 register_counter ("Event: Domain loads", &domain_loads_ctr
);
4005 register_counter ("Event: Domain unloads", &domain_unloads_ctr
);
4006 register_counter ("Event: Domain names", &domain_names_ctr
);
4007 register_counter ("Event: Context loads", &context_loads_ctr
);
4008 register_counter ("Event: Context unloads", &context_unloads_ctr
);
4009 register_counter ("Event: Sample binaries", &sample_ubins_ctr
);
4010 register_counter ("Event: Sample symbols", &sample_usyms_ctr
);
4011 register_counter ("Event: Sample hits", &sample_hits_ctr
);
4012 register_counter ("Event: Counter descriptors", &counter_descriptors_ctr
);
4013 register_counter ("Event: Counter samples", &counter_samples_ctr
);
4014 register_counter ("Event: Performance counter descriptors", &perfcounter_descriptors_ctr
);
4015 register_counter ("Event: Performance counter samples", &perfcounter_samples_ctr
);
4019 mono_os_sem_init (&log_profiler
.attach_threads_sem
, 0);
4022 * We must start the helper thread before the writer thread. This is
4023 * because start_helper_thread () sets up the command port which is written
4024 * to the log header by the writer thread.
4026 start_helper_thread ();
4027 start_writer_thread ();
4028 start_dumper_thread ();
4031 * Wait for all the internal threads to be started. If we don't do this, we
4032 * might shut down before they finish initializing, which could lead to
4033 * various deadlocks when waiting for them to exit during shutdown.
4035 for (int i
= 0; i
< 3; i
++)
4036 mono_os_sem_wait (&log_profiler
.attach_threads_sem
, MONO_SEM_FLAGS_NONE
);
4038 mono_os_sem_destroy (&log_profiler
.attach_threads_sem
);
4040 mono_coop_mutex_init (&log_profiler
.api_mutex
);
4042 #define ADD_ICALL(NAME) \
4043 mono_add_internal_call_internal ("Mono.Profiler.Log.LogProfiler::" EGLIB_STRINGIFY (NAME), proflog_icall_ ## NAME);
4045 ADD_ICALL (GetMaxStackTraceFrames
);
4046 ADD_ICALL (GetStackTraceFrames
);
4047 ADD_ICALL (SetStackTraceFrames
);
4048 ADD_ICALL (GetHeapshotMode
);
4049 ADD_ICALL (SetHeapshotMode
);
4050 ADD_ICALL (GetHeapshotMillisecondsFrequency
);
4051 ADD_ICALL (SetHeapshotMillisecondsFrequency
);
4052 ADD_ICALL (GetHeapshotCollectionsFrequency
);
4053 ADD_ICALL (SetHeapshotCollectionsFrequency
);
4054 ADD_ICALL (TriggerHeapshot
);
4055 ADD_ICALL (GetCallDepth
);
4056 ADD_ICALL (SetCallDepth
);
4057 ADD_ICALL (GetSampleMode
);
4058 ADD_ICALL (SetSampleMode
);
4059 ADD_ICALL (GetExceptionEvents
);
4060 ADD_ICALL (SetExceptionEvents
);
4061 ADD_ICALL (GetMonitorEvents
);
4062 ADD_ICALL (SetMonitorEvents
);
4063 ADD_ICALL (GetGCEvents
);
4064 ADD_ICALL (SetGCEvents
);
4065 ADD_ICALL (GetGCAllocationEvents
);
4066 ADD_ICALL (SetGCAllocationEvents
);
4067 ADD_ICALL (GetGCMoveEvents
);
4068 ADD_ICALL (SetGCMoveEvents
);
4069 ADD_ICALL (GetGCRootEvents
);
4070 ADD_ICALL (SetGCRootEvents
);
4071 ADD_ICALL (GetGCHandleEvents
);
4072 ADD_ICALL (SetGCHandleEvents
);
4073 ADD_ICALL (GetGCFinalizationEvents
);
4074 ADD_ICALL (SetGCFinalizationEvents
);
4075 ADD_ICALL (GetCounterEvents
);
4076 ADD_ICALL (SetCounterEvents
);
4077 ADD_ICALL (GetJitEvents
);
4078 ADD_ICALL (SetJitEvents
);
4084 create_profiler (const char *args
, const char *filename
, GPtrArray
*filters
)
4088 log_profiler
.args
= pstrdup (args
);
4089 log_profiler
.command_port
= log_config
.command_port
;
4091 //If filename begin with +, append the pid at the end
4092 if (filename
&& *filename
== '+')
4093 filename
= g_strdup_printf ("%s.%d", filename
+ 1, (int)process_id ());
4096 if (log_config
.do_report
)
4097 filename
= "|mprof-report -";
4099 filename
= "output.mlpd";
4100 nf
= (char*)filename
;
4102 nf
= new_filename (filename
);
4103 if (log_config
.do_report
) {
4104 int s
= strlen (nf
) + 32;
4105 char *p
= (char *) g_malloc (s
);
4106 snprintf (p
, s
, "|mprof-report '--out=%s' -", nf
);
4112 #if HAVE_API_SUPPORT_WIN32_PIPE_OPEN_CLOSE && !defined (HOST_WIN32)
4113 log_profiler
.file
= popen (nf
+ 1, "w");
4114 log_profiler
.pipe_output
= 1;
4116 mono_profiler_printf_err ("Platform doesn't support popen");
4118 } else if (*nf
== '#') {
4119 int fd
= strtol (nf
+ 1, NULL
, 10);
4120 log_profiler
.file
= fdopen (fd
, "a");
4122 log_profiler
.file
= fopen (nf
, "wb");
4124 if (!log_profiler
.file
) {
4125 mono_profiler_printf_err ("Could not create log profiler output file '%s': %s", nf
, g_strerror (errno
));
4129 #if defined (HAVE_SYS_ZLIB)
4130 if (log_config
.use_zip
)
4131 log_profiler
.gzfile
= gzdopen (fileno (log_profiler
.file
), "wb");
4134 // FIXME: We should free this stuff too.
4135 mono_lock_free_allocator_init_size_class (&log_profiler
.sample_size_class
, SAMPLE_SLOT_SIZE (log_config
.num_frames
), SAMPLE_BLOCK_SIZE
);
4136 mono_lock_free_allocator_init_allocator (&log_profiler
.sample_allocator
, &log_profiler
.sample_size_class
, MONO_MEM_ACCOUNT_PROFILER
);
4138 mono_lock_free_queue_init (&log_profiler
.sample_reuse_queue
);
4140 // FIXME: We should free this stuff too.
4141 mono_lock_free_allocator_init_size_class (&log_profiler
.writer_entry_size_class
, sizeof (WriterQueueEntry
), WRITER_ENTRY_BLOCK_SIZE
);
4142 mono_lock_free_allocator_init_allocator (&log_profiler
.writer_entry_allocator
, &log_profiler
.writer_entry_size_class
, MONO_MEM_ACCOUNT_PROFILER
);
4144 mono_os_event_init (&log_profiler
.helper_thread_exited
, FALSE
);
4146 mono_os_event_init (&log_profiler
.writer_thread_exited
, FALSE
);
4147 mono_lock_free_queue_init (&log_profiler
.writer_queue
);
4148 mono_os_sem_init (&log_profiler
.writer_queue_sem
, 0);
4150 mono_os_event_init (&log_profiler
.dumper_thread_exited
, FALSE
);
4151 mono_lock_free_queue_init (&log_profiler
.dumper_queue
);
4152 mono_os_sem_init (&log_profiler
.dumper_queue_sem
, 0);
4154 mono_os_mutex_init (&log_profiler
.method_table_mutex
);
4155 log_profiler
.method_table
= mono_conc_hashtable_new (NULL
, NULL
);
4157 log_profiler
.startup_time
= current_time ();
4161 mono_profiler_init_log (const char *desc
);
4164 mono_profiler_init_log (const char *desc
)
4167 * If you hit this assert while increasing MAX_FRAMES, you need to increase
4168 * SAMPLE_BLOCK_SIZE as well.
4170 g_assert (SAMPLE_SLOT_SIZE (MAX_FRAMES
) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (SAMPLE_BLOCK_SIZE
));
4171 g_assert (sizeof (WriterQueueEntry
) * 2 < LOCK_FREE_ALLOC_SB_USABLE_SIZE (WRITER_ENTRY_BLOCK_SIZE
));
4173 GPtrArray
*filters
= NULL
;
4175 proflog_parse_args (&log_config
, desc
[3] == ':' ? desc
+ 4 : "");
4177 MonoProfilerHandle handle
= log_profiler
.handle
= mono_profiler_create (&log_profiler
);
4179 if (log_config
.enter_leave
)
4180 mono_profiler_set_call_instrumentation_filter_callback (handle
, method_filter
);
4183 * If the runtime was invoked for the purpose of AOT compilation only, the
4184 * only thing we want to do is install the call instrumentation filter.
4186 if (mono_jit_aot_compiling ())
4191 create_profiler (desc
, log_config
.output_filename
, filters
);
4193 mono_lls_init (&log_profiler
.profiler_thread_list
, NULL
);
4196 * Required callbacks. These are either necessary for the profiler itself
4197 * to function, or provide metadata that's needed if other events (e.g.
4198 * allocations, exceptions) are dynamically enabled/disabled.
4201 mono_profiler_set_runtime_shutdown_begin_callback (handle
, log_early_shutdown
);
4202 mono_profiler_set_runtime_shutdown_end_callback (handle
, log_shutdown
);
4203 mono_profiler_set_runtime_initialized_callback (handle
, runtime_initialized
);
4205 mono_profiler_set_gc_event_callback (handle
, gc_event
);
4207 mono_profiler_set_thread_started_callback (handle
, thread_start
);
4208 mono_profiler_set_thread_exited_callback (handle
, thread_end
);
4209 mono_profiler_set_thread_name_callback (handle
, thread_name
);
4211 mono_profiler_set_domain_loaded_callback (handle
, domain_loaded
);
4212 mono_profiler_set_domain_unloading_callback (handle
, domain_unloaded
);
4213 mono_profiler_set_domain_name_callback (handle
, domain_name
);
4215 mono_profiler_set_context_loaded_callback (handle
, context_loaded
);
4216 mono_profiler_set_context_unloaded_callback (handle
, context_unloaded
);
4218 mono_profiler_set_assembly_loaded_callback (handle
, assembly_loaded
);
4219 mono_profiler_set_assembly_unloading_callback (handle
, assembly_unloaded
);
4221 mono_profiler_set_image_loaded_callback (handle
, image_loaded
);
4222 mono_profiler_set_image_unloading_callback (handle
, image_unloaded
);
4224 mono_profiler_set_class_loaded_callback (handle
, class_loaded
);
4226 mono_profiler_set_vtable_loaded_callback (handle
, vtable_loaded
);
4228 mono_profiler_set_jit_done_callback (handle
, method_jitted
);
4230 mono_profiler_set_gc_root_register_callback (handle
, gc_root_register
);
4231 mono_profiler_set_gc_root_unregister_callback (handle
, gc_root_deregister
);
4233 if (ENABLED (PROFLOG_EXCEPTION_EVENTS
)) {
4234 mono_profiler_set_exception_throw_callback (handle
, throw_exc
);
4235 mono_profiler_set_exception_clause_callback (handle
, clause_exc
);
4238 if (ENABLED (PROFLOG_MONITOR_EVENTS
)) {
4239 mono_profiler_set_monitor_contention_callback (handle
, monitor_contention
);
4240 mono_profiler_set_monitor_acquired_callback (handle
, monitor_acquired
);
4241 mono_profiler_set_monitor_failed_callback (handle
, monitor_failed
);
4244 if (ENABLED (PROFLOG_GC_EVENTS
))
4245 mono_profiler_set_gc_resize_callback (handle
, gc_resize
);
4247 if (ENABLED (PROFLOG_GC_ALLOCATION_EVENTS
))
4248 mono_profiler_set_gc_allocation_callback (handle
, gc_alloc
);
4250 if (ENABLED (PROFLOG_GC_MOVE_EVENTS
))
4251 mono_profiler_set_gc_moves_callback (handle
, gc_moves
);
4253 if (ENABLED (PROFLOG_GC_HANDLE_EVENTS
)) {
4254 mono_profiler_set_gc_handle_created_callback (handle
, gc_handle_created
);
4255 mono_profiler_set_gc_handle_deleted_callback (handle
, gc_handle_deleted
);
4258 if (ENABLED (PROFLOG_GC_FINALIZATION_EVENTS
)) {
4259 mono_profiler_set_gc_finalizing_callback (handle
, finalize_begin
);
4260 mono_profiler_set_gc_finalized_callback (handle
, finalize_end
);
4261 mono_profiler_set_gc_finalizing_object_callback (handle
, finalize_object_begin
);
4262 mono_profiler_set_gc_finalized_object_callback (handle
, finalize_object_end
);
4265 //On Demand heapshot uses the finalizer thread to force a collection and thus a heapshot
4266 mono_profiler_set_gc_finalized_callback (handle
, finalize_end
);
4268 if (ENABLED (PROFLOG_SAMPLE_EVENTS
))
4269 mono_profiler_set_sample_hit_callback (handle
, mono_sample_hit
);
4271 if (ENABLED (PROFLOG_JIT_EVENTS
))
4272 mono_profiler_set_jit_code_buffer_callback (handle
, code_buffer_new
);
4274 if (log_config
.enter_leave
) {
4275 mono_profiler_set_method_enter_callback (handle
, method_enter
);
4276 mono_profiler_set_method_leave_callback (handle
, method_leave
);
4277 mono_profiler_set_method_tail_call_callback (handle
, tailcall
);
4278 mono_profiler_set_method_exception_leave_callback (handle
, method_exc_leave
);
4281 mono_profiler_enable_allocations ();
4282 mono_profiler_enable_clauses ();
4283 mono_profiler_enable_sampling (handle
);
4286 * If no sample option was given by the user, this just leaves the sampling
4287 * thread in idle mode. We do this even if no option was given so that we
4288 * can warn if another profiler controls sampling parameters.
4290 if (!mono_profiler_set_sample_mode (handle
, log_config
.sampling_mode
, log_config
.sample_freq
))
4291 mono_profiler_printf_err ("Another profiler controls sampling parameters; the log profiler will not be able to modify them.");