+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.
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
+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.
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
+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
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)
#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){
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);
}
+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
#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>
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;
};
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;
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
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,
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);
* 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));
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;
/*
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)
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;
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);
/* 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;
}
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;
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
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;
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
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;
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);
+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.
$(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
#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)
#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);
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;
}
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;
}
! 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;
}
}
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...");
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;
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);
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);
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) {
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) {