diff --git a/include/jemalloc/internal/prof_externs.h b/include/jemalloc/internal/prof_externs.h index 135fb29d..96e08c89 100644 --- a/include/jemalloc/internal/prof_externs.h +++ b/include/jemalloc/internal/prof_externs.h @@ -58,11 +58,9 @@ void prof_malloc_sample_object(tsd_t *tsd, const void *ptr, size_t size, void prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_info_t *prof_info); prof_tctx_t *prof_tctx_create(tsd_t *tsd); int prof_getpid(void); -void prof_get_default_filename(tsdn_t *tsdn, char *filename, uint64_t ind); void prof_idump(tsdn_t *tsdn); bool prof_mdump(tsd_t *tsd, const char *filename); void prof_gdump(tsdn_t *tsdn); -bool prof_dump_prefix_set(tsdn_t *tsdn, const char *prefix); void prof_reset(tsd_t *tsd, size_t lg_sample); void prof_tdata_cleanup(tsd_t *tsd); diff --git a/include/jemalloc/internal/prof_sys.h b/include/jemalloc/internal/prof_sys.h index cfa00591..166df6fa 100644 --- a/include/jemalloc/internal/prof_sys.h +++ b/include/jemalloc/internal/prof_sys.h @@ -1,10 +1,20 @@ #ifndef JEMALLOC_INTERNAL_PROF_SYS_H #define JEMALLOC_INTERNAL_PROF_SYS_H +extern malloc_mutex_t prof_dump_filename_mtx; +extern base_t *prof_base; + void prof_sys_thread_name_fetch(tsd_t *tsd); /* Used in unit tests. */ typedef int (prof_sys_thread_name_read_t)(char *buf, size_t limit); extern prof_sys_thread_name_read_t *JET_MUTABLE prof_sys_thread_name_read; +void prof_get_default_filename(tsdn_t *tsdn, char *filename, uint64_t ind); +bool prof_dump_prefix_set(tsdn_t *tsdn, const char *prefix); +void prof_fdump_impl(tsd_t *tsd); +void prof_idump_impl(tsd_t *tsd); +bool prof_mdump_impl(tsd_t *tsd, const char *filename); +void prof_gdump_impl(tsd_t *tsd); + #endif /* JEMALLOC_INTERNAL_PROF_SYS_H */ diff --git a/src/ctl.c b/src/ctl.c index 5cba9af9..fe0b9f99 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -9,6 +9,7 @@ #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/nstime.h" #include "jemalloc/internal/peak_event.h" +#include "jemalloc/internal/prof_sys.h" #include "jemalloc/internal/sc.h" #include "jemalloc/internal/util.h" diff --git a/src/prof.c b/src/prof.c index ea63cfdd..7732edea 100644 --- a/src/prof.c +++ b/src/prof.c @@ -86,38 +86,13 @@ malloc_mutex_t tdatas_mtx; static uint64_t next_thr_uid; static malloc_mutex_t next_thr_uid_mtx; -static malloc_mutex_t prof_dump_filename_mtx; -static uint64_t prof_dump_seq; -static uint64_t prof_dump_iseq; -static uint64_t prof_dump_mseq; -static uint64_t prof_dump_useq; - -/* The fallback allocator profiling functionality will use. */ -base_t *prof_base; - malloc_mutex_t prof_dump_mtx; -static char *prof_dump_prefix = NULL; /* Do not dump any profiles until bootstrapping is complete. */ bool prof_booted = false; /******************************************************************************/ -/* - * If profiling is off, then PROF_DUMP_FILENAME_LEN is 1, so we'll end up - * calling strncpy with a size of 0, which triggers a -Wstringop-truncation - * warning (strncpy can never actually be called in this case, since we bail out - * much earlier when config_prof is false). This function works around the - * warning to let us leave the warning on. - */ -static inline void -prof_strncpy(char *UNUSED dest, const char *UNUSED src, size_t UNUSED size) { - cassert(config_prof); -#ifdef JEMALLOC_PROF - strncpy(dest, src, size); -#endif -} - void prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx) { cassert(config_prof); @@ -507,57 +482,9 @@ prof_getpid(void) { #endif } -static const char * -prof_dump_prefix_get(tsdn_t* tsdn) { - malloc_mutex_assert_owner(tsdn, &prof_dump_filename_mtx); - - return prof_dump_prefix == NULL ? opt_prof_prefix : prof_dump_prefix; -} - -static bool -prof_dump_prefix_is_empty(tsdn_t *tsdn) { - malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); - bool ret = (prof_dump_prefix_get(tsdn)[0] == '\0'); - malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); - return ret; -} - -#define DUMP_FILENAME_BUFSIZE (PATH_MAX + 1) -#define VSEQ_INVALID UINT64_C(0xffffffffffffffff) -static void -prof_dump_filename(tsd_t *tsd, char *filename, char v, uint64_t vseq) { - cassert(config_prof); - - assert(tsd_reentrancy_level_get(tsd) == 0); - const char *prof_prefix = prof_dump_prefix_get(tsd_tsdn(tsd)); - - if (vseq != VSEQ_INVALID) { - /* "...v.heap" */ - malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE, - "%s.%d.%"FMTu64".%c%"FMTu64".heap", - prof_prefix, prof_getpid(), prof_dump_seq, v, vseq); - } else { - /* "....heap" */ - malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE, - "%s.%d.%"FMTu64".%c.heap", - prof_prefix, prof_getpid(), prof_dump_seq, v); - } - prof_dump_seq++; -} - -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_dump_prefix_get(tsdn), prof_getpid(), - ind); - malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); -} - static void prof_fdump(void) { tsd_t *tsd; - char filename[DUMP_FILENAME_BUFSIZE]; cassert(config_prof); assert(opt_prof_final); @@ -567,12 +494,8 @@ prof_fdump(void) { } tsd = tsd_fetch(); assert(tsd_reentrancy_level_get(tsd) == 0); - assert(!prof_dump_prefix_is_empty(tsd_tsdn(tsd))); - malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx); - prof_dump_filename(tsd, filename, 'f', VSEQ_INVALID); - malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); - prof_dump(tsd, false, filename, opt_prof_leak); + prof_fdump_impl(tsd); } static bool @@ -582,31 +505,6 @@ prof_idump_accum_init(void) { return counter_accum_init(&prof_idump_accumulated, prof_interval); } -bool -prof_dump_prefix_set(tsdn_t *tsdn, const char *prefix) { - cassert(config_prof); - ctl_mtx_assert_held(tsdn); - malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); - if (prof_dump_prefix == NULL) { - malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); - /* Everything is still guarded by ctl_mtx. */ - char *buffer = base_alloc(tsdn, prof_base, - PROF_DUMP_FILENAME_LEN, QUANTUM); - if (buffer == NULL) { - return true; - } - malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); - prof_dump_prefix = buffer; - } - assert(prof_dump_prefix != NULL); - - prof_strncpy(prof_dump_prefix, prefix, PROF_DUMP_FILENAME_LEN - 1); - prof_dump_prefix[PROF_DUMP_FILENAME_LEN - 1] = '\0'; - malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); - - return false; -} - void prof_idump(tsdn_t *tsdn) { tsd_t *tsd; @@ -631,16 +529,7 @@ prof_idump(tsdn_t *tsdn) { return; } - malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx); - if (prof_dump_prefix_get(tsd_tsdn(tsd))[0] == '\0') { - malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); - return; - } - char filename[PATH_MAX + 1]; - prof_dump_filename(tsd, filename, 'i', prof_dump_iseq); - prof_dump_iseq++; - malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); - prof_dump(tsd, false, filename, false); + prof_idump_impl(tsd); } bool @@ -651,20 +540,8 @@ prof_mdump(tsd_t *tsd, const char *filename) { if (!opt_prof || !prof_booted) { return true; } - char filename_buf[DUMP_FILENAME_BUFSIZE]; - if (filename == NULL) { - /* No filename specified, so automatically generate one. */ - malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx); - if (prof_dump_prefix_get(tsd_tsdn(tsd))[0] == '\0') { - malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); - return true; - } - prof_dump_filename(tsd, filename_buf, 'm', prof_dump_mseq); - prof_dump_mseq++; - malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); - filename = filename_buf; - } - return prof_dump(tsd, true, filename, false); + + return prof_mdump_impl(tsd, filename); } void @@ -691,16 +568,7 @@ prof_gdump(tsdn_t *tsdn) { return; } - malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); - if (prof_dump_prefix_get(tsdn)[0] == '\0') { - malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); - return; - } - char filename[DUMP_FILENAME_BUFSIZE]; - prof_dump_filename(tsd, filename, 'u', prof_dump_useq); - prof_dump_useq++; - malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); - prof_dump(tsd, false, filename, false); + prof_gdump_impl(tsd); } static uint64_t diff --git a/src/prof_log.c b/src/prof_log.c index bda01d04..b32d6f63 100644 --- a/src/prof_log.c +++ b/src/prof_log.c @@ -10,6 +10,7 @@ #include "jemalloc/internal/mutex.h" #include "jemalloc/internal/prof_data.h" #include "jemalloc/internal/prof_log.h" +#include "jemalloc/internal/prof_sys.h" bool opt_prof_log = false; typedef enum prof_logging_state_e prof_logging_state_t; diff --git a/src/prof_sys.c b/src/prof_sys.c index 521a71a0..47bc43b7 100644 --- a/src/prof_sys.c +++ b/src/prof_sys.c @@ -2,9 +2,22 @@ #include "jemalloc/internal/jemalloc_preamble.h" #include "jemalloc/internal/jemalloc_internal_includes.h" +#include "jemalloc/internal/ctl.h" #include "jemalloc/internal/prof_data.h" #include "jemalloc/internal/prof_sys.h" +malloc_mutex_t prof_dump_filename_mtx; + +static uint64_t prof_dump_seq; +static uint64_t prof_dump_iseq; +static uint64_t prof_dump_mseq; +static uint64_t prof_dump_useq; + +static char *prof_dump_prefix = NULL; + +/* The fallback allocator profiling functionality will use. */ +base_t *prof_base; + static int prof_sys_thread_name_read_impl(char *buf, size_t limit) { #ifdef JEMALLOC_HAVE_PTHREAD_SETNAME_NP @@ -25,3 +38,148 @@ prof_sys_thread_name_fetch(tsd_t *tsd) { } #undef THREAD_NAME_MAX_LEN } + +/* + * If profiling is off, then PROF_DUMP_FILENAME_LEN is 1, so we'll end up + * calling strncpy with a size of 0, which triggers a -Wstringop-truncation + * warning (strncpy can never actually be called in this case, since we bail out + * much earlier when config_prof is false). This function works around the + * warning to let us leave the warning on. + */ +static inline void +prof_strncpy(char *UNUSED dest, const char *UNUSED src, size_t UNUSED size) { + cassert(config_prof); +#ifdef JEMALLOC_PROF + strncpy(dest, src, size); +#endif +} + +static const char * +prof_dump_prefix_get(tsdn_t* tsdn) { + malloc_mutex_assert_owner(tsdn, &prof_dump_filename_mtx); + + return prof_dump_prefix == NULL ? opt_prof_prefix : prof_dump_prefix; +} + +static bool +prof_dump_prefix_is_empty(tsdn_t *tsdn) { + malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); + bool ret = (prof_dump_prefix_get(tsdn)[0] == '\0'); + malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); + return ret; +} + +#define DUMP_FILENAME_BUFSIZE (PATH_MAX + 1) +#define VSEQ_INVALID UINT64_C(0xffffffffffffffff) +static void +prof_dump_filename(tsd_t *tsd, char *filename, char v, uint64_t vseq) { + cassert(config_prof); + + assert(tsd_reentrancy_level_get(tsd) == 0); + const char *prof_prefix = prof_dump_prefix_get(tsd_tsdn(tsd)); + + if (vseq != VSEQ_INVALID) { + /* "...v.heap" */ + malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE, + "%s.%d.%"FMTu64".%c%"FMTu64".heap", + prof_prefix, prof_getpid(), prof_dump_seq, v, vseq); + } else { + /* "....heap" */ + malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE, + "%s.%d.%"FMTu64".%c.heap", + prof_prefix, prof_getpid(), prof_dump_seq, v); + } + prof_dump_seq++; +} + +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_dump_prefix_get(tsdn), prof_getpid(), + ind); + malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); +} + +void +prof_fdump_impl(tsd_t *tsd) { + char filename[DUMP_FILENAME_BUFSIZE]; + + assert(!prof_dump_prefix_is_empty(tsd_tsdn(tsd))); + malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx); + prof_dump_filename(tsd, filename, 'f', VSEQ_INVALID); + malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); + prof_dump(tsd, false, filename, opt_prof_leak); +} + +bool +prof_dump_prefix_set(tsdn_t *tsdn, const char *prefix) { + cassert(config_prof); + ctl_mtx_assert_held(tsdn); + malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); + if (prof_dump_prefix == NULL) { + malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); + /* Everything is still guarded by ctl_mtx. */ + char *buffer = base_alloc(tsdn, prof_base, + PROF_DUMP_FILENAME_LEN, QUANTUM); + if (buffer == NULL) { + return true; + } + malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); + prof_dump_prefix = buffer; + } + assert(prof_dump_prefix != NULL); + + prof_strncpy(prof_dump_prefix, prefix, PROF_DUMP_FILENAME_LEN - 1); + prof_dump_prefix[PROF_DUMP_FILENAME_LEN - 1] = '\0'; + malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); + + return false; +} + +void +prof_idump_impl(tsd_t *tsd) { + malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx); + if (prof_dump_prefix_get(tsd_tsdn(tsd))[0] == '\0') { + malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); + return; + } + char filename[PATH_MAX + 1]; + prof_dump_filename(tsd, filename, 'i', prof_dump_iseq); + prof_dump_iseq++; + malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); + prof_dump(tsd, false, filename, false); +} + +bool +prof_mdump_impl(tsd_t *tsd, const char *filename) { + char filename_buf[DUMP_FILENAME_BUFSIZE]; + if (filename == NULL) { + /* No filename specified, so automatically generate one. */ + malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_filename_mtx); + if (prof_dump_prefix_get(tsd_tsdn(tsd))[0] == '\0') { + malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); + return true; + } + prof_dump_filename(tsd, filename_buf, 'm', prof_dump_mseq); + prof_dump_mseq++; + malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_filename_mtx); + filename = filename_buf; + } + return prof_dump(tsd, true, filename, false); +} + +void +prof_gdump_impl(tsd_t *tsd) { + tsdn_t *tsdn = tsd_tsdn(tsd); + malloc_mutex_lock(tsdn, &prof_dump_filename_mtx); + if (prof_dump_prefix_get(tsdn)[0] == '\0') { + malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); + return; + } + char filename[DUMP_FILENAME_BUFSIZE]; + prof_dump_filename(tsd, filename, 'u', prof_dump_useq); + prof_dump_useq++; + malloc_mutex_unlock(tsdn, &prof_dump_filename_mtx); + prof_dump(tsd, false, filename, false); +}