merge from trunk at 97714
authorJb Evain <jbevain@gmail.com>
Fri, 28 Mar 2008 10:23:33 +0000 (10:23 -0000)
committerJb Evain <jbevain@gmail.com>
Fri, 28 Mar 2008 10:23:33 +0000 (10:23 -0000)
svn path=/branches/jb/ml2/mono/; revision=99176

16 files changed:
ChangeLog
configure.in
man/ChangeLog
man/mono.1
mono/io-layer/ChangeLog
mono/io-layer/processes.c
mono/metadata/ChangeLog
mono/metadata/object-internals.h
mono/metadata/threads.c
mono/metadata/threads.h
mono/mini/mini-amd64.c
mono/mini/mini.h
mono/mini/tramp-amd64.c
mono/profiler/ChangeLog
mono/profiler/Makefile.am
mono/profiler/mono-profiler-logging.c

index 3a88ca269de423ac7d92204da5c08c2e358e87c8..f74087dd0a7f96ac811c9566aec78d048ff667d1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,6 @@
+2008-03-26  Massimiliano Mantione  <massi@ximian.com>
+       * configure.in: Added PLATFORM_LINUX automake conditional.
+
 2008-03-25  Zoltan Varga  <vargaz@gmail.com>
 
        * runtime/Makefile.am (mcs-compileall): Skip net 2.1 assemblies for now.
index 66587b69e9c15d8b314020cd903fae3a66c8ccad..eb01bc535207cda301e8c7fce4db840351aa2d63 100644 (file)
@@ -250,6 +250,7 @@ if test x$need_link_unlink = xyes; then
 fi
 
 AM_CONDITIONAL(PLATFORM_WIN32, test x$platform_win32 = xyes)
+AM_CONDITIONAL(PLATFORM_LINUX, test x$target_os = xlinux-gnu)
 
 AC_CHECK_TOOL(CC, gcc, gcc)
 AC_PROG_CC
index 0c4cac085137c64a18f3686754c4417cff9ee8df..a53c56d90a9f4063475120043a40ac022ebf8870 100644 (file)
@@ -1,3 +1,6 @@
+2008-03-26  Massimiliano Mantione  <massi@ximian.com>
+       * mono.1: Added description of the logging profiler.
+
 2008-03-08  Zoltan Varga  <vargaz@gmail.com>
 
        * mono.1: Fix a typo.
index 159609499e359819701f94a0f4305680d79abb25..dc1ec175bc7e5b8ec6a40fbf4cb63baf2351803a 100644 (file)
@@ -462,6 +462,96 @@ use it, use:
 The output of this profile can be fed back into Mono's AOT compiler to
 order the functions on the disk to produce precompiled images that
 have methods in sequential pages.
+.PP
+The
+.I logging profiler
+will eventually replace the default one. It is a
+"general purpose" profiler, which can report method execution time,
+allocations, jit time, and can also work in statistical mode. You invoke
+it with:
+.nf
+       mono --profile=logging program.exe
+.fi
+Its main characteristic is that it does not print the profiling data
+at the end of the program execution, and in fact it does not elaborate
+the events at all; instead, it logs them into a file periodically
+during the program execution. The file is binary, and encoded as packed
+as possible, so to see the data you must use a decoder program, which
+you can find in svn in the "Mono.Profiler" module.
+.PP
+Some examples: to use the statistical profiler:
+.nf
+       mono --profile=logging:s program.exe
+.fi
+To profile method enter-exit and allocations:
+.nf
+       mono --profile=logging:c,a program.exe
+.fi
+To profile method enter-exit and jit time, and write the data to "mydata.mprof":
+.nf
+       mono --profile=logging:c,j,o=mydata.mprof program.exe
+.fi
+Then you would need to invoke the decoder on "mydata.mprof" to see the
+profiling results.
+.PP
+In its current state, this profiler can also perform heap analysis (like
+heap-shot), and the decoder is already able to read the data, however
+the user interface for this feature has not yet been written (which means
+that the data is not printed by the decoder).
+.PP
+More explanations are provided here: "http://www.mono-project.com/LoggingProfiler".
+.PP
+The whole set of options accepted by the logging profiler is the following:
+.TP
+.I output
+(or "out" or "o", default "o=profiler-log.prof"): the name of the output file.
+.TP
+.I jit
+(or "j"): collect information about time spent jitting methods.
+.TP
+.I allocations
+(or "alloc" or "a"): collect information about each allocation (object class
+and size).
+.TP
+.I enter-leave
+(or "calls" or "c"): measure the time spent inside each method call.
+.TP
+.I statistical
+(or "stat" or "s"): do statistical profiling. 
+.TP
+.I unreachable
+(or "free" or "f"): enable garbage collection profiling in its lightweight
+form (at each collection, the list if unreachable objects is dumped, and
+for each object the class and size is provided, which together with the
+basic allocation information allows to compute the heap size broken down
+by class).
+.TP
+.I heap-shot
+(or "heap" or "h"): enable full heap profiling, in this case at each
+collection a full heap snapshot is dumped to disk.
+.TP
+.I gc-commands
+(or "gc-c" or "gcc", default none, file name required): the name of the
+file that controls the heap snapshot dumps.
+.TP
+.I gc-dumps
+(or "gc-d" or "gcd", default "gcd=0"): the initial number of heap
+snapshots to dump (if the control file is not used). 
+.TP
+.I per-thread-buffer-size
+(or "tbs", default "tbs=10000"): the number of events that a thread buffer
+can hold, when it's full it is written to disk (the writing thread is the
+one that filled its buffer).
+.TP
+.I statistical-thread-buffer-size
+(or "sbs", default "sbs=10000"): the number of statistical samples that
+are hold in memory before they are dumped to disk (the system does
+double-buffering and the statistical samples are written by a helper
+thread).
+.TP
+.I write-buffer-size
+(or "wbs", default "wbs=1024"): size in bytes of the internal write
+buffers. 
 .SH CUSTOM PROFILERS
 Mono provides a mechanism for loading other profiling modules which in
 the form of shared libraries.  These profiling modules can hook up to
index 23870af8da3c1ffb58d98e2b8121c12f00a8705f..a6ba63b1b3f2c7491dad1d8294822c1a346090b4 100644 (file)
@@ -1,3 +1,17 @@
+2008-03-27  Dick Porter  <dick@ximian.com>
+
+       * processes.c (match_procname_to_modulename): Check the whole
+       process name first, in case it is recorded as an absolute path.
+       Fixes bug 360348.
+
+2008-03-27  Dick Porter  <dick@ximian.com>
+
+       * processes.c (ShellExecuteEx): Grotty kludge to work around
+       unpleasant feature in g_shell_parse_argv() where it treats '#'
+       embedded in a filename as a comment marker, and throws away the
+       rest of the line.  When we're directly opening URLs quote the
+       filename, to avoid this.  Fixes bug 371567.
+
 2008-03-25  Dick Porter  <dick@ximian.com>
 
        * wapi-private.h (_WAPI_HANDLE_VERSION): Increment file layout
index 5f01c382f5e27e63b8e838027389a5a8834cca37..b0dbacf1f48e1f53e84105f5209e0fe79b3654ef 100644 (file)
@@ -378,6 +378,8 @@ utf16_concat (const gunichar2 *first, ...)
 
 static const gunichar2 utf16_space_bytes [2] = { 0x20, 0 };
 static const gunichar2 *utf16_space = utf16_space_bytes; 
+static const gunichar2 utf16_quote_bytes [2] = { 0x22, 0 };
+static const gunichar2 *utf16_quote = utf16_quote_bytes;
 
 /* Implemented as just a wrapper around CreateProcess () */
 gboolean ShellExecuteEx (WapiShellExecuteInfo *sei)
@@ -448,7 +450,15 @@ gboolean ShellExecuteEx (WapiShellExecuteInfo *sei)
 #endif
                handler_utf16 = g_utf8_to_utf16 (handler, -1, NULL, NULL, NULL);
                g_free (handler);
-               args = utf16_concat (handler_utf16, utf16_space, sei->lpFile,
+
+               /* Put quotes around the filename, in case it's a url
+                * that contains #'s (CreateProcess() calls
+                * g_shell_parse_argv(), which deliberately throws
+                * away anything after an unquoted #).  Fixes bug
+                * 371567.
+                */
+               args = utf16_concat (handler_utf16, utf16_space, utf16_quote,
+                                    sei->lpFile, utf16_quote,
                                     sei->lpParameters == NULL ? NULL : utf16_space,
                                     sei->lpParameters, NULL);
                if (args == NULL){
@@ -1714,16 +1724,16 @@ static gboolean match_procname_to_modulename (gchar *procname, gchar *modulename
        if (procname == NULL || modulename == NULL)
                return (FALSE);
 
+       if (!strcmp (procname, modulename))
+               return (TRUE);
+
        lastsep = strrchr (modulename, '/');
        if (lastsep) {
-               if (0 == strcmp (lastsep+1, procname))
+               if (!strcmp (lastsep+1, procname))
                        return (TRUE);
                return (FALSE);
        }
 
-       if (0 == strcmp (procname, modulename))
-               return (TRUE);
-
        return (FALSE);
 }
 
index 4ad98c82b89628307eeaedf9480af7b29bbb6d03..268478eee8822434a83611f9b14ae1b616b079d4 100644 (file)
@@ -1,3 +1,11 @@
+2008-03-26  Massimiliano Mantione  <massi@ximian.com>
+       * threads.h: Added MonoThreadManageCallback type and
+       mono_thread_set_manage_callback prototype
+       * object-internals.h: In _MonoThread, renamed unused6 to manage_callback
+       (used to store the mono_thread_manage callback).
+       * threads.c: Added mono_thread_set_manage_callback, and handle
+       "MonoThread->manage_callback" in build_wait_tids.
+
 2008-03-26  Dick Porter  <dick@ximian.com>
 
        * process.c (process_get_fileversion): Set FileVersionInfo strings
index 77326c5e8728b684004b9f955252b98bd69605c6..df479b861b6f39786ca239e60447e870a50397d9 100644 (file)
@@ -2,6 +2,7 @@
 #define __MONO_OBJECT_INTERNALS_H__
 
 #include <mono/metadata/object.h>
+#include <mono/metadata/threads.h>
 #include <mono/metadata/reflection.h>
 #include <mono/metadata/mempool.h>
 #include <mono/io-layer/io-layer.h>
@@ -279,7 +280,7 @@ struct _MonoThread {
        gssize small_id;    /* A small, unique id, used for the hazard
                               pointer table.  Should be changed to a
                               guint32 at the next corlib version bump. */
-       gpointer unused6;
+       MonoThreadManageCallback manage_callback;
        gpointer unused7;
 };
 
index 93f700ddce96d631323a5fdcc4cef4f9c7adc3da..ad432fc1e4386247b977b0f46f181dfd3b8e0259 100644 (file)
@@ -2300,6 +2300,12 @@ mono_threads_install_cleanup (MonoThreadCleanupFunc func)
        mono_thread_cleanup_fn = func;
 }
 
+void
+mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func)
+{
+       thread->manage_callback = func;
+}
+
 void mono_threads_install_notify_pending_exc (MonoThreadNotifyPendingExcFunc func)
 {
        mono_thread_notify_pending_exc_fn = func;
@@ -2447,11 +2453,18 @@ static void build_wait_tids (gpointer key, gpointer value, gpointer user)
                        return;
                }
                
-               wait->handles[wait->num]=handle;
-               wait->threads[wait->num]=thread;
-               wait->num++;
+               THREAD_DEBUG (g_message ("%s: Invoking mono_thread_manage callback on thread %p", __func__, thread));
+               if ((thread->manage_callback == NULL) || (thread->manage_callback (thread) == TRUE)) {
+                       wait->handles[wait->num]=handle;
+                       wait->threads[wait->num]=thread;
+                       wait->num++;
 
-               THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
+                       THREAD_DEBUG (g_message ("%s: adding thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
+               } else {
+                       THREAD_DEBUG (g_message ("%s: ignoring (because of callback) thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
+               }
+               
+               
        } else {
                /* Just ignore the rest, we can't do anything with
                 * them yet
index f8c57488b35b71c4d8ad7d254d4f3844632d4c9d..39e134b2e06a43443af8e1a25f32cd124be9c97e 100644 (file)
@@ -19,6 +19,9 @@ G_BEGIN_DECLS
 
 typedef void (*MonoThreadCleanupFunc) (MonoThread* thread);
 
+/* This callback should return TRUE if the runtime must wait for the thread, FALSE otherwise */
+typedef gboolean (*MonoThreadManageCallback) (MonoThread* thread);
+
 extern int  mono_thread_get_abort_signal (void);
 
 extern void mono_thread_init (MonoThreadStartCB start_cb,
@@ -50,6 +53,7 @@ extern void mono_thread_detach (MonoThread *thread);
 extern void mono_thread_exit (void);
 
 void     mono_threads_install_cleanup   (MonoThreadCleanupFunc func);
+void     mono_thread_set_manage_callback (MonoThread *thread, MonoThreadManageCallback func);
 
 extern void mono_threads_set_default_stacksize (guint32 stacksize);
 extern guint32 mono_threads_get_default_stacksize (void);
index fc83e91e0c1e1f5cdc56e6096f6569bcc670b062..a556402d7091d61000b409cede72c58a9045916f 100644 (file)
@@ -515,14 +515,13 @@ add_valuetype (MonoGenericSharingContext *gsctx, MonoMethodSignature *sig, ArgIn
  * Draft Version 0.23" document for more information.
  */
 static CallInfo*
-get_call_info (MonoCompile *cfg, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
+get_call_info (MonoGenericSharingContext *gsctx, MonoMemPool *mp, MonoMethodSignature *sig, gboolean is_pinvoke)
 {
        guint32 i, gr, fr;
        MonoType *ret_type;
        int n = sig->hasthis + sig->param_count;
        guint32 stack_size = 0;
        CallInfo *cinfo;
-       MonoGenericSharingContext *gsctx = cfg ? cfg->generic_sharing_context : NULL;
 
        if (mp)
                cinfo = mono_mempool_alloc0 (mp, sizeof (CallInfo) + (sizeof (ArgInfo) * n));
@@ -878,7 +877,7 @@ mono_arch_compute_omit_fp (MonoCompile *cfg)
        sig = mono_method_signature (cfg->method);
 
        if (!cfg->arch.cinfo)
-               cfg->arch.cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
+               cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
        cinfo = cfg->arch.cinfo;
 
        /*
@@ -1173,7 +1172,7 @@ mono_arch_create_vars (MonoCompile *cfg)
        sig = mono_method_signature (cfg->method);
 
        if (!cfg->arch.cinfo)
-               cfg->arch.cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
+               cfg->arch.cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
        cinfo = cfg->arch.cinfo;
 
        if (cinfo->ret.storage == ArgValuetypeInReg)
@@ -1288,7 +1287,7 @@ mono_arch_call_opcode (MonoCompile *cfg, MonoBasicBlock* bb, MonoCallInst *call,
        sig = call->signature;
        n = sig->param_count + sig->hasthis;
 
-       cinfo = get_call_info (cfg, cfg->mempool, sig, sig->pinvoke);
+       cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, sig->pinvoke);
 
        for (i = 0; i < n; ++i) {
                ainfo = cinfo->args + i;
@@ -2040,7 +2039,7 @@ emit_move_return_value (MonoCompile *cfg, MonoInst *ins, guint8 *code)
        case OP_VCALL:
        case OP_VCALL_REG:
        case OP_VCALL_MEMBASE:
-               cinfo = get_call_info (cfg, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
+               cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, ((MonoCallInst*)ins)->signature, FALSE);
                if (cinfo->ret.storage == ArgValuetypeInReg) {
                        /* Pop the destination address from the stack */
                        amd64_alu_reg_imm (code, X86_ADD, AMD64_RSP, 8);
@@ -4941,7 +4940,7 @@ mono_arch_instrument_prolog (MonoCompile *cfg, void *func, void *p, gboolean ena
                /* Allocate a new area on the stack and save arguments there */
                sig = mono_method_signature (cfg->method);
 
-               cinfo = get_call_info (cfg, cfg->mempool, sig, FALSE);
+               cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, sig, FALSE);
 
                n = sig->param_count + sig->hasthis;
 
@@ -5342,12 +5341,12 @@ mono_arch_get_vcall_slot_addr (guint8* code, gpointer *regs)
 }
 
 int
-mono_arch_get_this_arg_reg (MonoMethodSignature *sig)
+mono_arch_get_this_arg_reg (MonoMethodSignature *sig, MonoGenericSharingContext *gsctx)
 {
        int this_reg = AMD64_ARG_REG1;
 
        if (MONO_TYPE_ISSTRUCT (sig->ret)) {
-               CallInfo *cinfo = get_call_info (NULL, NULL, sig, FALSE);
+               CallInfo *cinfo = get_call_info (gsctx, NULL, sig, FALSE);
                
                if (cinfo->ret.storage != ArgValuetypeInReg)
                        this_reg = AMD64_ARG_REG2;
@@ -5360,7 +5359,7 @@ mono_arch_get_this_arg_reg (MonoMethodSignature *sig)
 gpointer
 mono_arch_get_this_arg_from_call (MonoMethodSignature *sig, gssize *regs, guint8 *code)
 {
-       return (gpointer)regs [mono_arch_get_this_arg_reg (sig)];
+       return (gpointer)regs [mono_arch_get_this_arg_reg (sig, NULL)];
 }
 
 #define MAX_ARCH_DELEGATE_PARAMS 10
@@ -5467,7 +5466,7 @@ void
 mono_arch_emit_this_vret_args (MonoCompile *cfg, MonoCallInst *inst, int this_reg, int this_type, int vt_reg)
 {
        MonoCallInst *call = (MonoCallInst*)inst;
-       CallInfo * cinfo = get_call_info (cfg, cfg->mempool, inst->signature, FALSE);
+       CallInfo * cinfo = get_call_info (cfg->generic_sharing_context, cfg->mempool, inst->signature, FALSE);
 
        if (vt_reg != -1) {
                MonoInst *vtarg;
@@ -5695,7 +5694,7 @@ mono_arch_find_imt_method (gpointer *regs, guint8 *code)
 MonoObject*
 mono_arch_find_this_argument (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx)
 {
-       return mono_arch_get_this_arg_from_call (mono_method_signature (method), (gssize*)regs, NULL);
+       return regs [mono_arch_get_this_arg_reg (mono_method_signature (method), gsctx)];
 }
 #endif
 
index 292853fbf52ca53f8d81b228eff29fc062db1e9a..68d3c3cd923dfae01f039404fbbc5100c26e2e05 100644 (file)
@@ -1255,14 +1255,14 @@ void     mono_arch_patch_callsite               (guint8 *method_start, guint8 *c
 void     mono_arch_patch_plt_entry              (guint8 *code, guint8 *addr) MONO_INTERNAL;
 void     mono_arch_nullify_class_init_trampoline(guint8 *code, gssize *regs) MONO_INTERNAL;
 void     mono_arch_nullify_plt_entry            (guint8 *code) MONO_INTERNAL;
-int      mono_arch_get_this_arg_reg             (MonoMethodSignature *sig) MONO_INTERNAL;
+int      mono_arch_get_this_arg_reg             (MonoMethodSignature *sig, MonoGenericSharingContext *gsctx) MONO_INTERNAL;
 gpointer mono_arch_get_this_arg_from_call       (MonoMethodSignature *sig, gssize *regs, guint8 *code) MONO_INTERNAL;
+MonoObject* mono_arch_find_this_argument        (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx) MONO_INTERNAL;
 gpointer mono_arch_get_delegate_invoke_impl     (MonoMethodSignature *sig, gboolean has_target) MONO_INTERNAL;
 gpointer mono_arch_create_specific_trampoline   (gpointer arg1, MonoTrampolineType tramp_type, MonoDomain *domain, guint32 *code_len) MONO_INTERNAL;
 void        mono_arch_emit_imt_argument         (MonoCompile *cfg, MonoCallInst *call) MONO_INTERNAL;
 MonoMethod* mono_arch_find_imt_method           (gpointer *regs, guint8 *code) MONO_INTERNAL;
 MonoRuntimeGenericContext* mono_arch_find_static_call_rgctx (gpointer *regs, guint8 *code) MONO_INTERNAL;
-MonoObject* mono_arch_find_this_argument        (gpointer *regs, MonoMethod *method, MonoGenericSharingContext *gsctx) MONO_INTERNAL;
 gpointer    mono_arch_build_imt_thunk           (MonoVTable *vtable, MonoDomain *domain, MonoIMTCheckItem **imt_entries, int count) MONO_INTERNAL;
 void    mono_arch_notify_pending_exc (void) MONO_INTERNAL;
 
index a15464d3208ece1cf99e813a6834d331f6dce823..44ae4db498152247571a938eb87851f9e55c5811 100644 (file)
@@ -45,7 +45,7 @@ mono_arch_get_unbox_trampoline (MonoMethod *m, gpointer addr)
 
        MonoDomain *domain = mono_domain_get ();
 
-       this_reg = mono_arch_get_this_arg_reg (mono_method_signature (m));
+       this_reg = mono_arch_get_this_arg_reg (mono_method_signature (m), NULL);
 
        mono_domain_lock (domain);
        start = code = mono_code_manager_reserve (domain->code_mp, 20);
index c80e3bc448dac3d3e327cd16f8bfc70e7bd1be75..16c85a2d68ad668f377c00cd56563581b31e0066 100644 (file)
@@ -1,3 +1,21 @@
+2008-03-27  Massimiliano Mantione <massi@ximian.com>
+       * mono-profiler-oprofile.c: setup_user_options: set default log file
+       name to the name of the executed application.
+
+2008-03-26  Massimiliano Mantione <massi@ximian.com>
+       * Makefile.am: enabled the logging profiler on Linux.
+
+2008-03-26  Massimiliano Mantione <massi@ximian.com>
+       * mono-profiler-oprofile.c: Attach and detach the writer thread.
+
+2008-03-25  Massimiliano Mantione <massi@ximian.com>
+       * mono-profiler-oprofile.c: Fixed bug with memory region indexes.
+
+2008-03-18  Massimiliano Mantione <massi@ximian.com>
+       * mono-profiler-oprofile.c:
+       OPEN_FILE(): Fixed file creation.
+       [UN]LOCK_PROFILER(): Removed logging message.
+
 2008-03-11  Massimiliano Mantione <massi@ximian.com>
        * mono-profiler-oprofile.c: Fixed heap profiler, added a new way to
        get the symbol names for unmanaged functions, and fixed lots of bugs.
index bf3b14ee331d3e3fa96e60109fd429fbea549699..9dc3d9530d4611713119154c60fb68705c4309e3 100644 (file)
@@ -5,9 +5,11 @@ INCLUDES = \
        $(GLIB_CFLAGS)
 
 if JIT_SUPPORTED
-
+if PLATFORM_LINUX
+lib_LTLIBRARIES = libmono-profiler-cov.la libmono-profiler-aot.la libmono-profiler-logging.la
+else
 lib_LTLIBRARIES = libmono-profiler-cov.la libmono-profiler-aot.la
-#lib_LTLIBRARIES = libmono-profiler-cov.la libmono-profiler-aot.la libmono-profiler-logging.la
+endif
 endif
 
 if HAVE_OPROFILE
index 0c361f3c39dd979a8572610f3034a8319e070720..cbbf9c0f49152e508fc1ebd4625d468fd7bc8220 100644 (file)
@@ -286,8 +286,8 @@ typedef struct _ProfilerUnmanagedFunctions {
 #define MUTEX_TYPE pthread_mutex_t
 #define INITIALIZE_PROFILER_MUTEX() pthread_mutex_init (&(profiler->mutex), NULL)
 #define DELETE_PROFILER_MUTEX() pthread_mutex_destroy (&(profiler->mutex))
-#define LOCK_PROFILER() do {LOG_WRITER_THREAD ("LOCK_PROFILER"); pthread_mutex_lock (&(profiler->mutex));} while (0)
-#define UNLOCK_PROFILER() do {LOG_WRITER_THREAD ("UNLOCK_PROFILER"); pthread_mutex_unlock (&(profiler->mutex));} while (0)
+#define LOCK_PROFILER() do {/*LOG_WRITER_THREAD ("LOCK_PROFILER");*/ pthread_mutex_lock (&(profiler->mutex));} while (0)
+#define UNLOCK_PROFILER() do {/*LOG_WRITER_THREAD ("UNLOCK_PROFILER");*/ pthread_mutex_unlock (&(profiler->mutex));} while (0)
 
 #define THREAD_TYPE pthread_t
 #define CREATE_WRITER_THREAD(f) pthread_create (&(profiler->data_writer_thread), NULL, ((void*(*)(void*))f), NULL)
@@ -322,7 +322,7 @@ make_pthread_profiler_key (void) {
 #define CLOSE_FILE() fclose (profiler->file);
 #else
 #define FILE_HANDLE_TYPE int
-#define OPEN_FILE() profiler->file = open (profiler->file_name, O_WRONLY|O_CREAT|O_TRUNC);
+#define OPEN_FILE() profiler->file = open (profiler->file_name, O_WRONLY|O_CREAT|O_TRUNC, 0664);
 #define WRITE_BUFFER(b,s) write (profiler->file, (b), (s))
 #define FLUSH_FILE()
 #define CLOSE_FILE() close (profiler->file);
@@ -422,6 +422,7 @@ struct _MonoProfiler {
        THREAD_TYPE data_writer_thread;
        EVENT_TYPE statistical_data_writer_event;
        gboolean terminate_writer_thread;
+       gboolean detach_writer_thread;
        
        ProfilerFileWriteBuffer *write_buffers;
        ProfilerFileWriteBuffer *current_write_buffer;
@@ -1707,12 +1708,12 @@ profiler_executable_memory_region_destroy (ProfilerExecutableMemoryRegionData *d
 }
 
 static ProfilerExecutableMemoryRegions*
-profiler_executable_memory_regions_new (void) {
+profiler_executable_memory_regions_new (int next_id) {
        ProfilerExecutableMemoryRegions *result = g_new (ProfilerExecutableMemoryRegions, 1);
        result->regions = g_new0 (ProfilerExecutableMemoryRegionData*, 32);
        result->regions_capacity = 32;
        result->regions_count = 0;
-       result->next_id = 1;
+       result->next_id = next_id;
        return result;
 }
 
@@ -1799,9 +1800,6 @@ restore_region_ids (ProfilerExecutableMemoryRegions *old_regions, ProfilerExecut
                                        ! strcmp (old_region->file_name, new_region->file_name)) {
                                new_region->is_new = FALSE;
                                new_region->id = old_region->id;
-                               if (new_region->id >= new_regions->next_id) {
-                                       new_regions->next_id = new_region->id + 1;
-                               }
                                old_region->is_new = TRUE;
                        }
                }
@@ -2040,8 +2038,8 @@ typedef enum {
 
 static void
 refresh_memory_regions (void) {
-       ProfilerExecutableMemoryRegions *new_regions = profiler_executable_memory_regions_new ();
        ProfilerExecutableMemoryRegions *old_regions = profiler->executable_regions;
+       ProfilerExecutableMemoryRegions *new_regions = profiler_executable_memory_regions_new (old_regions->next_id);
        int i;
        
        LOG_WRITER_THREAD ("Refreshing memory regions...");
@@ -3293,13 +3291,60 @@ setup_user_options (const char *arguments) {
        g_free (arguments_array);
        
        if (profiler->file_name == NULL) {
-               profiler->file_name = g_strdup ("profiler-log.prof");
+               char *program_name = g_get_prgname ();
+               
+               if (program_name != NULL) {
+                       char *name_buffer = g_strdup (program_name);
+                       char *name_start = name_buffer;
+                       char *cursor;
+                       
+                       /* Jump over the last '/' */
+                       cursor = strrchr (name_buffer, '/');
+                       if (cursor == NULL) {
+                               cursor = name_buffer;
+                       } else {
+                               cursor ++;
+                       }
+                       name_start = cursor;
+                       
+                       /* Then jump over the last '\\' */
+                       cursor = strrchr (name_start, '\\');
+                       if (cursor == NULL) {
+                               cursor = name_start;
+                       } else {
+                               cursor ++;
+                       }
+                       name_start = cursor;
+                       
+                       /* Finally, find the last '.' */
+                       cursor = strrchr (name_start, '.');
+                       if (cursor != NULL) {
+                               *cursor = 0;
+                       }
+                       
+                       profiler->file_name = g_strdup_printf ("%s.mprof", name_start);
+                       g_free (name_buffer);
+               } else {
+                       profiler->file_name = g_strdup_printf ("%s.mprof", "profiler-log");
+               }
        }
 }
 
+static gboolean
+thread_detach_callback (MonoThread *thread) {
+       LOG_WRITER_THREAD ("thread_detach_callback: asking writer thread to detach");
+       profiler->detach_writer_thread = TRUE;
+       WRITER_EVENT_RAISE ();
+       LOG_WRITER_THREAD ("thread_detach_callback: done");
+       return FALSE;
+}
 
 static guint32
 data_writer_thread (gpointer nothing) {
+       static gboolean thread_attached = FALSE;
+       static gboolean thread_detached = FALSE;
+       static MonoThread *this_thread = NULL;
+       
        for (;;) {
                ProfilerStatisticalData *statistical_data;
                gboolean done;
@@ -3308,6 +3353,24 @@ data_writer_thread (gpointer nothing) {
                WRITER_EVENT_WAIT ();
                LOG_WRITER_THREAD ("data_writer_thread: just woke up");
                
+               if (! thread_attached) {
+                       if (! profiler->terminate_writer_thread) {
+                               MonoDomain * root_domain = mono_get_root_domain ();
+                               if (root_domain != NULL) {
+                                       LOG_WRITER_THREAD ("data_writer_thread: attaching thread");
+                                       this_thread = mono_thread_attach (root_domain);
+                                       mono_thread_set_manage_callback (this_thread, thread_detach_callback);
+                                       thread_attached = TRUE;
+                               } else {
+                                       g_error ("Cannot get root domain\n");
+                               }
+                       } else {
+                               /* Execution was too short, pretend we attached and detached. */
+                               thread_attached = TRUE;
+                               thread_detached = TRUE;
+                       }
+               }
+               
                statistical_data = profiler->statistical_data_ready;
                done = (statistical_data == NULL) && (profiler->heap_shot_write_jobs == NULL);
                
@@ -3320,7 +3383,7 @@ data_writer_thread (gpointer nothing) {
                        flush_all_mappings ();
                        LOG_WRITER_THREAD ("data_writer_thread: wrote mapping");
                        
-                       if (statistical_data != NULL) {
+                       if ((statistical_data != NULL) && ! thread_detached) {
                                LOG_WRITER_THREAD ("data_writer_thread: writing statistical data...");
                                profiler->statistical_data_ready = NULL;
                                write_statistical_data_block (statistical_data);
@@ -3334,7 +3397,18 @@ data_writer_thread (gpointer nothing) {
                        
                        UNLOCK_PROFILER ();
                        LOG_WRITER_THREAD ("data_writer_thread: wrote data and released lock");
-                       
+               }
+               
+               if (profiler->detach_writer_thread) {
+                       if (this_thread != NULL) {
+                               LOG_WRITER_THREAD ("data_writer_thread: detaching thread");
+                               mono_thread_detach (this_thread);
+                               this_thread = NULL;
+                               profiler->detach_writer_thread = FALSE;
+                               thread_detached = TRUE;
+                       } else {
+                               LOG_WRITER_THREAD ("data_writer_thread: warning: thread has already been detached");
+                       }
                }
                
                if (profiler->terminate_writer_thread) {
@@ -3376,7 +3450,7 @@ mono_profiler_startup (const char *desc)
        profiler->current_write_position = 0;
        profiler->full_write_buffers = 0;
        
-       profiler->executable_regions = profiler_executable_memory_regions_new ();
+       profiler->executable_regions = profiler_executable_memory_regions_new (1);
        
        profiler->heap_shot_write_jobs = NULL;
        if (profiler->action_flags.unreachable_objects || profiler->action_flags.heap_shot) {