2 #include <mono/metadata/profiler.h>
3 #include <mono/metadata/class.h>
4 #include <mono/metadata/assembly.h>
5 #include <mono/metadata/loader.h>
6 #include <mono/metadata/threads.h>
7 #include <mono/metadata/debug-helpers.h>
8 #include <mono/io-layer/atomic.h>
17 #define HAS_OPROFILE 0
20 #include <libopagent.h>
23 // Needed for heap analysis
24 extern gboolean mono_object_is_alive (MonoObject* obj);
27 MONO_PROFILER_FILE_BLOCK_KIND_INTRO = 1,
28 MONO_PROFILER_FILE_BLOCK_KIND_END = 2,
29 MONO_PROFILER_FILE_BLOCK_KIND_MAPPING = 3,
30 MONO_PROFILER_FILE_BLOCK_KIND_LOADED = 4,
31 MONO_PROFILER_FILE_BLOCK_KIND_UNLOADED = 5,
32 MONO_PROFILER_FILE_BLOCK_KIND_EVENTS = 6,
33 MONO_PROFILER_FILE_BLOCK_KIND_STATISTICAL = 7,
34 MONO_PROFILER_FILE_BLOCK_KIND_HEAP = 8
35 } MonoProfilerFileBlockKind;
37 #define MONO_PROFILER_LOADED_EVENT_MODULE 1
38 #define MONO_PROFILER_LOADED_EVENT_ASSEMBLY 2
39 #define MONO_PROFILER_LOADED_EVENT_APPDOMAIN 4
40 #define MONO_PROFILER_LOADED_EVENT_SUCCESS 8
41 #define MONO_PROFILER_LOADED_EVENT_FAILURE 16
44 MONO_PROFILER_EVENT_DATA_TYPE_OTHER = 0,
45 MONO_PROFILER_EVENT_DATA_TYPE_METHOD = 1,
46 MONO_PROFILER_EVENT_DATA_TYPE_CLASS = 2
47 } MonoProfilerEventDataType;
49 typedef struct _ProfilerEventData {
54 unsigned int data_type:2;
57 unsigned int value:26;
60 #define EXTENDED_EVENT_VALUE_SHIFT (26)
61 #define MAX_EVENT_VALUE ((1<<EXTENDED_EVENT_VALUE_SHIFT)-1)
62 #define MAX_EXTENDED_EVENT_VALUE ((((guint64))MAX_EVENT_VALUE<<32)|((guint64)0xffffffff))
65 MONO_PROFILER_EVENT_METHOD_JIT = 0,
66 MONO_PROFILER_EVENT_METHOD_FREED = 1,
67 MONO_PROFILER_EVENT_METHOD_CALL = 2
68 } MonoProfilerMethodEvents;
70 MONO_PROFILER_EVENT_CLASS_LOAD = 0,
71 MONO_PROFILER_EVENT_CLASS_UNLOAD = 1,
72 MONO_PROFILER_EVENT_CLASS_EXCEPTION = 2,
73 MONO_PROFILER_EVENT_CLASS_ALLOCATION = 3
74 } MonoProfilerClassEvents;
76 MONO_PROFILER_EVENT_RESULT_SUCCESS = 0,
77 MONO_PROFILER_EVENT_RESULT_FAILURE = 4
78 } MonoProfilerEventResult;
79 #define MONO_PROFILER_EVENT_RESULT_MASK MONO_PROFILER_EVENT_RESULT_FAILURE
81 MONO_PROFILER_EVENT_THREAD = 1,
82 MONO_PROFILER_EVENT_GC_COLLECTION = 2,
83 MONO_PROFILER_EVENT_GC_MARK = 3,
84 MONO_PROFILER_EVENT_GC_SWEEP = 4,
85 MONO_PROFILER_EVENT_GC_RESIZE = 5,
86 MONO_PROFILER_EVENT_GC_STOP_WORLD = 6,
87 MONO_PROFILER_EVENT_GC_START_WORLD = 7
90 MONO_PROFILER_EVENT_KIND_START = 0,
91 MONO_PROFILER_EVENT_KIND_END = 1
92 } MonoProfilerEventKind;
94 #define MONO_PROFILER_GET_CURRENT_TIME(t) {\
95 struct timeval current_time;\
96 gettimeofday (¤t_time, NULL);\
97 (t) = (((guint64)current_time.tv_sec) * 1000000) + current_time.tv_usec;\
100 #define MONO_PROFILER_GET_CURRENT_COUNTER(c) MONO_PROFILER_GET_CURRENT_TIME ((c));
102 static __inline__ guint64 rdtsc(void) {
104 __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
105 return ((guint64) lo) | (((guint64) hi) << 32);
107 #define MONO_PROFILER_GET_CURRENT_COUNTER(c) {\
113 #define CLASS_LAYOUT_PACKED_BITMAP_SIZE 64
114 #define CLASS_LAYOUT_NOT_INITIALIZED (0xFFFF)
117 HEAP_CODE_OBJECT = 1,
118 HEAP_CODE_FREE_OBJECT_CLASS = 2,
120 } HeapProfilerJobValueCode;
121 typedef struct _MonoProfilerClassData {
130 } MonoProfilerClassData;
132 typedef struct _MonoProfilerMethodData {
135 } MonoProfilerMethodData;
137 typedef struct _ClassIdMappingElement {
141 struct _ClassIdMappingElement *next_unwritten;
142 MonoProfilerClassData data;
143 } ClassIdMappingElement;
145 typedef struct _MethodIdMappingElement {
149 struct _MethodIdMappingElement *next_unwritten;
150 MonoProfilerMethodData data;
151 } MethodIdMappingElement;
153 typedef struct _ClassIdMapping {
155 ClassIdMappingElement *unwritten;
159 typedef struct _MethodIdMapping {
161 MethodIdMappingElement *unwritten;
165 typedef struct _LoadedElement {
167 guint64 load_start_counter;
168 guint64 load_end_counter;
169 guint64 unload_start_counter;
170 guint64 unload_end_counter;
174 guint8 unload_written;
177 #define PROFILER_HEAP_SHOT_OBJECT_BUFFER_SIZE 1024
178 #define PROFILER_HEAP_SHOT_HEAP_BUFFER_SIZE 4096
179 #define PROFILER_HEAP_SHOT_WRITE_BUFFER_SIZE 4096
181 typedef struct _ProfilerHeapShotObjectBuffer {
182 struct _ProfilerHeapShotObjectBuffer *next;
183 MonoObject **next_free_slot;
185 MonoObject **first_unprocessed_slot;
186 MonoObject *buffer [PROFILER_HEAP_SHOT_OBJECT_BUFFER_SIZE];
187 } ProfilerHeapShotObjectBuffer;
189 typedef struct _ProfilerHeapShotHeapBuffer {
190 struct _ProfilerHeapShotHeapBuffer *next;
191 struct _ProfilerHeapShotHeapBuffer *previous;
192 MonoObject **start_slot;
193 MonoObject **end_slot;
194 MonoObject *buffer [PROFILER_HEAP_SHOT_HEAP_BUFFER_SIZE];
195 } ProfilerHeapShotHeapBuffer;
197 typedef struct _ProfilerHeapShotHeapBuffers {
198 ProfilerHeapShotHeapBuffer *buffers;
199 ProfilerHeapShotHeapBuffer *last;
200 ProfilerHeapShotHeapBuffer *current;
201 MonoObject **first_free_slot;
202 } ProfilerHeapShotHeapBuffers;
205 typedef struct _ProfilerHeapShotWriteBuffer {
206 struct _ProfilerHeapShotWriteBuffer *next;
207 gpointer buffer [PROFILER_HEAP_SHOT_WRITE_BUFFER_SIZE];
208 } ProfilerHeapShotWriteBuffer;
210 typedef struct _ProfilerHeapShotWriteJob {
211 struct _ProfilerHeapShotWriteJob *next;
212 struct _ProfilerHeapShotWriteJob *next_unwritten;
216 ProfilerHeapShotWriteBuffer *buffers;
217 ProfilerHeapShotWriteBuffer **last_next;
218 guint32 full_buffers;
219 gboolean heap_shot_was_signalled;
220 guint64 start_counter;
224 } ProfilerHeapShotWriteJob;
226 typedef struct _ProfilerPerThreadData {
227 ProfilerEventData *events;
228 ProfilerEventData *next_free_event;
229 ProfilerEventData *end_event;
230 ProfilerEventData *first_unwritten_event;
231 ProfilerEventData *first_unmapped_event;
232 guint64 start_event_counter;
233 guint64 last_event_counter;
235 ProfilerHeapShotObjectBuffer *heap_shot_object_buffers;
236 struct _ProfilerPerThreadData* next;
237 } ProfilerPerThreadData;
239 typedef struct _ProfilerStatisticalData {
243 int first_unwritten_index;
244 } ProfilerStatisticalData;
246 typedef struct _ProfilerExecutableMemoryRegionData {
253 } ProfilerExecutableMemoryRegionData;
255 typedef struct _ProfilerExecutableMemoryRegions {
256 ProfilerExecutableMemoryRegionData **regions;
257 guint32 regions_capacity;
258 guint32 regions_count;
260 } ProfilerExecutableMemoryRegions;
262 typedef struct _ProfilerUnmanagedFunction {
266 struct _ProfilerUnmanagedFunction *next_unwritten;
267 } ProfilerUnmanagedFunction;
269 typedef struct _ProfilerUnmanagedFunctions {
271 ProfilerUnmanagedFunction *unwritten_queue;
272 ProfilerUnmanagedFunction *unwritten_queue_end;
274 ProfilerUnmanagedFunction actual_unwritten_queue_end;
275 } ProfilerUnmanagedFunctions;
277 #ifndef PLATFORM_WIN32
278 #include <sys/types.h>
279 #include <sys/time.h>
280 #include <sys/stat.h>
284 #include <semaphore.h>
286 #define MUTEX_TYPE pthread_mutex_t
287 #define INITIALIZE_PROFILER_MUTEX() pthread_mutex_init (&(profiler->mutex), NULL)
288 #define DELETE_PROFILER_MUTEX() pthread_mutex_destroy (&(profiler->mutex))
289 #define LOCK_PROFILER() do {/*LOG_WRITER_THREAD ("LOCK_PROFILER");*/ pthread_mutex_lock (&(profiler->mutex));} while (0)
290 #define UNLOCK_PROFILER() do {/*LOG_WRITER_THREAD ("UNLOCK_PROFILER");*/ pthread_mutex_unlock (&(profiler->mutex));} while (0)
292 #define THREAD_TYPE pthread_t
293 #define CREATE_WRITER_THREAD(f) pthread_create (&(profiler->data_writer_thread), NULL, ((void*(*)(void*))f), NULL)
294 #define EXIT_THREAD() pthread_exit (NULL);
295 #define WAIT_WRITER_THREAD() pthread_join (profiler->data_writer_thread, NULL)
296 #define CURRENT_THREAD_ID() (gsize) pthread_self ()
298 #ifndef HAVE_KW_THREAD
299 static pthread_key_t pthread_profiler_key;
300 static pthread_once_t profiler_pthread_once = PTHREAD_ONCE_INIT;
302 make_pthread_profiler_key (void) {
303 (void) pthread_key_create (&pthread_profiler_key, NULL);
305 #define LOOKUP_PROFILER_THREAD_DATA() ((ProfilerPerThreadData*) pthread_getspecific (pthread_profiler_key))
306 #define SET_PROFILER_THREAD_DATA(x) (void) pthread_setspecific (pthread_profiler_key, (x))
307 #define ALLOCATE_PROFILER_THREAD_DATA() (void) pthread_once (&profiler_pthread_once, make_pthread_profiler_key)
308 #define FREE_PROFILER_THREAD_DATA() (void) pthread_key_delete (pthread_profiler_key)
311 #define EVENT_TYPE sem_t
312 #define WRITER_EVENT_INIT() (void) sem_init (&(profiler->statistical_data_writer_event), 0, 0)
313 #define WRITER_EVENT_DESTROY() (void) sem_destroy (&(profiler->statistical_data_writer_event))
314 #define WRITER_EVENT_WAIT() (void) sem_wait (&(profiler->statistical_data_writer_event))
315 #define WRITER_EVENT_RAISE() (void) sem_post (&(profiler->statistical_data_writer_event))
318 #define FILE_HANDLE_TYPE FILE*
319 #define OPEN_FILE() profiler->file = fopen (profiler->file_name, "wb");
320 #define WRITE_BUFFER(b,s) fwrite ((b), 1, (s), profiler->file)
321 #define FLUSH_FILE() fflush (profiler->file)
322 #define CLOSE_FILE() fclose (profiler->file);
324 #define FILE_HANDLE_TYPE int
325 #define OPEN_FILE() profiler->file = open (profiler->file_name, O_WRONLY|O_CREAT|O_TRUNC, 0664);
326 #define WRITE_BUFFER(b,s) write (profiler->file, (b), (s))
328 #define CLOSE_FILE() close (profiler->file);
335 #define MUTEX_TYPE CRITICAL_SECTION
336 #define INITIALIZE_PROFILER_MUTEX() InitializeCriticalSection (&(profiler->mutex))
337 #define DELETE_PROFILER_MUTEX() DeleteCriticalSection (&(profiler->mutex))
338 #define LOCK_PROFILER() EnterCriticalSection (&(profiler->mutex))
339 #define UNLOCK_PROFILER() LeaveCriticalSection (&(profiler->mutex))
341 #define THREAD_TYPE HANDLE
342 #define CREATE_WRITER_THREAD(f) CreateThread (NULL, (1*1024*1024), (f), NULL, 0, NULL);
343 #define EXIT_THREAD() ExitThread (0);
344 #define WAIT_WRITER_THREAD() WaitForSingleObject (profiler->data_writer_thread, INFINITE)
345 #define CURRENT_THREAD_ID() (gsize) GetCurrentThreadId ()
347 #ifndef HAVE_KW_THREAD
348 static guint32 profiler_thread_id = -1;
349 #define LOOKUP_PROFILER_THREAD_DATA() ((ProfilerPerThreadData*)TlsGetValue (profiler_thread_id))
350 #define SET_PROFILER_THREAD_DATA(x) TlsSetValue (profiler_thread_id, (x));
351 #define ALLOCATE_PROFILER_THREAD_DATA() profiler_thread_id = TlsAlloc ()
352 #define FREE_PROFILER_THREAD_DATA() TlsFree (profiler_thread_id)
355 #define EVENT_TYPE HANDLE
356 #define WRITER_EVENT_INIT() profiler->statistical_data_writer_event = CreateEvent (NULL, FALSE, FALSE, NULL)
357 #define WRITER_EVENT_DESTROY() CloseHandle (profiler->statistical_data_writer_event)
358 #define WRITER_EVENT_WAIT() WaitForSingleObject (profiler->statistical_data_writer_event, INFINITE)
359 #define WRITER_EVENT_RAISE() SetEvent (profiler->statistical_data_writer_event)
361 #define FILE_HANDLE_TYPE FILE*
362 #define OPEN_FILE() profiler->file = fopen (profiler->file_name, "wb");
363 #define WRITE_BUFFER(b,s) fwrite ((b), 1, (s), profiler->file)
364 #define FLUSH_FILE() fflush (profiler->file)
365 #define CLOSE_FILE() fclose (profiler->file);
369 #ifdef HAVE_KW_THREAD
370 static __thread ProfilerPerThreadData * tls_profiler_per_thread_data;
371 #define LOOKUP_PROFILER_THREAD_DATA() ((ProfilerPerThreadData*) tls_profiler_per_thread_data)
372 #define SET_PROFILER_THREAD_DATA(x) tls_profiler_per_thread_data = (x)
373 #define ALLOCATE_PROFILER_THREAD_DATA() /* nop */
374 #define FREE_PROFILER_THREAD_DATA() /* nop */
377 #define GET_PROFILER_THREAD_DATA(data) do {\
378 ProfilerPerThreadData *_result = LOOKUP_PROFILER_THREAD_DATA ();\
380 _result = profiler_per_thread_data_new (profiler->per_thread_buffer_size);\
382 _result->next = profiler->per_thread_data;\
383 profiler->per_thread_data = _result;\
385 SET_PROFILER_THREAD_DATA (_result);\
390 #define PROFILER_FILE_WRITE_BUFFER_SIZE (profiler->write_buffer_size)
391 typedef struct _ProfilerFileWriteBuffer {
392 struct _ProfilerFileWriteBuffer *next;
394 } ProfilerFileWriteBuffer;
396 struct _MonoProfiler {
399 MonoProfileFlags flags;
401 FILE_HANDLE_TYPE file;
404 guint64 start_counter;
408 MethodIdMapping *methods;
409 ClassIdMapping *classes;
411 GHashTable *loaded_assemblies;
412 GHashTable *loaded_modules;
413 GHashTable *loaded_appdomains;
415 guint32 per_thread_buffer_size;
416 guint32 statistical_buffer_size;
417 ProfilerPerThreadData* per_thread_data;
418 ProfilerStatisticalData *statistical_data;
419 ProfilerStatisticalData *statistical_data_ready;
420 ProfilerStatisticalData *statistical_data_second_buffer;
421 ProfilerUnmanagedFunctions unmanaged_functions;
422 THREAD_TYPE data_writer_thread;
423 EVENT_TYPE statistical_data_writer_event;
424 gboolean terminate_writer_thread;
426 ProfilerFileWriteBuffer *write_buffers;
427 ProfilerFileWriteBuffer *current_write_buffer;
428 int write_buffer_size;
429 int current_write_position;
430 int full_write_buffers;
432 ProfilerHeapShotWriteJob *heap_shot_write_jobs;
433 ProfilerHeapShotHeapBuffers heap;
435 char *heap_shot_command_file_name;
436 int dump_next_heap_snapshots;
437 guint64 heap_shot_command_file_access_time;
438 gboolean heap_shot_was_signalled;
440 ProfilerExecutableMemoryRegions *executable_regions;
447 gboolean unreachable_objects;
451 static MonoProfiler *profiler;
454 #define DEBUG_LOAD_EVENTS 0
455 #define DEBUG_MAPPING_EVENTS 0
456 #define DEBUG_LOGGING_PROFILER 0
457 #define DEBUG_HEAP_PROFILER 0
458 #define DEBUG_CLASS_BITMAPS 0
459 #define DEBUG_STATISTICAL_PROFILER 0
460 #define DEBUG_WRITER_THREAD 0
461 #if (DEBUG_LOGGING_PROFILER || DEBUG_STATISTICAL_PROFILER || DEBUG_HEAP_PROFILER || DEBUG_WRITER_THREAD)
462 #define LOG_WRITER_THREAD(m) printf ("WRITER-THREAD-LOG %s\n", m)
464 #define LOG_WRITER_THREAD(m)
467 #if DEBUG_LOGGING_PROFILER
468 static int event_counter = 0;
469 #define EVENT_MARK() printf ("[EVENT:%d]", ++ event_counter)
473 static ClassIdMappingElement*
474 class_id_mapping_element_get (MonoClass *klass) {
475 return g_hash_table_lookup (profiler->classes->table, (gconstpointer) klass);
478 static MethodIdMappingElement*
479 method_id_mapping_element_get (MonoMethod *method) {
480 return g_hash_table_lookup (profiler->methods->table, (gconstpointer) method);
483 #define BITS_TO_BYTES(v) do {\
489 static ClassIdMappingElement*
490 class_id_mapping_element_new (MonoClass *klass) {
491 ClassIdMappingElement *result = g_new (ClassIdMappingElement, 1);
493 result->name = g_strdup_printf ("%s.%s", mono_class_get_namespace (klass), mono_class_get_name (klass));
494 result->klass = klass;
495 result->next_unwritten = profiler->classes->unwritten;
496 profiler->classes->unwritten = result;
497 result->id = profiler->classes->next_id;
498 profiler->classes->next_id ++;
500 result->data.bitmap.compact = 0;
501 result->data.layout.slots = CLASS_LAYOUT_NOT_INITIALIZED;
502 result->data.layout.references = CLASS_LAYOUT_NOT_INITIALIZED;
504 g_hash_table_insert (profiler->classes->table, klass, result);
506 #if (DEBUG_MAPPING_EVENTS)
507 printf ("Created new CLASS mapping element \"%s\" (%p)[%d]\n", result->name, klass, result->id);
513 class_id_mapping_element_build_layout_bitmap (MonoClass *klass, ClassIdMappingElement *klass_id) {
514 MonoClass *parent_class = mono_class_get_parent (klass);
515 int number_of_reference_fields = 0;
516 int max_offset_of_reference_fields = 0;
517 ClassIdMappingElement *parent_id;
519 MonoClassField *field;
521 #if (DEBUG_CLASS_BITMAPS)
522 printf ("class_id_mapping_element_build_layout_bitmap: building layout for class %s.%s: ", mono_class_get_namespace (klass), mono_class_get_name (klass));
525 if (parent_class != NULL) {
526 parent_id = class_id_mapping_element_get (parent_class);
527 g_assert (parent_id != NULL);
529 if (parent_id->data.layout.slots == CLASS_LAYOUT_NOT_INITIALIZED) {
530 #if (DEBUG_CLASS_BITMAPS)
531 printf ("[recursively building bitmap for father class]\n");
533 class_id_mapping_element_build_layout_bitmap (parent_class, parent_id);
540 while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
541 MonoType* field_type = mono_field_get_type (field);
542 // For now, skip static fields
543 if (mono_field_get_flags (field) & 0x0010 /*FIELD_ATTRIBUTE_STATIC*/)
546 if (MONO_TYPE_IS_REFERENCE (field_type)) {
547 int field_offset = mono_field_get_offset (field) - sizeof (MonoObject);
548 if (field_offset > max_offset_of_reference_fields) {
549 max_offset_of_reference_fields = field_offset;
551 number_of_reference_fields ++;
553 MonoClass *field_class = mono_class_from_mono_type (field_type);
554 if (field_class && mono_class_is_valuetype (field_class)) {
555 ClassIdMappingElement *field_id = class_id_mapping_element_get (field_class);
556 g_assert (field_id != NULL);
558 if (field_id->data.layout.slots == CLASS_LAYOUT_NOT_INITIALIZED) {
559 if (field_id != klass_id) {
560 #if (DEBUG_CLASS_BITMAPS)
561 printf ("[recursively building bitmap for field %s]\n", mono_field_get_name (field));
563 class_id_mapping_element_build_layout_bitmap (field_class, field_id);
565 #if (DEBUG_CLASS_BITMAPS)
566 printf ("[breaking recursive bitmap build for field %s]", mono_field_get_name (field));
569 klass_id->data.bitmap.compact = 0;
570 klass_id->data.layout.slots = 0;
571 klass_id->data.layout.references = 0;
575 if (field_id->data.layout.references > 0) {
576 int field_offset = mono_field_get_offset (field) - sizeof (MonoObject);
577 int max_offset_reference_in_field = (field_id->data.layout.slots - 1) * sizeof (gpointer);
579 if ((field_offset + max_offset_reference_in_field) > max_offset_of_reference_fields) {
580 max_offset_of_reference_fields = field_offset + max_offset_reference_in_field;
583 number_of_reference_fields += field_id->data.layout.references;
589 #if (DEBUG_CLASS_BITMAPS)
590 printf ("[allocating bitmap for class %s.%s (references %d, max offset %d, slots %d)]", mono_class_get_namespace (klass), mono_class_get_name (klass), number_of_reference_fields, max_offset_of_reference_fields, (int)(max_offset_of_reference_fields / sizeof (gpointer)) + 1);
592 if ((number_of_reference_fields == 0) && ((parent_id == NULL) || (parent_id->data.layout.references == 0))) {
593 #if (DEBUG_CLASS_BITMAPS)
594 printf ("[no references at all]");
596 klass_id->data.bitmap.compact = 0;
597 klass_id->data.layout.slots = 0;
598 klass_id->data.layout.references = 0;
600 if ((parent_id != NULL) && (parent_id->data.layout.references > 0)) {
601 #if (DEBUG_CLASS_BITMAPS)
602 printf ("[parent %s.%s has %d references in %d slots]", mono_class_get_namespace (parent_class), mono_class_get_name (parent_class), parent_id->data.layout.references, parent_id->data.layout.slots);
604 klass_id->data.layout.slots = parent_id->data.layout.slots;
605 klass_id->data.layout.references = parent_id->data.layout.references;
607 #if (DEBUG_CLASS_BITMAPS)
608 printf ("[no references from parent]");
610 klass_id->data.layout.slots = 0;
611 klass_id->data.layout.references = 0;
614 if (number_of_reference_fields > 0) {
615 klass_id->data.layout.slots += ((max_offset_of_reference_fields / sizeof (gpointer)) + 1);
616 klass_id->data.layout.references += number_of_reference_fields;
617 #if (DEBUG_CLASS_BITMAPS)
618 printf ("[adding data, going to %d references in %d slots]", klass_id->data.layout.references, klass_id->data.layout.slots);
622 if (klass_id->data.layout.slots <= CLASS_LAYOUT_PACKED_BITMAP_SIZE) {
623 #if (DEBUG_CLASS_BITMAPS)
624 printf ("[zeroing bitmap]");
626 klass_id->data.bitmap.compact = 0;
627 if ((parent_id != NULL) && (parent_id->data.layout.references > 0)) {
628 #if (DEBUG_CLASS_BITMAPS)
629 printf ("[copying compact father bitmap]");
631 klass_id->data.bitmap.compact = parent_id->data.bitmap.compact;
634 int size_of_bitmap = klass_id->data.layout.slots;
635 BITS_TO_BYTES (size_of_bitmap);
636 #if (DEBUG_CLASS_BITMAPS)
637 printf ("[allocating %d bytes for bitmap]", size_of_bitmap);
639 klass_id->data.bitmap.extended = g_malloc0 (size_of_bitmap);
640 if ((parent_id != NULL) && (parent_id->data.layout.references > 0)) {
641 int size_of_father_bitmap = parent_id->data.layout.slots;
642 if (size_of_father_bitmap <= CLASS_LAYOUT_PACKED_BITMAP_SIZE) {
644 #if (DEBUG_CLASS_BITMAPS)
645 printf ("[copying %d bits from father bitmap]", size_of_father_bitmap);
647 for (father_slot = 0; father_slot < size_of_father_bitmap; father_slot ++) {
648 if (parent_id->data.bitmap.compact & (((guint64)1) << father_slot)) {
649 klass_id->data.bitmap.extended [father_slot >> 3] |= (1 << (father_slot & 7));
653 BITS_TO_BYTES (size_of_father_bitmap);
654 #if (DEBUG_CLASS_BITMAPS)
655 printf ("[copying %d bytes from father bitmap]", size_of_father_bitmap);
657 memcpy (klass_id->data.bitmap.extended, parent_id->data.bitmap.extended, size_of_father_bitmap);
663 #if (DEBUG_CLASS_BITMAPS)
664 printf ("[starting filling iteration]\n");
667 while ((field = mono_class_get_fields (klass, &iter)) != NULL) {
668 MonoType* field_type = mono_field_get_type (field);
669 // For now, skip static fields
670 if (mono_field_get_flags (field) & 0x0010 /*FIELD_ATTRIBUTE_STATIC*/)
673 #if (DEBUG_CLASS_BITMAPS)
674 printf ("[Working on field %s]", mono_field_get_name (field));
676 if (MONO_TYPE_IS_REFERENCE (field_type)) {
677 int field_offset = mono_field_get_offset (field) - sizeof (MonoObject);
679 g_assert ((field_offset % sizeof (gpointer)) == 0);
680 field_slot = field_offset / sizeof (gpointer);
681 if (klass_id->data.layout.slots <= CLASS_LAYOUT_PACKED_BITMAP_SIZE) {
682 klass_id->data.bitmap.compact |= (((guint64)1) << field_slot);
684 klass_id->data.bitmap.extended [field_slot >> 3] |= (1 << (field_slot & 7));
686 #if (DEBUG_CLASS_BITMAPS)
687 printf ("[reference at offset %d, slot %d]", field_offset, field_slot);
690 MonoClass *field_class = mono_class_from_mono_type (field_type);
691 if (field_class && mono_class_is_valuetype (field_class)) {
692 ClassIdMappingElement *field_id = class_id_mapping_element_get (field_class);
696 g_assert (field_id != NULL);
697 field_offset = mono_field_get_offset (field) - sizeof (MonoObject);
698 g_assert ((field_id->data.layout.references == 0) || ((field_offset % sizeof (gpointer)) == 0));
699 field_slot = field_offset / sizeof (gpointer);
700 #if (DEBUG_CLASS_BITMAPS)
701 printf ("[value type at offset %d, slot %d, with %d references in %d slots]", field_offset, field_slot, field_id->data.layout.references, field_id->data.layout.slots);
704 if (field_id->data.layout.references > 0) {
706 if (field_id->data.layout.slots <= CLASS_LAYOUT_PACKED_BITMAP_SIZE) {
707 for (sub_field_slot = 0; sub_field_slot < field_id->data.layout.slots; sub_field_slot ++) {
708 if (field_id->data.bitmap.compact & (((guint64)1) << sub_field_slot)) {
709 int actual_slot = field_slot + sub_field_slot;
710 if (klass_id->data.layout.slots <= CLASS_LAYOUT_PACKED_BITMAP_SIZE) {
711 klass_id->data.bitmap.compact |= (((guint64)1) << actual_slot);
713 klass_id->data.bitmap.extended [actual_slot >> 3] |= (1 << (actual_slot & 7));
718 for (sub_field_slot = 0; sub_field_slot < field_id->data.layout.slots; sub_field_slot ++) {
719 if (field_id->data.bitmap.extended [sub_field_slot >> 3] & (1 << (sub_field_slot & 7))) {
720 int actual_slot = field_slot + sub_field_slot;
721 if (klass_id->data.layout.slots <= CLASS_LAYOUT_PACKED_BITMAP_SIZE) {
722 klass_id->data.bitmap.compact |= (((guint64)1) << actual_slot);
724 klass_id->data.bitmap.extended [actual_slot >> 3] |= (1 << (actual_slot & 7));
733 #if (DEBUG_CLASS_BITMAPS)
736 printf ("\nLayot of class \"%s.%s\": references %d, slots %d, bitmap {", mono_class_get_namespace (klass), mono_class_get_name (klass), klass_id->data.layout.references, klass_id->data.layout.slots);
737 for (slot = 0; slot < klass_id->data.layout.slots; slot ++) {
738 if (klass_id->data.layout.slots <= CLASS_LAYOUT_PACKED_BITMAP_SIZE) {
739 if (klass_id->data.bitmap.compact & (((guint64)1) << slot)) {
745 if (klass_id->data.bitmap.extended [slot >> 3] & (1 << (slot & 7))) {
759 static MethodIdMappingElement*
760 method_id_mapping_element_new (MonoMethod *method) {
761 MethodIdMappingElement *result = g_new (MethodIdMappingElement, 1);
762 char *signature = mono_signature_get_desc (mono_method_signature (method), TRUE);
764 result->name = g_strdup_printf ("%s (%s)", mono_method_get_name (method), signature);
766 result->method = method;
767 result->next_unwritten = profiler->methods->unwritten;
768 profiler->methods->unwritten = result;
769 result->id = profiler->methods->next_id;
770 profiler->methods->next_id ++;
771 g_hash_table_insert (profiler->methods->table, method, result);
773 result->data.code_start = NULL;
774 result->data.code_size = 0;
776 #if (DEBUG_MAPPING_EVENTS)
777 printf ("Created new METHOD mapping element \"%s\" (%p)[%d]\n", result->name, method, result->id);
784 method_id_mapping_element_destroy (gpointer element) {
785 MethodIdMappingElement *e = (MethodIdMappingElement*) element;
792 class_id_mapping_element_destroy (gpointer element) {
793 ClassIdMappingElement *e = (ClassIdMappingElement*) element;
796 if ((e->data.layout.slots != CLASS_LAYOUT_NOT_INITIALIZED) && (e->data.layout.slots > CLASS_LAYOUT_PACKED_BITMAP_SIZE))
797 g_free (e->data.bitmap.extended);
801 static MethodIdMapping*
802 method_id_mapping_new (void) {
803 MethodIdMapping *result = g_new (MethodIdMapping, 1);
804 //result->table = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, method_id_mapping_element_destroy);
805 result->table = g_hash_table_new_full (g_direct_hash, NULL, NULL, method_id_mapping_element_destroy);
806 result->unwritten = NULL;
811 static ClassIdMapping*
812 class_id_mapping_new (void) {
813 ClassIdMapping *result = g_new (ClassIdMapping, 1);
814 //result->table = g_hash_table_new_full (mono_aligned_addr_hash, NULL, NULL, class_id_mapping_element_destroy);
815 result->table = g_hash_table_new_full (g_direct_hash, NULL, NULL, class_id_mapping_element_destroy);
816 result->unwritten = NULL;
822 method_id_mapping_destroy (MethodIdMapping *map) {
823 g_hash_table_destroy (map->table);
828 class_id_mapping_destroy (ClassIdMapping *map) {
829 g_hash_table_destroy (map->table);
834 unmanaged_function_new (ProfilerUnmanagedFunctions *functions, Dl_info *dl_info) {
835 ProfilerUnmanagedFunction *function = g_new (ProfilerUnmanagedFunction, 1);
836 function->id = functions->next_id;
837 functions->next_id ++;
839 function->next_unwritten = functions->unwritten_queue;
840 functions->unwritten_queue = function;
841 function->name = g_strdup_printf ("[%s]:%s", dl_info->dli_fname, dl_info->dli_sname);
842 g_hash_table_insert (functions->table, dl_info->dli_saddr, function);
846 unmanaged_function_destroy (gpointer element) {
847 ProfilerUnmanagedFunction *function = (ProfilerUnmanagedFunction*) element;
848 if (function->name) {
849 g_free (function->name);
850 function->name = NULL;
856 unmanaged_function_hit (ProfilerUnmanagedFunctions *functions, gpointer address) {
858 if (dladdr (address, &dl_info) && (dl_info.dli_saddr != NULL) && (dl_info.dli_fname != NULL)) {
859 ProfilerUnmanagedFunction *function = g_hash_table_lookup (functions->table, dl_info.dli_saddr);
861 if (function != NULL) {
862 if (function->next_unwritten != NULL) {
866 function->next_unwritten = functions->unwritten_queue;
867 functions->unwritten_queue = function;
870 unmanaged_function_new (functions, &dl_info);
880 unmanaged_functions_init (ProfilerUnmanagedFunctions *functions) {
881 functions->next_id = 1;
882 functions->table = g_hash_table_new_full (g_direct_hash, NULL, NULL, unmanaged_function_destroy);
883 functions->unwritten_queue_end = &(functions->actual_unwritten_queue_end);
884 functions->unwritten_queue = functions->unwritten_queue_end;
885 functions->actual_unwritten_queue_end.hits = 0;
886 functions->actual_unwritten_queue_end.id = 0;
887 functions->actual_unwritten_queue_end.name = NULL;
888 functions->actual_unwritten_queue_end.next_unwritten = NULL;
892 unmanaged_functions_dispose (ProfilerUnmanagedFunctions *functions) {
893 functions->next_id = 0;
894 g_hash_table_destroy (functions->table);
895 functions->table = NULL;
896 functions->unwritten_queue = NULL;
899 #if (DEBUG_LOAD_EVENTS)
901 print_load_event (const char *event_name, GHashTable *table, gpointer item, LoadedElement *element);
904 static LoadedElement*
905 loaded_element_load_start (GHashTable *table, gpointer item) {
906 LoadedElement *element = g_new0 (LoadedElement, 1);
907 #if (DEBUG_LOAD_EVENTS)
908 print_load_event ("LOAD START", table, item, element);
910 MONO_PROFILER_GET_CURRENT_COUNTER (element->load_start_counter);
911 g_hash_table_insert (table, item, element);
915 static LoadedElement*
916 loaded_element_load_end (GHashTable *table, gpointer item, char *name) {
917 LoadedElement *element = g_hash_table_lookup (table, item);
918 #if (DEBUG_LOAD_EVENTS)
919 print_load_event ("LOAD END", table, item, element);
921 g_assert (element != NULL);
922 MONO_PROFILER_GET_CURRENT_COUNTER (element->load_end_counter);
923 element->name = name;
924 element->loaded = TRUE;
928 static LoadedElement*
929 loaded_element_unload_start (GHashTable *table, gpointer item) {
930 LoadedElement *element = g_hash_table_lookup (table, item);
931 #if (DEBUG_LOAD_EVENTS)
932 print_load_event ("UNLOAD START", table, item, element);
934 g_assert (element != NULL);
935 MONO_PROFILER_GET_CURRENT_COUNTER (element->unload_start_counter);
939 static LoadedElement*
940 loaded_element_unload_end (GHashTable *table, gpointer item) {
941 LoadedElement *element = g_hash_table_lookup (table, item);
942 #if (DEBUG_LOAD_EVENTS)
943 print_load_event ("UNLOAD END", table, item, element);
945 g_assert (element != NULL);
946 MONO_PROFILER_GET_CURRENT_COUNTER (element->unload_end_counter);
947 element->unloaded = TRUE;
953 loaded_element_destroy (gpointer element) {
954 if (((LoadedElement*)element)->name)
955 g_free (((LoadedElement*)element)->name);
959 #if (DEBUG_LOAD_EVENTS)
961 print_load_event (const char *event_name, GHashTable *table, gpointer item, LoadedElement *element) {
962 const char* item_name;
965 if (table == profiler->loaded_assemblies) {
966 //item_info = g_strdup_printf("ASSEMBLY %p (dynamic %d)", item, mono_image_is_dynamic (mono_assembly_get_image((MonoAssembly*)item)));
967 item_info = g_strdup_printf("ASSEMBLY %p", item);
968 } else if (table == profiler->loaded_modules) {
969 //item_info = g_strdup_printf("MODULE %p (dynamic %d)", item, mono_image_is_dynamic ((MonoImage*)item));
970 item_info = g_strdup_printf("MODULE %p", item);
971 } else if (table == profiler->loaded_appdomains) {
972 item_info = g_strdup_printf("APPDOMAIN %p (id %d)", item, mono_domain_get_id ((MonoDomain*)item));
975 g_assert_not_reached ();
978 if (element != NULL) {
979 item_name = element->name;
981 item_name = "<NULL>";
984 printf ("%s EVENT for %s (%s)\n", event_name, item_info, item_name);
990 profiler_heap_shot_object_buffers_destroy (ProfilerHeapShotObjectBuffer *buffer) {
991 while (buffer != NULL) {
992 ProfilerHeapShotObjectBuffer *next = buffer->next;
993 #if DEBUG_HEAP_PROFILER
994 printf ("profiler_heap_shot_object_buffers_destroy: destroyed buffer %p (%p-%p)\n", buffer, & (buffer->buffer [0]), buffer->end);
1001 static ProfilerHeapShotObjectBuffer*
1002 profiler_heap_shot_object_buffer_new (ProfilerPerThreadData *data) {
1003 ProfilerHeapShotObjectBuffer *buffer;
1004 ProfilerHeapShotObjectBuffer *result = g_new (ProfilerHeapShotObjectBuffer, 1);
1005 result->next_free_slot = & (result->buffer [0]);
1006 result->end = & (result->buffer [PROFILER_HEAP_SHOT_OBJECT_BUFFER_SIZE]);
1007 result->first_unprocessed_slot = & (result->buffer [0]);
1008 result->next = data->heap_shot_object_buffers;
1009 data->heap_shot_object_buffers = result;
1010 #if DEBUG_HEAP_PROFILER
1011 printf ("profiler_heap_shot_object_buffer_new: created buffer %p (%p-%p)\n", result, result->next_free_slot, result->end);
1013 for (buffer = result; buffer != NULL; buffer = buffer->next) {
1014 ProfilerHeapShotObjectBuffer *last = buffer->next;
1015 if ((last != NULL) && (last->first_unprocessed_slot == last->end)) {
1016 buffer->next = NULL;
1017 profiler_heap_shot_object_buffers_destroy (last);
1024 static ProfilerHeapShotWriteJob*
1025 profiler_heap_shot_write_job_new (gboolean heap_shot_was_signalled) {
1026 ProfilerHeapShotWriteJob *job = g_new (ProfilerHeapShotWriteJob, 1);
1028 job->next_unwritten = NULL;
1029 job->buffers = g_new (ProfilerHeapShotWriteBuffer, 1);
1030 job->buffers->next = NULL;
1031 job->last_next = & (job->buffers->next);
1032 job->start = & (job->buffers->buffer [0]);
1033 job->cursor = job->start;
1034 job->end = & (job->buffers->buffer [PROFILER_HEAP_SHOT_WRITE_BUFFER_SIZE]);
1035 job->full_buffers = 0;
1036 job->heap_shot_was_signalled = heap_shot_was_signalled;
1037 #if DEBUG_HEAP_PROFILER
1038 printf ("profiler_heap_shot_write_job_new: created job %p with buffer %p(%p-%p)\n", job, job->buffers, job->start, job->end);
1044 profiler_heap_shot_write_job_add_buffer (ProfilerHeapShotWriteJob *job, gpointer value) {
1045 ProfilerHeapShotWriteBuffer *buffer = g_new (ProfilerHeapShotWriteBuffer, 1);
1046 buffer->next = NULL;
1047 *(job->last_next) = buffer;
1048 job->last_next = & (buffer->next);
1049 job->full_buffers ++;
1050 buffer->buffer [0] = value;
1051 job->start = & (buffer->buffer [0]);
1052 job->cursor = & (buffer->buffer [1]);
1053 job->end = & (buffer->buffer [PROFILER_HEAP_SHOT_WRITE_BUFFER_SIZE]);
1054 #if DEBUG_HEAP_PROFILER
1055 printf ("profiler_heap_shot_write_job_add_buffer: in job %p, added buffer %p(%p-%p) with value %p at address %p (cursor now %p)\n", job, buffer, job->start, job->end, value, &(buffer->buffer [0]), job->cursor);
1057 ProfilerHeapShotWriteBuffer *current_buffer;
1058 for (current_buffer = job->buffers; current_buffer != NULL; current_buffer = current_buffer->next) {
1059 printf ("profiler_heap_shot_write_job_add_buffer: now job %p has buffer %p\n", job, current_buffer);
1066 profiler_heap_shot_write_job_free_buffers (ProfilerHeapShotWriteJob *job) {
1067 ProfilerHeapShotWriteBuffer *buffer = job->buffers;
1069 while (buffer != NULL) {
1070 ProfilerHeapShotWriteBuffer *next = buffer->next;
1071 #if DEBUG_HEAP_PROFILER
1072 printf ("profiler_heap_shot_write_job_free_buffers: in job %p, freeing buffer %p\n", job, buffer);
1078 job->buffers = NULL;
1082 profiler_heap_shot_write_block (ProfilerHeapShotWriteJob *job);
1085 profiler_process_heap_shot_write_jobs (void) {
1086 gboolean done = FALSE;
1089 ProfilerHeapShotWriteJob *current_job = profiler->heap_shot_write_jobs;
1090 ProfilerHeapShotWriteJob *previous_job = NULL;
1091 ProfilerHeapShotWriteJob *next_job;
1094 while (current_job != NULL) {
1095 next_job = current_job->next_unwritten;
1097 if (next_job != NULL) {
1098 if (current_job->buffers != NULL) {
1101 if (next_job->buffers == NULL) {
1102 current_job->next_unwritten = NULL;
1106 if (current_job->buffers != NULL) {
1107 LOG_WRITER_THREAD ("profiler_process_heap_shot_write_jobs: writing...");
1108 profiler_heap_shot_write_block (current_job);
1109 LOG_WRITER_THREAD ("profiler_process_heap_shot_write_jobs: done");
1110 if (previous_job != NULL) {
1111 previous_job->next_unwritten = NULL;
1116 previous_job = current_job;
1117 current_job = next_job;
1123 profiler_free_heap_shot_write_jobs (void) {
1124 ProfilerHeapShotWriteJob *current_job = profiler->heap_shot_write_jobs;
1125 ProfilerHeapShotWriteJob *next_job;
1127 if (current_job != NULL) {
1128 while (current_job->next_unwritten != NULL) {
1129 #if DEBUG_HEAP_PROFILER
1130 printf ("profiler_free_heap_shot_write_jobs: job %p must not be freed\n", current_job);
1132 current_job = current_job->next_unwritten;
1135 next_job = current_job->next;
1136 current_job->next = NULL;
1137 current_job = next_job;
1139 while (current_job != NULL) {
1140 #if DEBUG_HEAP_PROFILER
1141 printf ("profiler_free_heap_shot_write_jobs: job %p will be freed\n", current_job);
1143 next_job = current_job->next;
1144 g_free (current_job);
1145 current_job = next_job;
1151 profiler_destroy_heap_shot_write_jobs (void) {
1152 ProfilerHeapShotWriteJob *current_job = profiler->heap_shot_write_jobs;
1153 ProfilerHeapShotWriteJob *next_job;
1155 while (current_job != NULL) {
1156 next_job = current_job->next;
1157 profiler_heap_shot_write_job_free_buffers (current_job);
1158 g_free (current_job);
1159 current_job = next_job;
1164 profiler_add_heap_shot_write_job (ProfilerHeapShotWriteJob *job) {
1165 job->next = profiler->heap_shot_write_jobs;
1166 job->next_unwritten = job->next;
1167 profiler->heap_shot_write_jobs = job;
1168 #if DEBUG_HEAP_PROFILER
1169 printf ("profiler_add_heap_shot_write_job: added job %p\n", job);
1173 #if DEBUG_HEAP_PROFILER
1174 #define STORE_ALLOCATED_OBJECT_MESSAGE1(d,o) printf ("STORE_ALLOCATED_OBJECT[TID %ld]: storing object %p at address %p\n", (d)->thread_id, (o), (d)->heap_shot_object_buffers->next_free_slot)
1175 #define STORE_ALLOCATED_OBJECT_MESSAGE2(d,o) printf ("STORE_ALLOCATED_OBJECT[TID %ld]: storing object %p at address %p in new buffer %p\n", (d)->thread_id, (o), buffer->next_free_slot, buffer)
1177 #define STORE_ALLOCATED_OBJECT_MESSAGE1(d,o)
1178 #define STORE_ALLOCATED_OBJECT_MESSAGE2(d,o)
1180 #define STORE_ALLOCATED_OBJECT(d,o) do {\
1181 if ((d)->heap_shot_object_buffers->next_free_slot < (d)->heap_shot_object_buffers->end) {\
1182 STORE_ALLOCATED_OBJECT_MESSAGE1 ((d), (o));\
1183 *((d)->heap_shot_object_buffers->next_free_slot) = (o);\
1184 (d)->heap_shot_object_buffers->next_free_slot ++;\
1186 ProfilerHeapShotObjectBuffer *buffer = profiler_heap_shot_object_buffer_new (d);\
1187 STORE_ALLOCATED_OBJECT_MESSAGE2 ((d), (o));\
1188 *((buffer)->next_free_slot) = (o);\
1189 (buffer)->next_free_slot ++;\
1193 static ProfilerPerThreadData*
1194 profiler_per_thread_data_new (guint32 buffer_size)
1196 ProfilerPerThreadData *data = g_new (ProfilerPerThreadData, 1);
1198 data->events = g_new0 (ProfilerEventData, buffer_size);
1199 data->next_free_event = data->events;
1200 data->end_event = data->events + (buffer_size - 1);
1201 data->first_unwritten_event = data->events;
1202 data->first_unmapped_event = data->events;
1203 MONO_PROFILER_GET_CURRENT_COUNTER (data->start_event_counter);
1204 data->last_event_counter = data->start_event_counter;
1205 data->thread_id = CURRENT_THREAD_ID ();
1206 data->heap_shot_object_buffers = NULL;
1207 if ((profiler->action_flags.unreachable_objects == TRUE) || (profiler->action_flags.heap_shot == TRUE)) {
1208 profiler_heap_shot_object_buffer_new (data);
1214 profiler_per_thread_data_destroy (ProfilerPerThreadData *data) {
1215 g_free (data->events);
1216 profiler_heap_shot_object_buffers_destroy (data->heap_shot_object_buffers);
1220 static ProfilerStatisticalData*
1221 profiler_statistical_data_new (guint32 buffer_size)
1223 ProfilerStatisticalData *data = g_new (ProfilerStatisticalData, 1);
1225 data->addresses = g_new0 (gpointer, buffer_size);
1226 data->next_free_index = 0;
1227 data->end_index = buffer_size;
1228 data->first_unwritten_index = 0;
1234 profiler_statistical_data_destroy (ProfilerStatisticalData *data) {
1235 g_free (data->addresses);
1240 profiler_add_write_buffer (void) {
1241 if (profiler->current_write_buffer->next == NULL) {
1242 profiler->current_write_buffer->next = g_malloc (sizeof (ProfilerFileWriteBuffer) + PROFILER_FILE_WRITE_BUFFER_SIZE);
1243 profiler->current_write_buffer->next->next = NULL;
1245 //printf ("Added next buffer %p, to buffer %p\n", profiler->current_write_buffer->next, profiler->current_write_buffer);
1248 profiler->current_write_buffer = profiler->current_write_buffer->next;
1249 profiler->current_write_position = 0;
1250 profiler->full_write_buffers ++;
1254 profiler_free_write_buffers (void) {
1255 ProfilerFileWriteBuffer *current_buffer = profiler->write_buffers;
1256 while (current_buffer != NULL) {
1257 ProfilerFileWriteBuffer *next_buffer = current_buffer->next;
1259 //printf ("Freeing write buffer %p, next is %p\n", current_buffer, next_buffer);
1261 g_free (current_buffer);
1262 current_buffer = next_buffer;
1266 #define WRITE_BYTE(b) do {\
1267 if (profiler->current_write_position >= PROFILER_FILE_WRITE_BUFFER_SIZE) {\
1268 profiler_add_write_buffer ();\
1270 profiler->current_write_buffer->buffer [profiler->current_write_position] = (b);\
1271 profiler->current_write_position ++;\
1276 write_current_block (guint16 code) {
1277 guint32 size = (profiler->full_write_buffers * PROFILER_FILE_WRITE_BUFFER_SIZE) + profiler->current_write_position;
1278 ProfilerFileWriteBuffer *current_buffer = profiler->write_buffers;
1281 header [0] = code & 0xff;
1282 header [1] = (code >> 8) & 0xff;
1283 header [2] = size & 0xff;
1284 header [3] = (size >> 8) & 0xff;
1285 header [4] = (size >> 16) & 0xff;
1286 header [5] = (size >> 24) & 0xff;
1288 WRITE_BUFFER (& (header [0]), 6);
1290 while ((current_buffer != NULL) && (profiler->full_write_buffers > 0)) {
1291 WRITE_BUFFER (& (current_buffer->buffer [0]), PROFILER_FILE_WRITE_BUFFER_SIZE);
1292 profiler->full_write_buffers --;
1293 current_buffer = current_buffer->next;
1295 if (profiler->current_write_position > 0) {
1296 WRITE_BUFFER (& (current_buffer->buffer [0]), profiler->current_write_position);
1300 profiler->current_write_buffer = profiler->write_buffers;
1301 profiler->current_write_position = 0;
1302 profiler->full_write_buffers = 0;
1306 #define SEVEN_BITS_MASK (0x7f)
1307 #define EIGHT_BIT_MASK (0x80)
1310 write_uint32 (guint32 value) {
1311 while (value > SEVEN_BITS_MASK) {
1312 WRITE_BYTE (value & SEVEN_BITS_MASK);
1315 WRITE_BYTE (value | EIGHT_BIT_MASK);
1318 write_uint64 (guint64 value) {
1319 while (value > SEVEN_BITS_MASK) {
1320 WRITE_BYTE (value & SEVEN_BITS_MASK);
1323 WRITE_BYTE (value | EIGHT_BIT_MASK);
1326 write_string (const char *string) {
1327 while (*string != 0) {
1328 WRITE_BYTE (*string);
1334 #if DEBUG_HEAP_PROFILER
1335 #define WRITE_HEAP_SHOT_JOB_VALUE_MESSAGE(v,c) printf ("WRITE_HEAP_SHOT_JOB_VALUE: writing value %p at cursor %p\n", (v), (c))
1337 #define WRITE_HEAP_SHOT_JOB_VALUE_MESSAGE(v,c)
1339 #define WRITE_HEAP_SHOT_JOB_VALUE(j,v) do {\
1340 if ((j)->cursor < (j)->end) {\
1341 WRITE_HEAP_SHOT_JOB_VALUE_MESSAGE ((v), ((j)->cursor));\
1342 *((j)->cursor) = (v);\
1345 profiler_heap_shot_write_job_add_buffer (j, v);\
1349 #undef GUINT_TO_POINTER
1350 #define GUINT_TO_POINTER(u) ((void*)(guint64)(u))
1351 #undef GPOINTER_TO_UINT
1352 #define GPOINTER_TO_UINT(p) ((guint64)(void*)(p))
1354 #define WRITE_HEAP_SHOT_JOB_VALUE_WITH_CODE(j,v,c) WRITE_HEAP_SHOT_JOB_VALUE (j, GUINT_TO_POINTER (GPOINTER_TO_UINT (v)|(c)))
1356 #if DEBUG_HEAP_PROFILER
1357 #define UPDATE_JOB_BUFFER_CURSOR_MESSAGE() printf ("profiler_heap_shot_write_block[UPDATE_JOB_BUFFER_CURSOR]: in job %p, moving to buffer %p and cursor %p\n", job, buffer, cursor)
1359 #define UPDATE_JOB_BUFFER_CURSOR_MESSAGE()
1361 #define UPDATE_JOB_BUFFER_CURSOR() do {\
1363 if (cursor >= end) {\
1364 buffer = buffer->next;\
1365 if (buffer != NULL) {\
1366 cursor = & (buffer->buffer [0]);\
1367 if (buffer->next != NULL) {\
1368 end = & (buffer->buffer [PROFILER_HEAP_SHOT_WRITE_BUFFER_SIZE]);\
1376 UPDATE_JOB_BUFFER_CURSOR_MESSAGE ();\
1380 profiler_heap_shot_write_block (ProfilerHeapShotWriteJob *job) {
1381 ProfilerHeapShotWriteBuffer *buffer;
1384 guint64 start_counter;
1386 guint64 end_counter;
1389 write_uint64 (job->start_counter);
1390 write_uint64 (job->start_time);
1391 write_uint64 (job->end_counter);
1392 write_uint64 (job->end_time);
1394 MONO_PROFILER_GET_CURRENT_COUNTER (start_counter);
1395 MONO_PROFILER_GET_CURRENT_TIME (start_time);
1396 write_uint64 (start_counter);
1397 write_uint64 (start_time);
1398 #if DEBUG_HEAP_PROFILER
1399 printf ("profiler_heap_shot_write_block: working on job %p...\n", job);
1401 buffer = job->buffers;
1402 cursor = & (buffer->buffer [0]);
1403 if (buffer->next != NULL) {
1404 end = & (buffer->buffer [PROFILER_HEAP_SHOT_WRITE_BUFFER_SIZE]);
1408 if (cursor >= end) {
1411 #if DEBUG_HEAP_PROFILER
1412 printf ("profiler_heap_shot_write_block: in job %p, starting at buffer %p and cursor %p\n", job, buffer, cursor);
1414 while (cursor != NULL) {
1415 gpointer value = *cursor;
1416 HeapProfilerJobValueCode code = GPOINTER_TO_UINT (value) & HEAP_CODE_MASK;
1417 #if DEBUG_HEAP_PROFILER
1418 printf ("profiler_heap_shot_write_block: got value %p and code %d\n", value, code);
1421 UPDATE_JOB_BUFFER_CURSOR ();
1422 if (code == HEAP_CODE_FREE_OBJECT_CLASS) {
1423 MonoClass *klass = GUINT_TO_POINTER (GPOINTER_TO_UINT (value) & (~ (guint64) HEAP_CODE_MASK));
1424 //MonoClass *klass = GUINT_TO_POINTER (GPOINTER_TO_UINT (value) % 4);
1425 ClassIdMappingElement *class_id;
1428 class_id = class_id_mapping_element_get (klass);
1429 if (class_id == NULL) {
1430 printf ("profiler_heap_shot_write_block: unknown class %p", klass);
1432 g_assert (class_id != NULL);
1433 write_uint32 ((class_id->id << 2) | HEAP_CODE_FREE_OBJECT_CLASS);
1435 size = GPOINTER_TO_UINT (*cursor);
1436 UPDATE_JOB_BUFFER_CURSOR ();
1437 write_uint32 (size);
1438 #if DEBUG_HEAP_PROFILER
1439 printf ("profiler_heap_shot_write_block: wrote unreachable object of class %p (id %d, size %d)\n", klass, class_id->id, size);
1441 } else if (code == HEAP_CODE_OBJECT) {
1442 MonoObject *object = GUINT_TO_POINTER (GPOINTER_TO_UINT (value) & (~ (guint64) HEAP_CODE_MASK));
1443 MonoClass *klass = mono_object_get_class (object);
1444 ClassIdMappingElement *class_id = class_id_mapping_element_get (klass);
1445 guint32 size = mono_object_get_size (object);
1446 guint32 references = GPOINTER_TO_UINT (*cursor);
1447 UPDATE_JOB_BUFFER_CURSOR ();
1449 if (class_id == NULL) {
1450 printf ("profiler_heap_shot_write_block: unknown class %p", klass);
1452 g_assert (class_id != NULL);
1454 write_uint64 (GPOINTER_TO_UINT (object));
1455 write_uint32 (class_id->id);
1456 write_uint32 (size);
1457 write_uint32 (references);
1458 #if DEBUG_HEAP_PROFILER
1459 printf ("profiler_heap_shot_write_block: writing object %p (references %d)\n", value, references);
1462 while (references > 0) {
1463 gpointer reference = *cursor;
1464 write_uint64 (GPOINTER_TO_UINT (reference));
1465 UPDATE_JOB_BUFFER_CURSOR ();
1467 #if DEBUG_HEAP_PROFILER
1468 printf ("profiler_heap_shot_write_block: inside object %p, wrote reference %p)\n", value, reference);
1472 #if DEBUG_HEAP_PROFILER
1473 printf ("profiler_heap_shot_write_block: unknown code %d in value %p\n", code, value);
1475 g_assert_not_reached ();
1480 MONO_PROFILER_GET_CURRENT_COUNTER (end_counter);
1481 MONO_PROFILER_GET_CURRENT_TIME (end_time);
1482 write_uint64 (end_counter);
1483 write_uint64 (end_time);
1485 write_current_block (MONO_PROFILER_FILE_BLOCK_KIND_HEAP);
1487 profiler_heap_shot_write_job_free_buffers (job);
1488 #if DEBUG_HEAP_PROFILER
1489 printf ("profiler_heap_shot_write_block: work on job %p done.\n", job);
1494 write_element_load_block (LoadedElement *element, guint8 kind, gsize thread_id) {
1496 write_uint64 (element->load_start_counter);
1497 write_uint64 (element->load_end_counter);
1498 write_uint64 (thread_id);
1499 write_string (element->name);
1500 write_current_block (MONO_PROFILER_FILE_BLOCK_KIND_LOADED);
1501 element->load_written = TRUE;
1505 write_element_unload_block (LoadedElement *element, guint8 kind, gsize thread_id) {
1507 write_uint64 (element->unload_start_counter);
1508 write_uint64 (element->unload_end_counter);
1509 write_uint64 (thread_id);
1510 write_string (element->name);
1511 write_current_block (MONO_PROFILER_FILE_BLOCK_KIND_UNLOADED);
1512 element->unload_written = TRUE;
1516 write_clock_data (void) {
1520 MONO_PROFILER_GET_CURRENT_COUNTER (counter);
1521 MONO_PROFILER_GET_CURRENT_TIME (time);
1523 write_uint64 (counter);
1524 write_uint64 (time);
1528 write_mapping_block (gsize thread_id) {
1529 ClassIdMappingElement *current_class;
1530 MethodIdMappingElement *current_method;
1532 if ((profiler->classes->unwritten == NULL) && (profiler->methods->unwritten == NULL))
1535 #if (DEBUG_MAPPING_EVENTS)
1536 printf ("[write_mapping_block][TID %ld] START\n", thread_id);
1539 write_clock_data ();
1540 write_uint64 (thread_id);
1542 for (current_class = profiler->classes->unwritten; current_class != NULL; current_class = current_class->next_unwritten) {
1543 write_uint32 (current_class->id);
1544 write_string (current_class->name);
1545 #if (DEBUG_MAPPING_EVENTS)
1546 printf ("mapping CLASS (%d => %s)\n", current_class->id, current_class->name);
1548 g_free (current_class->name);
1549 current_class->name = NULL;
1552 profiler->classes->unwritten = NULL;
1554 for (current_method = profiler->methods->unwritten; current_method != NULL; current_method = current_method->next_unwritten) {
1555 MonoMethod *method = current_method->method;
1556 MonoClass *klass = mono_method_get_class (method);
1557 ClassIdMappingElement *class_element = class_id_mapping_element_get (klass);
1558 g_assert (class_element != NULL);
1559 write_uint32 (current_method->id);
1560 write_uint32 (class_element->id);
1561 write_string (current_method->name);
1562 #if (DEBUG_MAPPING_EVENTS)
1563 printf ("mapping METHOD ([%d]%d => %s)\n", class_element?class_element->id:1, current_method->id, current_method->name);
1565 g_free (current_method->name);
1566 current_method->name = NULL;
1569 profiler->methods->unwritten = NULL;
1571 write_clock_data ();
1572 write_current_block (MONO_PROFILER_FILE_BLOCK_KIND_MAPPING);
1574 #if (DEBUG_MAPPING_EVENTS)
1575 printf ("[write_mapping_block][TID %ld] END\n", thread_id);
1580 get_extended_event_value (ProfilerEventData *event, ProfilerEventData *next) {
1581 guint64 result = next->data.number;
1582 result |= (((guint64) event->value) << 32);
1587 MONO_PROFILER_PACKED_EVENT_CODE_METHOD_ENTER = 1,
1588 MONO_PROFILER_PACKED_EVENT_CODE_METHOD_EXIT_IMPLICIT = 2,
1589 MONO_PROFILER_PACKED_EVENT_CODE_METHOD_EXIT_EXPLICIT = 3,
1590 MONO_PROFILER_PACKED_EVENT_CODE_CLASS_ALLOCATION = 4,
1591 MONO_PROFILER_PACKED_EVENT_CODE_METHOD_EVENT = 5,
1592 MONO_PROFILER_PACKED_EVENT_CODE_CLASS_EVENT = 6,
1593 MONO_PROFILER_PACKED_EVENT_CODE_OTHER_EVENT = 7
1594 } MonoProfilerPackedEventCode;
1595 #define MONO_PROFILER_PACKED_EVENT_CODE_BITS 3
1596 #define MONO_PROFILER_PACKED_EVENT_DATA_BITS (8-MONO_PROFILER_PACKED_EVENT_CODE_BITS)
1597 #define MONO_PROFILER_PACKED_EVENT_DATA_MASK ((1<<MONO_PROFILER_PACKED_EVENT_DATA_BITS)-1)
1599 #define MONO_PROFILER_EVENT_MAKE_PACKED_CODE(result,data,base) do {\
1600 result = ((base)|((data & MONO_PROFILER_PACKED_EVENT_DATA_MASK) << MONO_PROFILER_PACKED_EVENT_CODE_BITS));\
1601 data >>= MONO_PROFILER_PACKED_EVENT_DATA_BITS;\
1603 #define MONO_PROFILER_EVENT_MAKE_FULL_CODE(result,code,kind,base) do {\
1604 result = ((base)|((((kind)<<4) | (code)) << MONO_PROFILER_PACKED_EVENT_CODE_BITS));\
1607 static ProfilerEventData*
1608 write_event (ProfilerEventData *event) {
1609 ProfilerEventData *next = event + 1;
1610 gboolean write_event_value = TRUE;
1613 guint64 event_value;
1615 event_value = event->value;
1616 if (event_value > MAX_EVENT_VALUE) {
1617 event_value = get_extended_event_value (event, next);
1621 if (event->data_type == MONO_PROFILER_EVENT_DATA_TYPE_METHOD) {
1622 MethodIdMappingElement *element = method_id_mapping_element_get (event->data.address);
1623 g_assert (element != NULL);
1624 event_data = element->id;
1626 if (event->code == MONO_PROFILER_EVENT_METHOD_CALL) {
1627 if (event->kind == MONO_PROFILER_EVENT_KIND_START) {
1628 MONO_PROFILER_EVENT_MAKE_PACKED_CODE (event_code, event_data, MONO_PROFILER_PACKED_EVENT_CODE_METHOD_ENTER);
1630 MONO_PROFILER_EVENT_MAKE_PACKED_CODE (event_code, event_data, MONO_PROFILER_PACKED_EVENT_CODE_METHOD_EXIT_EXPLICIT);
1633 MONO_PROFILER_EVENT_MAKE_FULL_CODE (event_code, event->code, event->kind, MONO_PROFILER_PACKED_EVENT_CODE_METHOD_EVENT);
1635 } else if (event->data_type == MONO_PROFILER_EVENT_DATA_TYPE_CLASS) {
1636 ClassIdMappingElement *element = class_id_mapping_element_get (event->data.address);
1637 g_assert (element != NULL);
1638 event_data = element->id;
1640 if (event->code == MONO_PROFILER_EVENT_CLASS_ALLOCATION) {
1641 MONO_PROFILER_EVENT_MAKE_PACKED_CODE (event_code, event_data, MONO_PROFILER_PACKED_EVENT_CODE_CLASS_ALLOCATION);
1643 MONO_PROFILER_EVENT_MAKE_FULL_CODE (event_code, event->code, event->kind, MONO_PROFILER_PACKED_EVENT_CODE_CLASS_EVENT);
1646 event_data = event->data.number;
1647 MONO_PROFILER_EVENT_MAKE_FULL_CODE (event_code, event->code, event->kind, MONO_PROFILER_PACKED_EVENT_CODE_OTHER_EVENT);
1650 #if (DEBUG_LOGGING_PROFILER)
1652 printf ("writing EVENT[%p] data_type:%d, kind:%d, code:%d (%d:%ld:%ld)\n", event,
1653 event->data_type, event->kind, event->code,
1654 event_code, event_data, event_value);
1657 WRITE_BYTE (event_code);
1658 write_uint64 (event_data);
1659 if (write_event_value) {
1660 write_uint64 (event_value);
1667 write_thread_data_block (ProfilerPerThreadData *data) {
1668 ProfilerEventData *start = data->first_unwritten_event;
1669 ProfilerEventData *end = data->first_unmapped_event;
1674 write_clock_data ();
1675 write_uint64 (data->thread_id);
1677 write_uint64 (data->start_event_counter);
1679 while (start < end) {
1680 start = write_event (start);
1683 data->first_unwritten_event = end;
1685 write_clock_data ();
1686 write_current_block (MONO_PROFILER_FILE_BLOCK_KIND_EVENTS);
1689 static ProfilerExecutableMemoryRegionData*
1690 profiler_executable_memory_region_new (gpointer *start, gpointer *end, guint32 file_offset, char *file_name, guint32 id) {
1691 ProfilerExecutableMemoryRegionData *result = g_new (ProfilerExecutableMemoryRegionData, 1);
1692 result->start = start;
1694 result->file_offset = file_offset;
1695 result->file_name = g_strdup (file_name);
1697 result->is_new = TRUE;
1702 profiler_executable_memory_region_destroy (ProfilerExecutableMemoryRegionData *data) {
1703 if (data->file_name != NULL) {
1704 g_free (data->file_name);
1709 static ProfilerExecutableMemoryRegions*
1710 profiler_executable_memory_regions_new (int next_id) {
1711 ProfilerExecutableMemoryRegions *result = g_new (ProfilerExecutableMemoryRegions, 1);
1712 result->regions = g_new0 (ProfilerExecutableMemoryRegionData*, 32);
1713 result->regions_capacity = 32;
1714 result->regions_count = 0;
1715 result->next_id = next_id;
1720 profiler_executable_memory_regions_destroy (ProfilerExecutableMemoryRegions *regions) {
1723 for (i = 0; i < regions->regions_count; i++) {
1724 profiler_executable_memory_region_destroy (regions->regions [i]);
1726 g_free (regions->regions);
1730 static ProfilerExecutableMemoryRegionData*
1731 find_address_region (ProfilerExecutableMemoryRegions *regions, gpointer address) {
1733 int high_index = regions->regions_count;
1734 int middle_index = 0;
1735 ProfilerExecutableMemoryRegionData *middle_region = regions->regions [0];
1737 if ((regions->regions_count == 0) || (regions->regions [low_index]->start > address) || (regions->regions [high_index - 1]->end < address)) {
1741 //printf ("find_address_region: Looking for address %p in %d regions (from %p to %p)\n", address, regions->regions_count, regions->regions [low_index]->start, regions->regions [high_index - 1]->end);
1743 while (low_index != high_index) {
1744 middle_index = low_index + ((high_index - low_index) / 2);
1745 middle_region = regions->regions [middle_index];
1747 //printf ("find_address_region: Looking for address %p, considering index %d[%p-%p] (%d-%d)\n", address, middle_index, middle_region->start, middle_region->end, low_index, high_index);
1749 if (middle_region->start > address) {
1750 if (middle_index > 0) {
1751 high_index = middle_index;
1755 } else if (middle_region->end < address) {
1756 if (middle_index < regions->regions_count - 1) {
1757 low_index = middle_index + 1;
1762 return middle_region;
1766 if ((middle_region == NULL) || (middle_region->start > address) || (middle_region->end < address)) {
1769 return middle_region;
1774 append_region (ProfilerExecutableMemoryRegions *regions, gpointer *start, gpointer *end, guint32 file_offset, char *file_name) {
1775 if (regions->regions_count >= regions->regions_capacity) {
1776 ProfilerExecutableMemoryRegionData **new_regions = g_new0 (ProfilerExecutableMemoryRegionData*, regions->regions_capacity * 2);
1777 memcpy (new_regions, regions->regions, regions->regions_capacity * sizeof (ProfilerExecutableMemoryRegionData*));
1778 g_free (regions->regions);
1779 regions->regions = new_regions;
1780 regions->regions_capacity = regions->regions_capacity * 2;
1782 regions->regions [regions->regions_count] = profiler_executable_memory_region_new (start, end, file_offset, file_name, regions->next_id);
1783 regions->regions_count ++;
1784 regions->next_id ++;
1788 restore_region_ids (ProfilerExecutableMemoryRegions *old_regions, ProfilerExecutableMemoryRegions *new_regions) {
1792 for (old_i = 0; old_i < old_regions->regions_count; old_i++) {
1793 ProfilerExecutableMemoryRegionData *old_region = old_regions->regions [old_i];
1794 for (new_i = 0; new_i < new_regions->regions_count; new_i++) {
1795 ProfilerExecutableMemoryRegionData *new_region = new_regions->regions [new_i];
1796 if ((old_region->start == new_region->start) &&
1797 (old_region->end == new_region->end) &&
1798 (old_region->file_offset == new_region->file_offset) &&
1799 ! strcmp (old_region->file_name, new_region->file_name)) {
1800 new_region->is_new = FALSE;
1801 new_region->id = old_region->id;
1802 old_region->is_new = TRUE;
1809 compare_regions (const void *a1, const void *a2) {
1810 ProfilerExecutableMemoryRegionData *r1 = * (ProfilerExecutableMemoryRegionData**) a1;
1811 ProfilerExecutableMemoryRegionData *r2 = * (ProfilerExecutableMemoryRegionData**) a2;
1812 return (r1->start < r2->start)? -1 : ((r1->start > r2->start)? 1 : 0);
1816 sort_regions (ProfilerExecutableMemoryRegions *regions) {
1817 qsort (regions->regions, regions->regions_count, sizeof (ProfilerExecutableMemoryRegionData *), compare_regions);
1820 //FIXME: make also Win32 and BSD variants
1821 #define MAPS_BUFFER_SIZE 4096
1824 update_regions_buffer (int fd, char *buffer) {
1825 ssize_t result = read (fd, buffer, MAPS_BUFFER_SIZE);
1827 if (result == MAPS_BUFFER_SIZE) {
1829 } else if (result >= 0) {
1830 *(buffer + result) = 0;
1838 #define GOTO_NEXT_CHAR(c,b,fd) do {\
1840 if (((c) - (b) >= MAPS_BUFFER_SIZE) || ((*(c) == 0) && ((c) != (b)))) {\
1841 update_regions_buffer ((fd), (b));\
1846 static int hex_digit_value (char c) {
1847 if ((c >= '0') && (c <= '9')) {
1849 } else if ((c >= 'a') && (c <= 'f')) {
1851 } else if ((c >= 'A') && (c <= 'F')) {
1874 MAP_LINE_PARSER_STATE_INVALID,
1875 MAP_LINE_PARSER_STATE_START_ADDRESS,
1876 MAP_LINE_PARSER_STATE_END_ADDRESS,
1877 MAP_LINE_PARSER_STATE_PERMISSIONS,
1878 MAP_LINE_PARSER_STATE_OFFSET,
1879 MAP_LINE_PARSER_STATE_DEVICE,
1880 MAP_LINE_PARSER_STATE_INODE,
1881 MAP_LINE_PARSER_STATE_BLANK_BEFORE_FILENAME,
1882 MAP_LINE_PARSER_STATE_FILENAME,
1883 MAP_LINE_PARSER_STATE_DONE
1884 } MapLineParserState;
1886 const char *map_line_parser_state [] = {
1894 "BLANK_BEFORE_FILENAME",
1900 parse_map_line (ProfilerExecutableMemoryRegions *regions, int fd, char *buffer, char *current) {
1901 MapLineParserState state = MAP_LINE_PARSER_STATE_START_ADDRESS;
1902 gsize start_address = 0;
1903 gsize end_address = 0;
1905 char *start_filename = NULL;
1906 char *end_filename = NULL;
1907 gboolean is_executable = FALSE;
1908 gboolean done = FALSE;
1914 case MAP_LINE_PARSER_STATE_START_ADDRESS:
1916 start_address <<= 4;
1917 start_address |= hex_digit_value (c);
1918 } else if (c == '-') {
1919 state = MAP_LINE_PARSER_STATE_END_ADDRESS;
1921 state = MAP_LINE_PARSER_STATE_INVALID;
1924 case MAP_LINE_PARSER_STATE_END_ADDRESS:
1927 end_address |= hex_digit_value (c);
1928 } else if (isblank (c)) {
1929 state = MAP_LINE_PARSER_STATE_PERMISSIONS;
1931 state = MAP_LINE_PARSER_STATE_INVALID;
1934 case MAP_LINE_PARSER_STATE_PERMISSIONS:
1936 is_executable = TRUE;
1937 } else if (isblank (c)) {
1938 state = MAP_LINE_PARSER_STATE_OFFSET;
1939 } else if ((c != '-') && ! isalpha (c)) {
1940 state = MAP_LINE_PARSER_STATE_INVALID;
1943 case MAP_LINE_PARSER_STATE_OFFSET:
1946 offset |= hex_digit_value (c);
1947 } else if (isblank (c)) {
1948 state = MAP_LINE_PARSER_STATE_DEVICE;
1950 state = MAP_LINE_PARSER_STATE_INVALID;
1953 case MAP_LINE_PARSER_STATE_DEVICE:
1955 state = MAP_LINE_PARSER_STATE_INODE;
1956 } else if ((c != ':') && ! isxdigit (c)) {
1957 state = MAP_LINE_PARSER_STATE_INVALID;
1960 case MAP_LINE_PARSER_STATE_INODE:
1962 state = MAP_LINE_PARSER_STATE_BLANK_BEFORE_FILENAME;
1963 } else if (! isdigit (c)) {
1964 state = MAP_LINE_PARSER_STATE_INVALID;
1967 case MAP_LINE_PARSER_STATE_BLANK_BEFORE_FILENAME:
1969 state = MAP_LINE_PARSER_STATE_FILENAME;
1970 start_filename = current;
1971 } else if (! isblank (c)) {
1972 state = MAP_LINE_PARSER_STATE_INVALID;
1975 case MAP_LINE_PARSER_STATE_FILENAME:
1977 state = MAP_LINE_PARSER_STATE_DONE;
1979 end_filename = current;
1982 case MAP_LINE_PARSER_STATE_DONE:
1983 if (done && is_executable) {
1985 append_region (regions, (gpointer) start_address, (gpointer) end_address, offset, start_filename);
1988 case MAP_LINE_PARSER_STATE_INVALID:
1990 state = MAP_LINE_PARSER_STATE_DONE;
2000 GOTO_NEXT_CHAR(current, buffer, fd);
2006 scan_process_regions (ProfilerExecutableMemoryRegions *regions) {
2011 fd = open ("/proc/self/maps", O_RDONLY);
2016 buffer = malloc (MAPS_BUFFER_SIZE);
2017 update_regions_buffer (fd, buffer);
2019 while (current != NULL) {
2020 current = parse_map_line (regions, fd, buffer, current);
2031 MONO_PROFILER_STATISTICAL_CODE_END = 0,
2032 MONO_PROFILER_STATISTICAL_CODE_METHOD = 1,
2033 MONO_PROFILER_STATISTICAL_CODE_UNMANAGED_FUNCTION_ID = 2,
2034 MONO_PROFILER_STATISTICAL_CODE_UNMANAGED_FUNCTION_IN_REGION = 3,
2035 MONO_PROFILER_STATISTICAL_CODE_REGIONS = 7
2036 } MonoProfilerStatisticalCode;
2039 refresh_memory_regions (void) {
2040 ProfilerExecutableMemoryRegions *old_regions = profiler->executable_regions;
2041 ProfilerExecutableMemoryRegions *new_regions = profiler_executable_memory_regions_new (old_regions->next_id);
2044 LOG_WRITER_THREAD ("Refreshing memory regions...");
2045 scan_process_regions (new_regions);
2046 restore_region_ids (old_regions, new_regions);
2047 sort_regions (new_regions);
2048 LOG_WRITER_THREAD ("Refreshed memory regions.");
2050 // This marks the region "sub-block"
2051 write_uint32 (MONO_PROFILER_STATISTICAL_CODE_REGIONS);
2053 // First write the "removed" regions
2054 for (i = 0; i < old_regions->regions_count; i++) {
2055 ProfilerExecutableMemoryRegionData *region = old_regions->regions [i];
2056 if (! region->is_new) {
2057 #if DEBUG_STATISTICAL_PROFILER
2058 printf ("[refresh_memory_regions] Invalidated region %d\n", region->id);
2060 write_uint32 (region->id);
2065 // Then write the new ones
2066 for (i = 0; i < new_regions->regions_count; i++) {
2067 ProfilerExecutableMemoryRegionData *region = new_regions->regions [i];
2068 if (region->is_new) {
2069 region->is_new = FALSE;
2071 #if DEBUG_STATISTICAL_PROFILER
2072 printf ("[refresh_memory_regions] Wrote region %d (%p-%p[%d] '%s')\n", region->id, region->start, region->end, region->file_offset, region->file_name);
2074 write_uint32 (region->id);
2075 write_uint64 (GPOINTER_TO_INT (region->start));
2076 write_uint32 (GPOINTER_TO_INT (region->end) - GPOINTER_TO_INT (region->start));
2077 write_uint32 (region->file_offset);
2078 write_string (region->file_name);
2083 // Finally, free the old ones, and replace them
2084 profiler_executable_memory_regions_destroy (old_regions);
2085 profiler->executable_regions = new_regions;
2089 flush_all_mappings (void);
2092 write_statistical_data_block (ProfilerStatisticalData *data) {
2093 int start_index = data->first_unwritten_index;
2094 int end_index = data->next_free_index;
2095 gboolean regions_refreshed = FALSE;
2097 ProfilerUnmanagedFunctions *functions = &(profiler->unmanaged_functions);
2099 if (end_index > data->end_index)
2100 end_index = data->end_index;
2102 if (start_index == end_index)
2105 data->first_unwritten_index = end_index;
2107 write_clock_data ();
2109 for (index = start_index; index < end_index; index ++) {
2110 gpointer address = data->addresses [index];
2111 MonoJitInfo *ji = mono_jit_info_table_find (mono_domain_get (), (char*) address);
2114 MonoMethod *method = mono_jit_info_get_method (ji);
2115 MethodIdMappingElement *element = method_id_mapping_element_get (method);
2117 if (element != NULL) {
2118 #if DEBUG_STATISTICAL_PROFILER
2119 printf ("[write_statistical_data_block] Wrote method %d\n", element->id);
2121 write_uint32 ((element->id << 3) | MONO_PROFILER_STATISTICAL_CODE_METHOD);
2123 #if DEBUG_STATISTICAL_PROFILER
2124 printf ("[write_statistical_data_block] Wrote unknown method %p\n", method);
2126 write_uint32 (MONO_PROFILER_STATISTICAL_CODE_METHOD);
2129 if (! unmanaged_function_hit (functions, address)) {
2130 ProfilerExecutableMemoryRegionData *region = find_address_region (profiler->executable_regions, address);
2132 if (region == NULL && ! regions_refreshed) {
2133 refresh_memory_regions ();
2134 regions_refreshed = TRUE;
2135 region = find_address_region (profiler->executable_regions, address);
2138 if (region != NULL) {
2139 #if DEBUG_STATISTICAL_PROFILER
2140 printf ("[write_statistical_data_block] Wrote unmanaged hit %d[%d]\n", region->id, GPOINTER_TO_INT (address) - GPOINTER_TO_INT (region->start));
2142 write_uint32 ((region->id << 3) | MONO_PROFILER_STATISTICAL_CODE_UNMANAGED_FUNCTION_IN_REGION);
2143 write_uint32 (GPOINTER_TO_INT (address) - GPOINTER_TO_INT (region->start));
2145 #if DEBUG_STATISTICAL_PROFILER
2146 printf ("[write_statistical_data_block] Wrote unknown unmanaged hit %p\n", address);
2148 write_uint32 (MONO_PROFILER_STATISTICAL_CODE_UNMANAGED_FUNCTION_IN_REGION);
2149 write_uint64 (GPOINTER_TO_INT (address));
2154 if (functions->unwritten_queue != functions->unwritten_queue_end) {
2155 ProfilerUnmanagedFunction *end = functions->unwritten_queue_end;
2156 ProfilerUnmanagedFunction *function = functions->unwritten_queue;
2157 functions->unwritten_queue = functions->unwritten_queue_end;
2159 while (function != end) {
2160 ProfilerUnmanagedFunction *next = function->next_unwritten;
2162 write_uint32 ((function->id << 3) | MONO_PROFILER_STATISTICAL_CODE_UNMANAGED_FUNCTION_ID);
2163 if (function->name != NULL) {
2165 write_string (function->name);
2166 g_free (function->name);
2167 function->name = NULL;
2169 write_uint32 (function->hits);
2172 function->next_unwritten = NULL;
2176 write_uint32 (MONO_PROFILER_STATISTICAL_CODE_END);
2178 write_clock_data ();
2180 write_current_block (MONO_PROFILER_FILE_BLOCK_KIND_STATISTICAL);
2184 write_intro_block (void) {
2186 write_string ("mono");
2187 write_uint32 (profiler->flags);
2188 write_uint64 (profiler->start_counter);
2189 write_uint64 (profiler->start_time);
2190 write_current_block (MONO_PROFILER_FILE_BLOCK_KIND_INTRO);
2194 write_end_block (void) {
2196 write_uint64 (profiler->end_counter);
2197 write_uint64 (profiler->end_time);
2198 write_current_block (MONO_PROFILER_FILE_BLOCK_KIND_END);
2202 update_mapping (ProfilerPerThreadData *data) {
2203 ProfilerEventData *start = data->first_unmapped_event;
2204 ProfilerEventData *end = data->next_free_event;
2205 data->first_unmapped_event = end;
2207 #if (DEBUG_LOGGING_PROFILER)
2208 printf ("[update_mapping][TID %ld] START\n", data->thread_id);
2210 while (start < end) {
2211 #if DEBUG_LOGGING_PROFILER
2212 printf ("Examining event %p[TID %ld] looking for a new mapping...\n", start, data->thread_id);
2214 if (start->data_type == MONO_PROFILER_EVENT_DATA_TYPE_CLASS) {
2215 ClassIdMappingElement *element = class_id_mapping_element_get (start->data.address);
2216 if (element == NULL) {
2217 MonoClass *klass = start->data.address;
2218 class_id_mapping_element_new (klass);
2220 } else if (start->data_type == MONO_PROFILER_EVENT_DATA_TYPE_METHOD) {
2221 MethodIdMappingElement *element = method_id_mapping_element_get (start->data.address);
2222 if (element == NULL) {
2223 MonoMethod *method = start->data.address;
2224 method_id_mapping_element_new (method);
2230 #if (DEBUG_LOGGING_PROFILER)
2231 printf ("[update_mapping][TID %ld] END\n", data->thread_id);
2236 flush_all_mappings (void) {
2237 ProfilerPerThreadData *data;
2239 for (data = profiler->per_thread_data; data != NULL; data = data->next) {
2240 update_mapping (data);
2242 for (data = profiler->per_thread_data; data != NULL; data = data->next) {
2243 write_mapping_block (data->thread_id);
2248 flush_full_event_data_buffer (ProfilerPerThreadData *data) {
2251 // We flush all mappings because some id definitions could come
2252 // from other threads
2253 flush_all_mappings ();
2254 g_assert (data->first_unmapped_event == data->end_event);
2256 write_thread_data_block (data);
2258 data->next_free_event = data->events;
2259 data->first_unwritten_event = data->events;
2260 data->first_unmapped_event = data->events;
2261 MONO_PROFILER_GET_CURRENT_COUNTER (data->start_event_counter);
2262 data->last_event_counter = data->start_event_counter;
2267 #define GET_NEXT_FREE_EVENT(d,e) {\
2268 if ((d)->next_free_event >= (d)->end_event) {\
2269 flush_full_event_data_buffer (d);\
2271 (e) = (d)->next_free_event;\
2272 (d)->next_free_event ++;\
2276 flush_everything (void) {
2277 ProfilerPerThreadData *data;
2279 flush_all_mappings ();
2280 for (data = profiler->per_thread_data; data != NULL; data = data->next) {
2281 write_thread_data_block (data);
2283 write_statistical_data_block (profiler->statistical_data);
2286 #define RESULT_TO_LOAD_CODE(r) (((r)==MONO_PROFILE_OK)?MONO_PROFILER_LOADED_EVENT_SUCCESS:MONO_PROFILER_LOADED_EVENT_FAILURE)
2288 appdomain_start_load (MonoProfiler *profiler, MonoDomain *domain) {
2290 loaded_element_load_start (profiler->loaded_appdomains, domain);
2295 appdomain_end_load (MonoProfiler *profiler, MonoDomain *domain, int result) {
2297 LoadedElement *element;
2299 name = g_strdup_printf ("%d", mono_domain_get_id (domain));
2301 element = loaded_element_load_end (profiler->loaded_appdomains, domain, name);
2302 write_element_load_block (element, MONO_PROFILER_LOADED_EVENT_APPDOMAIN | RESULT_TO_LOAD_CODE (result), CURRENT_THREAD_ID ());
2307 appdomain_start_unload (MonoProfiler *profiler, MonoDomain *domain) {
2309 loaded_element_unload_start (profiler->loaded_appdomains, domain);
2310 flush_everything ();
2315 appdomain_end_unload (MonoProfiler *profiler, MonoDomain *domain) {
2316 LoadedElement *element;
2319 element = loaded_element_unload_end (profiler->loaded_appdomains, domain);
2320 write_element_unload_block (element, MONO_PROFILER_LOADED_EVENT_APPDOMAIN, CURRENT_THREAD_ID ());
2325 module_start_load (MonoProfiler *profiler, MonoImage *module) {
2327 loaded_element_load_start (profiler->loaded_modules, module);
2332 module_end_load (MonoProfiler *profiler, MonoImage *module, int result) {
2334 MonoAssemblyName aname;
2335 LoadedElement *element;
2337 mono_assembly_fill_assembly_name (module, &aname);
2338 name = mono_stringify_assembly_name (&aname);
2340 element = loaded_element_load_end (profiler->loaded_modules, module, name);
2341 write_element_load_block (element, MONO_PROFILER_LOADED_EVENT_MODULE | RESULT_TO_LOAD_CODE (result), CURRENT_THREAD_ID ());
2346 module_start_unload (MonoProfiler *profiler, MonoImage *module) {
2348 loaded_element_unload_start (profiler->loaded_modules, module);
2349 flush_everything ();
2354 module_end_unload (MonoProfiler *profiler, MonoImage *module) {
2355 LoadedElement *element;
2358 element = loaded_element_unload_end (profiler->loaded_modules, module);
2359 write_element_unload_block (element, MONO_PROFILER_LOADED_EVENT_MODULE, CURRENT_THREAD_ID ());
2364 assembly_start_load (MonoProfiler *profiler, MonoAssembly *assembly) {
2366 loaded_element_load_start (profiler->loaded_assemblies, assembly);
2371 assembly_end_load (MonoProfiler *profiler, MonoAssembly *assembly, int result) {
2373 MonoAssemblyName aname;
2374 LoadedElement *element;
2376 mono_assembly_fill_assembly_name (mono_assembly_get_image (assembly), &aname);
2377 name = mono_stringify_assembly_name (&aname);
2379 element = loaded_element_load_end (profiler->loaded_assemblies, assembly, name);
2380 write_element_load_block (element, MONO_PROFILER_LOADED_EVENT_ASSEMBLY | RESULT_TO_LOAD_CODE (result), CURRENT_THREAD_ID ());
2385 assembly_start_unload (MonoProfiler *profiler, MonoAssembly *assembly) {
2387 loaded_element_unload_start (profiler->loaded_assemblies, assembly);
2388 flush_everything ();
2392 assembly_end_unload (MonoProfiler *profiler, MonoAssembly *assembly) {
2393 LoadedElement *element;
2396 element = loaded_element_unload_end (profiler->loaded_assemblies, assembly);
2397 write_element_unload_block (element, MONO_PROFILER_LOADED_EVENT_ASSEMBLY, CURRENT_THREAD_ID ());
2401 #if (DEBUG_LOGGING_PROFILER)
2403 class_event_code_to_string (MonoProfilerClassEvents code) {
2405 case MONO_PROFILER_EVENT_CLASS_LOAD: return "LOAD";
2406 case MONO_PROFILER_EVENT_CLASS_UNLOAD: return "UNLOAD";
2407 case MONO_PROFILER_EVENT_CLASS_ALLOCATION: return "ALLOCATION";
2408 case MONO_PROFILER_EVENT_CLASS_EXCEPTION: return "EXCEPTION";
2409 default: g_assert_not_reached (); return "";
2413 method_event_code_to_string (MonoProfilerClassEvents code) {
2415 case MONO_PROFILER_EVENT_METHOD_CALL: return "CALL";
2416 case MONO_PROFILER_EVENT_METHOD_JIT: return "JIT";
2417 case MONO_PROFILER_EVENT_METHOD_FREED: return "FREED";
2418 default: g_assert_not_reached (); return "";
2422 number_event_code_to_string (MonoProfilerEvents code) {
2424 case MONO_PROFILER_EVENT_THREAD: return "THREAD";
2425 case MONO_PROFILER_EVENT_GC_COLLECTION: return "GC_COLLECTION";
2426 case MONO_PROFILER_EVENT_GC_MARK: return "GC_MARK";
2427 case MONO_PROFILER_EVENT_GC_SWEEP: return "GC_SWEEP";
2428 case MONO_PROFILER_EVENT_GC_RESIZE: return "GC_RESIZE";
2429 case MONO_PROFILER_EVENT_GC_STOP_WORLD: return "GC_STOP_WORLD";
2430 case MONO_PROFILER_EVENT_GC_START_WORLD: return "GC_START_WORLD";
2431 default: g_assert_not_reached (); return "";
2435 event_result_to_string (MonoProfilerEventResult code) {
2437 case MONO_PROFILER_EVENT_RESULT_SUCCESS: return "SUCCESS";
2438 case MONO_PROFILER_EVENT_RESULT_FAILURE: return "FAILURE";
2439 default: g_assert_not_reached (); return "";
2443 event_kind_to_string (MonoProfilerEventKind code) {
2445 case MONO_PROFILER_EVENT_KIND_START: return "START";
2446 case MONO_PROFILER_EVENT_KIND_END: return "END";
2447 default: g_assert_not_reached (); return "";
2451 print_event_data (gsize thread_id, ProfilerEventData *event, guint64 value) {
2452 if (event->data_type == MONO_PROFILER_EVENT_DATA_TYPE_CLASS) {
2453 printf ("[TID %ld] CLASS[%p] event [%p] %s:%s:%s[%d-%d-%d] %ld (%s.%s)\n",
2455 event->data.address,
2457 class_event_code_to_string (event->code & ~MONO_PROFILER_EVENT_RESULT_MASK),
2458 event_result_to_string (event->code & MONO_PROFILER_EVENT_RESULT_MASK),
2459 event_kind_to_string (event->kind),
2464 mono_class_get_namespace ((MonoClass*) event->data.address),
2465 mono_class_get_name ((MonoClass*) event->data.address));
2466 } else if (event->data_type == MONO_PROFILER_EVENT_DATA_TYPE_METHOD) {
2467 printf ("[TID %ld] METHOD[%p] event [%p] %s:%s:%s[%d-%d-%d] %ld (%s.%s:%s (?))\n",
2469 event->data.address,
2471 method_event_code_to_string (event->code & ~MONO_PROFILER_EVENT_RESULT_MASK),
2472 event_result_to_string (event->code & MONO_PROFILER_EVENT_RESULT_MASK),
2473 event_kind_to_string (event->kind),
2478 mono_class_get_namespace (mono_method_get_class ((MonoMethod*) event->data.address)),
2479 mono_class_get_name (mono_method_get_class ((MonoMethod*) event->data.address)),
2480 mono_method_get_name ((MonoMethod*) event->data.address));
2482 printf ("[TID %ld] NUMBER[%ld] event [%p] %s:%s[%d-%d-%d] %ld\n",
2484 (guint64) event->data.number,
2486 number_event_code_to_string (event->code),
2487 event_kind_to_string (event->kind),
2494 #define LOG_EVENT(tid,ev,val) print_event_data ((tid),(ev),(val))
2496 #define LOG_EVENT(tid,ev,val)
2499 #define RESULT_TO_EVENT_CODE(r) (((r)==MONO_PROFILE_OK)?MONO_PROFILER_EVENT_RESULT_SUCCESS:MONO_PROFILER_EVENT_RESULT_FAILURE)
2501 #define STORE_EVENT_ITEM_COUNTER(p,i,dt,c,k) do {\
2502 ProfilerPerThreadData *data;\
2503 ProfilerEventData *event;\
2506 GET_PROFILER_THREAD_DATA (data);\
2507 GET_NEXT_FREE_EVENT (data, event);\
2508 MONO_PROFILER_GET_CURRENT_COUNTER (counter);\
2509 event->data.address = (i);\
2510 event->data_type = (dt);\
2513 delta = counter - data->last_event_counter;\
2514 if (delta < MAX_EVENT_VALUE) {\
2515 event->value = delta;\
2517 ProfilerEventData *extension = data->next_free_event;\
2518 data->next_free_event ++;\
2519 event->value = delta >> 32;\
2520 extension->data.number = delta & 0xffffffff;\
2522 data->last_event_counter = counter;\
2523 LOG_EVENT (data->thread_id, event, delta);\
2525 #define STORE_EVENT_ITEM_VALUE(p,i,dt,c,k,v) do {\
2526 ProfilerPerThreadData *data;\
2527 ProfilerEventData *event;\
2528 GET_PROFILER_THREAD_DATA (data);\
2529 GET_NEXT_FREE_EVENT (data, event);\
2530 event->data.address = (i);\
2531 event->data_type = (dt);\
2534 if ((v) < MAX_EVENT_VALUE) {\
2535 event->value = (v);\
2537 ProfilerEventData *extension = data->next_free_event;\
2538 data->next_free_event ++;\
2539 event->value = (v) >> 32;\
2540 extension->data.number = (v) & 0xffffffff;\
2542 LOG_EVENT (data->thread_id, event, (v));\
2544 #define STORE_EVENT_NUMBER_COUNTER(p,n,dt,c,k) do {\
2545 ProfilerPerThreadData *data;\
2546 ProfilerEventData *event;\
2549 GET_PROFILER_THREAD_DATA (data);\
2550 GET_NEXT_FREE_EVENT (data, event);\
2551 MONO_PROFILER_GET_CURRENT_COUNTER (counter);\
2552 event->data.number = (n);\
2553 event->data_type = (dt);\
2556 delta = counter - data->last_event_counter;\
2557 if (delta < MAX_EVENT_VALUE) {\
2558 event->value = delta;\
2560 ProfilerEventData *extension = data->next_free_event;\
2561 data->next_free_event ++;\
2562 event->value = delta >> 32;\
2563 extension->data.number = delta & 0xffffffff;\
2565 data->last_event_counter = counter;\
2566 LOG_EVENT (data->thread_id, event, delta);\
2568 #define STORE_EVENT_NUMBER_VALUE(p,n,dt,c,k,v) do {\
2569 ProfilerPerThreadData *data;\
2570 ProfilerEventData *event;\
2571 GET_PROFILER_THREAD_DATA (data);\
2572 GET_NEXT_FREE_EVENT (data, event);\
2573 event->data.number = (n);\
2574 event->data_type = (dt);\
2577 if ((v) < MAX_EVENT_VALUE) {\
2578 event->value = (v);\
2580 ProfilerEventData *extension = data->next_free_event;\
2581 data->next_free_event ++;\
2582 event->value = (v) >> 32;\
2583 extension->data.number = (v) & 0xffffffff;\
2585 LOG_EVENT (data->thread_id, event, (v));\
2590 class_start_load (MonoProfiler *profiler, MonoClass *klass) {
2591 STORE_EVENT_ITEM_COUNTER (profiler, klass, MONO_PROFILER_EVENT_DATA_TYPE_CLASS, MONO_PROFILER_EVENT_CLASS_LOAD, MONO_PROFILER_EVENT_KIND_START);
2594 class_end_load (MonoProfiler *profiler, MonoClass *klass, int result) {
2595 STORE_EVENT_ITEM_COUNTER (profiler, klass, MONO_PROFILER_EVENT_DATA_TYPE_CLASS, MONO_PROFILER_EVENT_CLASS_LOAD | RESULT_TO_EVENT_CODE (result), MONO_PROFILER_EVENT_KIND_END);
2598 class_start_unload (MonoProfiler *profiler, MonoClass *klass) {
2599 STORE_EVENT_ITEM_COUNTER (profiler, klass, MONO_PROFILER_EVENT_DATA_TYPE_CLASS, MONO_PROFILER_EVENT_CLASS_UNLOAD, MONO_PROFILER_EVENT_KIND_START);
2602 class_end_unload (MonoProfiler *profiler, MonoClass *klass) {
2603 STORE_EVENT_ITEM_COUNTER (profiler, klass, MONO_PROFILER_EVENT_DATA_TYPE_CLASS, MONO_PROFILER_EVENT_CLASS_UNLOAD, MONO_PROFILER_EVENT_KIND_END);
2607 method_start_jit (MonoProfiler *profiler, MonoMethod *method) {
2608 if (profiler->action_flags.jit_time) {
2609 STORE_EVENT_ITEM_COUNTER (profiler, method, MONO_PROFILER_EVENT_DATA_TYPE_METHOD, MONO_PROFILER_EVENT_METHOD_JIT, MONO_PROFILER_EVENT_KIND_START);
2613 method_end_jit (MonoProfiler *profiler, MonoMethod *method, int result) {
2614 if (profiler->action_flags.jit_time) {
2615 STORE_EVENT_ITEM_COUNTER (profiler, method, MONO_PROFILER_EVENT_DATA_TYPE_METHOD, MONO_PROFILER_EVENT_METHOD_JIT | RESULT_TO_EVENT_CODE (result), MONO_PROFILER_EVENT_KIND_END);
2621 method_jit_result (MonoProfiler *prof, MonoMethod *method, MonoJitInfo* jinfo, int result) {
2622 if (profiler->action_flags.oprofile && (result == MONO_PROFILE_OK)) {
2623 MonoClass *klass = mono_method_get_class (method);
2624 char *signature = mono_signature_get_desc (mono_method_signature (method), TRUE);
2625 char *name = g_strdup_printf ("%s.%s:%s (%s)", mono_class_get_namespace (klass), mono_class_get_name (klass), mono_method_get_name (method), signature);
2626 gpointer code_start = mono_jit_info_get_code_start (jinfo);
2627 int code_size = mono_jit_info_get_code_size (jinfo);
2629 if (op_write_native_code (name, code_start, code_size)) {
2630 g_warning ("Problem calling op_write_native_code\n");
2641 method_enter (MonoProfiler *profiler, MonoMethod *method) {
2642 STORE_EVENT_ITEM_COUNTER (profiler, method, MONO_PROFILER_EVENT_DATA_TYPE_METHOD, MONO_PROFILER_EVENT_METHOD_CALL, MONO_PROFILER_EVENT_KIND_START);
2645 method_leave (MonoProfiler *profiler, MonoMethod *method) {
2646 STORE_EVENT_ITEM_COUNTER (profiler, method, MONO_PROFILER_EVENT_DATA_TYPE_METHOD, MONO_PROFILER_EVENT_METHOD_CALL, MONO_PROFILER_EVENT_KIND_END);
2650 method_free (MonoProfiler *profiler, MonoMethod *method) {
2651 STORE_EVENT_ITEM_COUNTER (profiler, method, MONO_PROFILER_EVENT_DATA_TYPE_METHOD, MONO_PROFILER_EVENT_METHOD_FREED, 0);
2655 thread_start (MonoProfiler *profiler, gsize tid) {
2656 STORE_EVENT_NUMBER_COUNTER (profiler, tid, MONO_PROFILER_EVENT_DATA_TYPE_OTHER, MONO_PROFILER_EVENT_THREAD, MONO_PROFILER_EVENT_KIND_START);
2659 thread_end (MonoProfiler *profiler, gsize tid) {
2660 STORE_EVENT_NUMBER_COUNTER (profiler, tid, MONO_PROFILER_EVENT_DATA_TYPE_OTHER, MONO_PROFILER_EVENT_THREAD, MONO_PROFILER_EVENT_KIND_END);
2664 object_allocated (MonoProfiler *profiler, MonoObject *obj, MonoClass *klass) {
2665 ProfilerPerThreadData *thread_data;
2667 STORE_EVENT_ITEM_VALUE (profiler, klass, MONO_PROFILER_EVENT_DATA_TYPE_CLASS, MONO_PROFILER_EVENT_CLASS_ALLOCATION, 0, (guint64) mono_object_get_size (obj));
2668 if (profiler->action_flags.unreachable_objects || profiler->action_flags.heap_shot) {
2669 GET_PROFILER_THREAD_DATA (thread_data);
2670 STORE_ALLOCATED_OBJECT (thread_data, obj);
2676 statistical_hit (MonoProfiler *profiler, guchar *ip, void *context) {
2677 ProfilerStatisticalData *data;
2681 data = profiler->statistical_data;
2682 index = InterlockedIncrement (&data->next_free_index);
2684 if (index <= data->end_index) {
2685 data->addresses [index - 1] = (gpointer) ip;
2687 /* Check if we are the one that must swap the buffers */
2688 if (index == data->end_index + 1) {
2689 ProfilerStatisticalData *new_data;
2691 /* In the *impossible* case that the writer thread has not finished yet, */
2692 /* loop waiting for it and meanwhile lose all statistical events... */
2694 /* First, wait that it consumed the ready buffer */
2695 while (profiler->statistical_data_ready != NULL);
2696 /* Then, wait that it produced the free buffer */
2697 new_data = profiler->statistical_data_second_buffer;
2698 } while (new_data == NULL);
2700 profiler->statistical_data_ready = data;
2701 profiler->statistical_data = new_data;
2702 profiler->statistical_data_second_buffer = NULL;
2703 WRITER_EVENT_RAISE ();
2706 /* Loop again, hoping to acquire a free slot this time */
2709 } while (data == NULL);
2712 static MonoProfilerEvents
2713 gc_event_code_from_profiler_event (MonoGCEvent event) {
2715 case MONO_GC_EVENT_START:
2716 case MONO_GC_EVENT_END:
2717 return MONO_PROFILER_EVENT_GC_COLLECTION;
2718 case MONO_GC_EVENT_MARK_START:
2719 case MONO_GC_EVENT_MARK_END:
2720 return MONO_PROFILER_EVENT_GC_MARK;
2721 case MONO_GC_EVENT_RECLAIM_START:
2722 case MONO_GC_EVENT_RECLAIM_END:
2723 return MONO_PROFILER_EVENT_GC_SWEEP;
2724 case MONO_GC_EVENT_PRE_STOP_WORLD:
2725 case MONO_GC_EVENT_POST_STOP_WORLD:
2726 return MONO_PROFILER_EVENT_GC_STOP_WORLD;
2727 case MONO_GC_EVENT_PRE_START_WORLD:
2728 case MONO_GC_EVENT_POST_START_WORLD:
2729 return MONO_PROFILER_EVENT_GC_START_WORLD;
2731 g_assert_not_reached ();
2736 static MonoProfilerEventKind
2737 gc_event_kind_from_profiler_event (MonoGCEvent event) {
2739 case MONO_GC_EVENT_START:
2740 case MONO_GC_EVENT_MARK_START:
2741 case MONO_GC_EVENT_RECLAIM_START:
2742 case MONO_GC_EVENT_PRE_STOP_WORLD:
2743 case MONO_GC_EVENT_PRE_START_WORLD:
2744 return MONO_PROFILER_EVENT_KIND_START;
2745 case MONO_GC_EVENT_END:
2746 case MONO_GC_EVENT_MARK_END:
2747 case MONO_GC_EVENT_RECLAIM_END:
2748 case MONO_GC_EVENT_POST_START_WORLD:
2749 case MONO_GC_EVENT_POST_STOP_WORLD:
2750 return MONO_PROFILER_EVENT_KIND_END;
2752 g_assert_not_reached ();
2757 #define HEAP_SHOT_COMMAND_FILE_MAX_LENGTH 64
2759 profiler_heap_shot_process_command_file (void) {
2760 //FIXME: Port to Windows as well
2761 struct stat stat_buf;
2763 char buffer [HEAP_SHOT_COMMAND_FILE_MAX_LENGTH + 1];
2765 if (profiler->heap_shot_command_file_name == NULL)
2767 if (stat (profiler->heap_shot_command_file_name, &stat_buf) != 0)
2769 if (stat_buf.st_size > HEAP_SHOT_COMMAND_FILE_MAX_LENGTH)
2771 if ((stat_buf.st_mtim.tv_sec * 1000000) < profiler->heap_shot_command_file_access_time)
2774 fd = open (profiler->heap_shot_command_file_name, O_RDONLY);
2778 if (read (fd, &(buffer [0]), stat_buf.st_size) != stat_buf.st_size) {
2781 buffer [stat_buf.st_size] = 0;
2782 profiler->dump_next_heap_snapshots = atoi (buffer);
2783 MONO_PROFILER_GET_CURRENT_TIME (profiler->heap_shot_command_file_access_time);
2790 dump_current_heap_snapshot (void) {
2793 profiler_heap_shot_process_command_file ();
2794 if (profiler->dump_next_heap_snapshots > 0) {
2795 profiler->dump_next_heap_snapshots--;
2797 } else if (profiler->dump_next_heap_snapshots < 0) {
2803 return (result || (profiler->heap_shot_was_signalled));
2807 profiler_heap_buffers_setup (ProfilerHeapShotHeapBuffers *heap) {
2808 heap->buffers = g_new (ProfilerHeapShotHeapBuffer, 1);
2809 heap->buffers->previous = NULL;
2810 heap->buffers->next = NULL;
2811 heap->buffers->start_slot = &(heap->buffers->buffer [0]);
2812 heap->buffers->end_slot = &(heap->buffers->buffer [PROFILER_HEAP_SHOT_HEAP_BUFFER_SIZE]);
2813 heap->last = heap->buffers;
2814 heap->current = heap->buffers;
2815 heap->first_free_slot = & (heap->buffers->buffer [0]);
2818 profiler_heap_buffers_clear (ProfilerHeapShotHeapBuffers *heap) {
2819 heap->buffers = NULL;
2821 heap->current = NULL;
2822 heap->first_free_slot = NULL;
2825 profiler_heap_buffers_free (ProfilerHeapShotHeapBuffers *heap) {
2826 ProfilerHeapShotHeapBuffer *current = heap->buffers;
2827 while (current != NULL) {
2828 ProfilerHeapShotHeapBuffer *next = current->next;
2832 profiler_heap_buffers_clear (heap);
2836 report_object_references (gpointer *start, ClassIdMappingElement *layout, ProfilerHeapShotWriteJob *job) {
2837 int reported_references = 0;
2840 for (slot = 0; slot < layout->data.layout.slots; slot ++) {
2841 gboolean slot_has_reference;
2842 if (layout->data.layout.slots <= CLASS_LAYOUT_PACKED_BITMAP_SIZE) {
2843 if (layout->data.bitmap.compact & (((guint64)1) << slot)) {
2844 slot_has_reference = TRUE;
2846 slot_has_reference = FALSE;
2849 if (layout->data.bitmap.extended [slot >> 3] & (1 << (slot & 7))) {
2850 slot_has_reference = TRUE;
2852 slot_has_reference = FALSE;
2856 if (slot_has_reference) {
2857 gpointer field = start [slot];
2859 if ((field != NULL) && mono_object_is_alive (field)) {
2860 reported_references ++;
2861 WRITE_HEAP_SHOT_JOB_VALUE (job, field);
2866 return reported_references;
2870 profiler_heap_report_object_reachable (ProfilerHeapShotWriteJob *job, MonoObject *obj) {
2871 if (profiler->action_flags.heap_shot && (job != NULL)) {
2872 MonoClass *klass = mono_object_get_class (obj);
2873 int reference_counter = 0;
2874 gpointer *reference_counter_location;
2876 WRITE_HEAP_SHOT_JOB_VALUE_WITH_CODE (job, obj, HEAP_CODE_OBJECT);
2877 #if DEBUG_HEAP_PROFILER
2878 printf ("profiler_heap_report_object_reachable: reported object %p at cursor %p\n", obj, (job->cursor - 1));
2880 WRITE_HEAP_SHOT_JOB_VALUE (job, NULL);
2881 reference_counter_location = job->cursor - 1;
2883 if (mono_class_get_rank (klass)) {
2884 MonoArray *array = (MonoArray *) obj;
2885 MonoClass *element_class = mono_class_get_element_class (klass);
2886 ClassIdMappingElement *element_id = class_id_mapping_element_get (element_class);
2888 g_assert (element_id != NULL);
2889 if (element_id->data.layout.slots == CLASS_LAYOUT_NOT_INITIALIZED) {
2890 class_id_mapping_element_build_layout_bitmap (element_class, element_id);
2892 if (! mono_class_is_valuetype (element_class)) {
2893 int length = mono_array_length (array);
2895 for (i = 0; i < length; i++) {
2896 MonoObject *array_element = mono_array_get (array, MonoObject*, i);
2897 if ((array_element != NULL) && mono_object_is_alive (array_element)) {
2898 reference_counter ++;
2899 WRITE_HEAP_SHOT_JOB_VALUE (job, array_element);
2902 } else if (element_id->data.layout.references > 0) {
2903 int length = mono_array_length (array);
2904 int array_element_size = mono_array_element_size (klass);
2906 for (i = 0; i < length; i++) {
2907 gpointer array_element_address = mono_array_addr_with_size (array, array_element_size, i);
2908 reference_counter += report_object_references (array_element_address, element_id, job);
2912 ClassIdMappingElement *class_id = class_id_mapping_element_get (klass);
2913 if (class_id == NULL) {
2914 printf ("profiler_heap_report_object_reachable: class %p (%s.%s) has no id\n", klass, mono_class_get_namespace (klass), mono_class_get_name (klass));
2916 g_assert (class_id != NULL);
2917 if (class_id->data.layout.slots == CLASS_LAYOUT_NOT_INITIALIZED) {
2918 class_id_mapping_element_build_layout_bitmap (klass, class_id);
2920 if (class_id->data.layout.references > 0) {
2921 reference_counter += report_object_references ((gpointer)(((char*)obj) + sizeof (MonoObject)), class_id, job);
2925 *reference_counter_location = GINT_TO_POINTER (reference_counter);
2926 #if DEBUG_HEAP_PROFILER
2927 printf ("profiler_heap_report_object_reachable: updated reference_counter_location %p with value %d\n", reference_counter_location, reference_counter);
2932 profiler_heap_report_object_unreachable (ProfilerHeapShotWriteJob *job, MonoObject *obj) {
2934 MonoClass *klass = mono_object_get_class (obj);
2935 guint32 size = mono_object_get_size (obj);
2937 #if DEBUG_HEAP_PROFILER
2938 printf ("profiler_heap_report_object_unreachable: at job %p writing klass %p\n", job, klass);
2940 WRITE_HEAP_SHOT_JOB_VALUE_WITH_CODE (job, klass, HEAP_CODE_FREE_OBJECT_CLASS);
2942 #if DEBUG_HEAP_PROFILER
2943 printf ("profiler_heap_report_object_unreachable: at job %p writing size %p\n", job, GUINT_TO_POINTER (size));
2945 WRITE_HEAP_SHOT_JOB_VALUE (job, GUINT_TO_POINTER (size));
2950 profiler_heap_add_object (ProfilerHeapShotHeapBuffers *heap, ProfilerHeapShotWriteJob *job, MonoObject *obj) {
2951 if (heap->first_free_slot >= heap->current->end_slot) {
2952 if (heap->current->next != NULL) {
2953 heap->current = heap->current->next;
2955 ProfilerHeapShotHeapBuffer *buffer = g_new (ProfilerHeapShotHeapBuffer, 1);
2956 buffer->previous = heap->last;
2957 buffer->next = NULL;
2958 buffer->start_slot = &(buffer->buffer [0]);
2959 buffer->end_slot = &(buffer->buffer [PROFILER_HEAP_SHOT_HEAP_BUFFER_SIZE]);
2960 heap->current = buffer;
2961 heap->last->next = buffer;
2962 heap->last = buffer;
2964 heap->first_free_slot = &(heap->current->buffer [0]);
2967 *(heap->first_free_slot) = obj;
2968 heap->first_free_slot ++;
2969 profiler_heap_report_object_reachable (job, obj);
2973 profiler_heap_pop_object_from_end (ProfilerHeapShotHeapBuffers *heap, ProfilerHeapShotWriteJob *job, MonoObject** current_slot) {
2974 while (heap->first_free_slot != current_slot) {
2977 if (heap->first_free_slot > heap->current->start_slot) {
2978 heap->first_free_slot --;
2980 heap->current = heap->current->previous;
2981 g_assert (heap->current != NULL);
2982 heap->first_free_slot = heap->current->end_slot - 1;
2985 obj = *(heap->first_free_slot);
2987 if (mono_object_is_alive (obj)) {
2988 profiler_heap_report_object_reachable (job, obj);
2991 profiler_heap_report_object_unreachable (job, obj);
2998 profiler_heap_scan (ProfilerHeapShotHeapBuffers *heap, ProfilerHeapShotWriteJob *job) {
2999 ProfilerHeapShotHeapBuffer *current_buffer = heap->buffers;
3000 MonoObject** current_slot = current_buffer->start_slot;
3002 while (current_slot != heap->first_free_slot) {
3003 MonoObject *obj = *current_slot;
3004 if (mono_object_is_alive (obj)) {
3005 profiler_heap_report_object_reachable (job, obj);
3007 profiler_heap_report_object_unreachable (job, obj);
3008 *current_slot = profiler_heap_pop_object_from_end (heap, job, current_slot);
3011 if (*current_slot != NULL) {
3014 if (current_slot == current_buffer->end_slot) {
3015 current_buffer = current_buffer->next;
3016 //g_assert (current_buffer != NULL);
3017 if (current_buffer == NULL) {
3020 g_assert_not_reached ();
3022 current_slot = current_buffer->start_slot;
3029 handle_heap_profiling (MonoProfiler *profiler, MonoGCEvent ev) {
3031 case MONO_GC_EVENT_PRE_STOP_WORLD:
3032 // Get the lock, so we are sure nobody is flushing events during the collection,
3033 // and we can update all mappings (building the class descriptors).
3036 case MONO_GC_EVENT_POST_STOP_WORLD:
3037 // Update all mappings, so that we have built all the class descriptors.
3038 flush_all_mappings ();
3042 case MONO_GC_EVENT_MARK_END: {
3043 ProfilerHeapShotWriteJob *job;
3044 ProfilerPerThreadData *data;
3046 if (dump_current_heap_snapshot ()) {
3047 job = profiler_heap_shot_write_job_new (profiler->heap_shot_was_signalled);
3048 profiler->heap_shot_was_signalled = FALSE;
3049 MONO_PROFILER_GET_CURRENT_COUNTER (job->start_counter);
3050 MONO_PROFILER_GET_CURRENT_TIME (job->start_time);
3055 profiler_heap_scan (&(profiler->heap), job);
3057 for (data = profiler->per_thread_data; data != NULL; data = data->next) {
3058 ProfilerHeapShotObjectBuffer *buffer;
3059 for (buffer = data->heap_shot_object_buffers; buffer != NULL; buffer = buffer->next) {
3060 MonoObject **cursor;
3061 for (cursor = buffer->first_unprocessed_slot; cursor < buffer->next_free_slot; cursor ++) {
3062 MonoObject *obj = *cursor;
3063 #if DEBUG_HEAP_PROFILER
3064 printf ("gc_event: in object buffer %p(%p-%p) cursor at %p has object %p ", buffer, &(buffer->buffer [0]), buffer->end, cursor, obj);
3066 if (mono_object_is_alive (obj)) {
3067 #if DEBUG_HEAP_PROFILER
3068 printf ("(object is alive, adding to heap)\n");
3070 profiler_heap_add_object (&(profiler->heap), job, obj);
3072 #if DEBUG_HEAP_PROFILER
3073 printf ("(object is unreachable, reporting in job)\n");
3075 profiler_heap_report_object_unreachable (job, obj);
3078 buffer->first_unprocessed_slot = cursor;
3083 MONO_PROFILER_GET_CURRENT_COUNTER (job->end_counter);
3084 MONO_PROFILER_GET_CURRENT_TIME (job->end_time);
3086 profiler_add_heap_shot_write_job (job);
3087 profiler_free_heap_shot_write_jobs ();
3088 WRITER_EVENT_RAISE ();
3098 gc_event (MonoProfiler *profiler, MonoGCEvent ev, int generation) {
3099 STORE_EVENT_NUMBER_COUNTER (profiler, generation, MONO_PROFILER_EVENT_DATA_TYPE_OTHER, gc_event_code_from_profiler_event (ev), gc_event_kind_from_profiler_event (ev));
3100 if (profiler->action_flags.unreachable_objects || profiler->action_flags.heap_shot) {
3101 handle_heap_profiling (profiler, ev);
3106 gc_resize (MonoProfiler *profiler, gint64 new_size) {
3107 STORE_EVENT_NUMBER_COUNTER (profiler, new_size, MONO_PROFILER_EVENT_DATA_TYPE_OTHER, MONO_PROFILER_EVENT_GC_RESIZE, 0);
3110 /* called at the end of the program */
3112 profiler_shutdown (MonoProfiler *prof)
3114 ProfilerPerThreadData* current_thread_data;
3116 LOG_WRITER_THREAD ("profiler_shutdown: zeroing relevant flags");
3117 mono_profiler_set_events (0);
3118 //profiler->flags = 0;
3119 //profiler->action_flags.unreachable_objects = FALSE;
3120 //profiler->action_flags.heap_shot = FALSE;
3122 LOG_WRITER_THREAD ("profiler_shutdown: asking stats thread to exit");
3123 profiler->terminate_writer_thread = TRUE;
3124 WRITER_EVENT_RAISE ();
3125 LOG_WRITER_THREAD ("profiler_shutdown: waiting for stats thread to exit");
3126 WAIT_WRITER_THREAD ();
3127 LOG_WRITER_THREAD ("profiler_shutdown: stats thread should be dead now");
3128 WRITER_EVENT_DESTROY ();
3132 MONO_PROFILER_GET_CURRENT_TIME (profiler->end_time);
3133 MONO_PROFILER_GET_CURRENT_COUNTER (profiler->end_counter);
3135 flush_everything ();
3140 g_free (profiler->file_name);
3142 method_id_mapping_destroy (profiler->methods);
3143 class_id_mapping_destroy (profiler->classes);
3144 g_hash_table_destroy (profiler->loaded_assemblies);
3145 g_hash_table_destroy (profiler->loaded_modules);
3146 g_hash_table_destroy (profiler->loaded_appdomains);
3148 FREE_PROFILER_THREAD_DATA ();
3150 for (current_thread_data = profiler->per_thread_data; current_thread_data != NULL; current_thread_data = current_thread_data->next) {
3151 profiler_per_thread_data_destroy (current_thread_data);
3153 if (profiler->statistical_data != NULL) {
3154 profiler_statistical_data_destroy (profiler->statistical_data);
3156 if (profiler->statistical_data_ready != NULL) {
3157 profiler_statistical_data_destroy (profiler->statistical_data_ready);
3159 if (profiler->statistical_data_second_buffer != NULL) {
3160 profiler_statistical_data_destroy (profiler->statistical_data_second_buffer);
3162 if (profiler->executable_regions != NULL) {
3163 profiler_executable_memory_regions_destroy (profiler->executable_regions);
3165 unmanaged_functions_dispose (&(profiler->unmanaged_functions));
3167 profiler_heap_buffers_free (&(profiler->heap));
3168 if (profiler->heap_shot_command_file_name != NULL) {
3169 g_free (profiler->heap_shot_command_file_name);
3172 profiler_free_write_buffers ();
3173 profiler_destroy_heap_shot_write_jobs ();
3175 DELETE_PROFILER_MUTEX ();
3178 if (profiler->action_flags.oprofile) {
3187 #define DEFAULT_ARGUMENTS "s"
3189 setup_user_options (const char *arguments) {
3190 gchar **arguments_array, **current_argument;
3192 profiler->file_name = NULL;
3193 profiler->per_thread_buffer_size = 10000;
3194 profiler->statistical_buffer_size = 10000;
3195 profiler->write_buffer_size = 1024;
3196 profiler->heap_shot_command_file_name = NULL;
3197 profiler->dump_next_heap_snapshots = 0;
3198 profiler->heap_shot_command_file_access_time = 0;
3199 profiler->heap_shot_was_signalled = FALSE;
3200 profiler->flags = MONO_PROFILE_APPDOMAIN_EVENTS|
3201 MONO_PROFILE_ASSEMBLY_EVENTS|
3202 MONO_PROFILE_MODULE_EVENTS|
3203 MONO_PROFILE_CLASS_EVENTS|
3204 MONO_PROFILE_METHOD_EVENTS;
3206 if (arguments == NULL) {
3207 arguments = DEFAULT_ARGUMENTS;
3208 } else if (strstr (arguments, ":")) {
3209 arguments = strstr (arguments, ":") + 1;
3210 if (arguments [0] == 0) {
3211 arguments = DEFAULT_ARGUMENTS;
3215 arguments_array = g_strsplit (arguments, ",", -1);
3217 for (current_argument = arguments_array; ((current_argument != NULL) && (current_argument [0] != 0)); current_argument ++) {
3218 char *argument = *current_argument;
3219 char *equals = strstr (argument, "=");
3221 if (equals != NULL) {
3222 int equals_position = equals - argument;
3224 if (! (strncmp (argument, "per-thread-buffer-size", equals_position) && strncmp (argument, "tbs", equals_position))) {
3225 int value = atoi (equals + 1);
3227 profiler->per_thread_buffer_size = value;
3229 } else if (! (strncmp (argument, "statistical-thread-buffer-size", equals_position) && strncmp (argument, "sbs", equals_position))) {
3230 int value = atoi (equals + 1);
3232 profiler->statistical_buffer_size = value;
3234 } else if (! (strncmp (argument, "write-buffer-size", equals_position) && strncmp (argument, "wbs", equals_position))) {
3235 int value = atoi (equals + 1);
3237 profiler->write_buffer_size = value;
3239 } else if (! (strncmp (argument, "output", equals_position) && strncmp (argument, "out", equals_position) && strncmp (argument, "o", equals_position) && strncmp (argument, "O", equals_position))) {
3240 if (strlen (equals + 1) > 0) {
3241 profiler->file_name = g_strdup (equals + 1);
3243 } else if (! (strncmp (argument, "gc-commands", equals_position) && strncmp (argument, "gc-c", equals_position) && strncmp (argument, "gcc", equals_position))) {
3244 if (strlen (equals + 1) > 0) {
3245 profiler->heap_shot_command_file_name = g_strdup (equals + 1);
3247 } else if (! (strncmp (argument, "gc-dumps", equals_position) && strncmp (argument, "gc-d", equals_position) && strncmp (argument, "gcd", equals_position))) {
3248 if (strlen (equals + 1) > 0) {
3249 profiler->dump_next_heap_snapshots = atoi (equals + 1);
3252 g_warning ("Cannot parse valued argument %s\n", argument);
3255 if (! (strcmp (argument, "jit") && strcmp (argument, "j"))) {
3256 profiler->flags |= MONO_PROFILE_JIT_COMPILATION;
3257 profiler->action_flags.jit_time = TRUE;
3258 } else if (! (strcmp (argument, "allocations") && strcmp (argument, "alloc") && strcmp (argument, "a"))) {
3259 profiler->flags |= MONO_PROFILE_ALLOCATIONS|MONO_PROFILE_GC;
3260 } else if (! (strcmp (argument, "gc") && strcmp (argument, "g"))) {
3261 profiler->flags |= MONO_PROFILE_GC;
3262 } else if (! (strcmp (argument, "heap-shot") && strcmp (argument, "heap") && strcmp (argument, "h"))) {
3263 profiler->flags |= MONO_PROFILE_ALLOCATIONS|MONO_PROFILE_GC;
3264 profiler->action_flags.unreachable_objects = TRUE;
3265 profiler->action_flags.heap_shot = TRUE;
3266 } else if (! (strcmp (argument, "unreachable") && strcmp (argument, "free") && strcmp (argument, "f"))) {
3267 profiler->flags |= MONO_PROFILE_ALLOCATIONS|MONO_PROFILE_GC;
3268 profiler->action_flags.unreachable_objects = TRUE;
3269 } else if (! (strcmp (argument, "threads") && strcmp (argument, "t"))) {
3270 profiler->flags |= MONO_PROFILE_THREADS;
3271 } else if (! (strcmp (argument, "enter-leave") && strcmp (argument, "calls") && strcmp (argument, "c"))) {
3272 profiler->flags |= MONO_PROFILE_ENTER_LEAVE;
3273 } else if (! (strcmp (argument, "statistical") && strcmp (argument, "stat") && strcmp (argument, "s"))) {
3274 profiler->flags |= MONO_PROFILE_STATISTICAL|MONO_PROFILE_JIT_COMPILATION;
3275 profiler->action_flags.jit_time = TRUE;
3277 } else if (! (strcmp (argument, "oprofile") && strcmp (argument, "oprof"))) {
3278 profiler->flags |= MONO_PROFILE_JIT_COMPILATION;
3279 profiler->action_flags.oprofile = TRUE;
3280 if (op_open_agent ()) {
3281 g_warning ("Problem calling op_open_agent\n");
3284 } else if (strcmp (argument, "logging")) {
3285 g_warning ("Cannot parse flag argument %s\n", argument);
3290 g_free (arguments_array);
3292 if (profiler->file_name == NULL) {
3293 profiler->file_name = g_strdup ("profiler-log.prof");
3299 data_writer_thread (gpointer nothing) {
3301 ProfilerStatisticalData *statistical_data;
3304 LOG_WRITER_THREAD ("data_writer_thread: going to sleep");
3305 WRITER_EVENT_WAIT ();
3306 LOG_WRITER_THREAD ("data_writer_thread: just woke up");
3308 statistical_data = profiler->statistical_data_ready;
3309 done = (statistical_data == NULL) && (profiler->heap_shot_write_jobs == NULL);
3312 LOG_WRITER_THREAD ("data_writer_thread: acquiring lock and writing data");
3315 // This makes sure that all method ids are in place
3316 LOG_WRITER_THREAD ("data_writer_thread: writing mapping...");
3317 flush_all_mappings ();
3318 LOG_WRITER_THREAD ("data_writer_thread: wrote mapping");
3320 if (statistical_data != NULL) {
3321 LOG_WRITER_THREAD ("data_writer_thread: writing statistical data...");
3322 profiler->statistical_data_ready = NULL;
3323 write_statistical_data_block (statistical_data);
3324 statistical_data->next_free_index = 0;
3325 statistical_data->first_unwritten_index = 0;
3326 profiler->statistical_data_second_buffer = statistical_data;
3327 LOG_WRITER_THREAD ("data_writer_thread: wrote statistical data");
3330 profiler_process_heap_shot_write_jobs ();
3333 LOG_WRITER_THREAD ("data_writer_thread: wrote data and released lock");
3337 if (profiler->terminate_writer_thread) {
3338 LOG_WRITER_THREAD ("data_writer_thread: exiting thread");
3346 mono_profiler_startup (const char *desc);
3348 /* the entry point (mono_profiler_load?) */
3350 mono_profiler_startup (const char *desc)
3352 profiler = g_new0 (MonoProfiler, 1);
3354 setup_user_options ((desc != NULL) ? desc : "");
3356 INITIALIZE_PROFILER_MUTEX ();
3357 MONO_PROFILER_GET_CURRENT_TIME (profiler->start_time);
3358 MONO_PROFILER_GET_CURRENT_COUNTER (profiler->start_counter);
3360 profiler->methods = method_id_mapping_new ();
3361 profiler->classes = class_id_mapping_new ();
3362 profiler->loaded_assemblies = g_hash_table_new_full (g_direct_hash, NULL, NULL, loaded_element_destroy);
3363 profiler->loaded_modules = g_hash_table_new_full (g_direct_hash, NULL, NULL, loaded_element_destroy);
3364 profiler->loaded_appdomains = g_hash_table_new_full (g_direct_hash, NULL, NULL, loaded_element_destroy);
3366 profiler->statistical_data = profiler_statistical_data_new (profiler->statistical_buffer_size);
3367 profiler->statistical_data_second_buffer = profiler_statistical_data_new (profiler->statistical_buffer_size);
3368 unmanaged_functions_init (&(profiler->unmanaged_functions));
3370 profiler->write_buffers = g_malloc (sizeof (ProfilerFileWriteBuffer) + PROFILER_FILE_WRITE_BUFFER_SIZE);
3371 profiler->write_buffers->next = NULL;
3372 profiler->current_write_buffer = profiler->write_buffers;
3373 profiler->current_write_position = 0;
3374 profiler->full_write_buffers = 0;
3376 profiler->executable_regions = profiler_executable_memory_regions_new (1);
3378 profiler->heap_shot_write_jobs = NULL;
3379 if (profiler->action_flags.unreachable_objects || profiler->action_flags.heap_shot) {
3380 profiler_heap_buffers_setup (&(profiler->heap));
3382 profiler_heap_buffers_clear (&(profiler->heap));
3385 WRITER_EVENT_INIT ();
3386 LOG_WRITER_THREAD ("mono_profiler_startup: creating writer thread");
3387 CREATE_WRITER_THREAD (data_writer_thread);
3388 LOG_WRITER_THREAD ("mono_profiler_startup: created writer thread");
3390 ALLOCATE_PROFILER_THREAD_DATA ();
3394 write_intro_block ();
3396 mono_profiler_install (profiler, profiler_shutdown);
3398 mono_profiler_install_appdomain (appdomain_start_load, appdomain_end_load,
3399 appdomain_start_unload, appdomain_end_unload);
3400 mono_profiler_install_assembly (assembly_start_load, assembly_end_load,
3401 assembly_start_unload, assembly_end_unload);
3402 mono_profiler_install_module (module_start_load, module_end_load,
3403 module_start_unload, module_end_unload);
3404 mono_profiler_install_class (class_start_load, class_end_load,
3405 class_start_unload, class_end_unload);
3406 mono_profiler_install_jit_compile (method_start_jit, method_end_jit);
3407 mono_profiler_install_enter_leave (method_enter, method_leave);
3408 mono_profiler_install_method_free (method_free);
3409 mono_profiler_install_thread (thread_start, thread_end);
3410 mono_profiler_install_allocation (object_allocated);
3411 mono_profiler_install_statistical (statistical_hit);
3412 mono_profiler_install_gc (gc_event, gc_resize);
3414 mono_profiler_install_jit_end (method_jit_result);
3417 mono_profiler_set_events (profiler->flags);