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