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