Avoid atexit(3) when possible, disable prof_final by default.
atexit(3) can deadlock internally during its own initialization if jemalloc calls atexit() during jemalloc initialization. Mitigate the impact by restructuring prof initialization to avoid calling atexit() unless the registered function will actually dump a final heap profile. Additionally, disable prof_final by default so that this land mine is opt-in rather than opt-out. This resolves #144.
This commit is contained in:
parent
3a8b9b1fd9
commit
57efa7bb0e
@ -857,8 +857,14 @@ for (i = 0; i < nbins; i++) {
|
|||||||
<option>--enable-stats</option> is specified during configuration, this
|
<option>--enable-stats</option> is specified during configuration, this
|
||||||
has the potential to cause deadlock for a multi-threaded process that
|
has the potential to cause deadlock for a multi-threaded process that
|
||||||
exits while one or more threads are executing in the memory allocation
|
exits while one or more threads are executing in the memory allocation
|
||||||
functions. Therefore, this option should only be used with care; it is
|
functions. Furthermore, <function>atexit<parameter/></function> may
|
||||||
primarily intended as a performance tuning aid during application
|
allocate memory during application initialization and then deadlock
|
||||||
|
internally when jemalloc in turn calls
|
||||||
|
<function>atexit<parameter/></function>, so this option is not
|
||||||
|
univerally usable (though the application can register its own
|
||||||
|
<function>atexit<parameter/></function> function with equivalent
|
||||||
|
functionality). Therefore, this option should only be used with care;
|
||||||
|
it is primarily intended as a performance tuning aid during application
|
||||||
development. This option is disabled by default.</para></listitem>
|
development. This option is disabled by default.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
@ -1155,7 +1161,13 @@ malloc_conf = "xmalloc:true";]]></programlisting>
|
|||||||
<filename><prefix>.<pid>.<seq>.f.heap</filename>,
|
<filename><prefix>.<pid>.<seq>.f.heap</filename>,
|
||||||
where <literal><prefix></literal> is controlled by the <link
|
where <literal><prefix></literal> is controlled by the <link
|
||||||
linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link>
|
linkend="opt.prof_prefix"><mallctl>opt.prof_prefix</mallctl></link>
|
||||||
option. This option is enabled by default.</para></listitem>
|
option. Note that <function>atexit<parameter/></function> may allocate
|
||||||
|
memory during application initialization and then deadlock internally
|
||||||
|
when jemalloc in turn calls <function>atexit<parameter/></function>, so
|
||||||
|
this option is not univerally usable (though the application can
|
||||||
|
register its own <function>atexit<parameter/></function> function with
|
||||||
|
equivalent functionality). This option is disabled by
|
||||||
|
default.</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry id="opt.prof_leak">
|
<varlistentry id="opt.prof_leak">
|
||||||
|
@ -20,7 +20,7 @@ bool opt_prof_thread_active_init = true;
|
|||||||
size_t opt_lg_prof_sample = LG_PROF_SAMPLE_DEFAULT;
|
size_t opt_lg_prof_sample = LG_PROF_SAMPLE_DEFAULT;
|
||||||
ssize_t opt_lg_prof_interval = LG_PROF_INTERVAL_DEFAULT;
|
ssize_t opt_lg_prof_interval = LG_PROF_INTERVAL_DEFAULT;
|
||||||
bool opt_prof_gdump = false;
|
bool opt_prof_gdump = false;
|
||||||
bool opt_prof_final = true;
|
bool opt_prof_final = false;
|
||||||
bool opt_prof_leak = false;
|
bool opt_prof_leak = false;
|
||||||
bool opt_prof_accum = false;
|
bool opt_prof_accum = false;
|
||||||
char opt_prof_prefix[
|
char opt_prof_prefix[
|
||||||
@ -1487,18 +1487,18 @@ prof_fdump(void)
|
|||||||
char filename[DUMP_FILENAME_BUFSIZE];
|
char filename[DUMP_FILENAME_BUFSIZE];
|
||||||
|
|
||||||
cassert(config_prof);
|
cassert(config_prof);
|
||||||
|
assert(opt_prof_final);
|
||||||
|
assert(opt_prof_prefix[0] != '\0');
|
||||||
|
|
||||||
if (!prof_booted)
|
if (!prof_booted)
|
||||||
return;
|
return;
|
||||||
tsd = tsd_fetch();
|
tsd = tsd_fetch();
|
||||||
|
|
||||||
if (opt_prof_final && opt_prof_prefix[0] != '\0') {
|
|
||||||
malloc_mutex_lock(&prof_dump_seq_mtx);
|
malloc_mutex_lock(&prof_dump_seq_mtx);
|
||||||
prof_dump_filename(filename, 'f', VSEQ_INVALID);
|
prof_dump_filename(filename, 'f', VSEQ_INVALID);
|
||||||
malloc_mutex_unlock(&prof_dump_seq_mtx);
|
malloc_mutex_unlock(&prof_dump_seq_mtx);
|
||||||
prof_dump(tsd, false, filename, opt_prof_leak);
|
prof_dump(tsd, false, filename, opt_prof_leak);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
prof_idump(void)
|
prof_idump(void)
|
||||||
@ -2023,7 +2023,8 @@ prof_boot2(void)
|
|||||||
if (malloc_mutex_init(&prof_dump_mtx))
|
if (malloc_mutex_init(&prof_dump_mtx))
|
||||||
return (true);
|
return (true);
|
||||||
|
|
||||||
if (atexit(prof_fdump) != 0) {
|
if (opt_prof_final && opt_prof_prefix[0] != '\0' &&
|
||||||
|
atexit(prof_fdump) != 0) {
|
||||||
malloc_write("<jemalloc>: Error in atexit()\n");
|
malloc_write("<jemalloc>: Error in atexit()\n");
|
||||||
if (opt_abort)
|
if (opt_abort)
|
||||||
abort();
|
abort();
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
const char *malloc_conf =
|
const char *malloc_conf =
|
||||||
"prof:true,prof_thread_active_init:false,lg_prof_sample:0,prof_final:false";
|
"prof:true,prof_thread_active_init:false,lg_prof_sample:0";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
#include "test/jemalloc_test.h"
|
#include "test/jemalloc_test.h"
|
||||||
|
|
||||||
#ifdef JEMALLOC_PROF
|
#ifdef JEMALLOC_PROF
|
||||||
const char *malloc_conf =
|
const char *malloc_conf = "prof:true,prof_active:false";
|
||||||
"prof:true,prof_active:false,prof_final:false";
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Loading…
Reference in New Issue
Block a user