2010-02-13 Zoltan Varga <vargaz@gmail.com>
authorZoltan Varga <vargaz@gmail.com>
Sat, 13 Feb 2010 10:05:28 +0000 (10:05 -0000)
committerZoltan Varga <vargaz@gmail.com>
Sat, 13 Feb 2010 10:05:28 +0000 (10:05 -0000)
* mini.c (mono_jit_compile_method_inner): Avoid passing icall wrappers to
mono_profiler_method_end_jit, since the profiler has no way to process wrappers.

* aot-runtime.c mini.c: Resurrect the aot pagefault profiling stuff, it is useful
for mtouch.

svn path=/trunk/mono/; revision=151694

mono/mini/ChangeLog
mono/mini/aot-runtime.c
mono/mini/mini.c
mono/mini/mini.h

index ee5510b880fce54601ec238182a0807f837f5f62..65d90015aed87044bad822e876d9a7610e0e15b8 100755 (executable)
@@ -1,3 +1,11 @@
+2010-02-13  Zoltan Varga  <vargaz@gmail.com>
+
+       * mini.c (mono_jit_compile_method_inner): Avoid passing icall wrappers to
+       mono_profiler_method_end_jit, since the profiler has no way to process wrappers.
+
+       * aot-runtime.c mini.c: Resurrect the aot pagefault profiling stuff, it is useful
+       for mtouch.
+
 2010-02-13 Gonzalo Paniagua Javier <gonzalo@novell.com>
 
        * debugger-agent.c: handle incomplete reads and EINTR in
index d0fea4578a0e8731bd2f849581a385e4fb9f87f0..7f02b7593c66057a462593390cbf3ab581b6a34f 100644 (file)
@@ -162,6 +162,7 @@ static gint32 mono_last_aot_method = -1;
 
 static gboolean make_unreadable = FALSE;
 static guint32 name_table_accesses = 0;
+static guint32 n_pagefaults = 0;
 
 /* Used to speed-up find_aot_module () */
 static gsize aot_code_low_addr = (gssize)-1;
@@ -1175,17 +1176,19 @@ load_aot_module (MonoAssembly *assembly, gpointer user_data)
        if (make_unreadable) {
 #ifndef TARGET_WIN32
                guint8 *addr;
-               guint8 *page_start;
-               int pages, err, len;
+               guint8 *page_start, *page_end;
+               int err, len;
 
                addr = amodule->mem_begin;
                len = amodule->mem_end - amodule->mem_begin;
 
                /* Round down in both directions to avoid modifying data which is not ours */
                page_start = (guint8 *) (((gssize) (addr)) & ~ (mono_pagesize () - 1)) + mono_pagesize ();
-               pages = ((addr + len - page_start + mono_pagesize () - 1) / mono_pagesize ()) - 1;
-               err = mono_mprotect (page_start, pages * mono_pagesize (), MONO_MMAP_NONE);
-               g_assert (err == 0);
+               page_end = (guint8 *) (((gssize) (addr + len)) & ~ (mono_pagesize () - 1));
+               if (page_end > page_start) {
+                       err = mono_mprotect (page_start, (page_end - page_start), MONO_MMAP_NONE);
+                       g_assert (err == 0);
+               }
 #endif
        }
 
@@ -3574,6 +3577,98 @@ mono_aot_get_imt_thunk (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem
 
        return code;
 }
+/*
+ * mono_aot_set_make_unreadable:
+ *
+ *   Set whenever to make all mmaped memory unreadable. In conjuction with a
+ * SIGSEGV handler, this is useful to find out which pages the runtime tries to read.
+ */
+void
+mono_aot_set_make_unreadable (gboolean unreadable)
+{
+       static int inited;
+
+       make_unreadable = unreadable;
+
+       if (make_unreadable && !inited) {
+               mono_counters_register ("AOT pagefaults", MONO_COUNTER_JIT | MONO_COUNTER_INT, &n_pagefaults);
+       }               
+}
+
+typedef struct {
+       MonoAotModule *module;
+       guint8 *ptr;
+} FindMapUserData;
+
+static void
+find_map (gpointer key, gpointer value, gpointer user_data)
+{
+       MonoAotModule *module = (MonoAotModule*)value;
+       FindMapUserData *data = (FindMapUserData*)user_data;
+
+       if (!data->module)
+               if ((data->ptr >= module->mem_begin) && (data->ptr < module->mem_end))
+                       data->module = module;
+}
+
+static MonoAotModule*
+find_module_for_addr (void *ptr)
+{
+       FindMapUserData data;
+
+       if (!make_unreadable)
+               return NULL;
+
+       data.module = NULL;
+       data.ptr = (guint8*)ptr;
+
+       mono_aot_lock ();
+       g_hash_table_foreach (aot_modules, (GHFunc)find_map, &data);
+       mono_aot_unlock ();
+
+       return data.module;
+}
+
+/*
+ * mono_aot_is_pagefault:
+ *
+ *   Should be called from a SIGSEGV signal handler to find out whenever @ptr is
+ * within memory allocated by this module.
+ */
+gboolean
+mono_aot_is_pagefault (void *ptr)
+{
+       if (!make_unreadable)
+               return FALSE;
+
+       /* 
+        * Not signal safe, but SIGSEGV's are synchronous, and
+        * this is only turned on by a MONO_DEBUG option.
+        */
+       return find_module_for_addr (ptr) != NULL;
+}
+
+/*
+ * mono_aot_handle_pagefault:
+ *
+ *   Handle a pagefault caused by an unreadable page by making it readable again.
+ */
+void
+mono_aot_handle_pagefault (void *ptr)
+{
+#ifndef PLATFORM_WIN32
+       guint8* start = (guint8*)ROUND_DOWN (((gssize)ptr), mono_pagesize ());
+       int res;
+
+       mono_aot_lock ();
+       res = mono_mprotect (start, mono_pagesize (), MONO_MMAP_READ|MONO_MMAP_WRITE|MONO_MMAP_EXEC);
+       g_assert (res == 0);
+
+       n_pagefaults ++;
+       mono_aot_unlock ();
+#endif
+}
 
 #else
 /* AOT disabled */
index e7d96da5e9ea3de60dc8862b81ae59a7f1afdefe..27af9a0c23074b692fd1c7ea1765c8d23e0a1a32 100644 (file)
@@ -4570,8 +4570,13 @@ mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *target_domain, in
                mono_raise_exception (exc);
        }
 
-       if (prof_options & MONO_PROFILE_JIT_COMPILATION)
-               mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
+       if (prof_options & MONO_PROFILE_JIT_COMPILATION) {
+               if (method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
+                       /* The profiler doesn't know about wrappers, so pass the original icall method */
+                       mono_profiler_method_end_jit (mono_marshal_method_from_wrapper (method), jinfo, MONO_PROFILE_OK);
+               else
+                       mono_profiler_method_end_jit (method, jinfo, MONO_PROFILE_OK);
+       }
 
        mono_runtime_class_init (vtable);
        return code;
@@ -5039,6 +5044,11 @@ SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler)
        }
 #endif
 
+       if (mono_aot_is_pagefault (info->si_addr)) {
+               mono_aot_handle_pagefault (info->si_addr);
+               return;
+       }
+
        /* The thread might no be registered with the runtime */
        if (!mono_domain_get () || !jit_tls) {
                if (mono_chain_signal (SIG_HANDLER_PARAMS))
@@ -5451,6 +5461,10 @@ mini_init (const char *filename, const char *runtime_version)
        mono_install_get_class_from_name (mono_aot_get_class_from_name);
        mono_install_jit_info_find_in_aot (mono_aot_find_jit_info);
 
+       if (debug_options.collect_pagefault_stats) {
+               mono_aot_set_make_unreadable (TRUE);
+       }
+
        if (runtime_version)
                domain = mono_init_version (filename, runtime_version);
        else
index 5937e6c1e1bbe46d4da543258b0d5115f779c465..8ff511dd4b5dc3494b2ed19adfa8d839c4ae3885 100644 (file)
@@ -1543,6 +1543,9 @@ char*    mono_aot_get_method_name           (MonoCompile *cfg) MONO_INTERNAL;
 char*    mono_aot_get_plt_symbol            (MonoJumpInfoType type, gconstpointer data) MONO_INTERNAL;
 char*    mono_aot_get_method_debug_name     (MonoCompile *cfg) MONO_INTERNAL;
 MonoJumpInfo* mono_aot_patch_info_dup       (MonoJumpInfo* ji) MONO_INTERNAL;
+void     mono_aot_set_make_unreadable       (gboolean unreadable) MONO_INTERNAL;
+gboolean mono_aot_is_pagefault              (void *ptr) MONO_INTERNAL;
+void     mono_aot_handle_pagefault          (void *ptr) MONO_INTERNAL;
 
 /* This is an exported function */
 void     mono_aot_register_globals          (gpointer *globals);