From 11038ff762a2ba11eec26d3ffb32026424d2ccfe Mon Sep 17 00:00:00 2001 From: Daniel Hodges Date: Sat, 23 Dec 2023 19:40:44 -0500 Subject: [PATCH] Add support for namespace pids in heap profile names This change adds support for writing pid namespaces to the filename of a heap profile. When running with namespaces pids may reused across namespaces and if mounts are shared where profiles are written there is not a great way to differentiate profiles between pids. Signed-off-by: Daniel Hodges Signed-off-by: Daniel Hodges --- doc/jemalloc.xml.in | 17 ++++++ include/jemalloc/internal/prof_externs.h | 3 + src/ctl.c | 4 ++ src/jemalloc.c | 1 + src/prof.c | 1 + src/prof_sys.c | 76 ++++++++++++++++++++---- test/unit/mallctl.c | 1 + 7 files changed, 93 insertions(+), 10 deletions(-) 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);