[runtime] New profiler API.
[mono.git] / mono / utils / mono-codeman.c
index 83c2bdcc690dcf1847789d4491897350cf6dea90..4738808880bbdff9dcfe3d8b3e2df5fa5b4d8abb 100644 (file)
@@ -1,3 +1,7 @@
+/**
+ * \file
+ */
+
 #include "config.h"
 
 #ifdef HAVE_UNISTD_H
@@ -15,7 +19,6 @@
 #include "mono-mmap.h"
 #include "mono-counters.h"
 #include "dlmalloc.h"
-#include <mono/io-layer/io-layer.h>
 #include <mono/metadata/profiler-private.h>
 #ifdef HAVE_VALGRIND_MEMCHECK_H
 #include <valgrind/memcheck.h>
@@ -28,6 +31,7 @@ static uintptr_t code_memory_used = 0;
 static size_t dynamic_code_alloc_count;
 static size_t dynamic_code_bytes_count;
 static size_t dynamic_code_frees_count;
+static MonoCodeManagerCallbacks code_manager_callbacks;
 
 /*
  * AMD64 processors maintain icache coherency only for pages which are 
@@ -39,7 +43,7 @@ static size_t dynamic_code_frees_count;
 
 #define MIN_PAGES 16
 
-#if defined(__ia64__) || defined(__x86_64__) || defined (_WIN64)
+#if defined(__x86_64__) || defined (_WIN64)
 /*
  * We require 16 byte alignment on amd64 so the fp literals embedded in the code are 
  * properly aligned for SSE2.
@@ -115,9 +119,9 @@ codechunk_valloc (void *preferred, guint32 size)
                freelist = g_slist_delete_link (freelist, freelist);
                g_hash_table_insert (valloc_freelists, GUINT_TO_POINTER (size), freelist);
        } else {
-               ptr = mono_valloc (preferred, size, MONO_PROT_RWX | ARCH_MAP_FLAGS);
+               ptr = mono_valloc (preferred, size, MONO_PROT_RWX | ARCH_MAP_FLAGS, MONO_MEM_ACCOUNT_CODE);
                if (!ptr && preferred)
-                       ptr = mono_valloc (NULL, size, MONO_PROT_RWX | ARCH_MAP_FLAGS);
+                       ptr = mono_valloc (NULL, size, MONO_PROT_RWX | ARCH_MAP_FLAGS, MONO_MEM_ACCOUNT_CODE);
        }
        mono_os_mutex_unlock (&valloc_mutex);
        return ptr;
@@ -134,7 +138,7 @@ codechunk_vfree (void *ptr, guint32 size)
                freelist = g_slist_prepend (freelist, ptr);
                g_hash_table_insert (valloc_freelists, GUINT_TO_POINTER (size), freelist);
        } else {
-               mono_vfree (ptr, size);
+               mono_vfree (ptr, size, MONO_MEM_ACCOUNT_CODE);
        }
        mono_os_mutex_unlock (&valloc_mutex);
 }              
@@ -153,7 +157,7 @@ codechunk_cleanup (void)
                GSList *l;
 
                for (l = freelist; l; l = l->next) {
-                       mono_vfree (l->data, GPOINTER_TO_UINT (key));
+                       mono_vfree (l->data, GPOINTER_TO_UINT (key), MONO_MEM_ACCOUNT_CODE);
                }
                g_slist_free (freelist);
        }
@@ -174,6 +178,12 @@ mono_code_manager_cleanup (void)
        codechunk_cleanup ();
 }
 
+void
+mono_code_manager_install_callbacks (MonoCodeManagerCallbacks* callbacks)
+{
+       code_manager_callbacks = *callbacks;
+}
+
 /**
  * mono_code_manager_new:
  *
@@ -225,7 +235,9 @@ free_chunklist (CodeChunk *chunk)
 
        for (; chunk; ) {
                dead = chunk;
-               mono_profiler_code_chunk_destroy ((gpointer) dead->data);
+               MONO_PROFILER_RAISE (jit_chunk_destroyed, ((mono_byte *) dead->data));
+               if (code_manager_callbacks.chunk_destroy)
+                       code_manager_callbacks.chunk_destroy ((gpointer)dead->data);
                chunk = chunk->next;
                if (dead->flags == CODE_FLAG_MMAP) {
                        codechunk_vfree (dead->data, dead->size);
@@ -234,31 +246,29 @@ free_chunklist (CodeChunk *chunk)
                        dlfree (dead->data);
                }
                code_memory_used -= dead->size;
-               free (dead);
+               g_free (dead);
        }
 }
 
 /**
  * mono_code_manager_destroy:
- * @cman: a code manager
- *
- * Free all the memory associated with the code manager @cman.
+ * \param cman a code manager
+ * Free all the memory associated with the code manager \p cman.
  */
 void
 mono_code_manager_destroy (MonoCodeManager *cman)
 {
        free_chunklist (cman->full);
        free_chunklist (cman->current);
-       free (cman);
+       g_free (cman);
 }
 
 /**
  * mono_code_manager_invalidate:
- * @cman: a code manager
- *
+ * \param cman a code manager
  * Fill all the memory with an invalid native code value
  * so that any attempt to execute code allocated in the code
- * manager @cman will fail. This is used for debugging purposes.
+ * manager \p cman will fail. This is used for debugging purposes.
  */
 void             
 mono_code_manager_invalidate (MonoCodeManager *cman)
@@ -279,8 +289,7 @@ mono_code_manager_invalidate (MonoCodeManager *cman)
 
 /**
  * mono_code_manager_set_read_only:
- * @cman: a code manager
- *
+ * \param cman a code manager
  * Make the code manager read only, so further allocation requests cause an assert.
  */
 void             
@@ -291,12 +300,11 @@ mono_code_manager_set_read_only (MonoCodeManager *cman)
 
 /**
  * mono_code_manager_foreach:
- * @cman: a code manager
- * @func: a callback function pointer
- * @user_data: additional data to pass to @func
- *
- * Invokes the callback @func for each different chunk of memory allocated
- * in the code manager @cman.
+ * \param cman a code manager
+ * \param func a callback function pointer
+ * \param user_data additional data to pass to \p func
+  * Invokes the callback \p func for each different chunk of memory allocated
+ * in the code manager \p cman.
  */
 void
 mono_code_manager_foreach (MonoCodeManager *cman, MonoCodeManagerFunc func, void *user_data)
@@ -329,7 +337,7 @@ new_codechunk (CodeChunk *last, int dynamic, int size)
 {
        int minsize, flags = CODE_FLAG_MMAP;
        int chunk_size, bsize = 0;
-       int pagesize;
+       int pagesize, valloc_granule;
        CodeChunk *chunk;
        void *ptr;
 
@@ -338,12 +346,13 @@ new_codechunk (CodeChunk *last, int dynamic, int size)
 #endif
 
        pagesize = mono_pagesize ();
+       valloc_granule = mono_valloc_granule ();
 
        if (dynamic) {
                chunk_size = size;
                flags = CODE_FLAG_MALLOC;
        } else {
-               minsize = pagesize * MIN_PAGES;
+               minsize = MAX (pagesize * MIN_PAGES, valloc_granule);
                if (size < minsize)
                        chunk_size = minsize;
                else {
@@ -353,8 +362,8 @@ new_codechunk (CodeChunk *last, int dynamic, int size)
                        size += MIN_ALIGN - 1;
                        size &= ~(MIN_ALIGN - 1);
                        chunk_size = size;
-                       chunk_size += pagesize - 1;
-                       chunk_size &= ~ (pagesize - 1);
+                       chunk_size += valloc_granule - 1;
+                       chunk_size &= ~ (valloc_granule - 1);
                }
        }
 #ifdef BIND_ROOM
@@ -370,8 +379,8 @@ new_codechunk (CodeChunk *last, int dynamic, int size)
        if (chunk_size - size < bsize) {
                chunk_size = size + bsize;
                if (!dynamic) {
-                       chunk_size += pagesize - 1;
-                       chunk_size &= ~ (pagesize - 1);
+                       chunk_size += valloc_granule - 1;
+                       chunk_size &= ~ (valloc_granule - 1);
                }
        }
 #endif
@@ -398,12 +407,12 @@ new_codechunk (CodeChunk *last, int dynamic, int size)
 #endif
        }
 
-       chunk = (CodeChunk *) malloc (sizeof (CodeChunk));
+       chunk = (CodeChunk *) g_malloc (sizeof (CodeChunk));
        if (!chunk) {
                if (flags == CODE_FLAG_MALLOC)
                        dlfree (ptr);
                else
-                       mono_vfree (ptr, chunk_size);
+                       mono_vfree (ptr, chunk_size, MONO_MEM_ACCOUNT_CODE);
                return NULL;
        }
        chunk->next = NULL;
@@ -412,7 +421,9 @@ new_codechunk (CodeChunk *last, int dynamic, int size)
        chunk->flags = flags;
        chunk->pos = bsize;
        chunk->bsize = bsize;
-       mono_profiler_code_chunk_new((gpointer) chunk->data, chunk->size);
+       if (code_manager_callbacks.chunk_new)
+               code_manager_callbacks.chunk_new ((gpointer)chunk->data, chunk->size);
+       MONO_PROFILER_RAISE (jit_chunk_created, ((mono_byte *) chunk->data, chunk->size));
 
        code_memory_used += chunk_size;
        mono_runtime_resource_check_limit (MONO_RESOURCE_JIT_CODE, code_memory_used);
@@ -421,14 +432,12 @@ new_codechunk (CodeChunk *last, int dynamic, int size)
 }
 
 /**
- * mono_code_manager_reserve:
- * @cman: a code manager
- * @size: size of memory to allocate
- * @alignment: power of two alignment value
- *
- * Allocates at least @size bytes of memory inside the code manager @cman.
- *
- * Returns: the pointer to the allocated memory or #NULL on failure
+ * mono_code_manager_reserve_align:
+ * \param cman a code manager
+ * \param size size of memory to allocate
+ * \param alignment power of two alignment value
+ * Allocates at least \p size bytes of memory inside the code manager \p cman.
+ * \returns the pointer to the allocated memory or NULL on failure
  */
 void*
 mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
@@ -499,12 +508,10 @@ mono_code_manager_reserve_align (MonoCodeManager *cman, int size, int alignment)
 
 /**
  * mono_code_manager_reserve:
- * @cman: a code manager
- * @size: size of memory to allocate
- *
- * Allocates at least @size bytes of memory inside the code manager @cman.
- *
- * Returns: the pointer to the allocated memory or #NULL on failure
+ * \param cman a code manager
+ * \param size size of memory to allocate
+ * Allocates at least \p size bytes of memory inside the code manager \p cman.
+ * \returns the pointer to the allocated memory or NULL on failure
  */
 void*
 mono_code_manager_reserve (MonoCodeManager *cman, int size)
@@ -514,11 +521,10 @@ mono_code_manager_reserve (MonoCodeManager *cman, int size)
 
 /**
  * mono_code_manager_commit:
- * @cman: a code manager
- * @data: the pointer returned by mono_code_manager_reserve ()
- * @size: the size requested in the call to mono_code_manager_reserve ()
- * @newsize: the new size to reserve
- *
+ * \param cman a code manager
+ * \param data the pointer returned by mono_code_manager_reserve ()
+ * \param size the size requested in the call to mono_code_manager_reserve ()
+ * \param newsize the new size to reserve
  * If we reserved too much room for a method and we didn't allocate
  * already from the code manager, we can get back the excess allocation
  * for later use in the code manager.
@@ -535,14 +541,12 @@ mono_code_manager_commit (MonoCodeManager *cman, void *data, int size, int newsi
 
 /**
  * mono_code_manager_size:
- * @cman: a code manager
- * @used_size: pointer to an integer for the result
- *
+ * \param cman a code manager
+ * \param used_size pointer to an integer for the result
  * This function can be used to get statistics about a code manager:
- * the integer pointed to by @used_size will contain how much
- * memory is actually used inside the code managed @cman.
- *
- * Returns: the amount of memory allocated in @cman
+ * the integer pointed to by \p used_size will contain how much
+ * memory is actually used inside the code managed \p cman.
+ * \returns the amount of memory allocated in \p cman
  */
 int
 mono_code_manager_size (MonoCodeManager *cman, int *used_size)