diff --git a/doc/jemalloc.xml.in b/doc/jemalloc.xml.in
index d0d4b20b..89a176e0 100644
--- a/doc/jemalloc.xml.in
+++ b/doc/jemalloc.xml.in
@@ -1514,6 +1514,23 @@ malloc_conf = "xmalloc:true";]]>
by default.
+
+
+ opt.prof_pid_namespace
+ (bool)
+ r-
+ []
+
+ Enable adding the pid namespace to the profile
+ filename. Profiles are dumped to files named according to the pattern
+ <prefix>.<pid_namespace>.<pid>.<seq>.i<iseq>.heap,
+ where <prefix> is controlled by the opt.prof_prefix and
+ prof.prefix
+ options.
+
+
+
opt.lg_prof_interval
diff --git a/include/jemalloc/internal/prof_externs.h b/include/jemalloc/internal/prof_externs.h
index 514c5804..952ace7d 100644
--- a/include/jemalloc/internal/prof_externs.h
+++ b/include/jemalloc/internal/prof_externs.h
@@ -26,6 +26,9 @@ extern char opt_prof_prefix[
1];
extern bool opt_prof_unbias;
+/* Include pid namespace in profile file names. */
+extern bool opt_prof_pid_namespace;
+
/* For recording recent allocations */
extern ssize_t opt_prof_recent_alloc_max;
diff --git a/src/ctl.c b/src/ctl.c
index 7c349da7..37b69576 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -153,6 +153,7 @@ CTL_PROTO(opt_prof_final)
CTL_PROTO(opt_prof_leak)
CTL_PROTO(opt_prof_leak_error)
CTL_PROTO(opt_prof_accum)
+CTL_PROTO(opt_prof_pid_namespace)
CTL_PROTO(opt_prof_recent_alloc_max)
CTL_PROTO(opt_prof_stats)
CTL_PROTO(opt_prof_sys_thread_name)
@@ -507,6 +508,7 @@ static const ctl_named_node_t opt_node[] = {
{NAME("prof_leak"), CTL(opt_prof_leak)},
{NAME("prof_leak_error"), CTL(opt_prof_leak_error)},
{NAME("prof_accum"), CTL(opt_prof_accum)},
+ {NAME("prof_pid_namespace"), CTL(opt_prof_pid_namespace)},
{NAME("prof_recent_alloc_max"), CTL(opt_prof_recent_alloc_max)},
{NAME("prof_stats"), CTL(opt_prof_stats)},
{NAME("prof_sys_thread_name"), CTL(opt_prof_sys_thread_name)},
@@ -2226,6 +2228,8 @@ CTL_RO_NL_CGEN(config_prof, opt_prof_thread_active_init,
CTL_RO_NL_CGEN(config_prof, opt_prof_bt_max, opt_prof_bt_max, unsigned)
CTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t)
CTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool)
+CTL_RO_NL_CGEN(config_prof, opt_prof_pid_namespace, opt_prof_pid_namespace,
+ bool)
CTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t)
CTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool)
CTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool)
diff --git a/src/jemalloc.c b/src/jemalloc.c
index d83c191f..390912ba 100644
--- a/src/jemalloc.c
+++ b/src/jemalloc.c
@@ -1628,6 +1628,7 @@ malloc_conf_init_helper(sc_data_t *sc_data, unsigned bin_shard_sizes[SC_NBINS],
CONF_HANDLE_BOOL(opt_prof_leak_error,
"prof_leak_error")
CONF_HANDLE_BOOL(opt_prof_log, "prof_log")
+ CONF_HANDLE_BOOL(opt_prof_pid_namespace, "prof_pid_namespace")
CONF_HANDLE_SSIZE_T(opt_prof_recent_alloc_max,
"prof_recent_alloc_max", -1, SSIZE_MAX)
CONF_HANDLE_BOOL(opt_prof_stats, "prof_stats")
diff --git a/src/prof.c b/src/prof.c
index 1cf49740..6ae7f768 100644
--- a/src/prof.c
+++ b/src/prof.c
@@ -34,6 +34,7 @@ bool opt_prof_final = false;
bool opt_prof_leak = false;
bool opt_prof_leak_error = false;
bool opt_prof_accum = false;
+bool opt_prof_pid_namespace = false;
char opt_prof_prefix[PROF_DUMP_FILENAME_LEN];
bool opt_prof_sys_thread_name = false;
bool opt_prof_unbias = true;
diff --git a/src/prof_sys.c b/src/prof_sys.c
index c2998926..1e22332c 100644
--- a/src/prof_sys.c
+++ b/src/prof_sys.c
@@ -484,6 +484,41 @@ prof_getpid(void) {
#endif
}
+long
+prof_get_pid_namespace() {
+ long ret = 0;
+
+#if defined(_WIN32) || defined(__APPLE__)
+ // Not supported, do nothing.
+#else
+ char buf[PATH_MAX];
+ const char* linkname =
+# if defined(__FreeBSD__) || defined(__DragonFly__)
+ "/proc/curproc/ns/pid"
+# else
+ "/proc/self/ns/pid"
+# endif
+ ;
+ ssize_t linklen =
+# ifndef JEMALLOC_READLINKAT
+ readlink(linkname, buf, PATH_MAX)
+# else
+ readlinkat(AT_FDCWD, linkname, buf, PATH_MAX)
+# endif
+ ;
+
+ // namespace string is expected to be like pid:[4026531836]
+ if (linklen > 0) {
+ // Trim the trailing "]"
+ buf[linklen-1] = '\0';
+ char* index = strtok(buf, "pid:[");
+ ret = atol(index);
+ }
+#endif
+
+ return ret;
+}
+
/*
* This buffer is rather large for stack allocation, so use a single buffer for
* all profile dumps; protected by prof_dump_mtx.
@@ -713,15 +748,30 @@ prof_dump_filename(tsd_t *tsd, char *filename, char v, uint64_t vseq) {
const char *prefix = prof_prefix_get(tsd_tsdn(tsd));
if (vseq != VSEQ_INVALID) {
- /* "...v.heap" */
- malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE,
- "%s.%d.%"FMTu64".%c%"FMTu64".heap", prefix, prof_getpid(),
- prof_dump_seq, v, vseq);
+ if (opt_prof_pid_namespace) {
+ /* "....v.heap" */
+ malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE,
+ "%s.%ld.%d.%"FMTu64".%c%"FMTu64".heap", prefix,
+ prof_get_pid_namespace(), prof_getpid(), prof_dump_seq, v,
+ vseq);
+ } else {
+ /* "...v.heap" */
+ malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE,
+ "%s.%d.%"FMTu64".%c%"FMTu64".heap", prefix, prof_getpid(),
+ prof_dump_seq, v, vseq);
+ }
} else {
- /* "....heap" */
- malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE,
- "%s.%d.%"FMTu64".%c.heap", prefix, prof_getpid(),
- prof_dump_seq, v);
+ if (opt_prof_pid_namespace) {
+ /* ".....heap" */
+ malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE,
+ "%s.%ld.%d.%"FMTu64".%c.heap", prefix,
+ prof_get_pid_namespace(), prof_getpid(), prof_dump_seq, v);
+ } else {
+ /* "....heap" */
+ malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE,
+ "%s.%d.%"FMTu64".%c.heap", prefix, prof_getpid(),
+ prof_dump_seq, v);
+ }
}
prof_dump_seq++;
}
@@ -729,8 +779,14 @@ prof_dump_filename(tsd_t *tsd, char *filename, char v, uint64_t vseq) {
void
prof_get_default_filename(tsdn_t *tsdn, char *filename, uint64_t ind) {
malloc_mutex_lock(tsdn, &prof_dump_filename_mtx);
- malloc_snprintf(filename, PROF_DUMP_FILENAME_LEN,
- "%s.%d.%"FMTu64".json", prof_prefix_get(tsdn), prof_getpid(), ind);
+ if (opt_prof_pid_namespace) {
+ malloc_snprintf(filename, PROF_DUMP_FILENAME_LEN,
+ "%s.%ld.%d.%"FMTu64".json", prof_prefix_get(tsdn),
+ prof_get_pid_namespace(), prof_getpid(), ind);
+ } else {
+ malloc_snprintf(filename, PROF_DUMP_FILENAME_LEN,
+ "%s.%d.%"FMTu64".json", prof_prefix_get(tsdn), prof_getpid(), ind);
+ }
malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx);
}
diff --git a/test/unit/mallctl.c b/test/unit/mallctl.c
index 1ff8b564..9e5baff0 100644
--- a/test/unit/mallctl.c
+++ b/test/unit/mallctl.c
@@ -317,6 +317,7 @@ TEST_BEGIN(test_mallctl_opt) {
TEST_MALLCTL_OPT(unsigned, prof_bt_max, prof);
TEST_MALLCTL_OPT(ssize_t, lg_prof_sample, prof);
TEST_MALLCTL_OPT(bool, prof_accum, prof);
+ TEST_MALLCTL_OPT(bool, prof_pid_namespace, prof);
TEST_MALLCTL_OPT(ssize_t, lg_prof_interval, prof);
TEST_MALLCTL_OPT(bool, prof_gdump, prof);
TEST_MALLCTL_OPT(bool, prof_final, prof);