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, ®_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