1*8e33eff8Schristos #define JEMALLOC_PROF_C_ 2*8e33eff8Schristos #include "jemalloc/internal/jemalloc_preamble.h" 3*8e33eff8Schristos #include "jemalloc/internal/jemalloc_internal_includes.h" 4*8e33eff8Schristos 5*8e33eff8Schristos #include "jemalloc/internal/assert.h" 6*8e33eff8Schristos #include "jemalloc/internal/ckh.h" 7*8e33eff8Schristos #include "jemalloc/internal/hash.h" 8*8e33eff8Schristos #include "jemalloc/internal/malloc_io.h" 9*8e33eff8Schristos #include "jemalloc/internal/mutex.h" 10*8e33eff8Schristos 11*8e33eff8Schristos /******************************************************************************/ 12*8e33eff8Schristos 13*8e33eff8Schristos #ifdef JEMALLOC_PROF_LIBUNWIND 14*8e33eff8Schristos #define UNW_LOCAL_ONLY 15*8e33eff8Schristos #include <libunwind.h> 16*8e33eff8Schristos #endif 17*8e33eff8Schristos 18*8e33eff8Schristos #ifdef JEMALLOC_PROF_LIBGCC 19*8e33eff8Schristos /* 20*8e33eff8Schristos * We have a circular dependency -- jemalloc_internal.h tells us if we should 21*8e33eff8Schristos * use libgcc's unwinding functionality, but after we've included that, we've 22*8e33eff8Schristos * already hooked _Unwind_Backtrace. We'll temporarily disable hooking. 23*8e33eff8Schristos */ 24*8e33eff8Schristos #undef _Unwind_Backtrace 25*8e33eff8Schristos #include <unwind.h> 26*8e33eff8Schristos #define _Unwind_Backtrace JEMALLOC_HOOK(_Unwind_Backtrace, hooks_libc_hook) 27*8e33eff8Schristos #endif 28*8e33eff8Schristos 29*8e33eff8Schristos /******************************************************************************/ 30*8e33eff8Schristos /* Data. */ 31*8e33eff8Schristos 32*8e33eff8Schristos bool opt_prof = false; 33*8e33eff8Schristos bool opt_prof_active = true; 34*8e33eff8Schristos bool opt_prof_thread_active_init = true; 35*8e33eff8Schristos size_t opt_lg_prof_sample = LG_PROF_SAMPLE_DEFAULT; 36*8e33eff8Schristos ssize_t opt_lg_prof_interval = LG_PROF_INTERVAL_DEFAULT; 37*8e33eff8Schristos bool opt_prof_gdump = false; 38*8e33eff8Schristos bool opt_prof_final = false; 39*8e33eff8Schristos bool opt_prof_leak = false; 40*8e33eff8Schristos bool opt_prof_accum = false; 41*8e33eff8Schristos char opt_prof_prefix[ 42*8e33eff8Schristos /* Minimize memory bloat for non-prof builds. */ 43*8e33eff8Schristos #ifdef JEMALLOC_PROF 44*8e33eff8Schristos PATH_MAX + 45*8e33eff8Schristos #endif 46*8e33eff8Schristos 1]; 47*8e33eff8Schristos 48*8e33eff8Schristos /* 49*8e33eff8Schristos * Initialized as opt_prof_active, and accessed via 50*8e33eff8Schristos * prof_active_[gs]et{_unlocked,}(). 51*8e33eff8Schristos */ 52*8e33eff8Schristos bool prof_active; 53*8e33eff8Schristos static malloc_mutex_t prof_active_mtx; 54*8e33eff8Schristos 55*8e33eff8Schristos /* 56*8e33eff8Schristos * Initialized as opt_prof_thread_active_init, and accessed via 57*8e33eff8Schristos * prof_thread_active_init_[gs]et(). 58*8e33eff8Schristos */ 59*8e33eff8Schristos static bool prof_thread_active_init; 60*8e33eff8Schristos static malloc_mutex_t prof_thread_active_init_mtx; 61*8e33eff8Schristos 62*8e33eff8Schristos /* 63*8e33eff8Schristos * Initialized as opt_prof_gdump, and accessed via 64*8e33eff8Schristos * prof_gdump_[gs]et{_unlocked,}(). 65*8e33eff8Schristos */ 66*8e33eff8Schristos bool prof_gdump_val; 67*8e33eff8Schristos static malloc_mutex_t prof_gdump_mtx; 68*8e33eff8Schristos 69*8e33eff8Schristos uint64_t prof_interval = 0; 70*8e33eff8Schristos 71*8e33eff8Schristos size_t lg_prof_sample; 72*8e33eff8Schristos 73*8e33eff8Schristos /* 74*8e33eff8Schristos * Table of mutexes that are shared among gctx's. These are leaf locks, so 75*8e33eff8Schristos * there is no problem with using them for more than one gctx at the same time. 76*8e33eff8Schristos * The primary motivation for this sharing though is that gctx's are ephemeral, 77*8e33eff8Schristos * and destroying mutexes causes complications for systems that allocate when 78*8e33eff8Schristos * creating/destroying mutexes. 79*8e33eff8Schristos */ 80*8e33eff8Schristos static malloc_mutex_t *gctx_locks; 81*8e33eff8Schristos #ifdef JEMALLOC_PROF 82*8e33eff8Schristos static atomic_u_t cum_gctxs; /* Atomic counter. */ 83*8e33eff8Schristos #endif 84*8e33eff8Schristos 85*8e33eff8Schristos /* 86*8e33eff8Schristos * Table of mutexes that are shared among tdata's. No operations require 87*8e33eff8Schristos * holding multiple tdata locks, so there is no problem with using them for more 88*8e33eff8Schristos * than one tdata at the same time, even though a gctx lock may be acquired 89*8e33eff8Schristos * while holding a tdata lock. 90*8e33eff8Schristos */ 91*8e33eff8Schristos static malloc_mutex_t *tdata_locks; 92*8e33eff8Schristos 93*8e33eff8Schristos /* 94*8e33eff8Schristos * Global hash of (prof_bt_t *)-->(prof_gctx_t *). This is the master data 95*8e33eff8Schristos * structure that knows about all backtraces currently captured. 96*8e33eff8Schristos */ 97*8e33eff8Schristos static ckh_t bt2gctx; 98*8e33eff8Schristos /* Non static to enable profiling. */ 99*8e33eff8Schristos malloc_mutex_t bt2gctx_mtx; 100*8e33eff8Schristos 101*8e33eff8Schristos /* 102*8e33eff8Schristos * Tree of all extant prof_tdata_t structures, regardless of state, 103*8e33eff8Schristos * {attached,detached,expired}. 104*8e33eff8Schristos */ 105*8e33eff8Schristos static prof_tdata_tree_t tdatas; 106*8e33eff8Schristos static malloc_mutex_t tdatas_mtx; 107*8e33eff8Schristos 108*8e33eff8Schristos #ifdef JEMALLOC_PROF 109*8e33eff8Schristos static uint64_t next_thr_uid; 110*8e33eff8Schristos #endif 111*8e33eff8Schristos static malloc_mutex_t next_thr_uid_mtx; 112*8e33eff8Schristos 113*8e33eff8Schristos static malloc_mutex_t prof_dump_seq_mtx; 114*8e33eff8Schristos #ifdef JEMALLOC_PROF 115*8e33eff8Schristos static uint64_t prof_dump_seq; 116*8e33eff8Schristos static uint64_t prof_dump_iseq; 117*8e33eff8Schristos static uint64_t prof_dump_mseq; 118*8e33eff8Schristos static uint64_t prof_dump_useq; 119*8e33eff8Schristos #endif 120*8e33eff8Schristos 121*8e33eff8Schristos /* 122*8e33eff8Schristos * This buffer is rather large for stack allocation, so use a single buffer for 123*8e33eff8Schristos * all profile dumps. 124*8e33eff8Schristos */ 125*8e33eff8Schristos static malloc_mutex_t prof_dump_mtx; 126*8e33eff8Schristos static char prof_dump_buf[ 127*8e33eff8Schristos /* Minimize memory bloat for non-prof builds. */ 128*8e33eff8Schristos #ifdef JEMALLOC_PROF 129*8e33eff8Schristos PROF_DUMP_BUFSIZE 130*8e33eff8Schristos #else 131*8e33eff8Schristos 1 132*8e33eff8Schristos #endif 133*8e33eff8Schristos ]; 134*8e33eff8Schristos static size_t prof_dump_buf_end; 135*8e33eff8Schristos static int prof_dump_fd; 136*8e33eff8Schristos 137*8e33eff8Schristos #ifdef JEMALLOC_PROF 138*8e33eff8Schristos /* Do not dump any profiles until bootstrapping is complete. */ 139*8e33eff8Schristos static bool prof_booted = false; 140*8e33eff8Schristos #endif 141*8e33eff8Schristos 142*8e33eff8Schristos /******************************************************************************/ 143*8e33eff8Schristos /* 144*8e33eff8Schristos * Function prototypes for static functions that are referenced prior to 145*8e33eff8Schristos * definition. 146*8e33eff8Schristos */ 147*8e33eff8Schristos 148*8e33eff8Schristos static bool prof_tctx_should_destroy(tsdn_t *tsdn, prof_tctx_t *tctx); 149*8e33eff8Schristos static void prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx); 150*8e33eff8Schristos static bool prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, 151*8e33eff8Schristos bool even_if_attached); 152*8e33eff8Schristos static void prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, 153*8e33eff8Schristos bool even_if_attached); 154*8e33eff8Schristos #ifdef JEMALLOC_PROF 155*8e33eff8Schristos static char *prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name); 156*8e33eff8Schristos #endif 157*8e33eff8Schristos 158*8e33eff8Schristos /******************************************************************************/ 159*8e33eff8Schristos /* Red-black trees. */ 160*8e33eff8Schristos 161*8e33eff8Schristos static int 162*8e33eff8Schristos prof_tctx_comp(const prof_tctx_t *a, const prof_tctx_t *b) { 163*8e33eff8Schristos uint64_t a_thr_uid = a->thr_uid; 164*8e33eff8Schristos uint64_t b_thr_uid = b->thr_uid; 165*8e33eff8Schristos int ret = (a_thr_uid > b_thr_uid) - (a_thr_uid < b_thr_uid); 166*8e33eff8Schristos if (ret == 0) { 167*8e33eff8Schristos uint64_t a_thr_discrim = a->thr_discrim; 168*8e33eff8Schristos uint64_t b_thr_discrim = b->thr_discrim; 169*8e33eff8Schristos ret = (a_thr_discrim > b_thr_discrim) - (a_thr_discrim < 170*8e33eff8Schristos b_thr_discrim); 171*8e33eff8Schristos if (ret == 0) { 172*8e33eff8Schristos uint64_t a_tctx_uid = a->tctx_uid; 173*8e33eff8Schristos uint64_t b_tctx_uid = b->tctx_uid; 174*8e33eff8Schristos ret = (a_tctx_uid > b_tctx_uid) - (a_tctx_uid < 175*8e33eff8Schristos b_tctx_uid); 176*8e33eff8Schristos } 177*8e33eff8Schristos } 178*8e33eff8Schristos return ret; 179*8e33eff8Schristos } 180*8e33eff8Schristos 181*8e33eff8Schristos rb_gen(static UNUSED, tctx_tree_, prof_tctx_tree_t, prof_tctx_t, 182*8e33eff8Schristos tctx_link, prof_tctx_comp) 183*8e33eff8Schristos 184*8e33eff8Schristos static int 185*8e33eff8Schristos prof_gctx_comp(const prof_gctx_t *a, const prof_gctx_t *b) { 186*8e33eff8Schristos unsigned a_len = a->bt.len; 187*8e33eff8Schristos unsigned b_len = b->bt.len; 188*8e33eff8Schristos unsigned comp_len = (a_len < b_len) ? a_len : b_len; 189*8e33eff8Schristos int ret = memcmp(a->bt.vec, b->bt.vec, comp_len * sizeof(void *)); 190*8e33eff8Schristos if (ret == 0) { 191*8e33eff8Schristos ret = (a_len > b_len) - (a_len < b_len); 192*8e33eff8Schristos } 193*8e33eff8Schristos return ret; 194*8e33eff8Schristos } 195*8e33eff8Schristos 196*8e33eff8Schristos rb_gen(static UNUSED, gctx_tree_, prof_gctx_tree_t, prof_gctx_t, dump_link, 197*8e33eff8Schristos prof_gctx_comp) 198*8e33eff8Schristos 199*8e33eff8Schristos static int 200*8e33eff8Schristos prof_tdata_comp(const prof_tdata_t *a, const prof_tdata_t *b) { 201*8e33eff8Schristos int ret; 202*8e33eff8Schristos uint64_t a_uid = a->thr_uid; 203*8e33eff8Schristos uint64_t b_uid = b->thr_uid; 204*8e33eff8Schristos 205*8e33eff8Schristos ret = ((a_uid > b_uid) - (a_uid < b_uid)); 206*8e33eff8Schristos if (ret == 0) { 207*8e33eff8Schristos uint64_t a_discrim = a->thr_discrim; 208*8e33eff8Schristos uint64_t b_discrim = b->thr_discrim; 209*8e33eff8Schristos 210*8e33eff8Schristos ret = ((a_discrim > b_discrim) - (a_discrim < b_discrim)); 211*8e33eff8Schristos } 212*8e33eff8Schristos return ret; 213*8e33eff8Schristos } 214*8e33eff8Schristos 215*8e33eff8Schristos rb_gen(static UNUSED, tdata_tree_, prof_tdata_tree_t, prof_tdata_t, tdata_link, 216*8e33eff8Schristos prof_tdata_comp) 217*8e33eff8Schristos 218*8e33eff8Schristos /******************************************************************************/ 219*8e33eff8Schristos 220*8e33eff8Schristos JEMALLOC_PROF_NORETURN void 221*8e33eff8Schristos prof_alloc_rollback(tsd_t *tsd, prof_tctx_t *tctx, bool updated) { 222*8e33eff8Schristos prof_tdata_t *tdata; 223*8e33eff8Schristos 224*8e33eff8Schristos cassert(config_prof); 225*8e33eff8Schristos 226*8e33eff8Schristos if (updated) { 227*8e33eff8Schristos /* 228*8e33eff8Schristos * Compute a new sample threshold. This isn't very important in 229*8e33eff8Schristos * practice, because this function is rarely executed, so the 230*8e33eff8Schristos * potential for sample bias is minimal except in contrived 231*8e33eff8Schristos * programs. 232*8e33eff8Schristos */ 233*8e33eff8Schristos tdata = prof_tdata_get(tsd, true); 234*8e33eff8Schristos if (tdata != NULL) { 235*8e33eff8Schristos prof_sample_threshold_update(tdata); 236*8e33eff8Schristos } 237*8e33eff8Schristos } 238*8e33eff8Schristos 239*8e33eff8Schristos if ((uintptr_t)tctx > (uintptr_t)1U) { 240*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock); 241*8e33eff8Schristos tctx->prepared = false; 242*8e33eff8Schristos if (prof_tctx_should_destroy(tsd_tsdn(tsd), tctx)) { 243*8e33eff8Schristos prof_tctx_destroy(tsd, tctx); 244*8e33eff8Schristos } else { 245*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), tctx->tdata->lock); 246*8e33eff8Schristos } 247*8e33eff8Schristos } 248*8e33eff8Schristos } 249*8e33eff8Schristos 250*8e33eff8Schristos JEMALLOC_PROF_NORETURN void 251*8e33eff8Schristos prof_malloc_sample_object(tsdn_t *tsdn, const void *ptr, size_t usize, 252*8e33eff8Schristos prof_tctx_t *tctx) { 253*8e33eff8Schristos prof_tctx_set(tsdn, ptr, usize, NULL, tctx); 254*8e33eff8Schristos 255*8e33eff8Schristos malloc_mutex_lock(tsdn, tctx->tdata->lock); 256*8e33eff8Schristos tctx->cnts.curobjs++; 257*8e33eff8Schristos tctx->cnts.curbytes += usize; 258*8e33eff8Schristos if (opt_prof_accum) { 259*8e33eff8Schristos tctx->cnts.accumobjs++; 260*8e33eff8Schristos tctx->cnts.accumbytes += usize; 261*8e33eff8Schristos } 262*8e33eff8Schristos tctx->prepared = false; 263*8e33eff8Schristos malloc_mutex_unlock(tsdn, tctx->tdata->lock); 264*8e33eff8Schristos } 265*8e33eff8Schristos 266*8e33eff8Schristos void 267*8e33eff8Schristos prof_free_sampled_object(tsd_t *tsd, size_t usize, prof_tctx_t *tctx) { 268*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), tctx->tdata->lock); 269*8e33eff8Schristos assert(tctx->cnts.curobjs > 0); 270*8e33eff8Schristos assert(tctx->cnts.curbytes >= usize); 271*8e33eff8Schristos tctx->cnts.curobjs--; 272*8e33eff8Schristos tctx->cnts.curbytes -= usize; 273*8e33eff8Schristos 274*8e33eff8Schristos if (prof_tctx_should_destroy(tsd_tsdn(tsd), tctx)) { 275*8e33eff8Schristos prof_tctx_destroy(tsd, tctx); 276*8e33eff8Schristos } else { 277*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), tctx->tdata->lock); 278*8e33eff8Schristos } 279*8e33eff8Schristos } 280*8e33eff8Schristos 281*8e33eff8Schristos JEMALLOC_PROF_NORETURN void 282*8e33eff8Schristos bt_init(prof_bt_t *bt, void **vec) { 283*8e33eff8Schristos cassert(config_prof); 284*8e33eff8Schristos 285*8e33eff8Schristos bt->vec = vec; 286*8e33eff8Schristos bt->len = 0; 287*8e33eff8Schristos } 288*8e33eff8Schristos 289*8e33eff8Schristos static JEMALLOC_PROF_NORETURN void 290*8e33eff8Schristos prof_enter(tsd_t *tsd, prof_tdata_t *tdata) { 291*8e33eff8Schristos cassert(config_prof); 292*8e33eff8Schristos assert(tdata == prof_tdata_get(tsd, false)); 293*8e33eff8Schristos 294*8e33eff8Schristos if (tdata != NULL) { 295*8e33eff8Schristos assert(!tdata->enq); 296*8e33eff8Schristos tdata->enq = true; 297*8e33eff8Schristos } 298*8e33eff8Schristos 299*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &bt2gctx_mtx); 300*8e33eff8Schristos } 301*8e33eff8Schristos 302*8e33eff8Schristos static JEMALLOC_PROF_NORETURN void 303*8e33eff8Schristos prof_leave(tsd_t *tsd, prof_tdata_t *tdata) { 304*8e33eff8Schristos cassert(config_prof); 305*8e33eff8Schristos assert(tdata == prof_tdata_get(tsd, false)); 306*8e33eff8Schristos 307*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &bt2gctx_mtx); 308*8e33eff8Schristos 309*8e33eff8Schristos if (tdata != NULL) { 310*8e33eff8Schristos bool idump, gdump; 311*8e33eff8Schristos 312*8e33eff8Schristos assert(tdata->enq); 313*8e33eff8Schristos tdata->enq = false; 314*8e33eff8Schristos idump = tdata->enq_idump; 315*8e33eff8Schristos tdata->enq_idump = false; 316*8e33eff8Schristos gdump = tdata->enq_gdump; 317*8e33eff8Schristos tdata->enq_gdump = false; 318*8e33eff8Schristos 319*8e33eff8Schristos if (idump) { 320*8e33eff8Schristos prof_idump(tsd_tsdn(tsd)); 321*8e33eff8Schristos } 322*8e33eff8Schristos if (gdump) { 323*8e33eff8Schristos prof_gdump(tsd_tsdn(tsd)); 324*8e33eff8Schristos } 325*8e33eff8Schristos } 326*8e33eff8Schristos } 327*8e33eff8Schristos 328*8e33eff8Schristos #ifdef JEMALLOC_PROF_LIBUNWIND 329*8e33eff8Schristos void 330*8e33eff8Schristos prof_backtrace(prof_bt_t *bt) { 331*8e33eff8Schristos int nframes; 332*8e33eff8Schristos 333*8e33eff8Schristos cassert(config_prof); 334*8e33eff8Schristos assert(bt->len == 0); 335*8e33eff8Schristos assert(bt->vec != NULL); 336*8e33eff8Schristos 337*8e33eff8Schristos nframes = unw_backtrace(bt->vec, PROF_BT_MAX); 338*8e33eff8Schristos if (nframes <= 0) { 339*8e33eff8Schristos return; 340*8e33eff8Schristos } 341*8e33eff8Schristos bt->len = nframes; 342*8e33eff8Schristos } 343*8e33eff8Schristos #elif (defined(JEMALLOC_PROF_LIBGCC)) 344*8e33eff8Schristos static _Unwind_Reason_Code 345*8e33eff8Schristos prof_unwind_init_callback(struct _Unwind_Context *context, void *arg) { 346*8e33eff8Schristos cassert(config_prof); 347*8e33eff8Schristos 348*8e33eff8Schristos return _URC_NO_REASON; 349*8e33eff8Schristos } 350*8e33eff8Schristos 351*8e33eff8Schristos static _Unwind_Reason_Code 352*8e33eff8Schristos prof_unwind_callback(struct _Unwind_Context *context, void *arg) { 353*8e33eff8Schristos prof_unwind_data_t *data = (prof_unwind_data_t *)arg; 354*8e33eff8Schristos void *ip; 355*8e33eff8Schristos 356*8e33eff8Schristos cassert(config_prof); 357*8e33eff8Schristos 358*8e33eff8Schristos ip = (void *)_Unwind_GetIP(context); 359*8e33eff8Schristos if (ip == NULL) { 360*8e33eff8Schristos return _URC_END_OF_STACK; 361*8e33eff8Schristos } 362*8e33eff8Schristos data->bt->vec[data->bt->len] = ip; 363*8e33eff8Schristos data->bt->len++; 364*8e33eff8Schristos if (data->bt->len == data->max) { 365*8e33eff8Schristos return _URC_END_OF_STACK; 366*8e33eff8Schristos } 367*8e33eff8Schristos 368*8e33eff8Schristos return _URC_NO_REASON; 369*8e33eff8Schristos } 370*8e33eff8Schristos 371*8e33eff8Schristos void 372*8e33eff8Schristos prof_backtrace(prof_bt_t *bt) { 373*8e33eff8Schristos prof_unwind_data_t data = {bt, PROF_BT_MAX}; 374*8e33eff8Schristos 375*8e33eff8Schristos cassert(config_prof); 376*8e33eff8Schristos 377*8e33eff8Schristos _Unwind_Backtrace(prof_unwind_callback, &data); 378*8e33eff8Schristos } 379*8e33eff8Schristos #elif (defined(JEMALLOC_PROF_GCC)) 380*8e33eff8Schristos void 381*8e33eff8Schristos prof_backtrace(prof_bt_t *bt) { 382*8e33eff8Schristos #define BT_FRAME(i) \ 383*8e33eff8Schristos if ((i) < PROF_BT_MAX) { \ 384*8e33eff8Schristos void *p; \ 385*8e33eff8Schristos if (__builtin_frame_address(i) == 0) { \ 386*8e33eff8Schristos return; \ 387*8e33eff8Schristos } \ 388*8e33eff8Schristos p = __builtin_return_address(i); \ 389*8e33eff8Schristos if (p == NULL) { \ 390*8e33eff8Schristos return; \ 391*8e33eff8Schristos } \ 392*8e33eff8Schristos bt->vec[(i)] = p; \ 393*8e33eff8Schristos bt->len = (i) + 1; \ 394*8e33eff8Schristos } else { \ 395*8e33eff8Schristos return; \ 396*8e33eff8Schristos } 397*8e33eff8Schristos 398*8e33eff8Schristos cassert(config_prof); 399*8e33eff8Schristos 400*8e33eff8Schristos BT_FRAME(0) 401*8e33eff8Schristos BT_FRAME(1) 402*8e33eff8Schristos BT_FRAME(2) 403*8e33eff8Schristos BT_FRAME(3) 404*8e33eff8Schristos BT_FRAME(4) 405*8e33eff8Schristos BT_FRAME(5) 406*8e33eff8Schristos BT_FRAME(6) 407*8e33eff8Schristos BT_FRAME(7) 408*8e33eff8Schristos BT_FRAME(8) 409*8e33eff8Schristos BT_FRAME(9) 410*8e33eff8Schristos 411*8e33eff8Schristos BT_FRAME(10) 412*8e33eff8Schristos BT_FRAME(11) 413*8e33eff8Schristos BT_FRAME(12) 414*8e33eff8Schristos BT_FRAME(13) 415*8e33eff8Schristos BT_FRAME(14) 416*8e33eff8Schristos BT_FRAME(15) 417*8e33eff8Schristos BT_FRAME(16) 418*8e33eff8Schristos BT_FRAME(17) 419*8e33eff8Schristos BT_FRAME(18) 420*8e33eff8Schristos BT_FRAME(19) 421*8e33eff8Schristos 422*8e33eff8Schristos BT_FRAME(20) 423*8e33eff8Schristos BT_FRAME(21) 424*8e33eff8Schristos BT_FRAME(22) 425*8e33eff8Schristos BT_FRAME(23) 426*8e33eff8Schristos BT_FRAME(24) 427*8e33eff8Schristos BT_FRAME(25) 428*8e33eff8Schristos BT_FRAME(26) 429*8e33eff8Schristos BT_FRAME(27) 430*8e33eff8Schristos BT_FRAME(28) 431*8e33eff8Schristos BT_FRAME(29) 432*8e33eff8Schristos 433*8e33eff8Schristos BT_FRAME(30) 434*8e33eff8Schristos BT_FRAME(31) 435*8e33eff8Schristos BT_FRAME(32) 436*8e33eff8Schristos BT_FRAME(33) 437*8e33eff8Schristos BT_FRAME(34) 438*8e33eff8Schristos BT_FRAME(35) 439*8e33eff8Schristos BT_FRAME(36) 440*8e33eff8Schristos BT_FRAME(37) 441*8e33eff8Schristos BT_FRAME(38) 442*8e33eff8Schristos BT_FRAME(39) 443*8e33eff8Schristos 444*8e33eff8Schristos BT_FRAME(40) 445*8e33eff8Schristos BT_FRAME(41) 446*8e33eff8Schristos BT_FRAME(42) 447*8e33eff8Schristos BT_FRAME(43) 448*8e33eff8Schristos BT_FRAME(44) 449*8e33eff8Schristos BT_FRAME(45) 450*8e33eff8Schristos BT_FRAME(46) 451*8e33eff8Schristos BT_FRAME(47) 452*8e33eff8Schristos BT_FRAME(48) 453*8e33eff8Schristos BT_FRAME(49) 454*8e33eff8Schristos 455*8e33eff8Schristos BT_FRAME(50) 456*8e33eff8Schristos BT_FRAME(51) 457*8e33eff8Schristos BT_FRAME(52) 458*8e33eff8Schristos BT_FRAME(53) 459*8e33eff8Schristos BT_FRAME(54) 460*8e33eff8Schristos BT_FRAME(55) 461*8e33eff8Schristos BT_FRAME(56) 462*8e33eff8Schristos BT_FRAME(57) 463*8e33eff8Schristos BT_FRAME(58) 464*8e33eff8Schristos BT_FRAME(59) 465*8e33eff8Schristos 466*8e33eff8Schristos BT_FRAME(60) 467*8e33eff8Schristos BT_FRAME(61) 468*8e33eff8Schristos BT_FRAME(62) 469*8e33eff8Schristos BT_FRAME(63) 470*8e33eff8Schristos BT_FRAME(64) 471*8e33eff8Schristos BT_FRAME(65) 472*8e33eff8Schristos BT_FRAME(66) 473*8e33eff8Schristos BT_FRAME(67) 474*8e33eff8Schristos BT_FRAME(68) 475*8e33eff8Schristos BT_FRAME(69) 476*8e33eff8Schristos 477*8e33eff8Schristos BT_FRAME(70) 478*8e33eff8Schristos BT_FRAME(71) 479*8e33eff8Schristos BT_FRAME(72) 480*8e33eff8Schristos BT_FRAME(73) 481*8e33eff8Schristos BT_FRAME(74) 482*8e33eff8Schristos BT_FRAME(75) 483*8e33eff8Schristos BT_FRAME(76) 484*8e33eff8Schristos BT_FRAME(77) 485*8e33eff8Schristos BT_FRAME(78) 486*8e33eff8Schristos BT_FRAME(79) 487*8e33eff8Schristos 488*8e33eff8Schristos BT_FRAME(80) 489*8e33eff8Schristos BT_FRAME(81) 490*8e33eff8Schristos BT_FRAME(82) 491*8e33eff8Schristos BT_FRAME(83) 492*8e33eff8Schristos BT_FRAME(84) 493*8e33eff8Schristos BT_FRAME(85) 494*8e33eff8Schristos BT_FRAME(86) 495*8e33eff8Schristos BT_FRAME(87) 496*8e33eff8Schristos BT_FRAME(88) 497*8e33eff8Schristos BT_FRAME(89) 498*8e33eff8Schristos 499*8e33eff8Schristos BT_FRAME(90) 500*8e33eff8Schristos BT_FRAME(91) 501*8e33eff8Schristos BT_FRAME(92) 502*8e33eff8Schristos BT_FRAME(93) 503*8e33eff8Schristos BT_FRAME(94) 504*8e33eff8Schristos BT_FRAME(95) 505*8e33eff8Schristos BT_FRAME(96) 506*8e33eff8Schristos BT_FRAME(97) 507*8e33eff8Schristos BT_FRAME(98) 508*8e33eff8Schristos BT_FRAME(99) 509*8e33eff8Schristos 510*8e33eff8Schristos BT_FRAME(100) 511*8e33eff8Schristos BT_FRAME(101) 512*8e33eff8Schristos BT_FRAME(102) 513*8e33eff8Schristos BT_FRAME(103) 514*8e33eff8Schristos BT_FRAME(104) 515*8e33eff8Schristos BT_FRAME(105) 516*8e33eff8Schristos BT_FRAME(106) 517*8e33eff8Schristos BT_FRAME(107) 518*8e33eff8Schristos BT_FRAME(108) 519*8e33eff8Schristos BT_FRAME(109) 520*8e33eff8Schristos 521*8e33eff8Schristos BT_FRAME(110) 522*8e33eff8Schristos BT_FRAME(111) 523*8e33eff8Schristos BT_FRAME(112) 524*8e33eff8Schristos BT_FRAME(113) 525*8e33eff8Schristos BT_FRAME(114) 526*8e33eff8Schristos BT_FRAME(115) 527*8e33eff8Schristos BT_FRAME(116) 528*8e33eff8Schristos BT_FRAME(117) 529*8e33eff8Schristos BT_FRAME(118) 530*8e33eff8Schristos BT_FRAME(119) 531*8e33eff8Schristos 532*8e33eff8Schristos BT_FRAME(120) 533*8e33eff8Schristos BT_FRAME(121) 534*8e33eff8Schristos BT_FRAME(122) 535*8e33eff8Schristos BT_FRAME(123) 536*8e33eff8Schristos BT_FRAME(124) 537*8e33eff8Schristos BT_FRAME(125) 538*8e33eff8Schristos BT_FRAME(126) 539*8e33eff8Schristos BT_FRAME(127) 540*8e33eff8Schristos #undef BT_FRAME 541*8e33eff8Schristos } 542*8e33eff8Schristos #else 543*8e33eff8Schristos JEMALLOC_NORETURN void 544*8e33eff8Schristos prof_backtrace(prof_bt_t *bt) { 545*8e33eff8Schristos cassert(config_prof); 546*8e33eff8Schristos not_reached(); 547*8e33eff8Schristos } 548*8e33eff8Schristos #endif 549*8e33eff8Schristos 550*8e33eff8Schristos #ifdef JEMALLOC_PROF 551*8e33eff8Schristos static malloc_mutex_t * 552*8e33eff8Schristos prof_gctx_mutex_choose(void) { 553*8e33eff8Schristos unsigned ngctxs = atomic_fetch_add_u(&cum_gctxs, 1, ATOMIC_RELAXED); 554*8e33eff8Schristos 555*8e33eff8Schristos return &gctx_locks[(ngctxs - 1) % PROF_NCTX_LOCKS]; 556*8e33eff8Schristos } 557*8e33eff8Schristos 558*8e33eff8Schristos static malloc_mutex_t * 559*8e33eff8Schristos prof_tdata_mutex_choose(uint64_t thr_uid) { 560*8e33eff8Schristos return &tdata_locks[thr_uid % PROF_NTDATA_LOCKS]; 561*8e33eff8Schristos } 562*8e33eff8Schristos 563*8e33eff8Schristos static prof_gctx_t * 564*8e33eff8Schristos prof_gctx_create(tsdn_t *tsdn, prof_bt_t *bt) { 565*8e33eff8Schristos /* 566*8e33eff8Schristos * Create a single allocation that has space for vec of length bt->len. 567*8e33eff8Schristos */ 568*8e33eff8Schristos size_t size = offsetof(prof_gctx_t, vec) + (bt->len * sizeof(void *)); 569*8e33eff8Schristos prof_gctx_t *gctx = (prof_gctx_t *)iallocztm(tsdn, size, 570*8e33eff8Schristos sz_size2index(size), false, NULL, true, arena_get(TSDN_NULL, 0, true), 571*8e33eff8Schristos true); 572*8e33eff8Schristos if (gctx == NULL) { 573*8e33eff8Schristos return NULL; 574*8e33eff8Schristos } 575*8e33eff8Schristos gctx->lock = prof_gctx_mutex_choose(); 576*8e33eff8Schristos /* 577*8e33eff8Schristos * Set nlimbo to 1, in order to avoid a race condition with 578*8e33eff8Schristos * prof_tctx_destroy()/prof_gctx_try_destroy(). 579*8e33eff8Schristos */ 580*8e33eff8Schristos gctx->nlimbo = 1; 581*8e33eff8Schristos tctx_tree_new(&gctx->tctxs); 582*8e33eff8Schristos /* Duplicate bt. */ 583*8e33eff8Schristos memcpy(gctx->vec, bt->vec, bt->len * sizeof(void *)); 584*8e33eff8Schristos gctx->bt.vec = gctx->vec; 585*8e33eff8Schristos gctx->bt.len = bt->len; 586*8e33eff8Schristos return gctx; 587*8e33eff8Schristos } 588*8e33eff8Schristos #endif 589*8e33eff8Schristos 590*8e33eff8Schristos static JEMALLOC_PROF_NORETURN void 591*8e33eff8Schristos prof_gctx_try_destroy(tsd_t *tsd, prof_tdata_t *tdata_self, prof_gctx_t *gctx, 592*8e33eff8Schristos prof_tdata_t *tdata) { 593*8e33eff8Schristos cassert(config_prof); 594*8e33eff8Schristos 595*8e33eff8Schristos /* 596*8e33eff8Schristos * Check that gctx is still unused by any thread cache before destroying 597*8e33eff8Schristos * it. prof_lookup() increments gctx->nlimbo in order to avoid a race 598*8e33eff8Schristos * condition with this function, as does prof_tctx_destroy() in order to 599*8e33eff8Schristos * avoid a race between the main body of prof_tctx_destroy() and entry 600*8e33eff8Schristos * into this function. 601*8e33eff8Schristos */ 602*8e33eff8Schristos prof_enter(tsd, tdata_self); 603*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); 604*8e33eff8Schristos assert(gctx->nlimbo != 0); 605*8e33eff8Schristos if (tctx_tree_empty(&gctx->tctxs) && gctx->nlimbo == 1) { 606*8e33eff8Schristos /* Remove gctx from bt2gctx. */ 607*8e33eff8Schristos if (ckh_remove(tsd, &bt2gctx, &gctx->bt, NULL, NULL)) { 608*8e33eff8Schristos not_reached(); 609*8e33eff8Schristos } 610*8e33eff8Schristos prof_leave(tsd, tdata_self); 611*8e33eff8Schristos /* Destroy gctx. */ 612*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); 613*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), gctx, NULL, NULL, true, true); 614*8e33eff8Schristos } else { 615*8e33eff8Schristos /* 616*8e33eff8Schristos * Compensate for increment in prof_tctx_destroy() or 617*8e33eff8Schristos * prof_lookup(). 618*8e33eff8Schristos */ 619*8e33eff8Schristos gctx->nlimbo--; 620*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); 621*8e33eff8Schristos prof_leave(tsd, tdata_self); 622*8e33eff8Schristos } 623*8e33eff8Schristos } 624*8e33eff8Schristos 625*8e33eff8Schristos static bool 626*8e33eff8Schristos prof_tctx_should_destroy(tsdn_t *tsdn, prof_tctx_t *tctx) { 627*8e33eff8Schristos malloc_mutex_assert_owner(tsdn, tctx->tdata->lock); 628*8e33eff8Schristos 629*8e33eff8Schristos if (opt_prof_accum) { 630*8e33eff8Schristos return false; 631*8e33eff8Schristos } 632*8e33eff8Schristos if (tctx->cnts.curobjs != 0) { 633*8e33eff8Schristos return false; 634*8e33eff8Schristos } 635*8e33eff8Schristos if (tctx->prepared) { 636*8e33eff8Schristos return false; 637*8e33eff8Schristos } 638*8e33eff8Schristos return true; 639*8e33eff8Schristos } 640*8e33eff8Schristos 641*8e33eff8Schristos static bool 642*8e33eff8Schristos prof_gctx_should_destroy(prof_gctx_t *gctx) { 643*8e33eff8Schristos if (opt_prof_accum) { 644*8e33eff8Schristos return false; 645*8e33eff8Schristos } 646*8e33eff8Schristos if (!tctx_tree_empty(&gctx->tctxs)) { 647*8e33eff8Schristos return false; 648*8e33eff8Schristos } 649*8e33eff8Schristos if (gctx->nlimbo != 0) { 650*8e33eff8Schristos return false; 651*8e33eff8Schristos } 652*8e33eff8Schristos return true; 653*8e33eff8Schristos } 654*8e33eff8Schristos 655*8e33eff8Schristos static void 656*8e33eff8Schristos prof_tctx_destroy(tsd_t *tsd, prof_tctx_t *tctx) { 657*8e33eff8Schristos prof_tdata_t *tdata = tctx->tdata; 658*8e33eff8Schristos prof_gctx_t *gctx = tctx->gctx; 659*8e33eff8Schristos bool destroy_tdata, destroy_tctx, destroy_gctx; 660*8e33eff8Schristos 661*8e33eff8Schristos malloc_mutex_assert_owner(tsd_tsdn(tsd), tctx->tdata->lock); 662*8e33eff8Schristos 663*8e33eff8Schristos assert(tctx->cnts.curobjs == 0); 664*8e33eff8Schristos assert(tctx->cnts.curbytes == 0); 665*8e33eff8Schristos assert(!opt_prof_accum); 666*8e33eff8Schristos assert(tctx->cnts.accumobjs == 0); 667*8e33eff8Schristos assert(tctx->cnts.accumbytes == 0); 668*8e33eff8Schristos 669*8e33eff8Schristos ckh_remove(tsd, &tdata->bt2tctx, &gctx->bt, NULL, NULL); 670*8e33eff8Schristos destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd), tdata, false); 671*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); 672*8e33eff8Schristos 673*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); 674*8e33eff8Schristos switch (tctx->state) { 675*8e33eff8Schristos case prof_tctx_state_nominal: 676*8e33eff8Schristos tctx_tree_remove(&gctx->tctxs, tctx); 677*8e33eff8Schristos destroy_tctx = true; 678*8e33eff8Schristos if (prof_gctx_should_destroy(gctx)) { 679*8e33eff8Schristos /* 680*8e33eff8Schristos * Increment gctx->nlimbo in order to keep another 681*8e33eff8Schristos * thread from winning the race to destroy gctx while 682*8e33eff8Schristos * this one has gctx->lock dropped. Without this, it 683*8e33eff8Schristos * would be possible for another thread to: 684*8e33eff8Schristos * 685*8e33eff8Schristos * 1) Sample an allocation associated with gctx. 686*8e33eff8Schristos * 2) Deallocate the sampled object. 687*8e33eff8Schristos * 3) Successfully prof_gctx_try_destroy(gctx). 688*8e33eff8Schristos * 689*8e33eff8Schristos * The result would be that gctx no longer exists by the 690*8e33eff8Schristos * time this thread accesses it in 691*8e33eff8Schristos * prof_gctx_try_destroy(). 692*8e33eff8Schristos */ 693*8e33eff8Schristos gctx->nlimbo++; 694*8e33eff8Schristos destroy_gctx = true; 695*8e33eff8Schristos } else { 696*8e33eff8Schristos destroy_gctx = false; 697*8e33eff8Schristos } 698*8e33eff8Schristos break; 699*8e33eff8Schristos case prof_tctx_state_dumping: 700*8e33eff8Schristos /* 701*8e33eff8Schristos * A dumping thread needs tctx to remain valid until dumping 702*8e33eff8Schristos * has finished. Change state such that the dumping thread will 703*8e33eff8Schristos * complete destruction during a late dump iteration phase. 704*8e33eff8Schristos */ 705*8e33eff8Schristos tctx->state = prof_tctx_state_purgatory; 706*8e33eff8Schristos destroy_tctx = false; 707*8e33eff8Schristos destroy_gctx = false; 708*8e33eff8Schristos break; 709*8e33eff8Schristos default: 710*8e33eff8Schristos not_reached(); 711*8e33eff8Schristos destroy_tctx = false; 712*8e33eff8Schristos destroy_gctx = false; 713*8e33eff8Schristos } 714*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); 715*8e33eff8Schristos if (destroy_gctx) { 716*8e33eff8Schristos prof_gctx_try_destroy(tsd, prof_tdata_get(tsd, false), gctx, 717*8e33eff8Schristos tdata); 718*8e33eff8Schristos } 719*8e33eff8Schristos 720*8e33eff8Schristos malloc_mutex_assert_not_owner(tsd_tsdn(tsd), tctx->tdata->lock); 721*8e33eff8Schristos 722*8e33eff8Schristos if (destroy_tdata) { 723*8e33eff8Schristos prof_tdata_destroy(tsd, tdata, false); 724*8e33eff8Schristos } 725*8e33eff8Schristos 726*8e33eff8Schristos if (destroy_tctx) { 727*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), tctx, NULL, NULL, true, true); 728*8e33eff8Schristos } 729*8e33eff8Schristos } 730*8e33eff8Schristos 731*8e33eff8Schristos #ifdef JEMALLOC_PROF 732*8e33eff8Schristos static bool 733*8e33eff8Schristos prof_lookup_global(tsd_t *tsd, prof_bt_t *bt, prof_tdata_t *tdata, 734*8e33eff8Schristos void **p_btkey, prof_gctx_t **p_gctx, bool *p_new_gctx) { 735*8e33eff8Schristos union { 736*8e33eff8Schristos prof_gctx_t *p; 737*8e33eff8Schristos void *v; 738*8e33eff8Schristos } gctx, tgctx; 739*8e33eff8Schristos union { 740*8e33eff8Schristos prof_bt_t *p; 741*8e33eff8Schristos void *v; 742*8e33eff8Schristos } btkey; 743*8e33eff8Schristos bool new_gctx; 744*8e33eff8Schristos 745*8e33eff8Schristos prof_enter(tsd, tdata); 746*8e33eff8Schristos if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) { 747*8e33eff8Schristos /* bt has never been seen before. Insert it. */ 748*8e33eff8Schristos prof_leave(tsd, tdata); 749*8e33eff8Schristos tgctx.p = prof_gctx_create(tsd_tsdn(tsd), bt); 750*8e33eff8Schristos if (tgctx.v == NULL) { 751*8e33eff8Schristos return true; 752*8e33eff8Schristos } 753*8e33eff8Schristos prof_enter(tsd, tdata); 754*8e33eff8Schristos if (ckh_search(&bt2gctx, bt, &btkey.v, &gctx.v)) { 755*8e33eff8Schristos gctx.p = tgctx.p; 756*8e33eff8Schristos btkey.p = &gctx.p->bt; 757*8e33eff8Schristos if (ckh_insert(tsd, &bt2gctx, btkey.v, gctx.v)) { 758*8e33eff8Schristos /* OOM. */ 759*8e33eff8Schristos prof_leave(tsd, tdata); 760*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), gctx.v, NULL, NULL, 761*8e33eff8Schristos true, true); 762*8e33eff8Schristos return true; 763*8e33eff8Schristos } 764*8e33eff8Schristos new_gctx = true; 765*8e33eff8Schristos } else { 766*8e33eff8Schristos new_gctx = false; 767*8e33eff8Schristos } 768*8e33eff8Schristos } else { 769*8e33eff8Schristos tgctx.v = NULL; 770*8e33eff8Schristos new_gctx = false; 771*8e33eff8Schristos } 772*8e33eff8Schristos 773*8e33eff8Schristos if (!new_gctx) { 774*8e33eff8Schristos /* 775*8e33eff8Schristos * Increment nlimbo, in order to avoid a race condition with 776*8e33eff8Schristos * prof_tctx_destroy()/prof_gctx_try_destroy(). 777*8e33eff8Schristos */ 778*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), gctx.p->lock); 779*8e33eff8Schristos gctx.p->nlimbo++; 780*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), gctx.p->lock); 781*8e33eff8Schristos new_gctx = false; 782*8e33eff8Schristos 783*8e33eff8Schristos if (tgctx.v != NULL) { 784*8e33eff8Schristos /* Lost race to insert. */ 785*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), tgctx.v, NULL, NULL, true, 786*8e33eff8Schristos true); 787*8e33eff8Schristos } 788*8e33eff8Schristos } 789*8e33eff8Schristos prof_leave(tsd, tdata); 790*8e33eff8Schristos 791*8e33eff8Schristos *p_btkey = btkey.v; 792*8e33eff8Schristos *p_gctx = gctx.p; 793*8e33eff8Schristos *p_new_gctx = new_gctx; 794*8e33eff8Schristos return false; 795*8e33eff8Schristos } 796*8e33eff8Schristos #endif 797*8e33eff8Schristos 798*8e33eff8Schristos JEMALLOC_PROF_NORETURN prof_tctx_t * 799*8e33eff8Schristos prof_lookup(tsd_t *tsd, prof_bt_t *bt) { 800*8e33eff8Schristos cassert(config_prof); 801*8e33eff8Schristos #ifdef JEMALLOC_PROF 802*8e33eff8Schristos union { 803*8e33eff8Schristos prof_tctx_t *p; 804*8e33eff8Schristos void *v; 805*8e33eff8Schristos } ret; 806*8e33eff8Schristos prof_tdata_t *tdata; 807*8e33eff8Schristos bool not_found; 808*8e33eff8Schristos 809*8e33eff8Schristos tdata = prof_tdata_get(tsd, false); 810*8e33eff8Schristos if (tdata == NULL) { 811*8e33eff8Schristos return NULL; 812*8e33eff8Schristos } 813*8e33eff8Schristos 814*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock); 815*8e33eff8Schristos not_found = ckh_search(&tdata->bt2tctx, bt, NULL, &ret.v); 816*8e33eff8Schristos if (!not_found) { /* Note double negative! */ 817*8e33eff8Schristos ret.p->prepared = true; 818*8e33eff8Schristos } 819*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); 820*8e33eff8Schristos if (not_found) { 821*8e33eff8Schristos void *btkey; 822*8e33eff8Schristos prof_gctx_t *gctx; 823*8e33eff8Schristos bool new_gctx, error; 824*8e33eff8Schristos 825*8e33eff8Schristos /* 826*8e33eff8Schristos * This thread's cache lacks bt. Look for it in the global 827*8e33eff8Schristos * cache. 828*8e33eff8Schristos */ 829*8e33eff8Schristos if (prof_lookup_global(tsd, bt, tdata, &btkey, &gctx, 830*8e33eff8Schristos &new_gctx)) { 831*8e33eff8Schristos return NULL; 832*8e33eff8Schristos } 833*8e33eff8Schristos 834*8e33eff8Schristos /* Link a prof_tctx_t into gctx for this thread. */ 835*8e33eff8Schristos ret.v = iallocztm(tsd_tsdn(tsd), sizeof(prof_tctx_t), 836*8e33eff8Schristos sz_size2index(sizeof(prof_tctx_t)), false, NULL, true, 837*8e33eff8Schristos arena_ichoose(tsd, NULL), true); 838*8e33eff8Schristos if (ret.p == NULL) { 839*8e33eff8Schristos if (new_gctx) { 840*8e33eff8Schristos prof_gctx_try_destroy(tsd, tdata, gctx, tdata); 841*8e33eff8Schristos } 842*8e33eff8Schristos return NULL; 843*8e33eff8Schristos } 844*8e33eff8Schristos ret.p->tdata = tdata; 845*8e33eff8Schristos ret.p->thr_uid = tdata->thr_uid; 846*8e33eff8Schristos ret.p->thr_discrim = tdata->thr_discrim; 847*8e33eff8Schristos memset(&ret.p->cnts, 0, sizeof(prof_cnt_t)); 848*8e33eff8Schristos ret.p->gctx = gctx; 849*8e33eff8Schristos ret.p->tctx_uid = tdata->tctx_uid_next++; 850*8e33eff8Schristos ret.p->prepared = true; 851*8e33eff8Schristos ret.p->state = prof_tctx_state_initializing; 852*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock); 853*8e33eff8Schristos error = ckh_insert(tsd, &tdata->bt2tctx, btkey, ret.v); 854*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); 855*8e33eff8Schristos if (error) { 856*8e33eff8Schristos if (new_gctx) { 857*8e33eff8Schristos prof_gctx_try_destroy(tsd, tdata, gctx, tdata); 858*8e33eff8Schristos } 859*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), ret.v, NULL, NULL, true, true); 860*8e33eff8Schristos return NULL; 861*8e33eff8Schristos } 862*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); 863*8e33eff8Schristos ret.p->state = prof_tctx_state_nominal; 864*8e33eff8Schristos tctx_tree_insert(&gctx->tctxs, ret.p); 865*8e33eff8Schristos gctx->nlimbo--; 866*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); 867*8e33eff8Schristos } 868*8e33eff8Schristos 869*8e33eff8Schristos return ret.p; 870*8e33eff8Schristos #endif 871*8e33eff8Schristos } 872*8e33eff8Schristos 873*8e33eff8Schristos /* 874*8e33eff8Schristos * The bodies of this function and prof_leakcheck() are compiled out unless heap 875*8e33eff8Schristos * profiling is enabled, so that it is possible to compile jemalloc with 876*8e33eff8Schristos * floating point support completely disabled. Avoiding floating point code is 877*8e33eff8Schristos * important on memory-constrained systems, but it also enables a workaround for 878*8e33eff8Schristos * versions of glibc that don't properly save/restore floating point registers 879*8e33eff8Schristos * during dynamic lazy symbol loading (which internally calls into whatever 880*8e33eff8Schristos * malloc implementation happens to be integrated into the application). Note 881*8e33eff8Schristos * that some compilers (e.g. gcc 4.8) may use floating point registers for fast 882*8e33eff8Schristos * memory moves, so jemalloc must be compiled with such optimizations disabled 883*8e33eff8Schristos * (e.g. 884*8e33eff8Schristos * -mno-sse) in order for the workaround to be complete. 885*8e33eff8Schristos */ 886*8e33eff8Schristos void 887*8e33eff8Schristos prof_sample_threshold_update(prof_tdata_t *tdata) { 888*8e33eff8Schristos #ifdef JEMALLOC_PROF 889*8e33eff8Schristos uint64_t r; 890*8e33eff8Schristos double u; 891*8e33eff8Schristos 892*8e33eff8Schristos if (!config_prof) { 893*8e33eff8Schristos return; 894*8e33eff8Schristos } 895*8e33eff8Schristos 896*8e33eff8Schristos if (lg_prof_sample == 0) { 897*8e33eff8Schristos tdata->bytes_until_sample = 0; 898*8e33eff8Schristos return; 899*8e33eff8Schristos } 900*8e33eff8Schristos 901*8e33eff8Schristos /* 902*8e33eff8Schristos * Compute sample interval as a geometrically distributed random 903*8e33eff8Schristos * variable with mean (2^lg_prof_sample). 904*8e33eff8Schristos * 905*8e33eff8Schristos * __ __ 906*8e33eff8Schristos * | log(u) | 1 907*8e33eff8Schristos * tdata->bytes_until_sample = | -------- |, where p = --------------- 908*8e33eff8Schristos * | log(1-p) | lg_prof_sample 909*8e33eff8Schristos * 2 910*8e33eff8Schristos * 911*8e33eff8Schristos * For more information on the math, see: 912*8e33eff8Schristos * 913*8e33eff8Schristos * Non-Uniform Random Variate Generation 914*8e33eff8Schristos * Luc Devroye 915*8e33eff8Schristos * Springer-Verlag, New York, 1986 916*8e33eff8Schristos * pp 500 917*8e33eff8Schristos * (http://luc.devroye.org/rnbookindex.html) 918*8e33eff8Schristos */ 919*8e33eff8Schristos r = prng_lg_range_u64(&tdata->prng_state, 53); 920*8e33eff8Schristos u = (double)r * (1.0/9007199254740992.0L); 921*8e33eff8Schristos tdata->bytes_until_sample = (uint64_t)(log(u) / 922*8e33eff8Schristos log(1.0 - (1.0 / (double)((uint64_t)1U << lg_prof_sample)))) 923*8e33eff8Schristos + (uint64_t)1U; 924*8e33eff8Schristos #endif 925*8e33eff8Schristos } 926*8e33eff8Schristos 927*8e33eff8Schristos #ifdef JEMALLOC_JET 928*8e33eff8Schristos static prof_tdata_t * 929*8e33eff8Schristos prof_tdata_count_iter(prof_tdata_tree_t *tdatas, prof_tdata_t *tdata, 930*8e33eff8Schristos void *arg) { 931*8e33eff8Schristos size_t *tdata_count = (size_t *)arg; 932*8e33eff8Schristos 933*8e33eff8Schristos (*tdata_count)++; 934*8e33eff8Schristos 935*8e33eff8Schristos return NULL; 936*8e33eff8Schristos } 937*8e33eff8Schristos 938*8e33eff8Schristos size_t 939*8e33eff8Schristos prof_tdata_count(void) { 940*8e33eff8Schristos size_t tdata_count = 0; 941*8e33eff8Schristos tsdn_t *tsdn; 942*8e33eff8Schristos 943*8e33eff8Schristos tsdn = tsdn_fetch(); 944*8e33eff8Schristos malloc_mutex_lock(tsdn, &tdatas_mtx); 945*8e33eff8Schristos tdata_tree_iter(&tdatas, NULL, prof_tdata_count_iter, 946*8e33eff8Schristos (void *)&tdata_count); 947*8e33eff8Schristos malloc_mutex_unlock(tsdn, &tdatas_mtx); 948*8e33eff8Schristos 949*8e33eff8Schristos return tdata_count; 950*8e33eff8Schristos } 951*8e33eff8Schristos 952*8e33eff8Schristos size_t 953*8e33eff8Schristos prof_bt_count(void) { 954*8e33eff8Schristos size_t bt_count; 955*8e33eff8Schristos tsd_t *tsd; 956*8e33eff8Schristos prof_tdata_t *tdata; 957*8e33eff8Schristos 958*8e33eff8Schristos tsd = tsd_fetch(); 959*8e33eff8Schristos tdata = prof_tdata_get(tsd, false); 960*8e33eff8Schristos if (tdata == NULL) { 961*8e33eff8Schristos return 0; 962*8e33eff8Schristos } 963*8e33eff8Schristos 964*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &bt2gctx_mtx); 965*8e33eff8Schristos bt_count = ckh_count(&bt2gctx); 966*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &bt2gctx_mtx); 967*8e33eff8Schristos 968*8e33eff8Schristos return bt_count; 969*8e33eff8Schristos } 970*8e33eff8Schristos #endif 971*8e33eff8Schristos 972*8e33eff8Schristos static int 973*8e33eff8Schristos prof_dump_open_impl(bool propagate_err, const char *filename) { 974*8e33eff8Schristos int fd; 975*8e33eff8Schristos 976*8e33eff8Schristos fd = creat(filename, 0644); 977*8e33eff8Schristos if (fd == -1 && !propagate_err) { 978*8e33eff8Schristos malloc_printf("<jemalloc>: creat(\"%s\"), 0644) failed\n", 979*8e33eff8Schristos filename); 980*8e33eff8Schristos if (opt_abort) { 981*8e33eff8Schristos abort(); 982*8e33eff8Schristos } 983*8e33eff8Schristos } 984*8e33eff8Schristos 985*8e33eff8Schristos return fd; 986*8e33eff8Schristos } 987*8e33eff8Schristos prof_dump_open_t *JET_MUTABLE prof_dump_open = prof_dump_open_impl; 988*8e33eff8Schristos 989*8e33eff8Schristos static bool 990*8e33eff8Schristos prof_dump_flush(bool propagate_err) { 991*8e33eff8Schristos bool ret = false; 992*8e33eff8Schristos ssize_t err; 993*8e33eff8Schristos 994*8e33eff8Schristos cassert(config_prof); 995*8e33eff8Schristos 996*8e33eff8Schristos err = malloc_write_fd(prof_dump_fd, prof_dump_buf, prof_dump_buf_end); 997*8e33eff8Schristos if (err == -1) { 998*8e33eff8Schristos if (!propagate_err) { 999*8e33eff8Schristos malloc_write("<jemalloc>: write() failed during heap " 1000*8e33eff8Schristos "profile flush\n"); 1001*8e33eff8Schristos if (opt_abort) { 1002*8e33eff8Schristos abort(); 1003*8e33eff8Schristos } 1004*8e33eff8Schristos } 1005*8e33eff8Schristos ret = true; 1006*8e33eff8Schristos } 1007*8e33eff8Schristos prof_dump_buf_end = 0; 1008*8e33eff8Schristos 1009*8e33eff8Schristos return ret; 1010*8e33eff8Schristos } 1011*8e33eff8Schristos 1012*8e33eff8Schristos #ifdef JEMALLOC_PROF 1013*8e33eff8Schristos static bool 1014*8e33eff8Schristos prof_dump_close(bool propagate_err) { 1015*8e33eff8Schristos bool ret; 1016*8e33eff8Schristos 1017*8e33eff8Schristos assert(prof_dump_fd != -1); 1018*8e33eff8Schristos ret = prof_dump_flush(propagate_err); 1019*8e33eff8Schristos close(prof_dump_fd); 1020*8e33eff8Schristos prof_dump_fd = -1; 1021*8e33eff8Schristos 1022*8e33eff8Schristos return ret; 1023*8e33eff8Schristos } 1024*8e33eff8Schristos #endif 1025*8e33eff8Schristos 1026*8e33eff8Schristos static bool 1027*8e33eff8Schristos prof_dump_write(bool propagate_err, const char *s) { 1028*8e33eff8Schristos size_t i, slen, n; 1029*8e33eff8Schristos 1030*8e33eff8Schristos cassert(config_prof); 1031*8e33eff8Schristos 1032*8e33eff8Schristos i = 0; 1033*8e33eff8Schristos slen = strlen(s); 1034*8e33eff8Schristos while (i < slen) { 1035*8e33eff8Schristos /* Flush the buffer if it is full. */ 1036*8e33eff8Schristos if (prof_dump_buf_end == PROF_DUMP_BUFSIZE) { 1037*8e33eff8Schristos if (prof_dump_flush(propagate_err) && propagate_err) { 1038*8e33eff8Schristos return true; 1039*8e33eff8Schristos } 1040*8e33eff8Schristos } 1041*8e33eff8Schristos 1042*8e33eff8Schristos if (prof_dump_buf_end + slen <= PROF_DUMP_BUFSIZE) { 1043*8e33eff8Schristos /* Finish writing. */ 1044*8e33eff8Schristos n = slen - i; 1045*8e33eff8Schristos } else { 1046*8e33eff8Schristos /* Write as much of s as will fit. */ 1047*8e33eff8Schristos n = PROF_DUMP_BUFSIZE - prof_dump_buf_end; 1048*8e33eff8Schristos } 1049*8e33eff8Schristos memcpy(&prof_dump_buf[prof_dump_buf_end], &s[i], n); 1050*8e33eff8Schristos prof_dump_buf_end += n; 1051*8e33eff8Schristos i += n; 1052*8e33eff8Schristos } 1053*8e33eff8Schristos 1054*8e33eff8Schristos return false; 1055*8e33eff8Schristos } 1056*8e33eff8Schristos 1057*8e33eff8Schristos JEMALLOC_FORMAT_PRINTF(2, 3) 1058*8e33eff8Schristos static bool 1059*8e33eff8Schristos prof_dump_printf(bool propagate_err, const char *format, ...) { 1060*8e33eff8Schristos bool ret; 1061*8e33eff8Schristos va_list ap; 1062*8e33eff8Schristos char buf[PROF_PRINTF_BUFSIZE]; 1063*8e33eff8Schristos 1064*8e33eff8Schristos va_start(ap, format); 1065*8e33eff8Schristos malloc_vsnprintf(buf, sizeof(buf), format, ap); 1066*8e33eff8Schristos va_end(ap); 1067*8e33eff8Schristos ret = prof_dump_write(propagate_err, buf); 1068*8e33eff8Schristos 1069*8e33eff8Schristos return ret; 1070*8e33eff8Schristos } 1071*8e33eff8Schristos 1072*8e33eff8Schristos #ifdef JEMALLOC_PROF 1073*8e33eff8Schristos static void 1074*8e33eff8Schristos prof_tctx_merge_tdata(tsdn_t *tsdn, prof_tctx_t *tctx, prof_tdata_t *tdata) { 1075*8e33eff8Schristos malloc_mutex_assert_owner(tsdn, tctx->tdata->lock); 1076*8e33eff8Schristos 1077*8e33eff8Schristos malloc_mutex_lock(tsdn, tctx->gctx->lock); 1078*8e33eff8Schristos 1079*8e33eff8Schristos switch (tctx->state) { 1080*8e33eff8Schristos case prof_tctx_state_initializing: 1081*8e33eff8Schristos malloc_mutex_unlock(tsdn, tctx->gctx->lock); 1082*8e33eff8Schristos return; 1083*8e33eff8Schristos case prof_tctx_state_nominal: 1084*8e33eff8Schristos tctx->state = prof_tctx_state_dumping; 1085*8e33eff8Schristos malloc_mutex_unlock(tsdn, tctx->gctx->lock); 1086*8e33eff8Schristos 1087*8e33eff8Schristos memcpy(&tctx->dump_cnts, &tctx->cnts, sizeof(prof_cnt_t)); 1088*8e33eff8Schristos 1089*8e33eff8Schristos tdata->cnt_summed.curobjs += tctx->dump_cnts.curobjs; 1090*8e33eff8Schristos tdata->cnt_summed.curbytes += tctx->dump_cnts.curbytes; 1091*8e33eff8Schristos if (opt_prof_accum) { 1092*8e33eff8Schristos tdata->cnt_summed.accumobjs += 1093*8e33eff8Schristos tctx->dump_cnts.accumobjs; 1094*8e33eff8Schristos tdata->cnt_summed.accumbytes += 1095*8e33eff8Schristos tctx->dump_cnts.accumbytes; 1096*8e33eff8Schristos } 1097*8e33eff8Schristos break; 1098*8e33eff8Schristos case prof_tctx_state_dumping: 1099*8e33eff8Schristos case prof_tctx_state_purgatory: 1100*8e33eff8Schristos not_reached(); 1101*8e33eff8Schristos } 1102*8e33eff8Schristos } 1103*8e33eff8Schristos 1104*8e33eff8Schristos static void 1105*8e33eff8Schristos prof_tctx_merge_gctx(tsdn_t *tsdn, prof_tctx_t *tctx, prof_gctx_t *gctx) { 1106*8e33eff8Schristos malloc_mutex_assert_owner(tsdn, gctx->lock); 1107*8e33eff8Schristos 1108*8e33eff8Schristos gctx->cnt_summed.curobjs += tctx->dump_cnts.curobjs; 1109*8e33eff8Schristos gctx->cnt_summed.curbytes += tctx->dump_cnts.curbytes; 1110*8e33eff8Schristos if (opt_prof_accum) { 1111*8e33eff8Schristos gctx->cnt_summed.accumobjs += tctx->dump_cnts.accumobjs; 1112*8e33eff8Schristos gctx->cnt_summed.accumbytes += tctx->dump_cnts.accumbytes; 1113*8e33eff8Schristos } 1114*8e33eff8Schristos } 1115*8e33eff8Schristos 1116*8e33eff8Schristos static prof_tctx_t * 1117*8e33eff8Schristos prof_tctx_merge_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) { 1118*8e33eff8Schristos tsdn_t *tsdn = (tsdn_t *)arg; 1119*8e33eff8Schristos 1120*8e33eff8Schristos malloc_mutex_assert_owner(tsdn, tctx->gctx->lock); 1121*8e33eff8Schristos 1122*8e33eff8Schristos switch (tctx->state) { 1123*8e33eff8Schristos case prof_tctx_state_nominal: 1124*8e33eff8Schristos /* New since dumping started; ignore. */ 1125*8e33eff8Schristos break; 1126*8e33eff8Schristos case prof_tctx_state_dumping: 1127*8e33eff8Schristos case prof_tctx_state_purgatory: 1128*8e33eff8Schristos prof_tctx_merge_gctx(tsdn, tctx, tctx->gctx); 1129*8e33eff8Schristos break; 1130*8e33eff8Schristos default: 1131*8e33eff8Schristos not_reached(); 1132*8e33eff8Schristos } 1133*8e33eff8Schristos 1134*8e33eff8Schristos return NULL; 1135*8e33eff8Schristos } 1136*8e33eff8Schristos 1137*8e33eff8Schristos struct prof_tctx_dump_iter_arg_s { 1138*8e33eff8Schristos tsdn_t *tsdn; 1139*8e33eff8Schristos bool propagate_err; 1140*8e33eff8Schristos }; 1141*8e33eff8Schristos 1142*8e33eff8Schristos static prof_tctx_t * 1143*8e33eff8Schristos prof_tctx_dump_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *opaque) { 1144*8e33eff8Schristos struct prof_tctx_dump_iter_arg_s *arg = 1145*8e33eff8Schristos (struct prof_tctx_dump_iter_arg_s *)opaque; 1146*8e33eff8Schristos 1147*8e33eff8Schristos malloc_mutex_assert_owner(arg->tsdn, tctx->gctx->lock); 1148*8e33eff8Schristos 1149*8e33eff8Schristos switch (tctx->state) { 1150*8e33eff8Schristos case prof_tctx_state_initializing: 1151*8e33eff8Schristos case prof_tctx_state_nominal: 1152*8e33eff8Schristos /* Not captured by this dump. */ 1153*8e33eff8Schristos break; 1154*8e33eff8Schristos case prof_tctx_state_dumping: 1155*8e33eff8Schristos case prof_tctx_state_purgatory: 1156*8e33eff8Schristos if (prof_dump_printf(arg->propagate_err, 1157*8e33eff8Schristos " t%"FMTu64": %"FMTu64": %"FMTu64" [%"FMTu64": " 1158*8e33eff8Schristos "%"FMTu64"]\n", tctx->thr_uid, tctx->dump_cnts.curobjs, 1159*8e33eff8Schristos tctx->dump_cnts.curbytes, tctx->dump_cnts.accumobjs, 1160*8e33eff8Schristos tctx->dump_cnts.accumbytes)) { 1161*8e33eff8Schristos return tctx; 1162*8e33eff8Schristos } 1163*8e33eff8Schristos break; 1164*8e33eff8Schristos default: 1165*8e33eff8Schristos not_reached(); 1166*8e33eff8Schristos } 1167*8e33eff8Schristos return NULL; 1168*8e33eff8Schristos } 1169*8e33eff8Schristos 1170*8e33eff8Schristos static prof_tctx_t * 1171*8e33eff8Schristos prof_tctx_finish_iter(prof_tctx_tree_t *tctxs, prof_tctx_t *tctx, void *arg) { 1172*8e33eff8Schristos tsdn_t *tsdn = (tsdn_t *)arg; 1173*8e33eff8Schristos prof_tctx_t *ret; 1174*8e33eff8Schristos 1175*8e33eff8Schristos malloc_mutex_assert_owner(tsdn, tctx->gctx->lock); 1176*8e33eff8Schristos 1177*8e33eff8Schristos switch (tctx->state) { 1178*8e33eff8Schristos case prof_tctx_state_nominal: 1179*8e33eff8Schristos /* New since dumping started; ignore. */ 1180*8e33eff8Schristos break; 1181*8e33eff8Schristos case prof_tctx_state_dumping: 1182*8e33eff8Schristos tctx->state = prof_tctx_state_nominal; 1183*8e33eff8Schristos break; 1184*8e33eff8Schristos case prof_tctx_state_purgatory: 1185*8e33eff8Schristos ret = tctx; 1186*8e33eff8Schristos goto label_return; 1187*8e33eff8Schristos default: 1188*8e33eff8Schristos not_reached(); 1189*8e33eff8Schristos } 1190*8e33eff8Schristos 1191*8e33eff8Schristos ret = NULL; 1192*8e33eff8Schristos label_return: 1193*8e33eff8Schristos return ret; 1194*8e33eff8Schristos } 1195*8e33eff8Schristos 1196*8e33eff8Schristos static void 1197*8e33eff8Schristos prof_dump_gctx_prep(tsdn_t *tsdn, prof_gctx_t *gctx, prof_gctx_tree_t *gctxs) { 1198*8e33eff8Schristos 1199*8e33eff8Schristos malloc_mutex_lock(tsdn, gctx->lock); 1200*8e33eff8Schristos 1201*8e33eff8Schristos /* 1202*8e33eff8Schristos * Increment nlimbo so that gctx won't go away before dump. 1203*8e33eff8Schristos * Additionally, link gctx into the dump list so that it is included in 1204*8e33eff8Schristos * prof_dump()'s second pass. 1205*8e33eff8Schristos */ 1206*8e33eff8Schristos gctx->nlimbo++; 1207*8e33eff8Schristos gctx_tree_insert(gctxs, gctx); 1208*8e33eff8Schristos 1209*8e33eff8Schristos memset(&gctx->cnt_summed, 0, sizeof(prof_cnt_t)); 1210*8e33eff8Schristos 1211*8e33eff8Schristos malloc_mutex_unlock(tsdn, gctx->lock); 1212*8e33eff8Schristos } 1213*8e33eff8Schristos 1214*8e33eff8Schristos struct prof_gctx_merge_iter_arg_s { 1215*8e33eff8Schristos tsdn_t *tsdn; 1216*8e33eff8Schristos size_t leak_ngctx; 1217*8e33eff8Schristos }; 1218*8e33eff8Schristos 1219*8e33eff8Schristos static prof_gctx_t * 1220*8e33eff8Schristos prof_gctx_merge_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) { 1221*8e33eff8Schristos struct prof_gctx_merge_iter_arg_s *arg = 1222*8e33eff8Schristos (struct prof_gctx_merge_iter_arg_s *)opaque; 1223*8e33eff8Schristos 1224*8e33eff8Schristos malloc_mutex_lock(arg->tsdn, gctx->lock); 1225*8e33eff8Schristos tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_merge_iter, 1226*8e33eff8Schristos (void *)arg->tsdn); 1227*8e33eff8Schristos if (gctx->cnt_summed.curobjs != 0) { 1228*8e33eff8Schristos arg->leak_ngctx++; 1229*8e33eff8Schristos } 1230*8e33eff8Schristos malloc_mutex_unlock(arg->tsdn, gctx->lock); 1231*8e33eff8Schristos 1232*8e33eff8Schristos return NULL; 1233*8e33eff8Schristos } 1234*8e33eff8Schristos 1235*8e33eff8Schristos static void 1236*8e33eff8Schristos prof_gctx_finish(tsd_t *tsd, prof_gctx_tree_t *gctxs) { 1237*8e33eff8Schristos prof_tdata_t *tdata = prof_tdata_get(tsd, false); 1238*8e33eff8Schristos prof_gctx_t *gctx; 1239*8e33eff8Schristos 1240*8e33eff8Schristos /* 1241*8e33eff8Schristos * Standard tree iteration won't work here, because as soon as we 1242*8e33eff8Schristos * decrement gctx->nlimbo and unlock gctx, another thread can 1243*8e33eff8Schristos * concurrently destroy it, which will corrupt the tree. Therefore, 1244*8e33eff8Schristos * tear down the tree one node at a time during iteration. 1245*8e33eff8Schristos */ 1246*8e33eff8Schristos while ((gctx = gctx_tree_first(gctxs)) != NULL) { 1247*8e33eff8Schristos gctx_tree_remove(gctxs, gctx); 1248*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), gctx->lock); 1249*8e33eff8Schristos { 1250*8e33eff8Schristos prof_tctx_t *next; 1251*8e33eff8Schristos 1252*8e33eff8Schristos next = NULL; 1253*8e33eff8Schristos do { 1254*8e33eff8Schristos prof_tctx_t *to_destroy = 1255*8e33eff8Schristos tctx_tree_iter(&gctx->tctxs, next, 1256*8e33eff8Schristos prof_tctx_finish_iter, 1257*8e33eff8Schristos (void *)tsd_tsdn(tsd)); 1258*8e33eff8Schristos if (to_destroy != NULL) { 1259*8e33eff8Schristos next = tctx_tree_next(&gctx->tctxs, 1260*8e33eff8Schristos to_destroy); 1261*8e33eff8Schristos tctx_tree_remove(&gctx->tctxs, 1262*8e33eff8Schristos to_destroy); 1263*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), to_destroy, 1264*8e33eff8Schristos NULL, NULL, true, true); 1265*8e33eff8Schristos } else { 1266*8e33eff8Schristos next = NULL; 1267*8e33eff8Schristos } 1268*8e33eff8Schristos } while (next != NULL); 1269*8e33eff8Schristos } 1270*8e33eff8Schristos gctx->nlimbo--; 1271*8e33eff8Schristos if (prof_gctx_should_destroy(gctx)) { 1272*8e33eff8Schristos gctx->nlimbo++; 1273*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); 1274*8e33eff8Schristos prof_gctx_try_destroy(tsd, tdata, gctx, tdata); 1275*8e33eff8Schristos } else { 1276*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), gctx->lock); 1277*8e33eff8Schristos } 1278*8e33eff8Schristos } 1279*8e33eff8Schristos } 1280*8e33eff8Schristos 1281*8e33eff8Schristos struct prof_tdata_merge_iter_arg_s { 1282*8e33eff8Schristos tsdn_t *tsdn; 1283*8e33eff8Schristos prof_cnt_t cnt_all; 1284*8e33eff8Schristos }; 1285*8e33eff8Schristos 1286*8e33eff8Schristos static prof_tdata_t * 1287*8e33eff8Schristos prof_tdata_merge_iter(prof_tdata_tree_t *tdatasunused, prof_tdata_t *tdata, 1288*8e33eff8Schristos void *opaque) { 1289*8e33eff8Schristos struct prof_tdata_merge_iter_arg_s *arg = 1290*8e33eff8Schristos (struct prof_tdata_merge_iter_arg_s *)opaque; 1291*8e33eff8Schristos 1292*8e33eff8Schristos malloc_mutex_lock(arg->tsdn, tdata->lock); 1293*8e33eff8Schristos if (!tdata->expired) { 1294*8e33eff8Schristos size_t tabind; 1295*8e33eff8Schristos union { 1296*8e33eff8Schristos prof_tctx_t *p; 1297*8e33eff8Schristos void *v; 1298*8e33eff8Schristos } tctx; 1299*8e33eff8Schristos 1300*8e33eff8Schristos tdata->dumping = true; 1301*8e33eff8Schristos memset(&tdata->cnt_summed, 0, sizeof(prof_cnt_t)); 1302*8e33eff8Schristos for (tabind = 0; !ckh_iter(&tdata->bt2tctx, &tabind, NULL, 1303*8e33eff8Schristos &tctx.v);) { 1304*8e33eff8Schristos prof_tctx_merge_tdata(arg->tsdn, tctx.p, tdata); 1305*8e33eff8Schristos } 1306*8e33eff8Schristos 1307*8e33eff8Schristos arg->cnt_all.curobjs += tdata->cnt_summed.curobjs; 1308*8e33eff8Schristos arg->cnt_all.curbytes += tdata->cnt_summed.curbytes; 1309*8e33eff8Schristos if (opt_prof_accum) { 1310*8e33eff8Schristos arg->cnt_all.accumobjs += tdata->cnt_summed.accumobjs; 1311*8e33eff8Schristos arg->cnt_all.accumbytes += tdata->cnt_summed.accumbytes; 1312*8e33eff8Schristos } 1313*8e33eff8Schristos } else { 1314*8e33eff8Schristos tdata->dumping = false; 1315*8e33eff8Schristos } 1316*8e33eff8Schristos malloc_mutex_unlock(arg->tsdn, tdata->lock); 1317*8e33eff8Schristos 1318*8e33eff8Schristos return NULL; 1319*8e33eff8Schristos } 1320*8e33eff8Schristos #endif 1321*8e33eff8Schristos 1322*8e33eff8Schristos static prof_tdata_t * 1323*8e33eff8Schristos prof_tdata_dump_iter(prof_tdata_tree_t *tdatasunused, prof_tdata_t *tdata, 1324*8e33eff8Schristos void *arg) { 1325*8e33eff8Schristos bool propagate_err = *(bool *)arg; 1326*8e33eff8Schristos 1327*8e33eff8Schristos if (!tdata->dumping) { 1328*8e33eff8Schristos return NULL; 1329*8e33eff8Schristos } 1330*8e33eff8Schristos 1331*8e33eff8Schristos if (prof_dump_printf(propagate_err, 1332*8e33eff8Schristos " t%"FMTu64": %"FMTu64": %"FMTu64" [%"FMTu64": %"FMTu64"]%s%s\n", 1333*8e33eff8Schristos tdata->thr_uid, tdata->cnt_summed.curobjs, 1334*8e33eff8Schristos tdata->cnt_summed.curbytes, tdata->cnt_summed.accumobjs, 1335*8e33eff8Schristos tdata->cnt_summed.accumbytes, 1336*8e33eff8Schristos (tdata->thread_name != NULL) ? " " : "", 1337*8e33eff8Schristos (tdata->thread_name != NULL) ? tdata->thread_name : "")) { 1338*8e33eff8Schristos return tdata; 1339*8e33eff8Schristos } 1340*8e33eff8Schristos return NULL; 1341*8e33eff8Schristos } 1342*8e33eff8Schristos 1343*8e33eff8Schristos static bool 1344*8e33eff8Schristos prof_dump_header_impl(tsdn_t *tsdn, bool propagate_err, 1345*8e33eff8Schristos const prof_cnt_t *cnt_all) { 1346*8e33eff8Schristos bool ret; 1347*8e33eff8Schristos 1348*8e33eff8Schristos if (prof_dump_printf(propagate_err, 1349*8e33eff8Schristos "heap_v2/%"FMTu64"\n" 1350*8e33eff8Schristos " t*: %"FMTu64": %"FMTu64" [%"FMTu64": %"FMTu64"]\n", 1351*8e33eff8Schristos ((uint64_t)1U << lg_prof_sample), cnt_all->curobjs, 1352*8e33eff8Schristos cnt_all->curbytes, cnt_all->accumobjs, cnt_all->accumbytes)) { 1353*8e33eff8Schristos return true; 1354*8e33eff8Schristos } 1355*8e33eff8Schristos 1356*8e33eff8Schristos malloc_mutex_lock(tsdn, &tdatas_mtx); 1357*8e33eff8Schristos ret = (tdata_tree_iter(&tdatas, NULL, prof_tdata_dump_iter, 1358*8e33eff8Schristos (void *)&propagate_err) != NULL); 1359*8e33eff8Schristos malloc_mutex_unlock(tsdn, &tdatas_mtx); 1360*8e33eff8Schristos return ret; 1361*8e33eff8Schristos } 1362*8e33eff8Schristos prof_dump_header_t *JET_MUTABLE prof_dump_header = prof_dump_header_impl; 1363*8e33eff8Schristos 1364*8e33eff8Schristos #ifdef JEMALLOC_PROF 1365*8e33eff8Schristos static bool 1366*8e33eff8Schristos prof_dump_gctx(tsdn_t *tsdn, bool propagate_err, prof_gctx_t *gctx, 1367*8e33eff8Schristos const prof_bt_t *bt, prof_gctx_tree_t *gctxs) { 1368*8e33eff8Schristos bool ret; 1369*8e33eff8Schristos unsigned i; 1370*8e33eff8Schristos struct prof_tctx_dump_iter_arg_s prof_tctx_dump_iter_arg; 1371*8e33eff8Schristos 1372*8e33eff8Schristos cassert(config_prof); 1373*8e33eff8Schristos malloc_mutex_assert_owner(tsdn, gctx->lock); 1374*8e33eff8Schristos 1375*8e33eff8Schristos /* Avoid dumping such gctx's that have no useful data. */ 1376*8e33eff8Schristos if ((!opt_prof_accum && gctx->cnt_summed.curobjs == 0) || 1377*8e33eff8Schristos (opt_prof_accum && gctx->cnt_summed.accumobjs == 0)) { 1378*8e33eff8Schristos assert(gctx->cnt_summed.curobjs == 0); 1379*8e33eff8Schristos assert(gctx->cnt_summed.curbytes == 0); 1380*8e33eff8Schristos assert(gctx->cnt_summed.accumobjs == 0); 1381*8e33eff8Schristos assert(gctx->cnt_summed.accumbytes == 0); 1382*8e33eff8Schristos ret = false; 1383*8e33eff8Schristos goto label_return; 1384*8e33eff8Schristos } 1385*8e33eff8Schristos 1386*8e33eff8Schristos if (prof_dump_printf(propagate_err, "@")) { 1387*8e33eff8Schristos ret = true; 1388*8e33eff8Schristos goto label_return; 1389*8e33eff8Schristos } 1390*8e33eff8Schristos for (i = 0; i < bt->len; i++) { 1391*8e33eff8Schristos if (prof_dump_printf(propagate_err, " %#"FMTxPTR, 1392*8e33eff8Schristos (uintptr_t)bt->vec[i])) { 1393*8e33eff8Schristos ret = true; 1394*8e33eff8Schristos goto label_return; 1395*8e33eff8Schristos } 1396*8e33eff8Schristos } 1397*8e33eff8Schristos 1398*8e33eff8Schristos if (prof_dump_printf(propagate_err, 1399*8e33eff8Schristos "\n" 1400*8e33eff8Schristos " t*: %"FMTu64": %"FMTu64" [%"FMTu64": %"FMTu64"]\n", 1401*8e33eff8Schristos gctx->cnt_summed.curobjs, gctx->cnt_summed.curbytes, 1402*8e33eff8Schristos gctx->cnt_summed.accumobjs, gctx->cnt_summed.accumbytes)) { 1403*8e33eff8Schristos ret = true; 1404*8e33eff8Schristos goto label_return; 1405*8e33eff8Schristos } 1406*8e33eff8Schristos 1407*8e33eff8Schristos prof_tctx_dump_iter_arg.tsdn = tsdn; 1408*8e33eff8Schristos prof_tctx_dump_iter_arg.propagate_err = propagate_err; 1409*8e33eff8Schristos if (tctx_tree_iter(&gctx->tctxs, NULL, prof_tctx_dump_iter, 1410*8e33eff8Schristos (void *)&prof_tctx_dump_iter_arg) != NULL) { 1411*8e33eff8Schristos ret = true; 1412*8e33eff8Schristos goto label_return; 1413*8e33eff8Schristos } 1414*8e33eff8Schristos 1415*8e33eff8Schristos ret = false; 1416*8e33eff8Schristos label_return: 1417*8e33eff8Schristos return ret; 1418*8e33eff8Schristos } 1419*8e33eff8Schristos 1420*8e33eff8Schristos #ifndef _WIN32 1421*8e33eff8Schristos JEMALLOC_FORMAT_PRINTF(1, 2) 1422*8e33eff8Schristos static int 1423*8e33eff8Schristos prof_open_maps(const char *format, ...) { 1424*8e33eff8Schristos int mfd; 1425*8e33eff8Schristos va_list ap; 1426*8e33eff8Schristos char filename[PATH_MAX + 1]; 1427*8e33eff8Schristos 1428*8e33eff8Schristos va_start(ap, format); 1429*8e33eff8Schristos malloc_vsnprintf(filename, sizeof(filename), format, ap); 1430*8e33eff8Schristos va_end(ap); 1431*8e33eff8Schristos 1432*8e33eff8Schristos #if defined(O_CLOEXEC) 1433*8e33eff8Schristos mfd = open(filename, O_RDONLY | O_CLOEXEC); 1434*8e33eff8Schristos #else 1435*8e33eff8Schristos mfd = open(filename, O_RDONLY); 1436*8e33eff8Schristos if (mfd != -1) { 1437*8e33eff8Schristos fcntl(mfd, F_SETFD, fcntl(mfd, F_GETFD) | FD_CLOEXEC); 1438*8e33eff8Schristos } 1439*8e33eff8Schristos #endif 1440*8e33eff8Schristos 1441*8e33eff8Schristos return mfd; 1442*8e33eff8Schristos } 1443*8e33eff8Schristos #endif 1444*8e33eff8Schristos 1445*8e33eff8Schristos static int 1446*8e33eff8Schristos prof_getpid(void) { 1447*8e33eff8Schristos #ifdef _WIN32 1448*8e33eff8Schristos return GetCurrentProcessId(); 1449*8e33eff8Schristos #else 1450*8e33eff8Schristos return getpid(); 1451*8e33eff8Schristos #endif 1452*8e33eff8Schristos } 1453*8e33eff8Schristos 1454*8e33eff8Schristos static bool 1455*8e33eff8Schristos prof_dump_maps(bool propagate_err) { 1456*8e33eff8Schristos bool ret; 1457*8e33eff8Schristos int mfd; 1458*8e33eff8Schristos 1459*8e33eff8Schristos cassert(config_prof); 1460*8e33eff8Schristos #ifdef __FreeBSD__ 1461*8e33eff8Schristos mfd = prof_open_maps("/proc/curproc/map"); 1462*8e33eff8Schristos #elif defined(_WIN32) 1463*8e33eff8Schristos mfd = -1; // Not implemented 1464*8e33eff8Schristos #else 1465*8e33eff8Schristos { 1466*8e33eff8Schristos int pid = prof_getpid(); 1467*8e33eff8Schristos 1468*8e33eff8Schristos mfd = prof_open_maps("/proc/%d/task/%d/maps", pid, pid); 1469*8e33eff8Schristos if (mfd == -1) { 1470*8e33eff8Schristos mfd = prof_open_maps("/proc/%d/maps", pid); 1471*8e33eff8Schristos } 1472*8e33eff8Schristos } 1473*8e33eff8Schristos #endif 1474*8e33eff8Schristos if (mfd != -1) { 1475*8e33eff8Schristos ssize_t nread; 1476*8e33eff8Schristos 1477*8e33eff8Schristos if (prof_dump_write(propagate_err, "\nMAPPED_LIBRARIES:\n") && 1478*8e33eff8Schristos propagate_err) { 1479*8e33eff8Schristos ret = true; 1480*8e33eff8Schristos goto label_return; 1481*8e33eff8Schristos } 1482*8e33eff8Schristos nread = 0; 1483*8e33eff8Schristos do { 1484*8e33eff8Schristos prof_dump_buf_end += nread; 1485*8e33eff8Schristos if (prof_dump_buf_end == PROF_DUMP_BUFSIZE) { 1486*8e33eff8Schristos /* Make space in prof_dump_buf before read(). */ 1487*8e33eff8Schristos if (prof_dump_flush(propagate_err) && 1488*8e33eff8Schristos propagate_err) { 1489*8e33eff8Schristos ret = true; 1490*8e33eff8Schristos goto label_return; 1491*8e33eff8Schristos } 1492*8e33eff8Schristos } 1493*8e33eff8Schristos nread = malloc_read_fd(mfd, 1494*8e33eff8Schristos &prof_dump_buf[prof_dump_buf_end], PROF_DUMP_BUFSIZE 1495*8e33eff8Schristos - prof_dump_buf_end); 1496*8e33eff8Schristos } while (nread > 0); 1497*8e33eff8Schristos } else { 1498*8e33eff8Schristos ret = true; 1499*8e33eff8Schristos goto label_return; 1500*8e33eff8Schristos } 1501*8e33eff8Schristos 1502*8e33eff8Schristos ret = false; 1503*8e33eff8Schristos label_return: 1504*8e33eff8Schristos if (mfd != -1) { 1505*8e33eff8Schristos close(mfd); 1506*8e33eff8Schristos } 1507*8e33eff8Schristos return ret; 1508*8e33eff8Schristos } 1509*8e33eff8Schristos 1510*8e33eff8Schristos /* 1511*8e33eff8Schristos * See prof_sample_threshold_update() comment for why the body of this function 1512*8e33eff8Schristos * is conditionally compiled. 1513*8e33eff8Schristos */ 1514*8e33eff8Schristos static void 1515*8e33eff8Schristos prof_leakcheck(const prof_cnt_t *cnt_all, size_t leak_ngctx, 1516*8e33eff8Schristos const char *filename) { 1517*8e33eff8Schristos /* 1518*8e33eff8Schristos * Scaling is equivalent AdjustSamples() in jeprof, but the result may 1519*8e33eff8Schristos * differ slightly from what jeprof reports, because here we scale the 1520*8e33eff8Schristos * summary values, whereas jeprof scales each context individually and 1521*8e33eff8Schristos * reports the sums of the scaled values. 1522*8e33eff8Schristos */ 1523*8e33eff8Schristos if (cnt_all->curbytes != 0) { 1524*8e33eff8Schristos double sample_period = (double)((uint64_t)1 << lg_prof_sample); 1525*8e33eff8Schristos double ratio = (((double)cnt_all->curbytes) / 1526*8e33eff8Schristos (double)cnt_all->curobjs) / sample_period; 1527*8e33eff8Schristos double scale_factor = 1.0 / (1.0 - exp(-ratio)); 1528*8e33eff8Schristos uint64_t curbytes = (uint64_t)round(((double)cnt_all->curbytes) 1529*8e33eff8Schristos * scale_factor); 1530*8e33eff8Schristos uint64_t curobjs = (uint64_t)round(((double)cnt_all->curobjs) * 1531*8e33eff8Schristos scale_factor); 1532*8e33eff8Schristos 1533*8e33eff8Schristos malloc_printf("<jemalloc>: Leak approximation summary: ~%"FMTu64 1534*8e33eff8Schristos " byte%s, ~%"FMTu64" object%s, >= %zu context%s\n", 1535*8e33eff8Schristos curbytes, (curbytes != 1) ? "s" : "", curobjs, (curobjs != 1536*8e33eff8Schristos 1) ? "s" : "", leak_ngctx, (leak_ngctx != 1) ? "s" : ""); 1537*8e33eff8Schristos malloc_printf( 1538*8e33eff8Schristos "<jemalloc>: Run jeprof on \"%s\" for leak detail\n", 1539*8e33eff8Schristos filename); 1540*8e33eff8Schristos } 1541*8e33eff8Schristos } 1542*8e33eff8Schristos 1543*8e33eff8Schristos struct prof_gctx_dump_iter_arg_s { 1544*8e33eff8Schristos tsdn_t *tsdn; 1545*8e33eff8Schristos bool propagate_err; 1546*8e33eff8Schristos }; 1547*8e33eff8Schristos 1548*8e33eff8Schristos static prof_gctx_t * 1549*8e33eff8Schristos prof_gctx_dump_iter(prof_gctx_tree_t *gctxs, prof_gctx_t *gctx, void *opaque) { 1550*8e33eff8Schristos prof_gctx_t *ret; 1551*8e33eff8Schristos struct prof_gctx_dump_iter_arg_s *arg = 1552*8e33eff8Schristos (struct prof_gctx_dump_iter_arg_s *)opaque; 1553*8e33eff8Schristos 1554*8e33eff8Schristos malloc_mutex_lock(arg->tsdn, gctx->lock); 1555*8e33eff8Schristos 1556*8e33eff8Schristos if (prof_dump_gctx(arg->tsdn, arg->propagate_err, gctx, &gctx->bt, 1557*8e33eff8Schristos gctxs)) { 1558*8e33eff8Schristos ret = gctx; 1559*8e33eff8Schristos goto label_return; 1560*8e33eff8Schristos } 1561*8e33eff8Schristos 1562*8e33eff8Schristos ret = NULL; 1563*8e33eff8Schristos label_return: 1564*8e33eff8Schristos malloc_mutex_unlock(arg->tsdn, gctx->lock); 1565*8e33eff8Schristos return ret; 1566*8e33eff8Schristos } 1567*8e33eff8Schristos 1568*8e33eff8Schristos static void 1569*8e33eff8Schristos prof_dump_prep(tsd_t *tsd, prof_tdata_t *tdata, 1570*8e33eff8Schristos struct prof_tdata_merge_iter_arg_s *prof_tdata_merge_iter_arg, 1571*8e33eff8Schristos struct prof_gctx_merge_iter_arg_s *prof_gctx_merge_iter_arg, 1572*8e33eff8Schristos prof_gctx_tree_t *gctxs) { 1573*8e33eff8Schristos size_t tabind; 1574*8e33eff8Schristos union { 1575*8e33eff8Schristos prof_gctx_t *p; 1576*8e33eff8Schristos void *v; 1577*8e33eff8Schristos } gctx; 1578*8e33eff8Schristos 1579*8e33eff8Schristos prof_enter(tsd, tdata); 1580*8e33eff8Schristos 1581*8e33eff8Schristos /* 1582*8e33eff8Schristos * Put gctx's in limbo and clear their counters in preparation for 1583*8e33eff8Schristos * summing. 1584*8e33eff8Schristos */ 1585*8e33eff8Schristos gctx_tree_new(gctxs); 1586*8e33eff8Schristos for (tabind = 0; !ckh_iter(&bt2gctx, &tabind, NULL, &gctx.v);) { 1587*8e33eff8Schristos prof_dump_gctx_prep(tsd_tsdn(tsd), gctx.p, gctxs); 1588*8e33eff8Schristos } 1589*8e33eff8Schristos 1590*8e33eff8Schristos /* 1591*8e33eff8Schristos * Iterate over tdatas, and for the non-expired ones snapshot their tctx 1592*8e33eff8Schristos * stats and merge them into the associated gctx's. 1593*8e33eff8Schristos */ 1594*8e33eff8Schristos prof_tdata_merge_iter_arg->tsdn = tsd_tsdn(tsd); 1595*8e33eff8Schristos memset(&prof_tdata_merge_iter_arg->cnt_all, 0, sizeof(prof_cnt_t)); 1596*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx); 1597*8e33eff8Schristos tdata_tree_iter(&tdatas, NULL, prof_tdata_merge_iter, 1598*8e33eff8Schristos (void *)prof_tdata_merge_iter_arg); 1599*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); 1600*8e33eff8Schristos 1601*8e33eff8Schristos /* Merge tctx stats into gctx's. */ 1602*8e33eff8Schristos prof_gctx_merge_iter_arg->tsdn = tsd_tsdn(tsd); 1603*8e33eff8Schristos prof_gctx_merge_iter_arg->leak_ngctx = 0; 1604*8e33eff8Schristos gctx_tree_iter(gctxs, NULL, prof_gctx_merge_iter, 1605*8e33eff8Schristos (void *)prof_gctx_merge_iter_arg); 1606*8e33eff8Schristos 1607*8e33eff8Schristos prof_leave(tsd, tdata); 1608*8e33eff8Schristos } 1609*8e33eff8Schristos 1610*8e33eff8Schristos static bool 1611*8e33eff8Schristos prof_dump_file(tsd_t *tsd, bool propagate_err, const char *filename, 1612*8e33eff8Schristos bool leakcheck, prof_tdata_t *tdata, 1613*8e33eff8Schristos struct prof_tdata_merge_iter_arg_s *prof_tdata_merge_iter_arg, 1614*8e33eff8Schristos struct prof_gctx_merge_iter_arg_s *prof_gctx_merge_iter_arg, 1615*8e33eff8Schristos struct prof_gctx_dump_iter_arg_s *prof_gctx_dump_iter_arg, 1616*8e33eff8Schristos prof_gctx_tree_t *gctxs) { 1617*8e33eff8Schristos /* Create dump file. */ 1618*8e33eff8Schristos if ((prof_dump_fd = prof_dump_open(propagate_err, filename)) == -1) { 1619*8e33eff8Schristos return true; 1620*8e33eff8Schristos } 1621*8e33eff8Schristos 1622*8e33eff8Schristos /* Dump profile header. */ 1623*8e33eff8Schristos if (prof_dump_header(tsd_tsdn(tsd), propagate_err, 1624*8e33eff8Schristos &prof_tdata_merge_iter_arg->cnt_all)) { 1625*8e33eff8Schristos goto label_write_error; 1626*8e33eff8Schristos } 1627*8e33eff8Schristos 1628*8e33eff8Schristos /* Dump per gctx profile stats. */ 1629*8e33eff8Schristos prof_gctx_dump_iter_arg->tsdn = tsd_tsdn(tsd); 1630*8e33eff8Schristos prof_gctx_dump_iter_arg->propagate_err = propagate_err; 1631*8e33eff8Schristos if (gctx_tree_iter(gctxs, NULL, prof_gctx_dump_iter, 1632*8e33eff8Schristos (void *)prof_gctx_dump_iter_arg) != NULL) { 1633*8e33eff8Schristos goto label_write_error; 1634*8e33eff8Schristos } 1635*8e33eff8Schristos 1636*8e33eff8Schristos /* Dump /proc/<pid>/maps if possible. */ 1637*8e33eff8Schristos if (prof_dump_maps(propagate_err)) { 1638*8e33eff8Schristos goto label_write_error; 1639*8e33eff8Schristos } 1640*8e33eff8Schristos 1641*8e33eff8Schristos if (prof_dump_close(propagate_err)) { 1642*8e33eff8Schristos return true; 1643*8e33eff8Schristos } 1644*8e33eff8Schristos 1645*8e33eff8Schristos return false; 1646*8e33eff8Schristos label_write_error: 1647*8e33eff8Schristos prof_dump_close(propagate_err); 1648*8e33eff8Schristos return true; 1649*8e33eff8Schristos } 1650*8e33eff8Schristos 1651*8e33eff8Schristos static bool 1652*8e33eff8Schristos prof_dump(tsd_t *tsd, bool propagate_err, const char *filename, 1653*8e33eff8Schristos bool leakcheck) { 1654*8e33eff8Schristos cassert(config_prof); 1655*8e33eff8Schristos assert(tsd_reentrancy_level_get(tsd) == 0); 1656*8e33eff8Schristos 1657*8e33eff8Schristos prof_tdata_t * tdata = prof_tdata_get(tsd, true); 1658*8e33eff8Schristos if (tdata == NULL) { 1659*8e33eff8Schristos return true; 1660*8e33eff8Schristos } 1661*8e33eff8Schristos 1662*8e33eff8Schristos pre_reentrancy(tsd, NULL); 1663*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx); 1664*8e33eff8Schristos 1665*8e33eff8Schristos prof_gctx_tree_t gctxs; 1666*8e33eff8Schristos struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg; 1667*8e33eff8Schristos struct prof_gctx_merge_iter_arg_s prof_gctx_merge_iter_arg; 1668*8e33eff8Schristos struct prof_gctx_dump_iter_arg_s prof_gctx_dump_iter_arg; 1669*8e33eff8Schristos prof_dump_prep(tsd, tdata, &prof_tdata_merge_iter_arg, 1670*8e33eff8Schristos &prof_gctx_merge_iter_arg, &gctxs); 1671*8e33eff8Schristos bool err = prof_dump_file(tsd, propagate_err, filename, leakcheck, tdata, 1672*8e33eff8Schristos &prof_tdata_merge_iter_arg, &prof_gctx_merge_iter_arg, 1673*8e33eff8Schristos &prof_gctx_dump_iter_arg, &gctxs); 1674*8e33eff8Schristos prof_gctx_finish(tsd, &gctxs); 1675*8e33eff8Schristos 1676*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx); 1677*8e33eff8Schristos post_reentrancy(tsd); 1678*8e33eff8Schristos 1679*8e33eff8Schristos if (err) { 1680*8e33eff8Schristos return true; 1681*8e33eff8Schristos } 1682*8e33eff8Schristos 1683*8e33eff8Schristos if (leakcheck) { 1684*8e33eff8Schristos prof_leakcheck(&prof_tdata_merge_iter_arg.cnt_all, 1685*8e33eff8Schristos prof_gctx_merge_iter_arg.leak_ngctx, filename); 1686*8e33eff8Schristos } 1687*8e33eff8Schristos return false; 1688*8e33eff8Schristos } 1689*8e33eff8Schristos #endif 1690*8e33eff8Schristos 1691*8e33eff8Schristos #ifdef JEMALLOC_JET 1692*8e33eff8Schristos void 1693*8e33eff8Schristos prof_cnt_all(uint64_t *curobjs, uint64_t *curbytes, uint64_t *accumobjs, 1694*8e33eff8Schristos uint64_t *accumbytes) { 1695*8e33eff8Schristos tsd_t *tsd; 1696*8e33eff8Schristos prof_tdata_t *tdata; 1697*8e33eff8Schristos struct prof_tdata_merge_iter_arg_s prof_tdata_merge_iter_arg; 1698*8e33eff8Schristos struct prof_gctx_merge_iter_arg_s prof_gctx_merge_iter_arg; 1699*8e33eff8Schristos prof_gctx_tree_t gctxs; 1700*8e33eff8Schristos 1701*8e33eff8Schristos tsd = tsd_fetch(); 1702*8e33eff8Schristos tdata = prof_tdata_get(tsd, false); 1703*8e33eff8Schristos if (tdata == NULL) { 1704*8e33eff8Schristos if (curobjs != NULL) { 1705*8e33eff8Schristos *curobjs = 0; 1706*8e33eff8Schristos } 1707*8e33eff8Schristos if (curbytes != NULL) { 1708*8e33eff8Schristos *curbytes = 0; 1709*8e33eff8Schristos } 1710*8e33eff8Schristos if (accumobjs != NULL) { 1711*8e33eff8Schristos *accumobjs = 0; 1712*8e33eff8Schristos } 1713*8e33eff8Schristos if (accumbytes != NULL) { 1714*8e33eff8Schristos *accumbytes = 0; 1715*8e33eff8Schristos } 1716*8e33eff8Schristos return; 1717*8e33eff8Schristos } 1718*8e33eff8Schristos 1719*8e33eff8Schristos prof_dump_prep(tsd, tdata, &prof_tdata_merge_iter_arg, 1720*8e33eff8Schristos &prof_gctx_merge_iter_arg, &gctxs); 1721*8e33eff8Schristos prof_gctx_finish(tsd, &gctxs); 1722*8e33eff8Schristos 1723*8e33eff8Schristos if (curobjs != NULL) { 1724*8e33eff8Schristos *curobjs = prof_tdata_merge_iter_arg.cnt_all.curobjs; 1725*8e33eff8Schristos } 1726*8e33eff8Schristos if (curbytes != NULL) { 1727*8e33eff8Schristos *curbytes = prof_tdata_merge_iter_arg.cnt_all.curbytes; 1728*8e33eff8Schristos } 1729*8e33eff8Schristos if (accumobjs != NULL) { 1730*8e33eff8Schristos *accumobjs = prof_tdata_merge_iter_arg.cnt_all.accumobjs; 1731*8e33eff8Schristos } 1732*8e33eff8Schristos if (accumbytes != NULL) { 1733*8e33eff8Schristos *accumbytes = prof_tdata_merge_iter_arg.cnt_all.accumbytes; 1734*8e33eff8Schristos } 1735*8e33eff8Schristos } 1736*8e33eff8Schristos #endif 1737*8e33eff8Schristos 1738*8e33eff8Schristos #ifdef JEMALLOC_PROF 1739*8e33eff8Schristos #define DUMP_FILENAME_BUFSIZE (PATH_MAX + 1) 1740*8e33eff8Schristos #define VSEQ_INVALID UINT64_C(0xffffffffffffffff) 1741*8e33eff8Schristos static void 1742*8e33eff8Schristos prof_dump_filename(char *filename, char v, uint64_t vseq) { 1743*8e33eff8Schristos cassert(config_prof); 1744*8e33eff8Schristos 1745*8e33eff8Schristos if (vseq != VSEQ_INVALID) { 1746*8e33eff8Schristos /* "<prefix>.<pid>.<seq>.v<vseq>.heap" */ 1747*8e33eff8Schristos malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE, 1748*8e33eff8Schristos "%s.%d.%"FMTu64".%c%"FMTu64".heap", 1749*8e33eff8Schristos opt_prof_prefix, prof_getpid(), prof_dump_seq, v, vseq); 1750*8e33eff8Schristos } else { 1751*8e33eff8Schristos /* "<prefix>.<pid>.<seq>.<v>.heap" */ 1752*8e33eff8Schristos malloc_snprintf(filename, DUMP_FILENAME_BUFSIZE, 1753*8e33eff8Schristos "%s.%d.%"FMTu64".%c.heap", 1754*8e33eff8Schristos opt_prof_prefix, prof_getpid(), prof_dump_seq, v); 1755*8e33eff8Schristos } 1756*8e33eff8Schristos prof_dump_seq++; 1757*8e33eff8Schristos } 1758*8e33eff8Schristos 1759*8e33eff8Schristos static void 1760*8e33eff8Schristos prof_fdump(void) { 1761*8e33eff8Schristos cassert(config_prof); 1762*8e33eff8Schristos tsd_t *tsd; 1763*8e33eff8Schristos char filename[DUMP_FILENAME_BUFSIZE]; 1764*8e33eff8Schristos 1765*8e33eff8Schristos assert(opt_prof_final); 1766*8e33eff8Schristos assert(opt_prof_prefix[0] != '\0'); 1767*8e33eff8Schristos 1768*8e33eff8Schristos if (!prof_booted) { 1769*8e33eff8Schristos return; 1770*8e33eff8Schristos } 1771*8e33eff8Schristos tsd = tsd_fetch(); 1772*8e33eff8Schristos assert(tsd_reentrancy_level_get(tsd) == 0); 1773*8e33eff8Schristos 1774*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_seq_mtx); 1775*8e33eff8Schristos prof_dump_filename(filename, 'f', VSEQ_INVALID); 1776*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_seq_mtx); 1777*8e33eff8Schristos prof_dump(tsd, false, filename, opt_prof_leak); 1778*8e33eff8Schristos } 1779*8e33eff8Schristos #endif 1780*8e33eff8Schristos 1781*8e33eff8Schristos JEMALLOC_PROF_NORETURN bool 1782*8e33eff8Schristos prof_accum_init(tsdn_t *tsdn, prof_accum_t *prof_accum) { 1783*8e33eff8Schristos cassert(config_prof); 1784*8e33eff8Schristos #ifdef JEMALLOC_PROF 1785*8e33eff8Schristos #ifndef JEMALLOC_ATOMIC_U64 1786*8e33eff8Schristos if (malloc_mutex_init(&prof_accum->mtx, "prof_accum", 1787*8e33eff8Schristos WITNESS_RANK_PROF_ACCUM, malloc_mutex_rank_exclusive)) { 1788*8e33eff8Schristos return true; 1789*8e33eff8Schristos } 1790*8e33eff8Schristos prof_accum->accumbytes = 0; 1791*8e33eff8Schristos #else 1792*8e33eff8Schristos atomic_store_u64(&prof_accum->accumbytes, 0, ATOMIC_RELAXED); 1793*8e33eff8Schristos #endif 1794*8e33eff8Schristos return false; 1795*8e33eff8Schristos #endif 1796*8e33eff8Schristos } 1797*8e33eff8Schristos 1798*8e33eff8Schristos JEMALLOC_PROF_NORETURN void 1799*8e33eff8Schristos prof_idump(tsdn_t *tsdn) { 1800*8e33eff8Schristos cassert(config_prof); 1801*8e33eff8Schristos #ifdef JEMALLOC_PROF 1802*8e33eff8Schristos tsd_t *tsd; 1803*8e33eff8Schristos prof_tdata_t *tdata; 1804*8e33eff8Schristos 1805*8e33eff8Schristos if (!prof_booted || tsdn_null(tsdn) || !prof_active_get_unlocked()) { 1806*8e33eff8Schristos return; 1807*8e33eff8Schristos } 1808*8e33eff8Schristos tsd = tsdn_tsd(tsdn); 1809*8e33eff8Schristos if (tsd_reentrancy_level_get(tsd) > 0) { 1810*8e33eff8Schristos return; 1811*8e33eff8Schristos } 1812*8e33eff8Schristos 1813*8e33eff8Schristos tdata = prof_tdata_get(tsd, false); 1814*8e33eff8Schristos if (tdata == NULL) { 1815*8e33eff8Schristos return; 1816*8e33eff8Schristos } 1817*8e33eff8Schristos if (tdata->enq) { 1818*8e33eff8Schristos tdata->enq_idump = true; 1819*8e33eff8Schristos return; 1820*8e33eff8Schristos } 1821*8e33eff8Schristos 1822*8e33eff8Schristos if (opt_prof_prefix[0] != '\0') { 1823*8e33eff8Schristos char filename[PATH_MAX + 1]; 1824*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_seq_mtx); 1825*8e33eff8Schristos prof_dump_filename(filename, 'i', prof_dump_iseq); 1826*8e33eff8Schristos prof_dump_iseq++; 1827*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_seq_mtx); 1828*8e33eff8Schristos prof_dump(tsd, false, filename, false); 1829*8e33eff8Schristos } 1830*8e33eff8Schristos #endif 1831*8e33eff8Schristos } 1832*8e33eff8Schristos 1833*8e33eff8Schristos JEMALLOC_PROF_NORETURN bool 1834*8e33eff8Schristos prof_mdump(tsd_t *tsd, const char *filename) { 1835*8e33eff8Schristos cassert(config_prof); 1836*8e33eff8Schristos #ifdef JEMALLOC_PROF 1837*8e33eff8Schristos assert(tsd_reentrancy_level_get(tsd) == 0); 1838*8e33eff8Schristos 1839*8e33eff8Schristos if (!opt_prof || !prof_booted) { 1840*8e33eff8Schristos return true; 1841*8e33eff8Schristos } 1842*8e33eff8Schristos char filename_buf[DUMP_FILENAME_BUFSIZE]; 1843*8e33eff8Schristos if (filename == NULL) { 1844*8e33eff8Schristos /* No filename specified, so automatically generate one. */ 1845*8e33eff8Schristos if (opt_prof_prefix[0] == '\0') { 1846*8e33eff8Schristos return true; 1847*8e33eff8Schristos } 1848*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_seq_mtx); 1849*8e33eff8Schristos prof_dump_filename(filename_buf, 'm', prof_dump_mseq); 1850*8e33eff8Schristos prof_dump_mseq++; 1851*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_seq_mtx); 1852*8e33eff8Schristos filename = filename_buf; 1853*8e33eff8Schristos } 1854*8e33eff8Schristos return prof_dump(tsd, true, filename, false); 1855*8e33eff8Schristos #endif 1856*8e33eff8Schristos } 1857*8e33eff8Schristos 1858*8e33eff8Schristos JEMALLOC_PROF_NORETURN void 1859*8e33eff8Schristos prof_gdump(tsdn_t *tsdn) { 1860*8e33eff8Schristos cassert(config_prof); 1861*8e33eff8Schristos #ifdef JEMALLOC_PROF 1862*8e33eff8Schristos tsd_t *tsd; 1863*8e33eff8Schristos prof_tdata_t *tdata; 1864*8e33eff8Schristos 1865*8e33eff8Schristos if (!prof_booted || tsdn_null(tsdn) || !prof_active_get_unlocked()) { 1866*8e33eff8Schristos return; 1867*8e33eff8Schristos } 1868*8e33eff8Schristos tsd = tsdn_tsd(tsdn); 1869*8e33eff8Schristos if (tsd_reentrancy_level_get(tsd) > 0) { 1870*8e33eff8Schristos return; 1871*8e33eff8Schristos } 1872*8e33eff8Schristos 1873*8e33eff8Schristos tdata = prof_tdata_get(tsd, false); 1874*8e33eff8Schristos if (tdata == NULL) { 1875*8e33eff8Schristos return; 1876*8e33eff8Schristos } 1877*8e33eff8Schristos if (tdata->enq) { 1878*8e33eff8Schristos tdata->enq_gdump = true; 1879*8e33eff8Schristos return; 1880*8e33eff8Schristos } 1881*8e33eff8Schristos 1882*8e33eff8Schristos if (opt_prof_prefix[0] != '\0') { 1883*8e33eff8Schristos char filename[DUMP_FILENAME_BUFSIZE]; 1884*8e33eff8Schristos malloc_mutex_lock(tsdn, &prof_dump_seq_mtx); 1885*8e33eff8Schristos prof_dump_filename(filename, 'u', prof_dump_useq); 1886*8e33eff8Schristos prof_dump_useq++; 1887*8e33eff8Schristos malloc_mutex_unlock(tsdn, &prof_dump_seq_mtx); 1888*8e33eff8Schristos prof_dump(tsd, false, filename, false); 1889*8e33eff8Schristos } 1890*8e33eff8Schristos #endif 1891*8e33eff8Schristos } 1892*8e33eff8Schristos 1893*8e33eff8Schristos #ifdef JEMALLOC_PROF 1894*8e33eff8Schristos static void 1895*8e33eff8Schristos prof_bt_hash(const void *key, size_t r_hash[2]) { 1896*8e33eff8Schristos const prof_bt_t *bt = (const prof_bt_t *)key; 1897*8e33eff8Schristos 1898*8e33eff8Schristos cassert(config_prof); 1899*8e33eff8Schristos 1900*8e33eff8Schristos hash(bt->vec, bt->len * sizeof(void *), 0x94122f33U, r_hash); 1901*8e33eff8Schristos } 1902*8e33eff8Schristos 1903*8e33eff8Schristos static bool 1904*8e33eff8Schristos prof_bt_keycomp(const void *k1, const void *k2) { 1905*8e33eff8Schristos const prof_bt_t *bt1 = (const prof_bt_t *)k1; 1906*8e33eff8Schristos const prof_bt_t *bt2 = (const prof_bt_t *)k2; 1907*8e33eff8Schristos 1908*8e33eff8Schristos cassert(config_prof); 1909*8e33eff8Schristos 1910*8e33eff8Schristos if (bt1->len != bt2->len) { 1911*8e33eff8Schristos return false; 1912*8e33eff8Schristos } 1913*8e33eff8Schristos return (memcmp(bt1->vec, bt2->vec, bt1->len * sizeof(void *)) == 0); 1914*8e33eff8Schristos } 1915*8e33eff8Schristos 1916*8e33eff8Schristos static uint64_t 1917*8e33eff8Schristos prof_thr_uid_alloc(tsdn_t *tsdn) { 1918*8e33eff8Schristos uint64_t thr_uid; 1919*8e33eff8Schristos 1920*8e33eff8Schristos malloc_mutex_lock(tsdn, &next_thr_uid_mtx); 1921*8e33eff8Schristos thr_uid = next_thr_uid; 1922*8e33eff8Schristos next_thr_uid++; 1923*8e33eff8Schristos malloc_mutex_unlock(tsdn, &next_thr_uid_mtx); 1924*8e33eff8Schristos 1925*8e33eff8Schristos return thr_uid; 1926*8e33eff8Schristos } 1927*8e33eff8Schristos 1928*8e33eff8Schristos static prof_tdata_t * 1929*8e33eff8Schristos prof_tdata_init_impl(tsd_t *tsd, uint64_t thr_uid, uint64_t thr_discrim, 1930*8e33eff8Schristos char *thread_name, bool active) { 1931*8e33eff8Schristos prof_tdata_t *tdata; 1932*8e33eff8Schristos 1933*8e33eff8Schristos cassert(config_prof); 1934*8e33eff8Schristos 1935*8e33eff8Schristos /* Initialize an empty cache for this thread. */ 1936*8e33eff8Schristos tdata = (prof_tdata_t *)iallocztm(tsd_tsdn(tsd), sizeof(prof_tdata_t), 1937*8e33eff8Schristos sz_size2index(sizeof(prof_tdata_t)), false, NULL, true, 1938*8e33eff8Schristos arena_get(TSDN_NULL, 0, true), true); 1939*8e33eff8Schristos if (tdata == NULL) { 1940*8e33eff8Schristos return NULL; 1941*8e33eff8Schristos } 1942*8e33eff8Schristos 1943*8e33eff8Schristos tdata->lock = prof_tdata_mutex_choose(thr_uid); 1944*8e33eff8Schristos tdata->thr_uid = thr_uid; 1945*8e33eff8Schristos tdata->thr_discrim = thr_discrim; 1946*8e33eff8Schristos tdata->thread_name = thread_name; 1947*8e33eff8Schristos tdata->attached = true; 1948*8e33eff8Schristos tdata->expired = false; 1949*8e33eff8Schristos tdata->tctx_uid_next = 0; 1950*8e33eff8Schristos 1951*8e33eff8Schristos if (ckh_new(tsd, &tdata->bt2tctx, PROF_CKH_MINITEMS, prof_bt_hash, 1952*8e33eff8Schristos prof_bt_keycomp)) { 1953*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), tdata, NULL, NULL, true, true); 1954*8e33eff8Schristos return NULL; 1955*8e33eff8Schristos } 1956*8e33eff8Schristos 1957*8e33eff8Schristos tdata->prng_state = (uint64_t)(uintptr_t)tdata; 1958*8e33eff8Schristos prof_sample_threshold_update(tdata); 1959*8e33eff8Schristos 1960*8e33eff8Schristos tdata->enq = false; 1961*8e33eff8Schristos tdata->enq_idump = false; 1962*8e33eff8Schristos tdata->enq_gdump = false; 1963*8e33eff8Schristos 1964*8e33eff8Schristos tdata->dumping = false; 1965*8e33eff8Schristos tdata->active = active; 1966*8e33eff8Schristos 1967*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx); 1968*8e33eff8Schristos tdata_tree_insert(&tdatas, tdata); 1969*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); 1970*8e33eff8Schristos 1971*8e33eff8Schristos return tdata; 1972*8e33eff8Schristos } 1973*8e33eff8Schristos #endif 1974*8e33eff8Schristos 1975*8e33eff8Schristos JEMALLOC_PROF_NORETURN prof_tdata_t * 1976*8e33eff8Schristos prof_tdata_init(tsd_t *tsd) { 1977*8e33eff8Schristos cassert(config_prof); 1978*8e33eff8Schristos #ifdef JEMALLOC_PROF 1979*8e33eff8Schristos return prof_tdata_init_impl(tsd, prof_thr_uid_alloc(tsd_tsdn(tsd)), 0, 1980*8e33eff8Schristos NULL, prof_thread_active_init_get(tsd_tsdn(tsd))); 1981*8e33eff8Schristos #endif 1982*8e33eff8Schristos } 1983*8e33eff8Schristos 1984*8e33eff8Schristos static bool 1985*8e33eff8Schristos prof_tdata_should_destroy_unlocked(prof_tdata_t *tdata, bool even_if_attached) { 1986*8e33eff8Schristos if (tdata->attached && !even_if_attached) { 1987*8e33eff8Schristos return false; 1988*8e33eff8Schristos } 1989*8e33eff8Schristos if (ckh_count(&tdata->bt2tctx) != 0) { 1990*8e33eff8Schristos return false; 1991*8e33eff8Schristos } 1992*8e33eff8Schristos return true; 1993*8e33eff8Schristos } 1994*8e33eff8Schristos 1995*8e33eff8Schristos static bool 1996*8e33eff8Schristos prof_tdata_should_destroy(tsdn_t *tsdn, prof_tdata_t *tdata, 1997*8e33eff8Schristos bool even_if_attached) { 1998*8e33eff8Schristos malloc_mutex_assert_owner(tsdn, tdata->lock); 1999*8e33eff8Schristos 2000*8e33eff8Schristos return prof_tdata_should_destroy_unlocked(tdata, even_if_attached); 2001*8e33eff8Schristos } 2002*8e33eff8Schristos 2003*8e33eff8Schristos static void 2004*8e33eff8Schristos prof_tdata_destroy_locked(tsd_t *tsd, prof_tdata_t *tdata, 2005*8e33eff8Schristos bool even_if_attached) { 2006*8e33eff8Schristos malloc_mutex_assert_owner(tsd_tsdn(tsd), &tdatas_mtx); 2007*8e33eff8Schristos 2008*8e33eff8Schristos tdata_tree_remove(&tdatas, tdata); 2009*8e33eff8Schristos 2010*8e33eff8Schristos assert(prof_tdata_should_destroy_unlocked(tdata, even_if_attached)); 2011*8e33eff8Schristos 2012*8e33eff8Schristos if (tdata->thread_name != NULL) { 2013*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, NULL, true, 2014*8e33eff8Schristos true); 2015*8e33eff8Schristos } 2016*8e33eff8Schristos ckh_delete(tsd, &tdata->bt2tctx); 2017*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), tdata, NULL, NULL, true, true); 2018*8e33eff8Schristos } 2019*8e33eff8Schristos 2020*8e33eff8Schristos static void 2021*8e33eff8Schristos prof_tdata_destroy(tsd_t *tsd, prof_tdata_t *tdata, bool even_if_attached) { 2022*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx); 2023*8e33eff8Schristos prof_tdata_destroy_locked(tsd, tdata, even_if_attached); 2024*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); 2025*8e33eff8Schristos } 2026*8e33eff8Schristos 2027*8e33eff8Schristos static void 2028*8e33eff8Schristos prof_tdata_detach(tsd_t *tsd, prof_tdata_t *tdata) { 2029*8e33eff8Schristos bool destroy_tdata; 2030*8e33eff8Schristos 2031*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), tdata->lock); 2032*8e33eff8Schristos if (tdata->attached) { 2033*8e33eff8Schristos destroy_tdata = prof_tdata_should_destroy(tsd_tsdn(tsd), tdata, 2034*8e33eff8Schristos true); 2035*8e33eff8Schristos /* 2036*8e33eff8Schristos * Only detach if !destroy_tdata, because detaching would allow 2037*8e33eff8Schristos * another thread to win the race to destroy tdata. 2038*8e33eff8Schristos */ 2039*8e33eff8Schristos if (!destroy_tdata) { 2040*8e33eff8Schristos tdata->attached = false; 2041*8e33eff8Schristos } 2042*8e33eff8Schristos tsd_prof_tdata_set(tsd, NULL); 2043*8e33eff8Schristos } else { 2044*8e33eff8Schristos destroy_tdata = false; 2045*8e33eff8Schristos } 2046*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), tdata->lock); 2047*8e33eff8Schristos if (destroy_tdata) { 2048*8e33eff8Schristos prof_tdata_destroy(tsd, tdata, true); 2049*8e33eff8Schristos } 2050*8e33eff8Schristos } 2051*8e33eff8Schristos 2052*8e33eff8Schristos JEMALLOC_PROF_NORETURN prof_tdata_t * 2053*8e33eff8Schristos prof_tdata_reinit(tsd_t *tsd, prof_tdata_t *tdata) { 2054*8e33eff8Schristos cassert(config_prof); 2055*8e33eff8Schristos #ifdef JEMALLOC_PROF 2056*8e33eff8Schristos uint64_t thr_uid = tdata->thr_uid; 2057*8e33eff8Schristos uint64_t thr_discrim = tdata->thr_discrim + 1; 2058*8e33eff8Schristos char *thread_name = (tdata->thread_name != NULL) ? 2059*8e33eff8Schristos prof_thread_name_alloc(tsd_tsdn(tsd), tdata->thread_name) : NULL; 2060*8e33eff8Schristos bool active = tdata->active; 2061*8e33eff8Schristos 2062*8e33eff8Schristos prof_tdata_detach(tsd, tdata); 2063*8e33eff8Schristos return prof_tdata_init_impl(tsd, thr_uid, thr_discrim, thread_name, 2064*8e33eff8Schristos active); 2065*8e33eff8Schristos #endif 2066*8e33eff8Schristos } 2067*8e33eff8Schristos 2068*8e33eff8Schristos static bool 2069*8e33eff8Schristos prof_tdata_expire(tsdn_t *tsdn, prof_tdata_t *tdata) { 2070*8e33eff8Schristos bool destroy_tdata; 2071*8e33eff8Schristos 2072*8e33eff8Schristos malloc_mutex_lock(tsdn, tdata->lock); 2073*8e33eff8Schristos if (!tdata->expired) { 2074*8e33eff8Schristos tdata->expired = true; 2075*8e33eff8Schristos destroy_tdata = tdata->attached ? false : 2076*8e33eff8Schristos prof_tdata_should_destroy(tsdn, tdata, false); 2077*8e33eff8Schristos } else { 2078*8e33eff8Schristos destroy_tdata = false; 2079*8e33eff8Schristos } 2080*8e33eff8Schristos malloc_mutex_unlock(tsdn, tdata->lock); 2081*8e33eff8Schristos 2082*8e33eff8Schristos return destroy_tdata; 2083*8e33eff8Schristos } 2084*8e33eff8Schristos 2085*8e33eff8Schristos static prof_tdata_t * 2086*8e33eff8Schristos prof_tdata_reset_iter(prof_tdata_tree_t *tdatasunused, prof_tdata_t *tdata, 2087*8e33eff8Schristos void *arg) { 2088*8e33eff8Schristos tsdn_t *tsdn = (tsdn_t *)arg; 2089*8e33eff8Schristos 2090*8e33eff8Schristos return (prof_tdata_expire(tsdn, tdata) ? tdata : NULL); 2091*8e33eff8Schristos } 2092*8e33eff8Schristos 2093*8e33eff8Schristos void 2094*8e33eff8Schristos prof_reset(tsd_t *tsd, size_t lg_sample) { 2095*8e33eff8Schristos prof_tdata_t *next; 2096*8e33eff8Schristos 2097*8e33eff8Schristos assert(lg_sample < (sizeof(uint64_t) << 3)); 2098*8e33eff8Schristos 2099*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &prof_dump_mtx); 2100*8e33eff8Schristos malloc_mutex_lock(tsd_tsdn(tsd), &tdatas_mtx); 2101*8e33eff8Schristos 2102*8e33eff8Schristos lg_prof_sample = lg_sample; 2103*8e33eff8Schristos 2104*8e33eff8Schristos next = NULL; 2105*8e33eff8Schristos do { 2106*8e33eff8Schristos prof_tdata_t *to_destroy = tdata_tree_iter(&tdatas, next, 2107*8e33eff8Schristos prof_tdata_reset_iter, (void *)tsd); 2108*8e33eff8Schristos if (to_destroy != NULL) { 2109*8e33eff8Schristos next = tdata_tree_next(&tdatas, to_destroy); 2110*8e33eff8Schristos prof_tdata_destroy_locked(tsd, to_destroy, false); 2111*8e33eff8Schristos } else { 2112*8e33eff8Schristos next = NULL; 2113*8e33eff8Schristos } 2114*8e33eff8Schristos } while (next != NULL); 2115*8e33eff8Schristos 2116*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &tdatas_mtx); 2117*8e33eff8Schristos malloc_mutex_unlock(tsd_tsdn(tsd), &prof_dump_mtx); 2118*8e33eff8Schristos } 2119*8e33eff8Schristos 2120*8e33eff8Schristos void 2121*8e33eff8Schristos prof_tdata_cleanup(tsd_t *tsd) { 2122*8e33eff8Schristos prof_tdata_t *tdata; 2123*8e33eff8Schristos 2124*8e33eff8Schristos if (!config_prof) { 2125*8e33eff8Schristos return; 2126*8e33eff8Schristos } 2127*8e33eff8Schristos 2128*8e33eff8Schristos tdata = tsd_prof_tdata_get(tsd); 2129*8e33eff8Schristos if (tdata != NULL) { 2130*8e33eff8Schristos prof_tdata_detach(tsd, tdata); 2131*8e33eff8Schristos } 2132*8e33eff8Schristos } 2133*8e33eff8Schristos 2134*8e33eff8Schristos bool 2135*8e33eff8Schristos prof_active_get(tsdn_t *tsdn) { 2136*8e33eff8Schristos bool prof_active_current; 2137*8e33eff8Schristos 2138*8e33eff8Schristos malloc_mutex_lock(tsdn, &prof_active_mtx); 2139*8e33eff8Schristos prof_active_current = prof_active; 2140*8e33eff8Schristos malloc_mutex_unlock(tsdn, &prof_active_mtx); 2141*8e33eff8Schristos return prof_active_current; 2142*8e33eff8Schristos } 2143*8e33eff8Schristos 2144*8e33eff8Schristos bool 2145*8e33eff8Schristos prof_active_set(tsdn_t *tsdn, bool active) { 2146*8e33eff8Schristos bool prof_active_old; 2147*8e33eff8Schristos 2148*8e33eff8Schristos malloc_mutex_lock(tsdn, &prof_active_mtx); 2149*8e33eff8Schristos prof_active_old = prof_active; 2150*8e33eff8Schristos prof_active = active; 2151*8e33eff8Schristos malloc_mutex_unlock(tsdn, &prof_active_mtx); 2152*8e33eff8Schristos return prof_active_old; 2153*8e33eff8Schristos } 2154*8e33eff8Schristos 2155*8e33eff8Schristos JEMALLOC_PROF_NORETURN const char * 2156*8e33eff8Schristos prof_thread_name_get(tsd_t *tsd) { 2157*8e33eff8Schristos cassert(config_prof); 2158*8e33eff8Schristos #ifdef JEMALLOC_PROF 2159*8e33eff8Schristos prof_tdata_t *tdata; 2160*8e33eff8Schristos 2161*8e33eff8Schristos tdata = prof_tdata_get(tsd, true); 2162*8e33eff8Schristos if (tdata == NULL) { 2163*8e33eff8Schristos return ""; 2164*8e33eff8Schristos } 2165*8e33eff8Schristos return (tdata->thread_name != NULL ? tdata->thread_name : ""); 2166*8e33eff8Schristos #endif 2167*8e33eff8Schristos } 2168*8e33eff8Schristos 2169*8e33eff8Schristos #ifdef JEMALLOC_PROF 2170*8e33eff8Schristos static char * 2171*8e33eff8Schristos prof_thread_name_alloc(tsdn_t *tsdn, const char *thread_name) { 2172*8e33eff8Schristos char *ret; 2173*8e33eff8Schristos size_t size; 2174*8e33eff8Schristos 2175*8e33eff8Schristos if (thread_name == NULL) { 2176*8e33eff8Schristos return NULL; 2177*8e33eff8Schristos } 2178*8e33eff8Schristos 2179*8e33eff8Schristos size = strlen(thread_name) + 1; 2180*8e33eff8Schristos if (size == 1) { 2181*8e33eff8Schristos return __UNCONST(""); // XXX 2182*8e33eff8Schristos } 2183*8e33eff8Schristos 2184*8e33eff8Schristos ret = iallocztm(tsdn, size, sz_size2index(size), false, NULL, true, 2185*8e33eff8Schristos arena_get(TSDN_NULL, 0, true), true); 2186*8e33eff8Schristos if (ret == NULL) { 2187*8e33eff8Schristos return NULL; 2188*8e33eff8Schristos } 2189*8e33eff8Schristos memcpy(ret, thread_name, size); 2190*8e33eff8Schristos return ret; 2191*8e33eff8Schristos } 2192*8e33eff8Schristos #endif 2193*8e33eff8Schristos 2194*8e33eff8Schristos JEMALLOC_PROF_NORETURN int 2195*8e33eff8Schristos prof_thread_name_set(tsd_t *tsd, const char *thread_name) { 2196*8e33eff8Schristos cassert(config_prof); 2197*8e33eff8Schristos #ifdef JEMALLOC_PROF 2198*8e33eff8Schristos prof_tdata_t *tdata; 2199*8e33eff8Schristos unsigned i; 2200*8e33eff8Schristos char *s; 2201*8e33eff8Schristos 2202*8e33eff8Schristos tdata = prof_tdata_get(tsd, true); 2203*8e33eff8Schristos if (tdata == NULL) { 2204*8e33eff8Schristos return EAGAIN; 2205*8e33eff8Schristos } 2206*8e33eff8Schristos 2207*8e33eff8Schristos /* Validate input. */ 2208*8e33eff8Schristos if (thread_name == NULL) { 2209*8e33eff8Schristos return EFAULT; 2210*8e33eff8Schristos } 2211*8e33eff8Schristos for (i = 0; thread_name[i] != '\0'; i++) { 2212*8e33eff8Schristos char c = thread_name[i]; 2213*8e33eff8Schristos if (!isgraph((unsigned char)c) && !isblank((unsigned char)c)) { 2214*8e33eff8Schristos return EFAULT; 2215*8e33eff8Schristos } 2216*8e33eff8Schristos } 2217*8e33eff8Schristos 2218*8e33eff8Schristos s = prof_thread_name_alloc(tsd_tsdn(tsd), thread_name); 2219*8e33eff8Schristos if (s == NULL) { 2220*8e33eff8Schristos return EAGAIN; 2221*8e33eff8Schristos } 2222*8e33eff8Schristos 2223*8e33eff8Schristos if (tdata->thread_name != NULL) { 2224*8e33eff8Schristos idalloctm(tsd_tsdn(tsd), tdata->thread_name, NULL, NULL, true, 2225*8e33eff8Schristos true); 2226*8e33eff8Schristos tdata->thread_name = NULL; 2227*8e33eff8Schristos } 2228*8e33eff8Schristos if (strlen(s) > 0) { 2229*8e33eff8Schristos tdata->thread_name = s; 2230*8e33eff8Schristos } 2231*8e33eff8Schristos return 0; 2232*8e33eff8Schristos #endif 2233*8e33eff8Schristos } 2234*8e33eff8Schristos 2235*8e33eff8Schristos JEMALLOC_PROF_NORETURN bool 2236*8e33eff8Schristos prof_thread_active_get(tsd_t *tsd) { 2237*8e33eff8Schristos cassert(config_prof); 2238*8e33eff8Schristos #ifdef JEMALLOC_PROF 2239*8e33eff8Schristos prof_tdata_t *tdata; 2240*8e33eff8Schristos 2241*8e33eff8Schristos tdata = prof_tdata_get(tsd, true); 2242*8e33eff8Schristos if (tdata == NULL) { 2243*8e33eff8Schristos return false; 2244*8e33eff8Schristos } 2245*8e33eff8Schristos return tdata->active; 2246*8e33eff8Schristos #endif 2247*8e33eff8Schristos } 2248*8e33eff8Schristos 2249*8e33eff8Schristos JEMALLOC_PROF_NORETURN bool 2250*8e33eff8Schristos prof_thread_active_set(tsd_t *tsd, bool active) { 2251*8e33eff8Schristos cassert(config_prof); 2252*8e33eff8Schristos #ifdef JEMALLOC_PROF 2253*8e33eff8Schristos prof_tdata_t *tdata; 2254*8e33eff8Schristos 2255*8e33eff8Schristos tdata = prof_tdata_get(tsd, true); 2256*8e33eff8Schristos if (tdata == NULL) { 2257*8e33eff8Schristos return true; 2258*8e33eff8Schristos } 2259*8e33eff8Schristos tdata->active = active; 2260*8e33eff8Schristos return false; 2261*8e33eff8Schristos #endif 2262*8e33eff8Schristos } 2263*8e33eff8Schristos 2264*8e33eff8Schristos bool 2265*8e33eff8Schristos prof_thread_active_init_get(tsdn_t *tsdn) { 2266*8e33eff8Schristos bool active_init; 2267*8e33eff8Schristos 2268*8e33eff8Schristos malloc_mutex_lock(tsdn, &prof_thread_active_init_mtx); 2269*8e33eff8Schristos active_init = prof_thread_active_init; 2270*8e33eff8Schristos malloc_mutex_unlock(tsdn, &prof_thread_active_init_mtx); 2271*8e33eff8Schristos return active_init; 2272*8e33eff8Schristos } 2273*8e33eff8Schristos 2274*8e33eff8Schristos bool 2275*8e33eff8Schristos prof_thread_active_init_set(tsdn_t *tsdn, bool active_init) { 2276*8e33eff8Schristos bool active_init_old; 2277*8e33eff8Schristos 2278*8e33eff8Schristos malloc_mutex_lock(tsdn, &prof_thread_active_init_mtx); 2279*8e33eff8Schristos active_init_old = prof_thread_active_init; 2280*8e33eff8Schristos prof_thread_active_init = active_init; 2281*8e33eff8Schristos malloc_mutex_unlock(tsdn, &prof_thread_active_init_mtx); 2282*8e33eff8Schristos return active_init_old; 2283*8e33eff8Schristos } 2284*8e33eff8Schristos 2285*8e33eff8Schristos bool 2286*8e33eff8Schristos prof_gdump_get(tsdn_t *tsdn) { 2287*8e33eff8Schristos bool prof_gdump_current; 2288*8e33eff8Schristos 2289*8e33eff8Schristos malloc_mutex_lock(tsdn, &prof_gdump_mtx); 2290*8e33eff8Schristos prof_gdump_current = prof_gdump_val; 2291*8e33eff8Schristos malloc_mutex_unlock(tsdn, &prof_gdump_mtx); 2292*8e33eff8Schristos return prof_gdump_current; 2293*8e33eff8Schristos } 2294*8e33eff8Schristos 2295*8e33eff8Schristos bool 2296*8e33eff8Schristos prof_gdump_set(tsdn_t *tsdn, bool gdump) { 2297*8e33eff8Schristos bool prof_gdump_old; 2298*8e33eff8Schristos 2299*8e33eff8Schristos malloc_mutex_lock(tsdn, &prof_gdump_mtx); 2300*8e33eff8Schristos prof_gdump_old = prof_gdump_val; 2301*8e33eff8Schristos prof_gdump_val = gdump; 2302*8e33eff8Schristos malloc_mutex_unlock(tsdn, &prof_gdump_mtx); 2303*8e33eff8Schristos return prof_gdump_old; 2304*8e33eff8Schristos } 2305*8e33eff8Schristos 2306*8e33eff8Schristos JEMALLOC_PROF_NORETURN void 2307*8e33eff8Schristos prof_boot0(void) { 2308*8e33eff8Schristos cassert(config_prof); 2309*8e33eff8Schristos 2310*8e33eff8Schristos memcpy(opt_prof_prefix, PROF_PREFIX_DEFAULT, 2311*8e33eff8Schristos sizeof(PROF_PREFIX_DEFAULT)); 2312*8e33eff8Schristos } 2313*8e33eff8Schristos 2314*8e33eff8Schristos JEMALLOC_PROF_NORETURN void 2315*8e33eff8Schristos prof_boot1(void) { 2316*8e33eff8Schristos cassert(config_prof); 2317*8e33eff8Schristos 2318*8e33eff8Schristos /* 2319*8e33eff8Schristos * opt_prof must be in its final state before any arenas are 2320*8e33eff8Schristos * initialized, so this function must be executed early. 2321*8e33eff8Schristos */ 2322*8e33eff8Schristos 2323*8e33eff8Schristos if (opt_prof_leak && !opt_prof) { 2324*8e33eff8Schristos /* 2325*8e33eff8Schristos * Enable opt_prof, but in such a way that profiles are never 2326*8e33eff8Schristos * automatically dumped. 2327*8e33eff8Schristos */ 2328*8e33eff8Schristos opt_prof = true; 2329*8e33eff8Schristos opt_prof_gdump = false; 2330*8e33eff8Schristos } else if (opt_prof) { 2331*8e33eff8Schristos if (opt_lg_prof_interval >= 0) { 2332*8e33eff8Schristos prof_interval = (((uint64_t)1U) << 2333*8e33eff8Schristos opt_lg_prof_interval); 2334*8e33eff8Schristos } 2335*8e33eff8Schristos } 2336*8e33eff8Schristos } 2337*8e33eff8Schristos 2338*8e33eff8Schristos JEMALLOC_PROF_NORETURN bool 2339*8e33eff8Schristos prof_boot2(tsd_t *tsd) { 2340*8e33eff8Schristos cassert(config_prof); 2341*8e33eff8Schristos #ifdef JEMALLOC_PROF 2342*8e33eff8Schristos if (opt_prof) { 2343*8e33eff8Schristos unsigned i; 2344*8e33eff8Schristos 2345*8e33eff8Schristos lg_prof_sample = opt_lg_prof_sample; 2346*8e33eff8Schristos 2347*8e33eff8Schristos prof_active = opt_prof_active; 2348*8e33eff8Schristos if (malloc_mutex_init(&prof_active_mtx, "prof_active", 2349*8e33eff8Schristos WITNESS_RANK_PROF_ACTIVE, malloc_mutex_rank_exclusive)) { 2350*8e33eff8Schristos return true; 2351*8e33eff8Schristos } 2352*8e33eff8Schristos 2353*8e33eff8Schristos prof_gdump_val = opt_prof_gdump; 2354*8e33eff8Schristos if (malloc_mutex_init(&prof_gdump_mtx, "prof_gdump", 2355*8e33eff8Schristos WITNESS_RANK_PROF_GDUMP, malloc_mutex_rank_exclusive)) { 2356*8e33eff8Schristos return true; 2357*8e33eff8Schristos } 2358*8e33eff8Schristos 2359*8e33eff8Schristos prof_thread_active_init = opt_prof_thread_active_init; 2360*8e33eff8Schristos if (malloc_mutex_init(&prof_thread_active_init_mtx, 2361*8e33eff8Schristos "prof_thread_active_init", 2362*8e33eff8Schristos WITNESS_RANK_PROF_THREAD_ACTIVE_INIT, 2363*8e33eff8Schristos malloc_mutex_rank_exclusive)) { 2364*8e33eff8Schristos return true; 2365*8e33eff8Schristos } 2366*8e33eff8Schristos 2367*8e33eff8Schristos if (ckh_new(tsd, &bt2gctx, PROF_CKH_MINITEMS, prof_bt_hash, 2368*8e33eff8Schristos prof_bt_keycomp)) { 2369*8e33eff8Schristos return true; 2370*8e33eff8Schristos } 2371*8e33eff8Schristos if (malloc_mutex_init(&bt2gctx_mtx, "prof_bt2gctx", 2372*8e33eff8Schristos WITNESS_RANK_PROF_BT2GCTX, malloc_mutex_rank_exclusive)) { 2373*8e33eff8Schristos return true; 2374*8e33eff8Schristos } 2375*8e33eff8Schristos 2376*8e33eff8Schristos tdata_tree_new(&tdatas); 2377*8e33eff8Schristos if (malloc_mutex_init(&tdatas_mtx, "prof_tdatas", 2378*8e33eff8Schristos WITNESS_RANK_PROF_TDATAS, malloc_mutex_rank_exclusive)) { 2379*8e33eff8Schristos return true; 2380*8e33eff8Schristos } 2381*8e33eff8Schristos 2382*8e33eff8Schristos next_thr_uid = 0; 2383*8e33eff8Schristos if (malloc_mutex_init(&next_thr_uid_mtx, "prof_next_thr_uid", 2384*8e33eff8Schristos WITNESS_RANK_PROF_NEXT_THR_UID, malloc_mutex_rank_exclusive)) { 2385*8e33eff8Schristos return true; 2386*8e33eff8Schristos } 2387*8e33eff8Schristos 2388*8e33eff8Schristos if (malloc_mutex_init(&prof_dump_seq_mtx, "prof_dump_seq", 2389*8e33eff8Schristos WITNESS_RANK_PROF_DUMP_SEQ, malloc_mutex_rank_exclusive)) { 2390*8e33eff8Schristos return true; 2391*8e33eff8Schristos } 2392*8e33eff8Schristos if (malloc_mutex_init(&prof_dump_mtx, "prof_dump", 2393*8e33eff8Schristos WITNESS_RANK_PROF_DUMP, malloc_mutex_rank_exclusive)) { 2394*8e33eff8Schristos return true; 2395*8e33eff8Schristos } 2396*8e33eff8Schristos 2397*8e33eff8Schristos if (opt_prof_final && opt_prof_prefix[0] != '\0' && 2398*8e33eff8Schristos atexit(prof_fdump) != 0) { 2399*8e33eff8Schristos malloc_write("<jemalloc>: Error in atexit()\n"); 2400*8e33eff8Schristos if (opt_abort) { 2401*8e33eff8Schristos abort(); 2402*8e33eff8Schristos } 2403*8e33eff8Schristos } 2404*8e33eff8Schristos 2405*8e33eff8Schristos gctx_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), 2406*8e33eff8Schristos b0get(), PROF_NCTX_LOCKS * sizeof(malloc_mutex_t), 2407*8e33eff8Schristos CACHELINE); 2408*8e33eff8Schristos if (gctx_locks == NULL) { 2409*8e33eff8Schristos return true; 2410*8e33eff8Schristos } 2411*8e33eff8Schristos for (i = 0; i < PROF_NCTX_LOCKS; i++) { 2412*8e33eff8Schristos if (malloc_mutex_init(&gctx_locks[i], "prof_gctx", 2413*8e33eff8Schristos WITNESS_RANK_PROF_GCTX, 2414*8e33eff8Schristos malloc_mutex_rank_exclusive)) { 2415*8e33eff8Schristos return true; 2416*8e33eff8Schristos } 2417*8e33eff8Schristos } 2418*8e33eff8Schristos 2419*8e33eff8Schristos tdata_locks = (malloc_mutex_t *)base_alloc(tsd_tsdn(tsd), 2420*8e33eff8Schristos b0get(), PROF_NTDATA_LOCKS * sizeof(malloc_mutex_t), 2421*8e33eff8Schristos CACHELINE); 2422*8e33eff8Schristos if (tdata_locks == NULL) { 2423*8e33eff8Schristos return true; 2424*8e33eff8Schristos } 2425*8e33eff8Schristos for (i = 0; i < PROF_NTDATA_LOCKS; i++) { 2426*8e33eff8Schristos if (malloc_mutex_init(&tdata_locks[i], "prof_tdata", 2427*8e33eff8Schristos WITNESS_RANK_PROF_TDATA, 2428*8e33eff8Schristos malloc_mutex_rank_exclusive)) { 2429*8e33eff8Schristos return true; 2430*8e33eff8Schristos } 2431*8e33eff8Schristos } 2432*8e33eff8Schristos } 2433*8e33eff8Schristos 2434*8e33eff8Schristos #ifdef JEMALLOC_PROF_LIBGCC 2435*8e33eff8Schristos /* 2436*8e33eff8Schristos * Cause the backtracing machinery to allocate its internal state 2437*8e33eff8Schristos * before enabling profiling. 2438*8e33eff8Schristos */ 2439*8e33eff8Schristos _Unwind_Backtrace(prof_unwind_init_callback, NULL); 2440*8e33eff8Schristos #endif 2441*8e33eff8Schristos 2442*8e33eff8Schristos prof_booted = true; 2443*8e33eff8Schristos 2444*8e33eff8Schristos return false; 2445*8e33eff8Schristos #endif 2446*8e33eff8Schristos } 2447*8e33eff8Schristos 2448*8e33eff8Schristos void 2449*8e33eff8Schristos prof_prefork0(tsdn_t *tsdn) { 2450*8e33eff8Schristos if (config_prof && opt_prof) { 2451*8e33eff8Schristos unsigned i; 2452*8e33eff8Schristos 2453*8e33eff8Schristos malloc_mutex_prefork(tsdn, &prof_dump_mtx); 2454*8e33eff8Schristos malloc_mutex_prefork(tsdn, &bt2gctx_mtx); 2455*8e33eff8Schristos malloc_mutex_prefork(tsdn, &tdatas_mtx); 2456*8e33eff8Schristos for (i = 0; i < PROF_NTDATA_LOCKS; i++) { 2457*8e33eff8Schristos malloc_mutex_prefork(tsdn, &tdata_locks[i]); 2458*8e33eff8Schristos } 2459*8e33eff8Schristos for (i = 0; i < PROF_NCTX_LOCKS; i++) { 2460*8e33eff8Schristos malloc_mutex_prefork(tsdn, &gctx_locks[i]); 2461*8e33eff8Schristos } 2462*8e33eff8Schristos } 2463*8e33eff8Schristos } 2464*8e33eff8Schristos 2465*8e33eff8Schristos void 2466*8e33eff8Schristos prof_prefork1(tsdn_t *tsdn) { 2467*8e33eff8Schristos if (config_prof && opt_prof) { 2468*8e33eff8Schristos malloc_mutex_prefork(tsdn, &prof_active_mtx); 2469*8e33eff8Schristos malloc_mutex_prefork(tsdn, &prof_dump_seq_mtx); 2470*8e33eff8Schristos malloc_mutex_prefork(tsdn, &prof_gdump_mtx); 2471*8e33eff8Schristos malloc_mutex_prefork(tsdn, &next_thr_uid_mtx); 2472*8e33eff8Schristos malloc_mutex_prefork(tsdn, &prof_thread_active_init_mtx); 2473*8e33eff8Schristos } 2474*8e33eff8Schristos } 2475*8e33eff8Schristos 2476*8e33eff8Schristos void 2477*8e33eff8Schristos prof_postfork_parent(tsdn_t *tsdn) { 2478*8e33eff8Schristos if (config_prof && opt_prof) { 2479*8e33eff8Schristos unsigned i; 2480*8e33eff8Schristos 2481*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn, 2482*8e33eff8Schristos &prof_thread_active_init_mtx); 2483*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn, &next_thr_uid_mtx); 2484*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn, &prof_gdump_mtx); 2485*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn, &prof_dump_seq_mtx); 2486*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn, &prof_active_mtx); 2487*8e33eff8Schristos for (i = 0; i < PROF_NCTX_LOCKS; i++) { 2488*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn, &gctx_locks[i]); 2489*8e33eff8Schristos } 2490*8e33eff8Schristos for (i = 0; i < PROF_NTDATA_LOCKS; i++) { 2491*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn, &tdata_locks[i]); 2492*8e33eff8Schristos } 2493*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn, &tdatas_mtx); 2494*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn, &bt2gctx_mtx); 2495*8e33eff8Schristos malloc_mutex_postfork_parent(tsdn, &prof_dump_mtx); 2496*8e33eff8Schristos } 2497*8e33eff8Schristos } 2498*8e33eff8Schristos 2499*8e33eff8Schristos void 2500*8e33eff8Schristos prof_postfork_child(tsdn_t *tsdn) { 2501*8e33eff8Schristos if (config_prof && opt_prof) { 2502*8e33eff8Schristos unsigned i; 2503*8e33eff8Schristos 2504*8e33eff8Schristos malloc_mutex_postfork_child(tsdn, &prof_thread_active_init_mtx); 2505*8e33eff8Schristos malloc_mutex_postfork_child(tsdn, &next_thr_uid_mtx); 2506*8e33eff8Schristos malloc_mutex_postfork_child(tsdn, &prof_gdump_mtx); 2507*8e33eff8Schristos malloc_mutex_postfork_child(tsdn, &prof_dump_seq_mtx); 2508*8e33eff8Schristos malloc_mutex_postfork_child(tsdn, &prof_active_mtx); 2509*8e33eff8Schristos for (i = 0; i < PROF_NCTX_LOCKS; i++) { 2510*8e33eff8Schristos malloc_mutex_postfork_child(tsdn, &gctx_locks[i]); 2511*8e33eff8Schristos } 2512*8e33eff8Schristos for (i = 0; i < PROF_NTDATA_LOCKS; i++) { 2513*8e33eff8Schristos malloc_mutex_postfork_child(tsdn, &tdata_locks[i]); 2514*8e33eff8Schristos } 2515*8e33eff8Schristos malloc_mutex_postfork_child(tsdn, &tdatas_mtx); 2516*8e33eff8Schristos malloc_mutex_postfork_child(tsdn, &bt2gctx_mtx); 2517*8e33eff8Schristos malloc_mutex_postfork_child(tsdn, &prof_dump_mtx); 2518*8e33eff8Schristos } 2519*8e33eff8Schristos } 2520*8e33eff8Schristos 2521*8e33eff8Schristos /******************************************************************************/ 2522