1*8e33eff8Schristos #define JEMALLOC_STATS_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/ctl.h" 7*8e33eff8Schristos #include "jemalloc/internal/emitter.h" 8*8e33eff8Schristos #include "jemalloc/internal/mutex.h" 9*8e33eff8Schristos #include "jemalloc/internal/mutex_prof.h" 10*8e33eff8Schristos 11*8e33eff8Schristos const char *global_mutex_names[mutex_prof_num_global_mutexes] = { 12*8e33eff8Schristos #define OP(mtx) #mtx, 13*8e33eff8Schristos MUTEX_PROF_GLOBAL_MUTEXES 14*8e33eff8Schristos #undef OP 15*8e33eff8Schristos }; 16*8e33eff8Schristos 17*8e33eff8Schristos const char *arena_mutex_names[mutex_prof_num_arena_mutexes] = { 18*8e33eff8Schristos #define OP(mtx) #mtx, 19*8e33eff8Schristos MUTEX_PROF_ARENA_MUTEXES 20*8e33eff8Schristos #undef OP 21*8e33eff8Schristos }; 22*8e33eff8Schristos 23*8e33eff8Schristos #define CTL_GET(n, v, t) do { \ 24*8e33eff8Schristos size_t sz = sizeof(t); \ 25*8e33eff8Schristos xmallctl(n, (void *)v, &sz, NULL, 0); \ 26*8e33eff8Schristos } while (0) 27*8e33eff8Schristos 28*8e33eff8Schristos #define CTL_M2_GET(n, i, v, t) do { \ 29*8e33eff8Schristos size_t mib[CTL_MAX_DEPTH]; \ 30*8e33eff8Schristos size_t miblen = sizeof(mib) / sizeof(size_t); \ 31*8e33eff8Schristos size_t sz = sizeof(t); \ 32*8e33eff8Schristos xmallctlnametomib(n, mib, &miblen); \ 33*8e33eff8Schristos mib[2] = (i); \ 34*8e33eff8Schristos xmallctlbymib(mib, miblen, (void *)v, &sz, NULL, 0); \ 35*8e33eff8Schristos } while (0) 36*8e33eff8Schristos 37*8e33eff8Schristos #define CTL_M2_M4_GET(n, i, j, v, t) do { \ 38*8e33eff8Schristos size_t mib[CTL_MAX_DEPTH]; \ 39*8e33eff8Schristos size_t miblen = sizeof(mib) / sizeof(size_t); \ 40*8e33eff8Schristos size_t sz = sizeof(t); \ 41*8e33eff8Schristos xmallctlnametomib(n, mib, &miblen); \ 42*8e33eff8Schristos mib[2] = (i); \ 43*8e33eff8Schristos mib[4] = (j); \ 44*8e33eff8Schristos xmallctlbymib(mib, miblen, (void *)v, &sz, NULL, 0); \ 45*8e33eff8Schristos } while (0) 46*8e33eff8Schristos 47*8e33eff8Schristos /******************************************************************************/ 48*8e33eff8Schristos /* Data. */ 49*8e33eff8Schristos 50*8e33eff8Schristos bool opt_stats_print = false; 51*8e33eff8Schristos char opt_stats_print_opts[stats_print_tot_num_options+1] = ""; 52*8e33eff8Schristos 53*8e33eff8Schristos /******************************************************************************/ 54*8e33eff8Schristos 55*8e33eff8Schristos /* Calculate x.yyy and output a string (takes a fixed sized char array). */ 56*8e33eff8Schristos static bool 57*8e33eff8Schristos get_rate_str(uint64_t dividend, uint64_t divisor, char str[6]) { 58*8e33eff8Schristos if (divisor == 0 || dividend > divisor) { 59*8e33eff8Schristos /* The rate is not supposed to be greater than 1. */ 60*8e33eff8Schristos return true; 61*8e33eff8Schristos } 62*8e33eff8Schristos if (dividend > 0) { 63*8e33eff8Schristos assert(UINT64_MAX / dividend >= 1000); 64*8e33eff8Schristos } 65*8e33eff8Schristos 66*8e33eff8Schristos unsigned n = (unsigned)((dividend * 1000) / divisor); 67*8e33eff8Schristos if (n < 10) { 68*8e33eff8Schristos malloc_snprintf(str, 6, "0.00%u", n); 69*8e33eff8Schristos } else if (n < 100) { 70*8e33eff8Schristos malloc_snprintf(str, 6, "0.0%u", n); 71*8e33eff8Schristos } else if (n < 1000) { 72*8e33eff8Schristos malloc_snprintf(str, 6, "0.%u", n); 73*8e33eff8Schristos } else { 74*8e33eff8Schristos malloc_snprintf(str, 6, "1"); 75*8e33eff8Schristos } 76*8e33eff8Schristos 77*8e33eff8Schristos return false; 78*8e33eff8Schristos } 79*8e33eff8Schristos 80*8e33eff8Schristos #define MUTEX_CTL_STR_MAX_LENGTH 128 81*8e33eff8Schristos static void 82*8e33eff8Schristos gen_mutex_ctl_str(char *str, size_t buf_len, const char *prefix, 83*8e33eff8Schristos const char *mutex, const char *counter) { 84*8e33eff8Schristos malloc_snprintf(str, buf_len, "stats.%s.%s.%s", prefix, mutex, counter); 85*8e33eff8Schristos } 86*8e33eff8Schristos 87*8e33eff8Schristos static void 88*8e33eff8Schristos mutex_stats_init_cols(emitter_row_t *row, const char *table_name, 89*8e33eff8Schristos emitter_col_t *name, 90*8e33eff8Schristos emitter_col_t col_uint64_t[mutex_prof_num_uint64_t_counters], 91*8e33eff8Schristos emitter_col_t col_uint32_t[mutex_prof_num_uint32_t_counters]) { 92*8e33eff8Schristos mutex_prof_uint64_t_counter_ind_t k_uint64_t = 0; 93*8e33eff8Schristos mutex_prof_uint32_t_counter_ind_t k_uint32_t = 0; 94*8e33eff8Schristos 95*8e33eff8Schristos emitter_col_t *col; 96*8e33eff8Schristos 97*8e33eff8Schristos if (name != NULL) { 98*8e33eff8Schristos emitter_col_init(name, row); 99*8e33eff8Schristos name->justify = emitter_justify_left; 100*8e33eff8Schristos name->width = 21; 101*8e33eff8Schristos name->type = emitter_type_title; 102*8e33eff8Schristos name->str_val = table_name; 103*8e33eff8Schristos } 104*8e33eff8Schristos 105*8e33eff8Schristos #define WIDTH_uint32_t 12 106*8e33eff8Schristos #define WIDTH_uint64_t 16 107*8e33eff8Schristos #define OP(counter, counter_type, human) \ 108*8e33eff8Schristos col = &col_##counter_type[k_##counter_type]; \ 109*8e33eff8Schristos ++k_##counter_type; \ 110*8e33eff8Schristos emitter_col_init(col, row); \ 111*8e33eff8Schristos col->justify = emitter_justify_right; \ 112*8e33eff8Schristos col->width = WIDTH_##counter_type; \ 113*8e33eff8Schristos col->type = emitter_type_title; \ 114*8e33eff8Schristos col->str_val = human; 115*8e33eff8Schristos MUTEX_PROF_COUNTERS 116*8e33eff8Schristos #undef OP 117*8e33eff8Schristos #undef WIDTH_uint32_t 118*8e33eff8Schristos #undef WIDTH_uint64_t 119*8e33eff8Schristos } 120*8e33eff8Schristos 121*8e33eff8Schristos static void 122*8e33eff8Schristos mutex_stats_read_global(const char *name, emitter_col_t *col_name, 123*8e33eff8Schristos emitter_col_t col_uint64_t[mutex_prof_num_uint64_t_counters], 124*8e33eff8Schristos emitter_col_t col_uint32_t[mutex_prof_num_uint32_t_counters]) { 125*8e33eff8Schristos char cmd[MUTEX_CTL_STR_MAX_LENGTH]; 126*8e33eff8Schristos 127*8e33eff8Schristos col_name->str_val = name; 128*8e33eff8Schristos 129*8e33eff8Schristos emitter_col_t *dst; 130*8e33eff8Schristos #define EMITTER_TYPE_uint32_t emitter_type_uint32 131*8e33eff8Schristos #define EMITTER_TYPE_uint64_t emitter_type_uint64 132*8e33eff8Schristos #define OP(counter, counter_type, human) \ 133*8e33eff8Schristos dst = &col_##counter_type[mutex_counter_##counter]; \ 134*8e33eff8Schristos dst->type = EMITTER_TYPE_##counter_type; \ 135*8e33eff8Schristos gen_mutex_ctl_str(cmd, MUTEX_CTL_STR_MAX_LENGTH, \ 136*8e33eff8Schristos "mutexes", name, #counter); \ 137*8e33eff8Schristos CTL_GET(cmd, (counter_type *)&dst->bool_val, counter_type); 138*8e33eff8Schristos MUTEX_PROF_COUNTERS 139*8e33eff8Schristos #undef OP 140*8e33eff8Schristos #undef EMITTER_TYPE_uint32_t 141*8e33eff8Schristos #undef EMITTER_TYPE_uint64_t 142*8e33eff8Schristos } 143*8e33eff8Schristos 144*8e33eff8Schristos static void 145*8e33eff8Schristos mutex_stats_read_arena(unsigned arena_ind, mutex_prof_arena_ind_t mutex_ind, 146*8e33eff8Schristos const char *name, emitter_col_t *col_name, 147*8e33eff8Schristos emitter_col_t col_uint64_t[mutex_prof_num_uint64_t_counters], 148*8e33eff8Schristos emitter_col_t col_uint32_t[mutex_prof_num_uint32_t_counters]) { 149*8e33eff8Schristos char cmd[MUTEX_CTL_STR_MAX_LENGTH]; 150*8e33eff8Schristos 151*8e33eff8Schristos col_name->str_val = name; 152*8e33eff8Schristos 153*8e33eff8Schristos emitter_col_t *dst; 154*8e33eff8Schristos #define EMITTER_TYPE_uint32_t emitter_type_uint32 155*8e33eff8Schristos #define EMITTER_TYPE_uint64_t emitter_type_uint64 156*8e33eff8Schristos #define OP(counter, counter_type, human) \ 157*8e33eff8Schristos dst = &col_##counter_type[mutex_counter_##counter]; \ 158*8e33eff8Schristos dst->type = EMITTER_TYPE_##counter_type; \ 159*8e33eff8Schristos gen_mutex_ctl_str(cmd, MUTEX_CTL_STR_MAX_LENGTH, \ 160*8e33eff8Schristos "arenas.0.mutexes", arena_mutex_names[mutex_ind], #counter);\ 161*8e33eff8Schristos CTL_M2_GET(cmd, arena_ind, \ 162*8e33eff8Schristos (counter_type *)&dst->bool_val, counter_type); 163*8e33eff8Schristos MUTEX_PROF_COUNTERS 164*8e33eff8Schristos #undef OP 165*8e33eff8Schristos #undef EMITTER_TYPE_uint32_t 166*8e33eff8Schristos #undef EMITTER_TYPE_uint64_t 167*8e33eff8Schristos } 168*8e33eff8Schristos 169*8e33eff8Schristos static void 170*8e33eff8Schristos mutex_stats_read_arena_bin(unsigned arena_ind, unsigned bin_ind, 171*8e33eff8Schristos emitter_col_t col_uint64_t[mutex_prof_num_uint64_t_counters], 172*8e33eff8Schristos emitter_col_t col_uint32_t[mutex_prof_num_uint32_t_counters]) { 173*8e33eff8Schristos char cmd[MUTEX_CTL_STR_MAX_LENGTH]; 174*8e33eff8Schristos emitter_col_t *dst; 175*8e33eff8Schristos 176*8e33eff8Schristos #define EMITTER_TYPE_uint32_t emitter_type_uint32 177*8e33eff8Schristos #define EMITTER_TYPE_uint64_t emitter_type_uint64 178*8e33eff8Schristos #define OP(counter, counter_type, human) \ 179*8e33eff8Schristos dst = &col_##counter_type[mutex_counter_##counter]; \ 180*8e33eff8Schristos dst->type = EMITTER_TYPE_##counter_type; \ 181*8e33eff8Schristos gen_mutex_ctl_str(cmd, MUTEX_CTL_STR_MAX_LENGTH, \ 182*8e33eff8Schristos "arenas.0.bins.0","mutex", #counter); \ 183*8e33eff8Schristos CTL_M2_M4_GET(cmd, arena_ind, bin_ind, \ 184*8e33eff8Schristos (counter_type *)&dst->bool_val, counter_type); 185*8e33eff8Schristos MUTEX_PROF_COUNTERS 186*8e33eff8Schristos #undef OP 187*8e33eff8Schristos #undef EMITTER_TYPE_uint32_t 188*8e33eff8Schristos #undef EMITTER_TYPE_uint64_t 189*8e33eff8Schristos } 190*8e33eff8Schristos 191*8e33eff8Schristos /* "row" can be NULL to avoid emitting in table mode. */ 192*8e33eff8Schristos static void 193*8e33eff8Schristos mutex_stats_emit(emitter_t *emitter, emitter_row_t *row, 194*8e33eff8Schristos emitter_col_t col_uint64_t[mutex_prof_num_uint64_t_counters], 195*8e33eff8Schristos emitter_col_t col_uint32_t[mutex_prof_num_uint32_t_counters]) { 196*8e33eff8Schristos if (row != NULL) { 197*8e33eff8Schristos emitter_table_row(emitter, row); 198*8e33eff8Schristos } 199*8e33eff8Schristos 200*8e33eff8Schristos mutex_prof_uint64_t_counter_ind_t k_uint64_t = 0; 201*8e33eff8Schristos mutex_prof_uint32_t_counter_ind_t k_uint32_t = 0; 202*8e33eff8Schristos 203*8e33eff8Schristos emitter_col_t *col; 204*8e33eff8Schristos 205*8e33eff8Schristos #define EMITTER_TYPE_uint32_t emitter_type_uint32 206*8e33eff8Schristos #define EMITTER_TYPE_uint64_t emitter_type_uint64 207*8e33eff8Schristos #define OP(counter, type, human) \ 208*8e33eff8Schristos col = &col_##type[k_##type]; \ 209*8e33eff8Schristos ++k_##type; \ 210*8e33eff8Schristos emitter_json_kv(emitter, #counter, EMITTER_TYPE_##type, \ 211*8e33eff8Schristos (const void *)&col->bool_val); 212*8e33eff8Schristos MUTEX_PROF_COUNTERS; 213*8e33eff8Schristos #undef OP 214*8e33eff8Schristos #undef EMITTER_TYPE_uint32_t 215*8e33eff8Schristos #undef EMITTER_TYPE_uint64_t 216*8e33eff8Schristos } 217*8e33eff8Schristos 218*8e33eff8Schristos static void 219*8e33eff8Schristos stats_arena_bins_print(emitter_t *emitter, bool mutex, unsigned i) { 220*8e33eff8Schristos size_t page; 221*8e33eff8Schristos bool in_gap, in_gap_prev; 222*8e33eff8Schristos unsigned nbins, j; 223*8e33eff8Schristos 224*8e33eff8Schristos CTL_GET("arenas.page", &page, size_t); 225*8e33eff8Schristos 226*8e33eff8Schristos CTL_GET("arenas.nbins", &nbins, unsigned); 227*8e33eff8Schristos 228*8e33eff8Schristos emitter_row_t header_row; 229*8e33eff8Schristos emitter_row_init(&header_row); 230*8e33eff8Schristos 231*8e33eff8Schristos emitter_row_t row; 232*8e33eff8Schristos emitter_row_init(&row); 233*8e33eff8Schristos #define COL(name, left_or_right, col_width, etype) \ 234*8e33eff8Schristos emitter_col_t col_##name; \ 235*8e33eff8Schristos emitter_col_init(&col_##name, &row); \ 236*8e33eff8Schristos col_##name.justify = emitter_justify_##left_or_right; \ 237*8e33eff8Schristos col_##name.width = col_width; \ 238*8e33eff8Schristos col_##name.type = emitter_type_##etype; \ 239*8e33eff8Schristos emitter_col_t header_col_##name; \ 240*8e33eff8Schristos emitter_col_init(&header_col_##name, &header_row); \ 241*8e33eff8Schristos header_col_##name.justify = emitter_justify_##left_or_right; \ 242*8e33eff8Schristos header_col_##name.width = col_width; \ 243*8e33eff8Schristos header_col_##name.type = emitter_type_title; \ 244*8e33eff8Schristos header_col_##name.str_val = #name; 245*8e33eff8Schristos 246*8e33eff8Schristos COL(size, right, 20, size) 247*8e33eff8Schristos COL(ind, right, 4, unsigned) 248*8e33eff8Schristos COL(allocated, right, 13, uint64) 249*8e33eff8Schristos COL(nmalloc, right, 13, uint64) 250*8e33eff8Schristos COL(ndalloc, right, 13, uint64) 251*8e33eff8Schristos COL(nrequests, right, 13, uint64) 252*8e33eff8Schristos COL(curregs, right, 13, size) 253*8e33eff8Schristos COL(curslabs, right, 13, size) 254*8e33eff8Schristos COL(regs, right, 5, unsigned) 255*8e33eff8Schristos COL(pgs, right, 4, size) 256*8e33eff8Schristos /* To buffer a right- and left-justified column. */ 257*8e33eff8Schristos COL(justify_spacer, right, 1, title) 258*8e33eff8Schristos COL(util, right, 6, title) 259*8e33eff8Schristos COL(nfills, right, 13, uint64) 260*8e33eff8Schristos COL(nflushes, right, 13, uint64) 261*8e33eff8Schristos COL(nslabs, right, 13, uint64) 262*8e33eff8Schristos COL(nreslabs, right, 13, uint64) 263*8e33eff8Schristos #undef COL 264*8e33eff8Schristos 265*8e33eff8Schristos /* Don't want to actually print the name. */ 266*8e33eff8Schristos header_col_justify_spacer.str_val = " "; 267*8e33eff8Schristos col_justify_spacer.str_val = " "; 268*8e33eff8Schristos 269*8e33eff8Schristos 270*8e33eff8Schristos emitter_col_t col_mutex64[mutex_prof_num_uint64_t_counters]; 271*8e33eff8Schristos emitter_col_t col_mutex32[mutex_prof_num_uint32_t_counters]; 272*8e33eff8Schristos 273*8e33eff8Schristos emitter_col_t header_mutex64[mutex_prof_num_uint64_t_counters]; 274*8e33eff8Schristos emitter_col_t header_mutex32[mutex_prof_num_uint32_t_counters]; 275*8e33eff8Schristos 276*8e33eff8Schristos if (mutex) { 277*8e33eff8Schristos mutex_stats_init_cols(&row, NULL, NULL, col_mutex64, 278*8e33eff8Schristos col_mutex32); 279*8e33eff8Schristos mutex_stats_init_cols(&header_row, NULL, NULL, header_mutex64, 280*8e33eff8Schristos header_mutex32); 281*8e33eff8Schristos } 282*8e33eff8Schristos 283*8e33eff8Schristos /* 284*8e33eff8Schristos * We print a "bins:" header as part of the table row; we need to adjust 285*8e33eff8Schristos * the header size column to compensate. 286*8e33eff8Schristos */ 287*8e33eff8Schristos header_col_size.width -=5; 288*8e33eff8Schristos emitter_table_printf(emitter, "bins:"); 289*8e33eff8Schristos emitter_table_row(emitter, &header_row); 290*8e33eff8Schristos emitter_json_arr_begin(emitter, "bins"); 291*8e33eff8Schristos 292*8e33eff8Schristos for (j = 0, in_gap = false; j < nbins; j++) { 293*8e33eff8Schristos uint64_t nslabs; 294*8e33eff8Schristos size_t reg_size, slab_size, curregs; 295*8e33eff8Schristos size_t curslabs; 296*8e33eff8Schristos uint32_t nregs; 297*8e33eff8Schristos uint64_t nmalloc, ndalloc, nrequests, nfills, nflushes; 298*8e33eff8Schristos uint64_t nreslabs; 299*8e33eff8Schristos 300*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.bins.0.nslabs", i, j, &nslabs, 301*8e33eff8Schristos uint64_t); 302*8e33eff8Schristos in_gap_prev = in_gap; 303*8e33eff8Schristos in_gap = (nslabs == 0); 304*8e33eff8Schristos 305*8e33eff8Schristos if (in_gap_prev && !in_gap) { 306*8e33eff8Schristos emitter_table_printf(emitter, 307*8e33eff8Schristos " ---\n"); 308*8e33eff8Schristos } 309*8e33eff8Schristos 310*8e33eff8Schristos CTL_M2_GET("arenas.bin.0.size", j, ®_size, size_t); 311*8e33eff8Schristos CTL_M2_GET("arenas.bin.0.nregs", j, &nregs, uint32_t); 312*8e33eff8Schristos CTL_M2_GET("arenas.bin.0.slab_size", j, &slab_size, size_t); 313*8e33eff8Schristos 314*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.bins.0.nmalloc", i, j, &nmalloc, 315*8e33eff8Schristos uint64_t); 316*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.bins.0.ndalloc", i, j, &ndalloc, 317*8e33eff8Schristos uint64_t); 318*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.bins.0.curregs", i, j, &curregs, 319*8e33eff8Schristos size_t); 320*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.bins.0.nrequests", i, j, 321*8e33eff8Schristos &nrequests, uint64_t); 322*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.bins.0.nfills", i, j, &nfills, 323*8e33eff8Schristos uint64_t); 324*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.bins.0.nflushes", i, j, &nflushes, 325*8e33eff8Schristos uint64_t); 326*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.bins.0.nreslabs", i, j, &nreslabs, 327*8e33eff8Schristos uint64_t); 328*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.bins.0.curslabs", i, j, &curslabs, 329*8e33eff8Schristos size_t); 330*8e33eff8Schristos 331*8e33eff8Schristos if (mutex) { 332*8e33eff8Schristos mutex_stats_read_arena_bin(i, j, col_mutex64, 333*8e33eff8Schristos col_mutex32); 334*8e33eff8Schristos } 335*8e33eff8Schristos 336*8e33eff8Schristos emitter_json_arr_obj_begin(emitter); 337*8e33eff8Schristos emitter_json_kv(emitter, "nmalloc", emitter_type_uint64, 338*8e33eff8Schristos &nmalloc); 339*8e33eff8Schristos emitter_json_kv(emitter, "ndalloc", emitter_type_uint64, 340*8e33eff8Schristos &ndalloc); 341*8e33eff8Schristos emitter_json_kv(emitter, "curregs", emitter_type_size, 342*8e33eff8Schristos &curregs); 343*8e33eff8Schristos emitter_json_kv(emitter, "nrequests", emitter_type_uint64, 344*8e33eff8Schristos &nrequests); 345*8e33eff8Schristos emitter_json_kv(emitter, "nfills", emitter_type_uint64, 346*8e33eff8Schristos &nfills); 347*8e33eff8Schristos emitter_json_kv(emitter, "nflushes", emitter_type_uint64, 348*8e33eff8Schristos &nflushes); 349*8e33eff8Schristos emitter_json_kv(emitter, "nreslabs", emitter_type_uint64, 350*8e33eff8Schristos &nreslabs); 351*8e33eff8Schristos emitter_json_kv(emitter, "curslabs", emitter_type_size, 352*8e33eff8Schristos &curslabs); 353*8e33eff8Schristos if (mutex) { 354*8e33eff8Schristos emitter_json_dict_begin(emitter, "mutex"); 355*8e33eff8Schristos mutex_stats_emit(emitter, NULL, col_mutex64, 356*8e33eff8Schristos col_mutex32); 357*8e33eff8Schristos emitter_json_dict_end(emitter); 358*8e33eff8Schristos } 359*8e33eff8Schristos emitter_json_arr_obj_end(emitter); 360*8e33eff8Schristos 361*8e33eff8Schristos size_t availregs = nregs * curslabs; 362*8e33eff8Schristos char util[6]; 363*8e33eff8Schristos if (get_rate_str((uint64_t)curregs, (uint64_t)availregs, util)) 364*8e33eff8Schristos { 365*8e33eff8Schristos if (availregs == 0) { 366*8e33eff8Schristos malloc_snprintf(util, sizeof(util), "1"); 367*8e33eff8Schristos } else if (curregs > availregs) { 368*8e33eff8Schristos /* 369*8e33eff8Schristos * Race detected: the counters were read in 370*8e33eff8Schristos * separate mallctl calls and concurrent 371*8e33eff8Schristos * operations happened in between. In this case 372*8e33eff8Schristos * no meaningful utilization can be computed. 373*8e33eff8Schristos */ 374*8e33eff8Schristos malloc_snprintf(util, sizeof(util), " race"); 375*8e33eff8Schristos } else { 376*8e33eff8Schristos not_reached(); 377*8e33eff8Schristos } 378*8e33eff8Schristos } 379*8e33eff8Schristos 380*8e33eff8Schristos col_size.size_val = reg_size; 381*8e33eff8Schristos col_ind.unsigned_val = j; 382*8e33eff8Schristos col_allocated.size_val = curregs * reg_size; 383*8e33eff8Schristos col_nmalloc.uint64_val = nmalloc; 384*8e33eff8Schristos col_ndalloc.uint64_val = ndalloc; 385*8e33eff8Schristos col_nrequests.uint64_val = nrequests; 386*8e33eff8Schristos col_curregs.size_val = curregs; 387*8e33eff8Schristos col_curslabs.size_val = curslabs; 388*8e33eff8Schristos col_regs.unsigned_val = nregs; 389*8e33eff8Schristos col_pgs.size_val = slab_size / page; 390*8e33eff8Schristos col_util.str_val = util; 391*8e33eff8Schristos col_nfills.uint64_val = nfills; 392*8e33eff8Schristos col_nflushes.uint64_val = nflushes; 393*8e33eff8Schristos col_nslabs.uint64_val = nslabs; 394*8e33eff8Schristos col_nreslabs.uint64_val = nreslabs; 395*8e33eff8Schristos 396*8e33eff8Schristos /* 397*8e33eff8Schristos * Note that mutex columns were initialized above, if mutex == 398*8e33eff8Schristos * true. 399*8e33eff8Schristos */ 400*8e33eff8Schristos 401*8e33eff8Schristos emitter_table_row(emitter, &row); 402*8e33eff8Schristos } 403*8e33eff8Schristos emitter_json_arr_end(emitter); /* Close "bins". */ 404*8e33eff8Schristos 405*8e33eff8Schristos if (in_gap) { 406*8e33eff8Schristos emitter_table_printf(emitter, " ---\n"); 407*8e33eff8Schristos } 408*8e33eff8Schristos } 409*8e33eff8Schristos 410*8e33eff8Schristos static void 411*8e33eff8Schristos stats_arena_lextents_print(emitter_t *emitter, unsigned i) { 412*8e33eff8Schristos unsigned nbins, nlextents, j; 413*8e33eff8Schristos bool in_gap, in_gap_prev; 414*8e33eff8Schristos 415*8e33eff8Schristos CTL_GET("arenas.nbins", &nbins, unsigned); 416*8e33eff8Schristos CTL_GET("arenas.nlextents", &nlextents, unsigned); 417*8e33eff8Schristos 418*8e33eff8Schristos emitter_row_t header_row; 419*8e33eff8Schristos emitter_row_init(&header_row); 420*8e33eff8Schristos emitter_row_t row; 421*8e33eff8Schristos emitter_row_init(&row); 422*8e33eff8Schristos 423*8e33eff8Schristos #define COL(name, left_or_right, col_width, etype) \ 424*8e33eff8Schristos emitter_col_t header_##name; \ 425*8e33eff8Schristos emitter_col_init(&header_##name, &header_row); \ 426*8e33eff8Schristos header_##name.justify = emitter_justify_##left_or_right; \ 427*8e33eff8Schristos header_##name.width = col_width; \ 428*8e33eff8Schristos header_##name.type = emitter_type_title; \ 429*8e33eff8Schristos header_##name.str_val = #name; \ 430*8e33eff8Schristos \ 431*8e33eff8Schristos emitter_col_t col_##name; \ 432*8e33eff8Schristos emitter_col_init(&col_##name, &row); \ 433*8e33eff8Schristos col_##name.justify = emitter_justify_##left_or_right; \ 434*8e33eff8Schristos col_##name.width = col_width; \ 435*8e33eff8Schristos col_##name.type = emitter_type_##etype; 436*8e33eff8Schristos 437*8e33eff8Schristos COL(size, right, 20, size) 438*8e33eff8Schristos COL(ind, right, 4, unsigned) 439*8e33eff8Schristos COL(allocated, right, 13, size) 440*8e33eff8Schristos COL(nmalloc, right, 13, uint64) 441*8e33eff8Schristos COL(ndalloc, right, 13, uint64) 442*8e33eff8Schristos COL(nrequests, right, 13, uint64) 443*8e33eff8Schristos COL(curlextents, right, 13, size) 444*8e33eff8Schristos #undef COL 445*8e33eff8Schristos 446*8e33eff8Schristos /* As with bins, we label the large extents table. */ 447*8e33eff8Schristos header_size.width -= 6; 448*8e33eff8Schristos emitter_table_printf(emitter, "large:"); 449*8e33eff8Schristos emitter_table_row(emitter, &header_row); 450*8e33eff8Schristos emitter_json_arr_begin(emitter, "lextents"); 451*8e33eff8Schristos 452*8e33eff8Schristos for (j = 0, in_gap = false; j < nlextents; j++) { 453*8e33eff8Schristos uint64_t nmalloc, ndalloc, nrequests; 454*8e33eff8Schristos size_t lextent_size, curlextents; 455*8e33eff8Schristos 456*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.lextents.0.nmalloc", i, j, 457*8e33eff8Schristos &nmalloc, uint64_t); 458*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.lextents.0.ndalloc", i, j, 459*8e33eff8Schristos &ndalloc, uint64_t); 460*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.lextents.0.nrequests", i, j, 461*8e33eff8Schristos &nrequests, uint64_t); 462*8e33eff8Schristos in_gap_prev = in_gap; 463*8e33eff8Schristos in_gap = (nrequests == 0); 464*8e33eff8Schristos 465*8e33eff8Schristos if (in_gap_prev && !in_gap) { 466*8e33eff8Schristos emitter_table_printf(emitter, 467*8e33eff8Schristos " ---\n"); 468*8e33eff8Schristos } 469*8e33eff8Schristos 470*8e33eff8Schristos CTL_M2_GET("arenas.lextent.0.size", j, &lextent_size, size_t); 471*8e33eff8Schristos CTL_M2_M4_GET("stats.arenas.0.lextents.0.curlextents", i, j, 472*8e33eff8Schristos &curlextents, size_t); 473*8e33eff8Schristos 474*8e33eff8Schristos emitter_json_arr_obj_begin(emitter); 475*8e33eff8Schristos emitter_json_kv(emitter, "curlextents", emitter_type_size, 476*8e33eff8Schristos &curlextents); 477*8e33eff8Schristos emitter_json_arr_obj_end(emitter); 478*8e33eff8Schristos 479*8e33eff8Schristos col_size.size_val = lextent_size; 480*8e33eff8Schristos col_ind.unsigned_val = nbins + j; 481*8e33eff8Schristos col_allocated.size_val = curlextents * lextent_size; 482*8e33eff8Schristos col_nmalloc.uint64_val = nmalloc; 483*8e33eff8Schristos col_ndalloc.uint64_val = ndalloc; 484*8e33eff8Schristos col_nrequests.uint64_val = nrequests; 485*8e33eff8Schristos col_curlextents.size_val = curlextents; 486*8e33eff8Schristos 487*8e33eff8Schristos if (!in_gap) { 488*8e33eff8Schristos emitter_table_row(emitter, &row); 489*8e33eff8Schristos } 490*8e33eff8Schristos } 491*8e33eff8Schristos emitter_json_arr_end(emitter); /* Close "lextents". */ 492*8e33eff8Schristos if (in_gap) { 493*8e33eff8Schristos emitter_table_printf(emitter, " ---\n"); 494*8e33eff8Schristos } 495*8e33eff8Schristos } 496*8e33eff8Schristos 497*8e33eff8Schristos static void 498*8e33eff8Schristos stats_arena_mutexes_print(emitter_t *emitter, unsigned arena_ind) { 499*8e33eff8Schristos emitter_row_t row; 500*8e33eff8Schristos emitter_col_t col_name; 501*8e33eff8Schristos emitter_col_t col64[mutex_prof_num_uint64_t_counters]; 502*8e33eff8Schristos emitter_col_t col32[mutex_prof_num_uint32_t_counters]; 503*8e33eff8Schristos 504*8e33eff8Schristos emitter_row_init(&row); 505*8e33eff8Schristos mutex_stats_init_cols(&row, "", &col_name, col64, col32); 506*8e33eff8Schristos 507*8e33eff8Schristos emitter_json_dict_begin(emitter, "mutexes"); 508*8e33eff8Schristos emitter_table_row(emitter, &row); 509*8e33eff8Schristos 510*8e33eff8Schristos for (mutex_prof_arena_ind_t i = 0; i < mutex_prof_num_arena_mutexes; 511*8e33eff8Schristos i++) { 512*8e33eff8Schristos const char *name = arena_mutex_names[i]; 513*8e33eff8Schristos emitter_json_dict_begin(emitter, name); 514*8e33eff8Schristos mutex_stats_read_arena(arena_ind, i, name, &col_name, col64, 515*8e33eff8Schristos col32); 516*8e33eff8Schristos mutex_stats_emit(emitter, &row, col64, col32); 517*8e33eff8Schristos emitter_json_dict_end(emitter); /* Close the mutex dict. */ 518*8e33eff8Schristos } 519*8e33eff8Schristos emitter_json_dict_end(emitter); /* End "mutexes". */ 520*8e33eff8Schristos } 521*8e33eff8Schristos 522*8e33eff8Schristos static void 523*8e33eff8Schristos stats_arena_print(emitter_t *emitter, unsigned i, bool bins, bool large, 524*8e33eff8Schristos bool mutex) { 525*8e33eff8Schristos unsigned nthreads; 526*8e33eff8Schristos const char *dss; 527*8e33eff8Schristos ssize_t dirty_decay_ms, muzzy_decay_ms; 528*8e33eff8Schristos size_t page, pactive, pdirty, pmuzzy, mapped, retained; 529*8e33eff8Schristos size_t base, internal, resident, metadata_thp; 530*8e33eff8Schristos uint64_t dirty_npurge, dirty_nmadvise, dirty_purged; 531*8e33eff8Schristos uint64_t muzzy_npurge, muzzy_nmadvise, muzzy_purged; 532*8e33eff8Schristos size_t small_allocated; 533*8e33eff8Schristos uint64_t small_nmalloc, small_ndalloc, small_nrequests; 534*8e33eff8Schristos size_t large_allocated; 535*8e33eff8Schristos uint64_t large_nmalloc, large_ndalloc, large_nrequests; 536*8e33eff8Schristos size_t tcache_bytes; 537*8e33eff8Schristos uint64_t uptime; 538*8e33eff8Schristos 539*8e33eff8Schristos CTL_GET("arenas.page", &page, size_t); 540*8e33eff8Schristos 541*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.nthreads", i, &nthreads, unsigned); 542*8e33eff8Schristos emitter_kv(emitter, "nthreads", "assigned threads", 543*8e33eff8Schristos emitter_type_unsigned, &nthreads); 544*8e33eff8Schristos 545*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.uptime", i, &uptime, uint64_t); 546*8e33eff8Schristos emitter_kv(emitter, "uptime_ns", "uptime", emitter_type_uint64, 547*8e33eff8Schristos &uptime); 548*8e33eff8Schristos 549*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.dss", i, &dss, const char *); 550*8e33eff8Schristos emitter_kv(emitter, "dss", "dss allocation precedence", 551*8e33eff8Schristos emitter_type_string, &dss); 552*8e33eff8Schristos 553*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.dirty_decay_ms", i, &dirty_decay_ms, 554*8e33eff8Schristos ssize_t); 555*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.muzzy_decay_ms", i, &muzzy_decay_ms, 556*8e33eff8Schristos ssize_t); 557*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.pactive", i, &pactive, size_t); 558*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.pdirty", i, &pdirty, size_t); 559*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.pmuzzy", i, &pmuzzy, size_t); 560*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.dirty_npurge", i, &dirty_npurge, uint64_t); 561*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.dirty_nmadvise", i, &dirty_nmadvise, 562*8e33eff8Schristos uint64_t); 563*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.dirty_purged", i, &dirty_purged, uint64_t); 564*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.muzzy_npurge", i, &muzzy_npurge, uint64_t); 565*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.muzzy_nmadvise", i, &muzzy_nmadvise, 566*8e33eff8Schristos uint64_t); 567*8e33eff8Schristos CTL_M2_GET("stats.arenas.0.muzzy_purged", i, &muzzy_purged, uint64_t); 568*8e33eff8Schristos 569*8e33eff8Schristos emitter_row_t decay_row; 570*8e33eff8Schristos emitter_row_init(&decay_row); 571*8e33eff8Schristos 572*8e33eff8Schristos /* JSON-style emission. */ 573*8e33eff8Schristos emitter_json_kv(emitter, "dirty_decay_ms", emitter_type_ssize, 574*8e33eff8Schristos &dirty_decay_ms); 575*8e33eff8Schristos emitter_json_kv(emitter, "muzzy_decay_ms", emitter_type_ssize, 576*8e33eff8Schristos &muzzy_decay_ms); 577*8e33eff8Schristos 578*8e33eff8Schristos emitter_json_kv(emitter, "pactive", emitter_type_size, &pactive); 579*8e33eff8Schristos emitter_json_kv(emitter, "pdirty", emitter_type_size, &pdirty); 580*8e33eff8Schristos emitter_json_kv(emitter, "pmuzzy", emitter_type_size, &pmuzzy); 581*8e33eff8Schristos 582*8e33eff8Schristos emitter_json_kv(emitter, "dirty_npurge", emitter_type_uint64, 583*8e33eff8Schristos &dirty_npurge); 584*8e33eff8Schristos emitter_json_kv(emitter, "dirty_nmadvise", emitter_type_uint64, 585*8e33eff8Schristos &dirty_nmadvise); 586*8e33eff8Schristos emitter_json_kv(emitter, "dirty_purged", emitter_type_uint64, 587*8e33eff8Schristos &dirty_purged); 588*8e33eff8Schristos 589*8e33eff8Schristos emitter_json_kv(emitter, "muzzy_npurge", emitter_type_uint64, 590*8e33eff8Schristos &muzzy_npurge); 591*8e33eff8Schristos emitter_json_kv(emitter, "muzzy_nmadvise", emitter_type_uint64, 592*8e33eff8Schristos &muzzy_nmadvise); 593*8e33eff8Schristos emitter_json_kv(emitter, "muzzy_purged", emitter_type_uint64, 594*8e33eff8Schristos &muzzy_purged); 595*8e33eff8Schristos 596*8e33eff8Schristos /* Table-style emission. */ 597*8e33eff8Schristos emitter_col_t decay_type; 598*8e33eff8Schristos emitter_col_init(&decay_type, &decay_row); 599*8e33eff8Schristos decay_type.justify = emitter_justify_right; 600*8e33eff8Schristos decay_type.width = 9; 601*8e33eff8Schristos decay_type.type = emitter_type_title; 602*8e33eff8Schristos decay_type.str_val = "decaying:"; 603*8e33eff8Schristos 604*8e33eff8Schristos emitter_col_t decay_time; 605*8e33eff8Schristos emitter_col_init(&decay_time, &decay_row); 606*8e33eff8Schristos decay_time.justify = emitter_justify_right; 607*8e33eff8Schristos decay_time.width = 6; 608*8e33eff8Schristos decay_time.type = emitter_type_title; 609*8e33eff8Schristos decay_time.str_val = "time"; 610*8e33eff8Schristos 611*8e33eff8Schristos emitter_col_t decay_npages; 612*8e33eff8Schristos emitter_col_init(&decay_npages, &decay_row); 613*8e33eff8Schristos decay_npages.justify = emitter_justify_right; 614*8e33eff8Schristos decay_npages.width = 13; 615*8e33eff8Schristos decay_npages.type = emitter_type_title; 616*8e33eff8Schristos decay_npages.str_val = "npages"; 617*8e33eff8Schristos 618*8e33eff8Schristos emitter_col_t decay_sweeps; 619*8e33eff8Schristos emitter_col_init(&decay_sweeps, &decay_row); 620*8e33eff8Schristos decay_sweeps.justify = emitter_justify_right; 621*8e33eff8Schristos decay_sweeps.width = 13; 622*8e33eff8Schristos decay_sweeps.type = emitter_type_title; 623*8e33eff8Schristos decay_sweeps.str_val = "sweeps"; 624*8e33eff8Schristos 625*8e33eff8Schristos emitter_col_t decay_madvises; 626*8e33eff8Schristos emitter_col_init(&decay_madvises, &decay_row); 627*8e33eff8Schristos decay_madvises.justify = emitter_justify_right; 628*8e33eff8Schristos decay_madvises.width = 13; 629*8e33eff8Schristos decay_madvises.type = emitter_type_title; 630*8e33eff8Schristos decay_madvises.str_val = "madvises"; 631*8e33eff8Schristos 632*8e33eff8Schristos emitter_col_t decay_purged; 633*8e33eff8Schristos emitter_col_init(&decay_purged, &decay_row); 634*8e33eff8Schristos decay_purged.justify = emitter_justify_right; 635*8e33eff8Schristos decay_purged.width = 13; 636*8e33eff8Schristos decay_purged.type = emitter_type_title; 637*8e33eff8Schristos decay_purged.str_val = "purged"; 638*8e33eff8Schristos 639*8e33eff8Schristos /* Title row. */ 640*8e33eff8Schristos emitter_table_row(emitter, &decay_row); 641*8e33eff8Schristos 642*8e33eff8Schristos /* Dirty row. */ 643*8e33eff8Schristos decay_type.str_val = "dirty:"; 644*8e33eff8Schristos 645*8e33eff8Schristos if (dirty_decay_ms >= 0) { 646*8e33eff8Schristos decay_time.type = emitter_type_ssize; 647*8e33eff8Schristos decay_time.ssize_val = dirty_decay_ms; 648*8e33eff8Schristos } else { 649*8e33eff8Schristos decay_time.type = emitter_type_title; 650*8e33eff8Schristos decay_time.str_val = "N/A"; 651*8e33eff8Schristos } 652*8e33eff8Schristos 653*8e33eff8Schristos decay_npages.type = emitter_type_size; 654*8e33eff8Schristos decay_npages.size_val = pdirty; 655*8e33eff8Schristos 656*8e33eff8Schristos decay_sweeps.type = emitter_type_uint64; 657*8e33eff8Schristos decay_sweeps.uint64_val = dirty_npurge; 658*8e33eff8Schristos 659*8e33eff8Schristos decay_madvises.type = emitter_type_uint64; 660*8e33eff8Schristos decay_madvises.uint64_val = dirty_nmadvise; 661*8e33eff8Schristos 662*8e33eff8Schristos decay_purged.type = emitter_type_uint64; 663*8e33eff8Schristos decay_purged.uint64_val = dirty_purged; 664*8e33eff8Schristos 665*8e33eff8Schristos emitter_table_row(emitter, &decay_row); 666*8e33eff8Schristos 667*8e33eff8Schristos /* Muzzy row. */ 668*8e33eff8Schristos decay_type.str_val = "muzzy:"; 669*8e33eff8Schristos 670*8e33eff8Schristos if (muzzy_decay_ms >= 0) { 671*8e33eff8Schristos decay_time.type = emitter_type_ssize; 672*8e33eff8Schristos decay_time.ssize_val = muzzy_decay_ms; 673*8e33eff8Schristos } else { 674*8e33eff8Schristos decay_time.type = emitter_type_title; 675*8e33eff8Schristos decay_time.str_val = "N/A"; 676*8e33eff8Schristos } 677*8e33eff8Schristos 678*8e33eff8Schristos decay_npages.type = emitter_type_size; 679*8e33eff8Schristos decay_npages.size_val = pmuzzy; 680*8e33eff8Schristos 681*8e33eff8Schristos decay_sweeps.type = emitter_type_uint64; 682*8e33eff8Schristos decay_sweeps.uint64_val = muzzy_npurge; 683*8e33eff8Schristos 684*8e33eff8Schristos decay_madvises.type = emitter_type_uint64; 685*8e33eff8Schristos decay_madvises.uint64_val = muzzy_nmadvise; 686*8e33eff8Schristos 687*8e33eff8Schristos decay_purged.type = emitter_type_uint64; 688*8e33eff8Schristos decay_purged.uint64_val = muzzy_purged; 689*8e33eff8Schristos 690*8e33eff8Schristos emitter_table_row(emitter, &decay_row); 691*8e33eff8Schristos 692*8e33eff8Schristos /* Small / large / total allocation counts. */ 693*8e33eff8Schristos emitter_row_t alloc_count_row; 694*8e33eff8Schristos emitter_row_init(&alloc_count_row); 695*8e33eff8Schristos 696*8e33eff8Schristos emitter_col_t alloc_count_title; 697*8e33eff8Schristos emitter_col_init(&alloc_count_title, &alloc_count_row); 698*8e33eff8Schristos alloc_count_title.justify = emitter_justify_left; 699*8e33eff8Schristos alloc_count_title.width = 25; 700*8e33eff8Schristos alloc_count_title.type = emitter_type_title; 701*8e33eff8Schristos alloc_count_title.str_val = ""; 702*8e33eff8Schristos 703*8e33eff8Schristos emitter_col_t alloc_count_allocated; 704*8e33eff8Schristos emitter_col_init(&alloc_count_allocated, &alloc_count_row); 705*8e33eff8Schristos alloc_count_allocated.justify = emitter_justify_right; 706*8e33eff8Schristos alloc_count_allocated.width = 12; 707*8e33eff8Schristos alloc_count_allocated.type = emitter_type_title; 708*8e33eff8Schristos alloc_count_allocated.str_val = "allocated"; 709*8e33eff8Schristos 710*8e33eff8Schristos emitter_col_t alloc_count_nmalloc; 711*8e33eff8Schristos emitter_col_init(&alloc_count_nmalloc, &alloc_count_row); 712*8e33eff8Schristos alloc_count_nmalloc.justify = emitter_justify_right; 713*8e33eff8Schristos alloc_count_nmalloc.width = 12; 714*8e33eff8Schristos alloc_count_nmalloc.type = emitter_type_title; 715*8e33eff8Schristos alloc_count_nmalloc.str_val = "nmalloc"; 716*8e33eff8Schristos 717*8e33eff8Schristos emitter_col_t alloc_count_ndalloc; 718*8e33eff8Schristos emitter_col_init(&alloc_count_ndalloc, &alloc_count_row); 719*8e33eff8Schristos alloc_count_ndalloc.justify = emitter_justify_right; 720*8e33eff8Schristos alloc_count_ndalloc.width = 12; 721*8e33eff8Schristos alloc_count_ndalloc.type = emitter_type_title; 722*8e33eff8Schristos alloc_count_ndalloc.str_val = "ndalloc"; 723*8e33eff8Schristos 724*8e33eff8Schristos emitter_col_t alloc_count_nrequests; 725*8e33eff8Schristos emitter_col_init(&alloc_count_nrequests, &alloc_count_row); 726*8e33eff8Schristos alloc_count_nrequests.justify = emitter_justify_right; 727*8e33eff8Schristos alloc_count_nrequests.width = 12; 728*8e33eff8Schristos alloc_count_nrequests.type = emitter_type_title; 729*8e33eff8Schristos alloc_count_nrequests.str_val = "nrequests"; 730*8e33eff8Schristos 731*8e33eff8Schristos emitter_table_row(emitter, &alloc_count_row); 732*8e33eff8Schristos 733*8e33eff8Schristos #define GET_AND_EMIT_ALLOC_STAT(small_or_large, name, valtype) \ 734*8e33eff8Schristos CTL_M2_GET("stats.arenas.0." #small_or_large "." #name, i, \ 735*8e33eff8Schristos &small_or_large##_##name, valtype##_t); \ 736*8e33eff8Schristos emitter_json_kv(emitter, #name, emitter_type_##valtype, \ 737*8e33eff8Schristos &small_or_large##_##name); \ 738*8e33eff8Schristos alloc_count_##name.type = emitter_type_##valtype; \ 739*8e33eff8Schristos alloc_count_##name.valtype##_val = small_or_large##_##name; 740*8e33eff8Schristos 741*8e33eff8Schristos emitter_json_dict_begin(emitter, "small"); 742*8e33eff8Schristos alloc_count_title.str_val = "small:"; 743*8e33eff8Schristos 744*8e33eff8Schristos GET_AND_EMIT_ALLOC_STAT(small, allocated, size) 745*8e33eff8Schristos GET_AND_EMIT_ALLOC_STAT(small, nmalloc, uint64) 746*8e33eff8Schristos GET_AND_EMIT_ALLOC_STAT(small, ndalloc, uint64) 747*8e33eff8Schristos GET_AND_EMIT_ALLOC_STAT(small, nrequests, uint64) 748*8e33eff8Schristos 749*8e33eff8Schristos emitter_table_row(emitter, &alloc_count_row); 750*8e33eff8Schristos emitter_json_dict_end(emitter); /* Close "small". */ 751*8e33eff8Schristos 752*8e33eff8Schristos emitter_json_dict_begin(emitter, "large"); 753*8e33eff8Schristos alloc_count_title.str_val = "large:"; 754*8e33eff8Schristos 755*8e33eff8Schristos GET_AND_EMIT_ALLOC_STAT(large, allocated, size) 756*8e33eff8Schristos GET_AND_EMIT_ALLOC_STAT(large, nmalloc, uint64) 757*8e33eff8Schristos GET_AND_EMIT_ALLOC_STAT(large, ndalloc, uint64) 758*8e33eff8Schristos GET_AND_EMIT_ALLOC_STAT(large, nrequests, uint64) 759*8e33eff8Schristos 760*8e33eff8Schristos emitter_table_row(emitter, &alloc_count_row); 761*8e33eff8Schristos emitter_json_dict_end(emitter); /* Close "large". */ 762*8e33eff8Schristos 763*8e33eff8Schristos #undef GET_AND_EMIT_ALLOC_STAT 764*8e33eff8Schristos 765*8e33eff8Schristos /* Aggregated small + large stats are emitter only in table mode. */ 766*8e33eff8Schristos alloc_count_title.str_val = "total:"; 767*8e33eff8Schristos alloc_count_allocated.size_val = small_allocated + large_allocated; 768*8e33eff8Schristos alloc_count_nmalloc.uint64_val = small_nmalloc + large_nmalloc; 769*8e33eff8Schristos alloc_count_ndalloc.uint64_val = small_ndalloc + large_ndalloc; 770*8e33eff8Schristos alloc_count_nrequests.uint64_val = small_nrequests + large_nrequests; 771*8e33eff8Schristos emitter_table_row(emitter, &alloc_count_row); 772*8e33eff8Schristos 773*8e33eff8Schristos emitter_row_t mem_count_row; 774*8e33eff8Schristos emitter_row_init(&mem_count_row); 775*8e33eff8Schristos 776*8e33eff8Schristos emitter_col_t mem_count_title; 777*8e33eff8Schristos emitter_col_init(&mem_count_title, &mem_count_row); 778*8e33eff8Schristos mem_count_title.justify = emitter_justify_left; 779*8e33eff8Schristos mem_count_title.width = 25; 780*8e33eff8Schristos mem_count_title.type = emitter_type_title; 781*8e33eff8Schristos mem_count_title.str_val = ""; 782*8e33eff8Schristos 783*8e33eff8Schristos emitter_col_t mem_count_val; 784*8e33eff8Schristos emitter_col_init(&mem_count_val, &mem_count_row); 785*8e33eff8Schristos mem_count_val.justify = emitter_justify_right; 786*8e33eff8Schristos mem_count_val.width = 12; 787*8e33eff8Schristos mem_count_val.type = emitter_type_title; 788*8e33eff8Schristos mem_count_val.str_val = ""; 789*8e33eff8Schristos 790*8e33eff8Schristos emitter_table_row(emitter, &mem_count_row); 791*8e33eff8Schristos mem_count_val.type = emitter_type_size; 792*8e33eff8Schristos 793*8e33eff8Schristos /* Active count in bytes is emitted only in table mode. */ 794*8e33eff8Schristos mem_count_title.str_val = "active:"; 795*8e33eff8Schristos mem_count_val.size_val = pactive * page; 796*8e33eff8Schristos emitter_table_row(emitter, &mem_count_row); 797*8e33eff8Schristos 798*8e33eff8Schristos #define GET_AND_EMIT_MEM_STAT(stat) \ 799*8e33eff8Schristos CTL_M2_GET("stats.arenas.0."#stat, i, &stat, size_t); \ 800*8e33eff8Schristos emitter_json_kv(emitter, #stat, emitter_type_size, &stat); \ 801*8e33eff8Schristos mem_count_title.str_val = #stat":"; \ 802*8e33eff8Schristos mem_count_val.size_val = stat; \ 803*8e33eff8Schristos emitter_table_row(emitter, &mem_count_row); 804*8e33eff8Schristos 805*8e33eff8Schristos GET_AND_EMIT_MEM_STAT(mapped) 806*8e33eff8Schristos GET_AND_EMIT_MEM_STAT(retained) 807*8e33eff8Schristos GET_AND_EMIT_MEM_STAT(base) 808*8e33eff8Schristos GET_AND_EMIT_MEM_STAT(internal) 809*8e33eff8Schristos GET_AND_EMIT_MEM_STAT(metadata_thp) 810*8e33eff8Schristos GET_AND_EMIT_MEM_STAT(tcache_bytes) 811*8e33eff8Schristos GET_AND_EMIT_MEM_STAT(resident) 812*8e33eff8Schristos #undef GET_AND_EMIT_MEM_STAT 813*8e33eff8Schristos 814*8e33eff8Schristos if (mutex) { 815*8e33eff8Schristos stats_arena_mutexes_print(emitter, i); 816*8e33eff8Schristos } 817*8e33eff8Schristos if (bins) { 818*8e33eff8Schristos stats_arena_bins_print(emitter, mutex, i); 819*8e33eff8Schristos } 820*8e33eff8Schristos if (large) { 821*8e33eff8Schristos stats_arena_lextents_print(emitter, i); 822*8e33eff8Schristos } 823*8e33eff8Schristos } 824*8e33eff8Schristos 825*8e33eff8Schristos static void 826*8e33eff8Schristos stats_general_print(emitter_t *emitter) { 827*8e33eff8Schristos const char *cpv; 828*8e33eff8Schristos bool bv, bv2; 829*8e33eff8Schristos unsigned uv; 830*8e33eff8Schristos uint32_t u32v; 831*8e33eff8Schristos uint64_t u64v; 832*8e33eff8Schristos ssize_t ssv, ssv2; 833*8e33eff8Schristos size_t sv, bsz, usz, ssz, sssz, cpsz; 834*8e33eff8Schristos 835*8e33eff8Schristos bsz = sizeof(bool); 836*8e33eff8Schristos usz = sizeof(unsigned); 837*8e33eff8Schristos ssz = sizeof(size_t); 838*8e33eff8Schristos sssz = sizeof(ssize_t); 839*8e33eff8Schristos cpsz = sizeof(const char *); 840*8e33eff8Schristos 841*8e33eff8Schristos CTL_GET("version", &cpv, const char *); 842*8e33eff8Schristos emitter_kv(emitter, "version", "Version", emitter_type_string, &cpv); 843*8e33eff8Schristos 844*8e33eff8Schristos /* config. */ 845*8e33eff8Schristos emitter_dict_begin(emitter, "config", "Build-time option settings"); 846*8e33eff8Schristos #define CONFIG_WRITE_BOOL(name) \ 847*8e33eff8Schristos do { \ 848*8e33eff8Schristos CTL_GET("config."#name, &bv, bool); \ 849*8e33eff8Schristos emitter_kv(emitter, #name, "config."#name, \ 850*8e33eff8Schristos emitter_type_bool, &bv); \ 851*8e33eff8Schristos } while (0) 852*8e33eff8Schristos 853*8e33eff8Schristos CONFIG_WRITE_BOOL(cache_oblivious); 854*8e33eff8Schristos CONFIG_WRITE_BOOL(debug); 855*8e33eff8Schristos CONFIG_WRITE_BOOL(fill); 856*8e33eff8Schristos CONFIG_WRITE_BOOL(lazy_lock); 857*8e33eff8Schristos emitter_kv(emitter, "malloc_conf", "config.malloc_conf", 858*8e33eff8Schristos emitter_type_string, &config_malloc_conf); 859*8e33eff8Schristos 860*8e33eff8Schristos CONFIG_WRITE_BOOL(prof); 861*8e33eff8Schristos CONFIG_WRITE_BOOL(prof_libgcc); 862*8e33eff8Schristos CONFIG_WRITE_BOOL(prof_libunwind); 863*8e33eff8Schristos CONFIG_WRITE_BOOL(stats); 864*8e33eff8Schristos CONFIG_WRITE_BOOL(utrace); 865*8e33eff8Schristos CONFIG_WRITE_BOOL(xmalloc); 866*8e33eff8Schristos #undef CONFIG_WRITE_BOOL 867*8e33eff8Schristos emitter_dict_end(emitter); /* Close "config" dict. */ 868*8e33eff8Schristos 869*8e33eff8Schristos /* opt. */ 870*8e33eff8Schristos #define OPT_WRITE(name, var, size, emitter_type) \ 871*8e33eff8Schristos if (je_mallctl("opt."name, (void *)&var, &size, NULL, 0) == \ 872*8e33eff8Schristos 0) { \ 873*8e33eff8Schristos emitter_kv(emitter, name, "opt."name, emitter_type, \ 874*8e33eff8Schristos &var); \ 875*8e33eff8Schristos } 876*8e33eff8Schristos 877*8e33eff8Schristos #define OPT_WRITE_MUTABLE(name, var1, var2, size, emitter_type, \ 878*8e33eff8Schristos altname) \ 879*8e33eff8Schristos if (je_mallctl("opt."name, (void *)&var1, &size, NULL, 0) == \ 880*8e33eff8Schristos 0 && je_mallctl(altname, (void *)&var2, &size, NULL, 0) \ 881*8e33eff8Schristos == 0) { \ 882*8e33eff8Schristos emitter_kv_note(emitter, name, "opt."name, \ 883*8e33eff8Schristos emitter_type, &var1, altname, emitter_type, \ 884*8e33eff8Schristos &var2); \ 885*8e33eff8Schristos } 886*8e33eff8Schristos 887*8e33eff8Schristos #define OPT_WRITE_BOOL(name) OPT_WRITE(name, bv, bsz, emitter_type_bool) 888*8e33eff8Schristos #define OPT_WRITE_BOOL_MUTABLE(name, altname) \ 889*8e33eff8Schristos OPT_WRITE_MUTABLE(name, bv, bv2, bsz, emitter_type_bool, altname) 890*8e33eff8Schristos 891*8e33eff8Schristos #define OPT_WRITE_UNSIGNED(name) \ 892*8e33eff8Schristos OPT_WRITE(name, uv, usz, emitter_type_unsigned) 893*8e33eff8Schristos 894*8e33eff8Schristos #define OPT_WRITE_SSIZE_T(name) \ 895*8e33eff8Schristos OPT_WRITE(name, ssv, sssz, emitter_type_ssize) 896*8e33eff8Schristos #define OPT_WRITE_SSIZE_T_MUTABLE(name, altname) \ 897*8e33eff8Schristos OPT_WRITE_MUTABLE(name, ssv, ssv2, sssz, emitter_type_ssize, \ 898*8e33eff8Schristos altname) 899*8e33eff8Schristos 900*8e33eff8Schristos #define OPT_WRITE_CHAR_P(name) \ 901*8e33eff8Schristos OPT_WRITE(name, cpv, cpsz, emitter_type_string) 902*8e33eff8Schristos 903*8e33eff8Schristos emitter_dict_begin(emitter, "opt", "Run-time option settings"); 904*8e33eff8Schristos 905*8e33eff8Schristos OPT_WRITE_BOOL("abort") 906*8e33eff8Schristos OPT_WRITE_BOOL("abort_conf") 907*8e33eff8Schristos OPT_WRITE_BOOL("retain") 908*8e33eff8Schristos OPT_WRITE_CHAR_P("dss") 909*8e33eff8Schristos OPT_WRITE_UNSIGNED("narenas") 910*8e33eff8Schristos OPT_WRITE_CHAR_P("percpu_arena") 911*8e33eff8Schristos OPT_WRITE_CHAR_P("metadata_thp") 912*8e33eff8Schristos OPT_WRITE_BOOL_MUTABLE("background_thread", "background_thread") 913*8e33eff8Schristos OPT_WRITE_SSIZE_T_MUTABLE("dirty_decay_ms", "arenas.dirty_decay_ms") 914*8e33eff8Schristos OPT_WRITE_SSIZE_T_MUTABLE("muzzy_decay_ms", "arenas.muzzy_decay_ms") 915*8e33eff8Schristos OPT_WRITE_UNSIGNED("lg_extent_max_active_fit") 916*8e33eff8Schristos OPT_WRITE_CHAR_P("junk") 917*8e33eff8Schristos OPT_WRITE_BOOL("zero") 918*8e33eff8Schristos OPT_WRITE_BOOL("utrace") 919*8e33eff8Schristos OPT_WRITE_BOOL("xmalloc") 920*8e33eff8Schristos OPT_WRITE_BOOL("tcache") 921*8e33eff8Schristos OPT_WRITE_SSIZE_T("lg_tcache_max") 922*8e33eff8Schristos OPT_WRITE_CHAR_P("thp") 923*8e33eff8Schristos OPT_WRITE_BOOL("prof") 924*8e33eff8Schristos OPT_WRITE_CHAR_P("prof_prefix") 925*8e33eff8Schristos OPT_WRITE_BOOL_MUTABLE("prof_active", "prof.active") 926*8e33eff8Schristos OPT_WRITE_BOOL_MUTABLE("prof_thread_active_init", 927*8e33eff8Schristos "prof.thread_active_init") 928*8e33eff8Schristos OPT_WRITE_SSIZE_T_MUTABLE("lg_prof_sample", "prof.lg_sample") 929*8e33eff8Schristos OPT_WRITE_BOOL("prof_accum") 930*8e33eff8Schristos OPT_WRITE_SSIZE_T("lg_prof_interval") 931*8e33eff8Schristos OPT_WRITE_BOOL("prof_gdump") 932*8e33eff8Schristos OPT_WRITE_BOOL("prof_final") 933*8e33eff8Schristos OPT_WRITE_BOOL("prof_leak") 934*8e33eff8Schristos OPT_WRITE_BOOL("stats_print") 935*8e33eff8Schristos OPT_WRITE_CHAR_P("stats_print_opts") 936*8e33eff8Schristos 937*8e33eff8Schristos emitter_dict_end(emitter); 938*8e33eff8Schristos 939*8e33eff8Schristos #undef OPT_WRITE 940*8e33eff8Schristos #undef OPT_WRITE_MUTABLE 941*8e33eff8Schristos #undef OPT_WRITE_BOOL 942*8e33eff8Schristos #undef OPT_WRITE_BOOL_MUTABLE 943*8e33eff8Schristos #undef OPT_WRITE_UNSIGNED 944*8e33eff8Schristos #undef OPT_WRITE_SSIZE_T 945*8e33eff8Schristos #undef OPT_WRITE_SSIZE_T_MUTABLE 946*8e33eff8Schristos #undef OPT_WRITE_CHAR_P 947*8e33eff8Schristos 948*8e33eff8Schristos /* prof. */ 949*8e33eff8Schristos if (config_prof) { 950*8e33eff8Schristos emitter_dict_begin(emitter, "prof", "Profiling settings"); 951*8e33eff8Schristos 952*8e33eff8Schristos CTL_GET("prof.thread_active_init", &bv, bool); 953*8e33eff8Schristos emitter_kv(emitter, "thread_active_init", 954*8e33eff8Schristos "prof.thread_active_init", emitter_type_bool, &bv); 955*8e33eff8Schristos 956*8e33eff8Schristos CTL_GET("prof.active", &bv, bool); 957*8e33eff8Schristos emitter_kv(emitter, "active", "prof.active", emitter_type_bool, 958*8e33eff8Schristos &bv); 959*8e33eff8Schristos 960*8e33eff8Schristos CTL_GET("prof.gdump", &bv, bool); 961*8e33eff8Schristos emitter_kv(emitter, "gdump", "prof.gdump", emitter_type_bool, 962*8e33eff8Schristos &bv); 963*8e33eff8Schristos 964*8e33eff8Schristos CTL_GET("prof.interval", &u64v, uint64_t); 965*8e33eff8Schristos emitter_kv(emitter, "interval", "prof.interval", 966*8e33eff8Schristos emitter_type_uint64, &u64v); 967*8e33eff8Schristos 968*8e33eff8Schristos CTL_GET("prof.lg_sample", &ssv, ssize_t); 969*8e33eff8Schristos emitter_kv(emitter, "lg_sample", "prof.lg_sample", 970*8e33eff8Schristos emitter_type_ssize, &ssv); 971*8e33eff8Schristos 972*8e33eff8Schristos emitter_dict_end(emitter); /* Close "prof". */ 973*8e33eff8Schristos } 974*8e33eff8Schristos 975*8e33eff8Schristos /* arenas. */ 976*8e33eff8Schristos /* 977*8e33eff8Schristos * The json output sticks arena info into an "arenas" dict; the table 978*8e33eff8Schristos * output puts them at the top-level. 979*8e33eff8Schristos */ 980*8e33eff8Schristos emitter_json_dict_begin(emitter, "arenas"); 981*8e33eff8Schristos 982*8e33eff8Schristos CTL_GET("arenas.narenas", &uv, unsigned); 983*8e33eff8Schristos emitter_kv(emitter, "narenas", "Arenas", emitter_type_unsigned, &uv); 984*8e33eff8Schristos 985*8e33eff8Schristos /* 986*8e33eff8Schristos * Decay settings are emitted only in json mode; in table mode, they're 987*8e33eff8Schristos * emitted as notes with the opt output, above. 988*8e33eff8Schristos */ 989*8e33eff8Schristos CTL_GET("arenas.dirty_decay_ms", &ssv, ssize_t); 990*8e33eff8Schristos emitter_json_kv(emitter, "dirty_decay_ms", emitter_type_ssize, &ssv); 991*8e33eff8Schristos 992*8e33eff8Schristos CTL_GET("arenas.muzzy_decay_ms", &ssv, ssize_t); 993*8e33eff8Schristos emitter_json_kv(emitter, "muzzy_decay_ms", emitter_type_ssize, &ssv); 994*8e33eff8Schristos 995*8e33eff8Schristos CTL_GET("arenas.quantum", &sv, size_t); 996*8e33eff8Schristos emitter_kv(emitter, "quantum", "Quantum size", emitter_type_size, &sv); 997*8e33eff8Schristos 998*8e33eff8Schristos CTL_GET("arenas.page", &sv, size_t); 999*8e33eff8Schristos emitter_kv(emitter, "page", "Page size", emitter_type_size, &sv); 1000*8e33eff8Schristos 1001*8e33eff8Schristos if (je_mallctl("arenas.tcache_max", (void *)&sv, &ssz, NULL, 0) == 0) { 1002*8e33eff8Schristos emitter_kv(emitter, "tcache_max", 1003*8e33eff8Schristos "Maximum thread-cached size class", emitter_type_size, &sv); 1004*8e33eff8Schristos } 1005*8e33eff8Schristos 1006*8e33eff8Schristos unsigned nbins; 1007*8e33eff8Schristos CTL_GET("arenas.nbins", &nbins, unsigned); 1008*8e33eff8Schristos emitter_kv(emitter, "nbins", "Number of bin size classes", 1009*8e33eff8Schristos emitter_type_unsigned, &nbins); 1010*8e33eff8Schristos 1011*8e33eff8Schristos unsigned nh_bins; 1012*8e33eff8Schristos CTL_GET("arenas.nhbins", &nh_bins, unsigned); 1013*8e33eff8Schristos emitter_kv(emitter, "nhbins", "Number of thread-cache bin size classes", 1014*8e33eff8Schristos emitter_type_unsigned, &nh_bins); 1015*8e33eff8Schristos 1016*8e33eff8Schristos /* 1017*8e33eff8Schristos * We do enough mallctls in a loop that we actually want to omit them 1018*8e33eff8Schristos * (not just omit the printing). 1019*8e33eff8Schristos */ 1020*8e33eff8Schristos if (emitter->output == emitter_output_json) { 1021*8e33eff8Schristos emitter_json_arr_begin(emitter, "bin"); 1022*8e33eff8Schristos for (unsigned i = 0; i < nbins; i++) { 1023*8e33eff8Schristos emitter_json_arr_obj_begin(emitter); 1024*8e33eff8Schristos 1025*8e33eff8Schristos CTL_M2_GET("arenas.bin.0.size", i, &sv, size_t); 1026*8e33eff8Schristos emitter_json_kv(emitter, "size", emitter_type_size, 1027*8e33eff8Schristos &sv); 1028*8e33eff8Schristos 1029*8e33eff8Schristos CTL_M2_GET("arenas.bin.0.nregs", i, &u32v, uint32_t); 1030*8e33eff8Schristos emitter_json_kv(emitter, "nregs", emitter_type_uint32, 1031*8e33eff8Schristos &u32v); 1032*8e33eff8Schristos 1033*8e33eff8Schristos CTL_M2_GET("arenas.bin.0.slab_size", i, &sv, size_t); 1034*8e33eff8Schristos emitter_json_kv(emitter, "slab_size", emitter_type_size, 1035*8e33eff8Schristos &sv); 1036*8e33eff8Schristos 1037*8e33eff8Schristos emitter_json_arr_obj_end(emitter); 1038*8e33eff8Schristos } 1039*8e33eff8Schristos emitter_json_arr_end(emitter); /* Close "bin". */ 1040*8e33eff8Schristos } 1041*8e33eff8Schristos 1042*8e33eff8Schristos unsigned nlextents; 1043*8e33eff8Schristos CTL_GET("arenas.nlextents", &nlextents, unsigned); 1044*8e33eff8Schristos emitter_kv(emitter, "nlextents", "Number of large size classes", 1045*8e33eff8Schristos emitter_type_unsigned, &nlextents); 1046*8e33eff8Schristos 1047*8e33eff8Schristos if (emitter->output == emitter_output_json) { 1048*8e33eff8Schristos emitter_json_arr_begin(emitter, "lextent"); 1049*8e33eff8Schristos for (unsigned i = 0; i < nlextents; i++) { 1050*8e33eff8Schristos emitter_json_arr_obj_begin(emitter); 1051*8e33eff8Schristos 1052*8e33eff8Schristos CTL_M2_GET("arenas.lextent.0.size", i, &sv, size_t); 1053*8e33eff8Schristos emitter_json_kv(emitter, "size", emitter_type_size, 1054*8e33eff8Schristos &sv); 1055*8e33eff8Schristos 1056*8e33eff8Schristos emitter_json_arr_obj_end(emitter); 1057*8e33eff8Schristos } 1058*8e33eff8Schristos emitter_json_arr_end(emitter); /* Close "lextent". */ 1059*8e33eff8Schristos } 1060*8e33eff8Schristos 1061*8e33eff8Schristos emitter_json_dict_end(emitter); /* Close "arenas" */ 1062*8e33eff8Schristos } 1063*8e33eff8Schristos 1064*8e33eff8Schristos static void 1065*8e33eff8Schristos stats_print_helper(emitter_t *emitter, bool merged, bool destroyed, 1066*8e33eff8Schristos bool unmerged, bool bins, bool large, bool mutex) { 1067*8e33eff8Schristos /* 1068*8e33eff8Schristos * These should be deleted. We keep them around for a while, to aid in 1069*8e33eff8Schristos * the transition to the emitter code. 1070*8e33eff8Schristos */ 1071*8e33eff8Schristos size_t allocated, active, metadata, metadata_thp, resident, mapped, 1072*8e33eff8Schristos retained; 1073*8e33eff8Schristos size_t num_background_threads; 1074*8e33eff8Schristos uint64_t background_thread_num_runs, background_thread_run_interval; 1075*8e33eff8Schristos 1076*8e33eff8Schristos CTL_GET("stats.allocated", &allocated, size_t); 1077*8e33eff8Schristos CTL_GET("stats.active", &active, size_t); 1078*8e33eff8Schristos CTL_GET("stats.metadata", &metadata, size_t); 1079*8e33eff8Schristos CTL_GET("stats.metadata_thp", &metadata_thp, size_t); 1080*8e33eff8Schristos CTL_GET("stats.resident", &resident, size_t); 1081*8e33eff8Schristos CTL_GET("stats.mapped", &mapped, size_t); 1082*8e33eff8Schristos CTL_GET("stats.retained", &retained, size_t); 1083*8e33eff8Schristos 1084*8e33eff8Schristos if (have_background_thread) { 1085*8e33eff8Schristos CTL_GET("stats.background_thread.num_threads", 1086*8e33eff8Schristos &num_background_threads, size_t); 1087*8e33eff8Schristos CTL_GET("stats.background_thread.num_runs", 1088*8e33eff8Schristos &background_thread_num_runs, uint64_t); 1089*8e33eff8Schristos CTL_GET("stats.background_thread.run_interval", 1090*8e33eff8Schristos &background_thread_run_interval, uint64_t); 1091*8e33eff8Schristos } else { 1092*8e33eff8Schristos num_background_threads = 0; 1093*8e33eff8Schristos background_thread_num_runs = 0; 1094*8e33eff8Schristos background_thread_run_interval = 0; 1095*8e33eff8Schristos } 1096*8e33eff8Schristos 1097*8e33eff8Schristos /* Generic global stats. */ 1098*8e33eff8Schristos emitter_json_dict_begin(emitter, "stats"); 1099*8e33eff8Schristos emitter_json_kv(emitter, "allocated", emitter_type_size, &allocated); 1100*8e33eff8Schristos emitter_json_kv(emitter, "active", emitter_type_size, &active); 1101*8e33eff8Schristos emitter_json_kv(emitter, "metadata", emitter_type_size, &metadata); 1102*8e33eff8Schristos emitter_json_kv(emitter, "metadata_thp", emitter_type_size, 1103*8e33eff8Schristos &metadata_thp); 1104*8e33eff8Schristos emitter_json_kv(emitter, "resident", emitter_type_size, &resident); 1105*8e33eff8Schristos emitter_json_kv(emitter, "mapped", emitter_type_size, &mapped); 1106*8e33eff8Schristos emitter_json_kv(emitter, "retained", emitter_type_size, &retained); 1107*8e33eff8Schristos 1108*8e33eff8Schristos emitter_table_printf(emitter, "Allocated: %zu, active: %zu, " 1109*8e33eff8Schristos "metadata: %zu (n_thp %zu), resident: %zu, mapped: %zu, " 1110*8e33eff8Schristos "retained: %zu\n", allocated, active, metadata, metadata_thp, 1111*8e33eff8Schristos resident, mapped, retained); 1112*8e33eff8Schristos 1113*8e33eff8Schristos /* Background thread stats. */ 1114*8e33eff8Schristos emitter_json_dict_begin(emitter, "background_thread"); 1115*8e33eff8Schristos emitter_json_kv(emitter, "num_threads", emitter_type_size, 1116*8e33eff8Schristos &num_background_threads); 1117*8e33eff8Schristos emitter_json_kv(emitter, "num_runs", emitter_type_uint64, 1118*8e33eff8Schristos &background_thread_num_runs); 1119*8e33eff8Schristos emitter_json_kv(emitter, "run_interval", emitter_type_uint64, 1120*8e33eff8Schristos &background_thread_run_interval); 1121*8e33eff8Schristos emitter_json_dict_end(emitter); /* Close "background_thread". */ 1122*8e33eff8Schristos 1123*8e33eff8Schristos emitter_table_printf(emitter, "Background threads: %zu, " 1124*8e33eff8Schristos "num_runs: %"FMTu64", run_interval: %"FMTu64" ns\n", 1125*8e33eff8Schristos num_background_threads, background_thread_num_runs, 1126*8e33eff8Schristos background_thread_run_interval); 1127*8e33eff8Schristos 1128*8e33eff8Schristos if (mutex) { 1129*8e33eff8Schristos emitter_row_t row; 1130*8e33eff8Schristos emitter_col_t name; 1131*8e33eff8Schristos emitter_col_t col64[mutex_prof_num_uint64_t_counters]; 1132*8e33eff8Schristos emitter_col_t col32[mutex_prof_num_uint32_t_counters]; 1133*8e33eff8Schristos 1134*8e33eff8Schristos emitter_row_init(&row); 1135*8e33eff8Schristos mutex_stats_init_cols(&row, "", &name, col64, col32); 1136*8e33eff8Schristos 1137*8e33eff8Schristos emitter_table_row(emitter, &row); 1138*8e33eff8Schristos emitter_json_dict_begin(emitter, "mutexes"); 1139*8e33eff8Schristos 1140*8e33eff8Schristos for (int i = 0; i < mutex_prof_num_global_mutexes; i++) { 1141*8e33eff8Schristos mutex_stats_read_global(global_mutex_names[i], &name, 1142*8e33eff8Schristos col64, col32); 1143*8e33eff8Schristos emitter_json_dict_begin(emitter, global_mutex_names[i]); 1144*8e33eff8Schristos mutex_stats_emit(emitter, &row, col64, col32); 1145*8e33eff8Schristos emitter_json_dict_end(emitter); 1146*8e33eff8Schristos } 1147*8e33eff8Schristos 1148*8e33eff8Schristos emitter_json_dict_end(emitter); /* Close "mutexes". */ 1149*8e33eff8Schristos } 1150*8e33eff8Schristos 1151*8e33eff8Schristos emitter_json_dict_end(emitter); /* Close "stats". */ 1152*8e33eff8Schristos 1153*8e33eff8Schristos if (merged || destroyed || unmerged) { 1154*8e33eff8Schristos unsigned narenas; 1155*8e33eff8Schristos 1156*8e33eff8Schristos emitter_json_dict_begin(emitter, "stats.arenas"); 1157*8e33eff8Schristos 1158*8e33eff8Schristos CTL_GET("arenas.narenas", &narenas, unsigned); 1159*8e33eff8Schristos size_t mib[3]; 1160*8e33eff8Schristos size_t miblen = sizeof(mib) / sizeof(size_t); 1161*8e33eff8Schristos size_t sz; 1162*8e33eff8Schristos VARIABLE_ARRAY(bool, initialized, narenas); 1163*8e33eff8Schristos bool destroyed_initialized; 1164*8e33eff8Schristos unsigned i, j, ninitialized; 1165*8e33eff8Schristos 1166*8e33eff8Schristos xmallctlnametomib("arena.0.initialized", mib, &miblen); 1167*8e33eff8Schristos for (i = ninitialized = 0; i < narenas; i++) { 1168*8e33eff8Schristos mib[1] = i; 1169*8e33eff8Schristos sz = sizeof(bool); 1170*8e33eff8Schristos xmallctlbymib(mib, miblen, &initialized[i], &sz, 1171*8e33eff8Schristos NULL, 0); 1172*8e33eff8Schristos if (initialized[i]) { 1173*8e33eff8Schristos ninitialized++; 1174*8e33eff8Schristos } 1175*8e33eff8Schristos } 1176*8e33eff8Schristos mib[1] = MALLCTL_ARENAS_DESTROYED; 1177*8e33eff8Schristos sz = sizeof(bool); 1178*8e33eff8Schristos xmallctlbymib(mib, miblen, &destroyed_initialized, &sz, 1179*8e33eff8Schristos NULL, 0); 1180*8e33eff8Schristos 1181*8e33eff8Schristos /* Merged stats. */ 1182*8e33eff8Schristos if (merged && (ninitialized > 1 || !unmerged)) { 1183*8e33eff8Schristos /* Print merged arena stats. */ 1184*8e33eff8Schristos emitter_table_printf(emitter, "Merged arenas stats:\n"); 1185*8e33eff8Schristos emitter_json_dict_begin(emitter, "merged"); 1186*8e33eff8Schristos stats_arena_print(emitter, MALLCTL_ARENAS_ALL, bins, 1187*8e33eff8Schristos large, mutex); 1188*8e33eff8Schristos emitter_json_dict_end(emitter); /* Close "merged". */ 1189*8e33eff8Schristos } 1190*8e33eff8Schristos 1191*8e33eff8Schristos /* Destroyed stats. */ 1192*8e33eff8Schristos if (destroyed_initialized && destroyed) { 1193*8e33eff8Schristos /* Print destroyed arena stats. */ 1194*8e33eff8Schristos emitter_table_printf(emitter, 1195*8e33eff8Schristos "Destroyed arenas stats:\n"); 1196*8e33eff8Schristos emitter_json_dict_begin(emitter, "destroyed"); 1197*8e33eff8Schristos stats_arena_print(emitter, MALLCTL_ARENAS_DESTROYED, 1198*8e33eff8Schristos bins, large, mutex); 1199*8e33eff8Schristos emitter_json_dict_end(emitter); /* Close "destroyed". */ 1200*8e33eff8Schristos } 1201*8e33eff8Schristos 1202*8e33eff8Schristos /* Unmerged stats. */ 1203*8e33eff8Schristos if (unmerged) { 1204*8e33eff8Schristos for (i = j = 0; i < narenas; i++) { 1205*8e33eff8Schristos if (initialized[i]) { 1206*8e33eff8Schristos char arena_ind_str[20]; 1207*8e33eff8Schristos malloc_snprintf(arena_ind_str, 1208*8e33eff8Schristos sizeof(arena_ind_str), "%u", i); 1209*8e33eff8Schristos emitter_json_dict_begin(emitter, 1210*8e33eff8Schristos arena_ind_str); 1211*8e33eff8Schristos emitter_table_printf(emitter, 1212*8e33eff8Schristos "arenas[%s]:\n", arena_ind_str); 1213*8e33eff8Schristos stats_arena_print(emitter, i, bins, 1214*8e33eff8Schristos large, mutex); 1215*8e33eff8Schristos /* Close "<arena-ind>". */ 1216*8e33eff8Schristos emitter_json_dict_end(emitter); 1217*8e33eff8Schristos } 1218*8e33eff8Schristos } 1219*8e33eff8Schristos } 1220*8e33eff8Schristos emitter_json_dict_end(emitter); /* Close "stats.arenas". */ 1221*8e33eff8Schristos } 1222*8e33eff8Schristos } 1223*8e33eff8Schristos 1224*8e33eff8Schristos void 1225*8e33eff8Schristos stats_print(void (*write_cb)(void *, const char *), void *cbopaque, 1226*8e33eff8Schristos const char *opts) { 1227*8e33eff8Schristos int err; 1228*8e33eff8Schristos uint64_t epoch; 1229*8e33eff8Schristos size_t u64sz; 1230*8e33eff8Schristos #define OPTION(o, v, d, s) bool v = d; 1231*8e33eff8Schristos STATS_PRINT_OPTIONS 1232*8e33eff8Schristos #undef OPTION 1233*8e33eff8Schristos 1234*8e33eff8Schristos /* 1235*8e33eff8Schristos * Refresh stats, in case mallctl() was called by the application. 1236*8e33eff8Schristos * 1237*8e33eff8Schristos * Check for OOM here, since refreshing the ctl cache can trigger 1238*8e33eff8Schristos * allocation. In practice, none of the subsequent mallctl()-related 1239*8e33eff8Schristos * calls in this function will cause OOM if this one succeeds. 1240*8e33eff8Schristos * */ 1241*8e33eff8Schristos epoch = 1; 1242*8e33eff8Schristos u64sz = sizeof(uint64_t); 1243*8e33eff8Schristos err = je_mallctl("epoch", (void *)&epoch, &u64sz, (void *)&epoch, 1244*8e33eff8Schristos sizeof(uint64_t)); 1245*8e33eff8Schristos if (err != 0) { 1246*8e33eff8Schristos if (err == EAGAIN) { 1247*8e33eff8Schristos malloc_write("<jemalloc>: Memory allocation failure in " 1248*8e33eff8Schristos "mallctl(\"epoch\", ...)\n"); 1249*8e33eff8Schristos return; 1250*8e33eff8Schristos } 1251*8e33eff8Schristos malloc_write("<jemalloc>: Failure in mallctl(\"epoch\", " 1252*8e33eff8Schristos "...)\n"); 1253*8e33eff8Schristos abort(); 1254*8e33eff8Schristos } 1255*8e33eff8Schristos 1256*8e33eff8Schristos if (opts != NULL) { 1257*8e33eff8Schristos for (unsigned i = 0; opts[i] != '\0'; i++) { 1258*8e33eff8Schristos switch (opts[i]) { 1259*8e33eff8Schristos #define OPTION(o, v, d, s) case o: v = s; break; 1260*8e33eff8Schristos STATS_PRINT_OPTIONS 1261*8e33eff8Schristos #undef OPTION 1262*8e33eff8Schristos default:; 1263*8e33eff8Schristos } 1264*8e33eff8Schristos } 1265*8e33eff8Schristos } 1266*8e33eff8Schristos 1267*8e33eff8Schristos emitter_t emitter; 1268*8e33eff8Schristos emitter_init(&emitter, 1269*8e33eff8Schristos json ? emitter_output_json : emitter_output_table, write_cb, 1270*8e33eff8Schristos cbopaque); 1271*8e33eff8Schristos emitter_begin(&emitter); 1272*8e33eff8Schristos emitter_table_printf(&emitter, "___ Begin jemalloc statistics ___\n"); 1273*8e33eff8Schristos emitter_json_dict_begin(&emitter, "jemalloc"); 1274*8e33eff8Schristos 1275*8e33eff8Schristos if (general) { 1276*8e33eff8Schristos stats_general_print(&emitter); 1277*8e33eff8Schristos } 1278*8e33eff8Schristos if (config_stats) { 1279*8e33eff8Schristos stats_print_helper(&emitter, merged, destroyed, unmerged, 1280*8e33eff8Schristos bins, large, mutex); 1281*8e33eff8Schristos } 1282*8e33eff8Schristos 1283*8e33eff8Schristos emitter_json_dict_end(&emitter); /* Closes the "jemalloc" dict. */ 1284*8e33eff8Schristos emitter_table_printf(&emitter, "--- End jemalloc statistics ---\n"); 1285*8e33eff8Schristos emitter_end(&emitter); 1286*8e33eff8Schristos } 1287