1 #define JEMALLOC_CTL_C_ 2 #include "jemalloc/internal/jemalloc_internal.h" 3 4 /******************************************************************************/ 5 /* Data. */ 6 7 /* 8 * ctl_mtx protects the following: 9 * - ctl_stats.* 10 */ 11 static malloc_mutex_t ctl_mtx; 12 static bool ctl_initialized; 13 static uint64_t ctl_epoch; 14 static ctl_stats_t ctl_stats; 15 16 /******************************************************************************/ 17 /* Helpers for named and indexed nodes. */ 18 19 JEMALLOC_INLINE_C const ctl_named_node_t * 20 ctl_named_node(const ctl_node_t *node) 21 { 22 23 return ((node->named) ? (const ctl_named_node_t *)node : NULL); 24 } 25 26 JEMALLOC_INLINE_C const ctl_named_node_t * 27 ctl_named_children(const ctl_named_node_t *node, size_t index) 28 { 29 const ctl_named_node_t *children = ctl_named_node(node->children); 30 31 return (children ? &children[index] : NULL); 32 } 33 34 JEMALLOC_INLINE_C const ctl_indexed_node_t * 35 ctl_indexed_node(const ctl_node_t *node) 36 { 37 38 return (!node->named ? (const ctl_indexed_node_t *)node : NULL); 39 } 40 41 /******************************************************************************/ 42 /* Function prototypes for non-inline static functions. */ 43 44 #define CTL_PROTO(n) \ 45 static int n##_ctl(const size_t *mib, size_t miblen, void *oldp, \ 46 size_t *oldlenp, void *newp, size_t newlen); 47 48 #define INDEX_PROTO(n) \ 49 static const ctl_named_node_t *n##_index(const size_t *mib, \ 50 size_t miblen, size_t i); 51 52 static bool ctl_arena_init(ctl_arena_stats_t *astats); 53 static void ctl_arena_clear(ctl_arena_stats_t *astats); 54 static void ctl_arena_stats_amerge(ctl_arena_stats_t *cstats, 55 arena_t *arena); 56 static void ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, 57 ctl_arena_stats_t *astats); 58 static void ctl_arena_refresh(arena_t *arena, unsigned i); 59 static bool ctl_grow(void); 60 static void ctl_refresh(void); 61 static bool ctl_init(void); 62 static int ctl_lookup(const char *name, ctl_node_t const **nodesp, 63 size_t *mibp, size_t *depthp); 64 65 CTL_PROTO(version) 66 CTL_PROTO(epoch) 67 CTL_PROTO(thread_tcache_enabled) 68 CTL_PROTO(thread_tcache_flush) 69 CTL_PROTO(thread_prof_name) 70 CTL_PROTO(thread_prof_active) 71 CTL_PROTO(thread_arena) 72 CTL_PROTO(thread_allocated) 73 CTL_PROTO(thread_allocatedp) 74 CTL_PROTO(thread_deallocated) 75 CTL_PROTO(thread_deallocatedp) 76 CTL_PROTO(config_cache_oblivious) 77 CTL_PROTO(config_debug) 78 CTL_PROTO(config_fill) 79 CTL_PROTO(config_lazy_lock) 80 CTL_PROTO(config_malloc_conf) 81 CTL_PROTO(config_munmap) 82 CTL_PROTO(config_prof) 83 CTL_PROTO(config_prof_libgcc) 84 CTL_PROTO(config_prof_libunwind) 85 CTL_PROTO(config_stats) 86 CTL_PROTO(config_tcache) 87 CTL_PROTO(config_tls) 88 CTL_PROTO(config_utrace) 89 CTL_PROTO(config_valgrind) 90 CTL_PROTO(config_xmalloc) 91 CTL_PROTO(opt_abort) 92 CTL_PROTO(opt_dss) 93 CTL_PROTO(opt_lg_chunk) 94 CTL_PROTO(opt_narenas) 95 CTL_PROTO(opt_purge) 96 CTL_PROTO(opt_lg_dirty_mult) 97 CTL_PROTO(opt_decay_time) 98 CTL_PROTO(opt_stats_print) 99 CTL_PROTO(opt_junk) 100 CTL_PROTO(opt_zero) 101 CTL_PROTO(opt_quarantine) 102 CTL_PROTO(opt_redzone) 103 CTL_PROTO(opt_utrace) 104 CTL_PROTO(opt_xmalloc) 105 CTL_PROTO(opt_tcache) 106 CTL_PROTO(opt_lg_tcache_max) 107 CTL_PROTO(opt_prof) 108 CTL_PROTO(opt_prof_prefix) 109 CTL_PROTO(opt_prof_active) 110 CTL_PROTO(opt_prof_thread_active_init) 111 CTL_PROTO(opt_lg_prof_sample) 112 CTL_PROTO(opt_lg_prof_interval) 113 CTL_PROTO(opt_prof_gdump) 114 CTL_PROTO(opt_prof_final) 115 CTL_PROTO(opt_prof_leak) 116 CTL_PROTO(opt_prof_accum) 117 CTL_PROTO(tcache_create) 118 CTL_PROTO(tcache_flush) 119 CTL_PROTO(tcache_destroy) 120 static void arena_i_purge(unsigned arena_ind, bool all); 121 CTL_PROTO(arena_i_purge) 122 CTL_PROTO(arena_i_decay) 123 CTL_PROTO(arena_i_dss) 124 CTL_PROTO(arena_i_lg_dirty_mult) 125 CTL_PROTO(arena_i_decay_time) 126 CTL_PROTO(arena_i_chunk_hooks) 127 INDEX_PROTO(arena_i) 128 CTL_PROTO(arenas_bin_i_size) 129 CTL_PROTO(arenas_bin_i_nregs) 130 CTL_PROTO(arenas_bin_i_run_size) 131 INDEX_PROTO(arenas_bin_i) 132 CTL_PROTO(arenas_lrun_i_size) 133 INDEX_PROTO(arenas_lrun_i) 134 CTL_PROTO(arenas_hchunk_i_size) 135 INDEX_PROTO(arenas_hchunk_i) 136 CTL_PROTO(arenas_narenas) 137 CTL_PROTO(arenas_initialized) 138 CTL_PROTO(arenas_lg_dirty_mult) 139 CTL_PROTO(arenas_decay_time) 140 CTL_PROTO(arenas_quantum) 141 CTL_PROTO(arenas_page) 142 CTL_PROTO(arenas_tcache_max) 143 CTL_PROTO(arenas_nbins) 144 CTL_PROTO(arenas_nhbins) 145 CTL_PROTO(arenas_nlruns) 146 CTL_PROTO(arenas_nhchunks) 147 CTL_PROTO(arenas_extend) 148 CTL_PROTO(prof_thread_active_init) 149 CTL_PROTO(prof_active) 150 CTL_PROTO(prof_dump) 151 CTL_PROTO(prof_gdump) 152 CTL_PROTO(prof_reset) 153 CTL_PROTO(prof_interval) 154 CTL_PROTO(lg_prof_sample) 155 CTL_PROTO(stats_arenas_i_small_allocated) 156 CTL_PROTO(stats_arenas_i_small_nmalloc) 157 CTL_PROTO(stats_arenas_i_small_ndalloc) 158 CTL_PROTO(stats_arenas_i_small_nrequests) 159 CTL_PROTO(stats_arenas_i_large_allocated) 160 CTL_PROTO(stats_arenas_i_large_nmalloc) 161 CTL_PROTO(stats_arenas_i_large_ndalloc) 162 CTL_PROTO(stats_arenas_i_large_nrequests) 163 CTL_PROTO(stats_arenas_i_huge_allocated) 164 CTL_PROTO(stats_arenas_i_huge_nmalloc) 165 CTL_PROTO(stats_arenas_i_huge_ndalloc) 166 CTL_PROTO(stats_arenas_i_huge_nrequests) 167 CTL_PROTO(stats_arenas_i_bins_j_nmalloc) 168 CTL_PROTO(stats_arenas_i_bins_j_ndalloc) 169 CTL_PROTO(stats_arenas_i_bins_j_nrequests) 170 CTL_PROTO(stats_arenas_i_bins_j_curregs) 171 CTL_PROTO(stats_arenas_i_bins_j_nfills) 172 CTL_PROTO(stats_arenas_i_bins_j_nflushes) 173 CTL_PROTO(stats_arenas_i_bins_j_nruns) 174 CTL_PROTO(stats_arenas_i_bins_j_nreruns) 175 CTL_PROTO(stats_arenas_i_bins_j_curruns) 176 INDEX_PROTO(stats_arenas_i_bins_j) 177 CTL_PROTO(stats_arenas_i_lruns_j_nmalloc) 178 CTL_PROTO(stats_arenas_i_lruns_j_ndalloc) 179 CTL_PROTO(stats_arenas_i_lruns_j_nrequests) 180 CTL_PROTO(stats_arenas_i_lruns_j_curruns) 181 INDEX_PROTO(stats_arenas_i_lruns_j) 182 CTL_PROTO(stats_arenas_i_hchunks_j_nmalloc) 183 CTL_PROTO(stats_arenas_i_hchunks_j_ndalloc) 184 CTL_PROTO(stats_arenas_i_hchunks_j_nrequests) 185 CTL_PROTO(stats_arenas_i_hchunks_j_curhchunks) 186 INDEX_PROTO(stats_arenas_i_hchunks_j) 187 CTL_PROTO(stats_arenas_i_nthreads) 188 CTL_PROTO(stats_arenas_i_dss) 189 CTL_PROTO(stats_arenas_i_lg_dirty_mult) 190 CTL_PROTO(stats_arenas_i_decay_time) 191 CTL_PROTO(stats_arenas_i_pactive) 192 CTL_PROTO(stats_arenas_i_pdirty) 193 CTL_PROTO(stats_arenas_i_mapped) 194 CTL_PROTO(stats_arenas_i_npurge) 195 CTL_PROTO(stats_arenas_i_nmadvise) 196 CTL_PROTO(stats_arenas_i_purged) 197 CTL_PROTO(stats_arenas_i_metadata_mapped) 198 CTL_PROTO(stats_arenas_i_metadata_allocated) 199 INDEX_PROTO(stats_arenas_i) 200 CTL_PROTO(stats_cactive) 201 CTL_PROTO(stats_allocated) 202 CTL_PROTO(stats_active) 203 CTL_PROTO(stats_metadata) 204 CTL_PROTO(stats_resident) 205 CTL_PROTO(stats_mapped) 206 207 /******************************************************************************/ 208 /* mallctl tree. */ 209 210 /* Maximum tree depth. */ 211 #define CTL_MAX_DEPTH 6 212 213 #define NAME(n) {true}, n 214 #define CHILD(t, c) \ 215 sizeof(c##_node) / sizeof(ctl_##t##_node_t), \ 216 (ctl_node_t *)c##_node, \ 217 NULL 218 #define CTL(c) 0, NULL, c##_ctl 219 220 /* 221 * Only handles internal indexed nodes, since there are currently no external 222 * ones. 223 */ 224 #define INDEX(i) {false}, i##_index 225 226 static const ctl_named_node_t thread_tcache_node[] = { 227 {NAME("enabled"), CTL(thread_tcache_enabled)}, 228 {NAME("flush"), CTL(thread_tcache_flush)} 229 }; 230 231 static const ctl_named_node_t thread_prof_node[] = { 232 {NAME("name"), CTL(thread_prof_name)}, 233 {NAME("active"), CTL(thread_prof_active)} 234 }; 235 236 static const ctl_named_node_t thread_node[] = { 237 {NAME("arena"), CTL(thread_arena)}, 238 {NAME("allocated"), CTL(thread_allocated)}, 239 {NAME("allocatedp"), CTL(thread_allocatedp)}, 240 {NAME("deallocated"), CTL(thread_deallocated)}, 241 {NAME("deallocatedp"), CTL(thread_deallocatedp)}, 242 {NAME("tcache"), CHILD(named, thread_tcache)}, 243 {NAME("prof"), CHILD(named, thread_prof)} 244 }; 245 246 static const ctl_named_node_t config_node[] = { 247 {NAME("cache_oblivious"), CTL(config_cache_oblivious)}, 248 {NAME("debug"), CTL(config_debug)}, 249 {NAME("fill"), CTL(config_fill)}, 250 {NAME("lazy_lock"), CTL(config_lazy_lock)}, 251 {NAME("malloc_conf"), CTL(config_malloc_conf)}, 252 {NAME("munmap"), CTL(config_munmap)}, 253 {NAME("prof"), CTL(config_prof)}, 254 {NAME("prof_libgcc"), CTL(config_prof_libgcc)}, 255 {NAME("prof_libunwind"), CTL(config_prof_libunwind)}, 256 {NAME("stats"), CTL(config_stats)}, 257 {NAME("tcache"), CTL(config_tcache)}, 258 {NAME("tls"), CTL(config_tls)}, 259 {NAME("utrace"), CTL(config_utrace)}, 260 {NAME("valgrind"), CTL(config_valgrind)}, 261 {NAME("xmalloc"), CTL(config_xmalloc)} 262 }; 263 264 static const ctl_named_node_t opt_node[] = { 265 {NAME("abort"), CTL(opt_abort)}, 266 {NAME("dss"), CTL(opt_dss)}, 267 {NAME("lg_chunk"), CTL(opt_lg_chunk)}, 268 {NAME("narenas"), CTL(opt_narenas)}, 269 {NAME("purge"), CTL(opt_purge)}, 270 {NAME("lg_dirty_mult"), CTL(opt_lg_dirty_mult)}, 271 {NAME("decay_time"), CTL(opt_decay_time)}, 272 {NAME("stats_print"), CTL(opt_stats_print)}, 273 {NAME("junk"), CTL(opt_junk)}, 274 {NAME("zero"), CTL(opt_zero)}, 275 {NAME("quarantine"), CTL(opt_quarantine)}, 276 {NAME("redzone"), CTL(opt_redzone)}, 277 {NAME("utrace"), CTL(opt_utrace)}, 278 {NAME("xmalloc"), CTL(opt_xmalloc)}, 279 {NAME("tcache"), CTL(opt_tcache)}, 280 {NAME("lg_tcache_max"), CTL(opt_lg_tcache_max)}, 281 {NAME("prof"), CTL(opt_prof)}, 282 {NAME("prof_prefix"), CTL(opt_prof_prefix)}, 283 {NAME("prof_active"), CTL(opt_prof_active)}, 284 {NAME("prof_thread_active_init"), CTL(opt_prof_thread_active_init)}, 285 {NAME("lg_prof_sample"), CTL(opt_lg_prof_sample)}, 286 {NAME("lg_prof_interval"), CTL(opt_lg_prof_interval)}, 287 {NAME("prof_gdump"), CTL(opt_prof_gdump)}, 288 {NAME("prof_final"), CTL(opt_prof_final)}, 289 {NAME("prof_leak"), CTL(opt_prof_leak)}, 290 {NAME("prof_accum"), CTL(opt_prof_accum)} 291 }; 292 293 static const ctl_named_node_t tcache_node[] = { 294 {NAME("create"), CTL(tcache_create)}, 295 {NAME("flush"), CTL(tcache_flush)}, 296 {NAME("destroy"), CTL(tcache_destroy)} 297 }; 298 299 static const ctl_named_node_t arena_i_node[] = { 300 {NAME("purge"), CTL(arena_i_purge)}, 301 {NAME("decay"), CTL(arena_i_decay)}, 302 {NAME("dss"), CTL(arena_i_dss)}, 303 {NAME("lg_dirty_mult"), CTL(arena_i_lg_dirty_mult)}, 304 {NAME("decay_time"), CTL(arena_i_decay_time)}, 305 {NAME("chunk_hooks"), CTL(arena_i_chunk_hooks)} 306 }; 307 static const ctl_named_node_t super_arena_i_node[] = { 308 {NAME(""), CHILD(named, arena_i)} 309 }; 310 311 static const ctl_indexed_node_t arena_node[] = { 312 {INDEX(arena_i)} 313 }; 314 315 static const ctl_named_node_t arenas_bin_i_node[] = { 316 {NAME("size"), CTL(arenas_bin_i_size)}, 317 {NAME("nregs"), CTL(arenas_bin_i_nregs)}, 318 {NAME("run_size"), CTL(arenas_bin_i_run_size)} 319 }; 320 static const ctl_named_node_t super_arenas_bin_i_node[] = { 321 {NAME(""), CHILD(named, arenas_bin_i)} 322 }; 323 324 static const ctl_indexed_node_t arenas_bin_node[] = { 325 {INDEX(arenas_bin_i)} 326 }; 327 328 static const ctl_named_node_t arenas_lrun_i_node[] = { 329 {NAME("size"), CTL(arenas_lrun_i_size)} 330 }; 331 static const ctl_named_node_t super_arenas_lrun_i_node[] = { 332 {NAME(""), CHILD(named, arenas_lrun_i)} 333 }; 334 335 static const ctl_indexed_node_t arenas_lrun_node[] = { 336 {INDEX(arenas_lrun_i)} 337 }; 338 339 static const ctl_named_node_t arenas_hchunk_i_node[] = { 340 {NAME("size"), CTL(arenas_hchunk_i_size)} 341 }; 342 static const ctl_named_node_t super_arenas_hchunk_i_node[] = { 343 {NAME(""), CHILD(named, arenas_hchunk_i)} 344 }; 345 346 static const ctl_indexed_node_t arenas_hchunk_node[] = { 347 {INDEX(arenas_hchunk_i)} 348 }; 349 350 static const ctl_named_node_t arenas_node[] = { 351 {NAME("narenas"), CTL(arenas_narenas)}, 352 {NAME("initialized"), CTL(arenas_initialized)}, 353 {NAME("lg_dirty_mult"), CTL(arenas_lg_dirty_mult)}, 354 {NAME("decay_time"), CTL(arenas_decay_time)}, 355 {NAME("quantum"), CTL(arenas_quantum)}, 356 {NAME("page"), CTL(arenas_page)}, 357 {NAME("tcache_max"), CTL(arenas_tcache_max)}, 358 {NAME("nbins"), CTL(arenas_nbins)}, 359 {NAME("nhbins"), CTL(arenas_nhbins)}, 360 {NAME("bin"), CHILD(indexed, arenas_bin)}, 361 {NAME("nlruns"), CTL(arenas_nlruns)}, 362 {NAME("lrun"), CHILD(indexed, arenas_lrun)}, 363 {NAME("nhchunks"), CTL(arenas_nhchunks)}, 364 {NAME("hchunk"), CHILD(indexed, arenas_hchunk)}, 365 {NAME("extend"), CTL(arenas_extend)} 366 }; 367 368 static const ctl_named_node_t prof_node[] = { 369 {NAME("thread_active_init"), CTL(prof_thread_active_init)}, 370 {NAME("active"), CTL(prof_active)}, 371 {NAME("dump"), CTL(prof_dump)}, 372 {NAME("gdump"), CTL(prof_gdump)}, 373 {NAME("reset"), CTL(prof_reset)}, 374 {NAME("interval"), CTL(prof_interval)}, 375 {NAME("lg_sample"), CTL(lg_prof_sample)} 376 }; 377 378 static const ctl_named_node_t stats_arenas_i_metadata_node[] = { 379 {NAME("mapped"), CTL(stats_arenas_i_metadata_mapped)}, 380 {NAME("allocated"), CTL(stats_arenas_i_metadata_allocated)} 381 }; 382 383 static const ctl_named_node_t stats_arenas_i_small_node[] = { 384 {NAME("allocated"), CTL(stats_arenas_i_small_allocated)}, 385 {NAME("nmalloc"), CTL(stats_arenas_i_small_nmalloc)}, 386 {NAME("ndalloc"), CTL(stats_arenas_i_small_ndalloc)}, 387 {NAME("nrequests"), CTL(stats_arenas_i_small_nrequests)} 388 }; 389 390 static const ctl_named_node_t stats_arenas_i_large_node[] = { 391 {NAME("allocated"), CTL(stats_arenas_i_large_allocated)}, 392 {NAME("nmalloc"), CTL(stats_arenas_i_large_nmalloc)}, 393 {NAME("ndalloc"), CTL(stats_arenas_i_large_ndalloc)}, 394 {NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)} 395 }; 396 397 static const ctl_named_node_t stats_arenas_i_huge_node[] = { 398 {NAME("allocated"), CTL(stats_arenas_i_huge_allocated)}, 399 {NAME("nmalloc"), CTL(stats_arenas_i_huge_nmalloc)}, 400 {NAME("ndalloc"), CTL(stats_arenas_i_huge_ndalloc)}, 401 {NAME("nrequests"), CTL(stats_arenas_i_huge_nrequests)} 402 }; 403 404 static const ctl_named_node_t stats_arenas_i_bins_j_node[] = { 405 {NAME("nmalloc"), CTL(stats_arenas_i_bins_j_nmalloc)}, 406 {NAME("ndalloc"), CTL(stats_arenas_i_bins_j_ndalloc)}, 407 {NAME("nrequests"), CTL(stats_arenas_i_bins_j_nrequests)}, 408 {NAME("curregs"), CTL(stats_arenas_i_bins_j_curregs)}, 409 {NAME("nfills"), CTL(stats_arenas_i_bins_j_nfills)}, 410 {NAME("nflushes"), CTL(stats_arenas_i_bins_j_nflushes)}, 411 {NAME("nruns"), CTL(stats_arenas_i_bins_j_nruns)}, 412 {NAME("nreruns"), CTL(stats_arenas_i_bins_j_nreruns)}, 413 {NAME("curruns"), CTL(stats_arenas_i_bins_j_curruns)} 414 }; 415 static const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = { 416 {NAME(""), CHILD(named, stats_arenas_i_bins_j)} 417 }; 418 419 static const ctl_indexed_node_t stats_arenas_i_bins_node[] = { 420 {INDEX(stats_arenas_i_bins_j)} 421 }; 422 423 static const ctl_named_node_t stats_arenas_i_lruns_j_node[] = { 424 {NAME("nmalloc"), CTL(stats_arenas_i_lruns_j_nmalloc)}, 425 {NAME("ndalloc"), CTL(stats_arenas_i_lruns_j_ndalloc)}, 426 {NAME("nrequests"), CTL(stats_arenas_i_lruns_j_nrequests)}, 427 {NAME("curruns"), CTL(stats_arenas_i_lruns_j_curruns)} 428 }; 429 static const ctl_named_node_t super_stats_arenas_i_lruns_j_node[] = { 430 {NAME(""), CHILD(named, stats_arenas_i_lruns_j)} 431 }; 432 433 static const ctl_indexed_node_t stats_arenas_i_lruns_node[] = { 434 {INDEX(stats_arenas_i_lruns_j)} 435 }; 436 437 static const ctl_named_node_t stats_arenas_i_hchunks_j_node[] = { 438 {NAME("nmalloc"), CTL(stats_arenas_i_hchunks_j_nmalloc)}, 439 {NAME("ndalloc"), CTL(stats_arenas_i_hchunks_j_ndalloc)}, 440 {NAME("nrequests"), CTL(stats_arenas_i_hchunks_j_nrequests)}, 441 {NAME("curhchunks"), CTL(stats_arenas_i_hchunks_j_curhchunks)} 442 }; 443 static const ctl_named_node_t super_stats_arenas_i_hchunks_j_node[] = { 444 {NAME(""), CHILD(named, stats_arenas_i_hchunks_j)} 445 }; 446 447 static const ctl_indexed_node_t stats_arenas_i_hchunks_node[] = { 448 {INDEX(stats_arenas_i_hchunks_j)} 449 }; 450 451 static const ctl_named_node_t stats_arenas_i_node[] = { 452 {NAME("nthreads"), CTL(stats_arenas_i_nthreads)}, 453 {NAME("dss"), CTL(stats_arenas_i_dss)}, 454 {NAME("lg_dirty_mult"), CTL(stats_arenas_i_lg_dirty_mult)}, 455 {NAME("decay_time"), CTL(stats_arenas_i_decay_time)}, 456 {NAME("pactive"), CTL(stats_arenas_i_pactive)}, 457 {NAME("pdirty"), CTL(stats_arenas_i_pdirty)}, 458 {NAME("mapped"), CTL(stats_arenas_i_mapped)}, 459 {NAME("npurge"), CTL(stats_arenas_i_npurge)}, 460 {NAME("nmadvise"), CTL(stats_arenas_i_nmadvise)}, 461 {NAME("purged"), CTL(stats_arenas_i_purged)}, 462 {NAME("metadata"), CHILD(named, stats_arenas_i_metadata)}, 463 {NAME("small"), CHILD(named, stats_arenas_i_small)}, 464 {NAME("large"), CHILD(named, stats_arenas_i_large)}, 465 {NAME("huge"), CHILD(named, stats_arenas_i_huge)}, 466 {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)}, 467 {NAME("lruns"), CHILD(indexed, stats_arenas_i_lruns)}, 468 {NAME("hchunks"), CHILD(indexed, stats_arenas_i_hchunks)} 469 }; 470 static const ctl_named_node_t super_stats_arenas_i_node[] = { 471 {NAME(""), CHILD(named, stats_arenas_i)} 472 }; 473 474 static const ctl_indexed_node_t stats_arenas_node[] = { 475 {INDEX(stats_arenas_i)} 476 }; 477 478 static const ctl_named_node_t stats_node[] = { 479 {NAME("cactive"), CTL(stats_cactive)}, 480 {NAME("allocated"), CTL(stats_allocated)}, 481 {NAME("active"), CTL(stats_active)}, 482 {NAME("metadata"), CTL(stats_metadata)}, 483 {NAME("resident"), CTL(stats_resident)}, 484 {NAME("mapped"), CTL(stats_mapped)}, 485 {NAME("arenas"), CHILD(indexed, stats_arenas)} 486 }; 487 488 static const ctl_named_node_t root_node[] = { 489 {NAME("version"), CTL(version)}, 490 {NAME("epoch"), CTL(epoch)}, 491 {NAME("thread"), CHILD(named, thread)}, 492 {NAME("config"), CHILD(named, config)}, 493 {NAME("opt"), CHILD(named, opt)}, 494 {NAME("tcache"), CHILD(named, tcache)}, 495 {NAME("arena"), CHILD(indexed, arena)}, 496 {NAME("arenas"), CHILD(named, arenas)}, 497 {NAME("prof"), CHILD(named, prof)}, 498 {NAME("stats"), CHILD(named, stats)} 499 }; 500 static const ctl_named_node_t super_root_node[] = { 501 {NAME(""), CHILD(named, root)} 502 }; 503 504 #undef NAME 505 #undef CHILD 506 #undef CTL 507 #undef INDEX 508 509 /******************************************************************************/ 510 511 static bool 512 ctl_arena_init(ctl_arena_stats_t *astats) 513 { 514 515 if (astats->lstats == NULL) { 516 astats->lstats = (malloc_large_stats_t *)a0malloc(nlclasses * 517 sizeof(malloc_large_stats_t)); 518 if (astats->lstats == NULL) 519 return (true); 520 } 521 522 if (astats->hstats == NULL) { 523 astats->hstats = (malloc_huge_stats_t *)a0malloc(nhclasses * 524 sizeof(malloc_huge_stats_t)); 525 if (astats->hstats == NULL) 526 return (true); 527 } 528 529 return (false); 530 } 531 532 static void 533 ctl_arena_clear(ctl_arena_stats_t *astats) 534 { 535 536 astats->nthreads = 0; 537 astats->dss = dss_prec_names[dss_prec_limit]; 538 astats->lg_dirty_mult = -1; 539 astats->decay_time = -1; 540 astats->pactive = 0; 541 astats->pdirty = 0; 542 if (config_stats) { 543 memset(&astats->astats, 0, sizeof(arena_stats_t)); 544 astats->allocated_small = 0; 545 astats->nmalloc_small = 0; 546 astats->ndalloc_small = 0; 547 astats->nrequests_small = 0; 548 memset(astats->bstats, 0, NBINS * sizeof(malloc_bin_stats_t)); 549 memset(astats->lstats, 0, nlclasses * 550 sizeof(malloc_large_stats_t)); 551 memset(astats->hstats, 0, nhclasses * 552 sizeof(malloc_huge_stats_t)); 553 } 554 } 555 556 static void 557 ctl_arena_stats_amerge(ctl_arena_stats_t *cstats, arena_t *arena) 558 { 559 unsigned i; 560 561 if (config_stats) { 562 arena_stats_merge(arena, &cstats->nthreads, &cstats->dss, 563 &cstats->lg_dirty_mult, &cstats->decay_time, 564 &cstats->pactive, &cstats->pdirty, &cstats->astats, 565 cstats->bstats, cstats->lstats, cstats->hstats); 566 567 for (i = 0; i < NBINS; i++) { 568 cstats->allocated_small += cstats->bstats[i].curregs * 569 index2size(i); 570 cstats->nmalloc_small += cstats->bstats[i].nmalloc; 571 cstats->ndalloc_small += cstats->bstats[i].ndalloc; 572 cstats->nrequests_small += cstats->bstats[i].nrequests; 573 } 574 } else { 575 arena_basic_stats_merge(arena, &cstats->nthreads, &cstats->dss, 576 &cstats->lg_dirty_mult, &cstats->decay_time, 577 &cstats->pactive, &cstats->pdirty); 578 } 579 } 580 581 static void 582 ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) 583 { 584 unsigned i; 585 586 sstats->nthreads += astats->nthreads; 587 sstats->pactive += astats->pactive; 588 sstats->pdirty += astats->pdirty; 589 590 if (config_stats) { 591 sstats->astats.mapped += astats->astats.mapped; 592 sstats->astats.npurge += astats->astats.npurge; 593 sstats->astats.nmadvise += astats->astats.nmadvise; 594 sstats->astats.purged += astats->astats.purged; 595 596 sstats->astats.metadata_mapped += 597 astats->astats.metadata_mapped; 598 sstats->astats.metadata_allocated += 599 astats->astats.metadata_allocated; 600 601 sstats->allocated_small += astats->allocated_small; 602 sstats->nmalloc_small += astats->nmalloc_small; 603 sstats->ndalloc_small += astats->ndalloc_small; 604 sstats->nrequests_small += astats->nrequests_small; 605 606 sstats->astats.allocated_large += 607 astats->astats.allocated_large; 608 sstats->astats.nmalloc_large += astats->astats.nmalloc_large; 609 sstats->astats.ndalloc_large += astats->astats.ndalloc_large; 610 sstats->astats.nrequests_large += 611 astats->astats.nrequests_large; 612 613 sstats->astats.allocated_huge += astats->astats.allocated_huge; 614 sstats->astats.nmalloc_huge += astats->astats.nmalloc_huge; 615 sstats->astats.ndalloc_huge += astats->astats.ndalloc_huge; 616 617 for (i = 0; i < NBINS; i++) { 618 sstats->bstats[i].nmalloc += astats->bstats[i].nmalloc; 619 sstats->bstats[i].ndalloc += astats->bstats[i].ndalloc; 620 sstats->bstats[i].nrequests += 621 astats->bstats[i].nrequests; 622 sstats->bstats[i].curregs += astats->bstats[i].curregs; 623 if (config_tcache) { 624 sstats->bstats[i].nfills += 625 astats->bstats[i].nfills; 626 sstats->bstats[i].nflushes += 627 astats->bstats[i].nflushes; 628 } 629 sstats->bstats[i].nruns += astats->bstats[i].nruns; 630 sstats->bstats[i].reruns += astats->bstats[i].reruns; 631 sstats->bstats[i].curruns += astats->bstats[i].curruns; 632 } 633 634 for (i = 0; i < nlclasses; i++) { 635 sstats->lstats[i].nmalloc += astats->lstats[i].nmalloc; 636 sstats->lstats[i].ndalloc += astats->lstats[i].ndalloc; 637 sstats->lstats[i].nrequests += 638 astats->lstats[i].nrequests; 639 sstats->lstats[i].curruns += astats->lstats[i].curruns; 640 } 641 642 for (i = 0; i < nhclasses; i++) { 643 sstats->hstats[i].nmalloc += astats->hstats[i].nmalloc; 644 sstats->hstats[i].ndalloc += astats->hstats[i].ndalloc; 645 sstats->hstats[i].curhchunks += 646 astats->hstats[i].curhchunks; 647 } 648 } 649 } 650 651 static void 652 ctl_arena_refresh(arena_t *arena, unsigned i) 653 { 654 ctl_arena_stats_t *astats = &ctl_stats.arenas[i]; 655 ctl_arena_stats_t *sstats = &ctl_stats.arenas[ctl_stats.narenas]; 656 657 ctl_arena_clear(astats); 658 ctl_arena_stats_amerge(astats, arena); 659 /* Merge into sum stats as well. */ 660 ctl_arena_stats_smerge(sstats, astats); 661 } 662 663 static bool 664 ctl_grow(void) 665 { 666 ctl_arena_stats_t *astats; 667 668 /* Initialize new arena. */ 669 if (arena_init(ctl_stats.narenas) == NULL) 670 return (true); 671 672 /* Allocate extended arena stats. */ 673 astats = (ctl_arena_stats_t *)a0malloc((ctl_stats.narenas + 2) * 674 sizeof(ctl_arena_stats_t)); 675 if (astats == NULL) 676 return (true); 677 678 /* Initialize the new astats element. */ 679 memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) * 680 sizeof(ctl_arena_stats_t)); 681 memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t)); 682 if (ctl_arena_init(&astats[ctl_stats.narenas + 1])) { 683 a0dalloc(astats); 684 return (true); 685 } 686 /* Swap merged stats to their new location. */ 687 { 688 ctl_arena_stats_t tstats; 689 memcpy(&tstats, &astats[ctl_stats.narenas], 690 sizeof(ctl_arena_stats_t)); 691 memcpy(&astats[ctl_stats.narenas], 692 &astats[ctl_stats.narenas + 1], sizeof(ctl_arena_stats_t)); 693 memcpy(&astats[ctl_stats.narenas + 1], &tstats, 694 sizeof(ctl_arena_stats_t)); 695 } 696 a0dalloc(ctl_stats.arenas); 697 ctl_stats.arenas = astats; 698 ctl_stats.narenas++; 699 700 return (false); 701 } 702 703 static void 704 ctl_refresh(void) 705 { 706 unsigned i; 707 VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas); 708 709 /* 710 * Clear sum stats, since they will be merged into by 711 * ctl_arena_refresh(). 712 */ 713 ctl_arena_clear(&ctl_stats.arenas[ctl_stats.narenas]); 714 715 for (i = 0; i < ctl_stats.narenas; i++) 716 tarenas[i] = arena_get(i, false); 717 718 for (i = 0; i < ctl_stats.narenas; i++) { 719 bool initialized = (tarenas[i] != NULL); 720 721 ctl_stats.arenas[i].initialized = initialized; 722 if (initialized) 723 ctl_arena_refresh(tarenas[i], i); 724 } 725 726 if (config_stats) { 727 size_t base_allocated, base_resident, base_mapped; 728 base_stats_get(&base_allocated, &base_resident, &base_mapped); 729 ctl_stats.allocated = 730 ctl_stats.arenas[ctl_stats.narenas].allocated_small + 731 ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large + 732 ctl_stats.arenas[ctl_stats.narenas].astats.allocated_huge; 733 ctl_stats.active = 734 (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE); 735 ctl_stats.metadata = base_allocated + 736 ctl_stats.arenas[ctl_stats.narenas].astats.metadata_mapped + 737 ctl_stats.arenas[ctl_stats.narenas].astats 738 .metadata_allocated; 739 ctl_stats.resident = base_resident + 740 ctl_stats.arenas[ctl_stats.narenas].astats.metadata_mapped + 741 ((ctl_stats.arenas[ctl_stats.narenas].pactive + 742 ctl_stats.arenas[ctl_stats.narenas].pdirty) << LG_PAGE); 743 ctl_stats.mapped = base_mapped + 744 ctl_stats.arenas[ctl_stats.narenas].astats.mapped; 745 } 746 747 ctl_epoch++; 748 } 749 750 static bool 751 ctl_init(void) 752 { 753 bool ret; 754 755 malloc_mutex_lock(&ctl_mtx); 756 if (!ctl_initialized) { 757 /* 758 * Allocate space for one extra arena stats element, which 759 * contains summed stats across all arenas. 760 */ 761 ctl_stats.narenas = narenas_total_get(); 762 ctl_stats.arenas = (ctl_arena_stats_t *)a0malloc( 763 (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t)); 764 if (ctl_stats.arenas == NULL) { 765 ret = true; 766 goto label_return; 767 } 768 memset(ctl_stats.arenas, 0, (ctl_stats.narenas + 1) * 769 sizeof(ctl_arena_stats_t)); 770 771 /* 772 * Initialize all stats structures, regardless of whether they 773 * ever get used. Lazy initialization would allow errors to 774 * cause inconsistent state to be viewable by the application. 775 */ 776 if (config_stats) { 777 unsigned i; 778 for (i = 0; i <= ctl_stats.narenas; i++) { 779 if (ctl_arena_init(&ctl_stats.arenas[i])) { 780 unsigned j; 781 for (j = 0; j < i; j++) { 782 a0dalloc( 783 ctl_stats.arenas[j].lstats); 784 a0dalloc( 785 ctl_stats.arenas[j].hstats); 786 } 787 a0dalloc(ctl_stats.arenas); 788 ctl_stats.arenas = NULL; 789 ret = true; 790 goto label_return; 791 } 792 } 793 } 794 ctl_stats.arenas[ctl_stats.narenas].initialized = true; 795 796 ctl_epoch = 0; 797 ctl_refresh(); 798 ctl_initialized = true; 799 } 800 801 ret = false; 802 label_return: 803 malloc_mutex_unlock(&ctl_mtx); 804 return (ret); 805 } 806 807 static int 808 ctl_lookup(const char *name, ctl_node_t const **nodesp, size_t *mibp, 809 size_t *depthp) 810 { 811 int ret; 812 const char *elm, *tdot, *dot; 813 size_t elen, i, j; 814 const ctl_named_node_t *node; 815 816 elm = name; 817 /* Equivalent to strchrnul(). */ 818 dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot : strchr(elm, '\0'); 819 elen = (size_t)((uintptr_t)dot - (uintptr_t)elm); 820 if (elen == 0) { 821 ret = ENOENT; 822 goto label_return; 823 } 824 node = super_root_node; 825 for (i = 0; i < *depthp; i++) { 826 assert(node); 827 assert(node->nchildren > 0); 828 if (ctl_named_node(node->children) != NULL) { 829 const ctl_named_node_t *pnode = node; 830 831 /* Children are named. */ 832 for (j = 0; j < node->nchildren; j++) { 833 const ctl_named_node_t *child = 834 ctl_named_children(node, j); 835 if (strlen(child->name) == elen && 836 strncmp(elm, child->name, elen) == 0) { 837 node = child; 838 if (nodesp != NULL) 839 nodesp[i] = 840 (const ctl_node_t *)node; 841 mibp[i] = j; 842 break; 843 } 844 } 845 if (node == pnode) { 846 ret = ENOENT; 847 goto label_return; 848 } 849 } else { 850 uintmax_t index; 851 const ctl_indexed_node_t *inode; 852 853 /* Children are indexed. */ 854 index = malloc_strtoumax(elm, NULL, 10); 855 if (index == UINTMAX_MAX || index > SIZE_T_MAX) { 856 ret = ENOENT; 857 goto label_return; 858 } 859 860 inode = ctl_indexed_node(node->children); 861 node = inode->index(mibp, *depthp, (size_t)index); 862 if (node == NULL) { 863 ret = ENOENT; 864 goto label_return; 865 } 866 867 if (nodesp != NULL) 868 nodesp[i] = (const ctl_node_t *)node; 869 mibp[i] = (size_t)index; 870 } 871 872 if (node->ctl != NULL) { 873 /* Terminal node. */ 874 if (*dot != '\0') { 875 /* 876 * The name contains more elements than are 877 * in this path through the tree. 878 */ 879 ret = ENOENT; 880 goto label_return; 881 } 882 /* Complete lookup successful. */ 883 *depthp = i + 1; 884 break; 885 } 886 887 /* Update elm. */ 888 if (*dot == '\0') { 889 /* No more elements. */ 890 ret = ENOENT; 891 goto label_return; 892 } 893 elm = &dot[1]; 894 dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot : 895 strchr(elm, '\0'); 896 elen = (size_t)((uintptr_t)dot - (uintptr_t)elm); 897 } 898 899 ret = 0; 900 label_return: 901 return (ret); 902 } 903 904 int 905 ctl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp, 906 size_t newlen) 907 { 908 int ret; 909 size_t depth; 910 ctl_node_t const *nodes[CTL_MAX_DEPTH]; 911 size_t mib[CTL_MAX_DEPTH]; 912 const ctl_named_node_t *node; 913 914 if (!ctl_initialized && ctl_init()) { 915 ret = EAGAIN; 916 goto label_return; 917 } 918 919 depth = CTL_MAX_DEPTH; 920 ret = ctl_lookup(name, nodes, mib, &depth); 921 if (ret != 0) 922 goto label_return; 923 924 node = ctl_named_node(nodes[depth-1]); 925 if (node != NULL && node->ctl) 926 ret = node->ctl(mib, depth, oldp, oldlenp, newp, newlen); 927 else { 928 /* The name refers to a partial path through the ctl tree. */ 929 ret = ENOENT; 930 } 931 932 label_return: 933 return(ret); 934 } 935 936 int 937 ctl_nametomib(const char *name, size_t *mibp, size_t *miblenp) 938 { 939 int ret; 940 941 if (!ctl_initialized && ctl_init()) { 942 ret = EAGAIN; 943 goto label_return; 944 } 945 946 ret = ctl_lookup(name, NULL, mibp, miblenp); 947 label_return: 948 return(ret); 949 } 950 951 int 952 ctl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 953 void *newp, size_t newlen) 954 { 955 int ret; 956 const ctl_named_node_t *node; 957 size_t i; 958 959 if (!ctl_initialized && ctl_init()) { 960 ret = EAGAIN; 961 goto label_return; 962 } 963 964 /* Iterate down the tree. */ 965 node = super_root_node; 966 for (i = 0; i < miblen; i++) { 967 assert(node); 968 assert(node->nchildren > 0); 969 if (ctl_named_node(node->children) != NULL) { 970 /* Children are named. */ 971 if (node->nchildren <= (unsigned)mib[i]) { 972 ret = ENOENT; 973 goto label_return; 974 } 975 node = ctl_named_children(node, mib[i]); 976 } else { 977 const ctl_indexed_node_t *inode; 978 979 /* Indexed element. */ 980 inode = ctl_indexed_node(node->children); 981 node = inode->index(mib, miblen, mib[i]); 982 if (node == NULL) { 983 ret = ENOENT; 984 goto label_return; 985 } 986 } 987 } 988 989 /* Call the ctl function. */ 990 if (node && node->ctl) 991 ret = node->ctl(mib, miblen, oldp, oldlenp, newp, newlen); 992 else { 993 /* Partial MIB. */ 994 ret = ENOENT; 995 } 996 997 label_return: 998 return(ret); 999 } 1000 1001 bool 1002 ctl_boot(void) 1003 { 1004 1005 if (malloc_mutex_init(&ctl_mtx)) 1006 return (true); 1007 1008 ctl_initialized = false; 1009 1010 return (false); 1011 } 1012 1013 void 1014 ctl_prefork(void) 1015 { 1016 1017 malloc_mutex_prefork(&ctl_mtx); 1018 } 1019 1020 void 1021 ctl_postfork_parent(void) 1022 { 1023 1024 malloc_mutex_postfork_parent(&ctl_mtx); 1025 } 1026 1027 void 1028 ctl_postfork_child(void) 1029 { 1030 1031 malloc_mutex_postfork_child(&ctl_mtx); 1032 } 1033 1034 /******************************************************************************/ 1035 /* *_ctl() functions. */ 1036 1037 #define READONLY() do { \ 1038 if (newp != NULL || newlen != 0) { \ 1039 ret = EPERM; \ 1040 goto label_return; \ 1041 } \ 1042 } while (0) 1043 1044 #define WRITEONLY() do { \ 1045 if (oldp != NULL || oldlenp != NULL) { \ 1046 ret = EPERM; \ 1047 goto label_return; \ 1048 } \ 1049 } while (0) 1050 1051 #define READ_XOR_WRITE() do { \ 1052 if ((oldp != NULL && oldlenp != NULL) && (newp != NULL || \ 1053 newlen != 0)) { \ 1054 ret = EPERM; \ 1055 goto label_return; \ 1056 } \ 1057 } while (0) 1058 1059 #define READ(v, t) do { \ 1060 if (oldp != NULL && oldlenp != NULL) { \ 1061 if (*oldlenp != sizeof(t)) { \ 1062 size_t copylen = (sizeof(t) <= *oldlenp) \ 1063 ? sizeof(t) : *oldlenp; \ 1064 memcpy(oldp, (void *)&(v), copylen); \ 1065 ret = EINVAL; \ 1066 goto label_return; \ 1067 } \ 1068 *(t *)oldp = (v); \ 1069 } \ 1070 } while (0) 1071 1072 #define WRITE(v, t) do { \ 1073 if (newp != NULL) { \ 1074 if (newlen != sizeof(t)) { \ 1075 ret = EINVAL; \ 1076 goto label_return; \ 1077 } \ 1078 (v) = *(t *)newp; \ 1079 } \ 1080 } while (0) 1081 1082 /* 1083 * There's a lot of code duplication in the following macros due to limitations 1084 * in how nested cpp macros are expanded. 1085 */ 1086 #define CTL_RO_CLGEN(c, l, n, v, t) \ 1087 static int \ 1088 n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1089 void *newp, size_t newlen) \ 1090 { \ 1091 int ret; \ 1092 t oldval; \ 1093 \ 1094 if (!(c)) \ 1095 return (ENOENT); \ 1096 if (l) \ 1097 malloc_mutex_lock(&ctl_mtx); \ 1098 READONLY(); \ 1099 oldval = (v); \ 1100 READ(oldval, t); \ 1101 \ 1102 ret = 0; \ 1103 label_return: \ 1104 if (l) \ 1105 malloc_mutex_unlock(&ctl_mtx); \ 1106 return (ret); \ 1107 } 1108 1109 #define CTL_RO_CGEN(c, n, v, t) \ 1110 static int \ 1111 n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1112 void *newp, size_t newlen) \ 1113 { \ 1114 int ret; \ 1115 t oldval; \ 1116 \ 1117 if (!(c)) \ 1118 return (ENOENT); \ 1119 malloc_mutex_lock(&ctl_mtx); \ 1120 READONLY(); \ 1121 oldval = (v); \ 1122 READ(oldval, t); \ 1123 \ 1124 ret = 0; \ 1125 label_return: \ 1126 malloc_mutex_unlock(&ctl_mtx); \ 1127 return (ret); \ 1128 } 1129 1130 #define CTL_RO_GEN(n, v, t) \ 1131 static int \ 1132 n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1133 void *newp, size_t newlen) \ 1134 { \ 1135 int ret; \ 1136 t oldval; \ 1137 \ 1138 malloc_mutex_lock(&ctl_mtx); \ 1139 READONLY(); \ 1140 oldval = (v); \ 1141 READ(oldval, t); \ 1142 \ 1143 ret = 0; \ 1144 label_return: \ 1145 malloc_mutex_unlock(&ctl_mtx); \ 1146 return (ret); \ 1147 } 1148 1149 /* 1150 * ctl_mtx is not acquired, under the assumption that no pertinent data will 1151 * mutate during the call. 1152 */ 1153 #define CTL_RO_NL_CGEN(c, n, v, t) \ 1154 static int \ 1155 n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1156 void *newp, size_t newlen) \ 1157 { \ 1158 int ret; \ 1159 t oldval; \ 1160 \ 1161 if (!(c)) \ 1162 return (ENOENT); \ 1163 READONLY(); \ 1164 oldval = (v); \ 1165 READ(oldval, t); \ 1166 \ 1167 ret = 0; \ 1168 label_return: \ 1169 return (ret); \ 1170 } 1171 1172 #define CTL_RO_NL_GEN(n, v, t) \ 1173 static int \ 1174 n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1175 void *newp, size_t newlen) \ 1176 { \ 1177 int ret; \ 1178 t oldval; \ 1179 \ 1180 READONLY(); \ 1181 oldval = (v); \ 1182 READ(oldval, t); \ 1183 \ 1184 ret = 0; \ 1185 label_return: \ 1186 return (ret); \ 1187 } 1188 1189 #define CTL_TSD_RO_NL_CGEN(c, n, m, t) \ 1190 static int \ 1191 n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1192 void *newp, size_t newlen) \ 1193 { \ 1194 int ret; \ 1195 t oldval; \ 1196 tsd_t *tsd; \ 1197 \ 1198 if (!(c)) \ 1199 return (ENOENT); \ 1200 READONLY(); \ 1201 tsd = tsd_fetch(); \ 1202 oldval = (m(tsd)); \ 1203 READ(oldval, t); \ 1204 \ 1205 ret = 0; \ 1206 label_return: \ 1207 return (ret); \ 1208 } 1209 1210 #define CTL_RO_CONFIG_GEN(n, t) \ 1211 static int \ 1212 n##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1213 void *newp, size_t newlen) \ 1214 { \ 1215 int ret; \ 1216 t oldval; \ 1217 \ 1218 READONLY(); \ 1219 oldval = n; \ 1220 READ(oldval, t); \ 1221 \ 1222 ret = 0; \ 1223 label_return: \ 1224 return (ret); \ 1225 } 1226 1227 /******************************************************************************/ 1228 1229 CTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *) 1230 1231 static int 1232 epoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1233 void *newp, size_t newlen) 1234 { 1235 int ret; 1236 UNUSED uint64_t newval; 1237 1238 malloc_mutex_lock(&ctl_mtx); 1239 WRITE(newval, uint64_t); 1240 if (newp != NULL) 1241 ctl_refresh(); 1242 READ(ctl_epoch, uint64_t); 1243 1244 ret = 0; 1245 label_return: 1246 malloc_mutex_unlock(&ctl_mtx); 1247 return (ret); 1248 } 1249 1250 /******************************************************************************/ 1251 1252 CTL_RO_CONFIG_GEN(config_cache_oblivious, bool) 1253 CTL_RO_CONFIG_GEN(config_debug, bool) 1254 CTL_RO_CONFIG_GEN(config_fill, bool) 1255 CTL_RO_CONFIG_GEN(config_lazy_lock, bool) 1256 CTL_RO_CONFIG_GEN(config_malloc_conf, const char *) 1257 CTL_RO_CONFIG_GEN(config_munmap, bool) 1258 CTL_RO_CONFIG_GEN(config_prof, bool) 1259 CTL_RO_CONFIG_GEN(config_prof_libgcc, bool) 1260 CTL_RO_CONFIG_GEN(config_prof_libunwind, bool) 1261 CTL_RO_CONFIG_GEN(config_stats, bool) 1262 CTL_RO_CONFIG_GEN(config_tcache, bool) 1263 CTL_RO_CONFIG_GEN(config_tls, bool) 1264 CTL_RO_CONFIG_GEN(config_utrace, bool) 1265 CTL_RO_CONFIG_GEN(config_valgrind, bool) 1266 CTL_RO_CONFIG_GEN(config_xmalloc, bool) 1267 1268 /******************************************************************************/ 1269 1270 CTL_RO_NL_GEN(opt_abort, opt_abort, bool) 1271 CTL_RO_NL_GEN(opt_dss, opt_dss, const char *) 1272 CTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t) 1273 CTL_RO_NL_GEN(opt_narenas, opt_narenas, unsigned) 1274 CTL_RO_NL_GEN(opt_purge, purge_mode_names[opt_purge], const char *) 1275 CTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t) 1276 CTL_RO_NL_GEN(opt_decay_time, opt_decay_time, ssize_t) 1277 CTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) 1278 CTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, const char *) 1279 CTL_RO_NL_CGEN(config_fill, opt_quarantine, opt_quarantine, size_t) 1280 CTL_RO_NL_CGEN(config_fill, opt_redzone, opt_redzone, bool) 1281 CTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool) 1282 CTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool) 1283 CTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool) 1284 CTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool) 1285 CTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t) 1286 CTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool) 1287 CTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *) 1288 CTL_RO_NL_CGEN(config_prof, opt_prof_active, opt_prof_active, bool) 1289 CTL_RO_NL_CGEN(config_prof, opt_prof_thread_active_init, 1290 opt_prof_thread_active_init, bool) 1291 CTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t) 1292 CTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool) 1293 CTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t) 1294 CTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool) 1295 CTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool) 1296 CTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool) 1297 1298 /******************************************************************************/ 1299 1300 static int 1301 thread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1302 void *newp, size_t newlen) 1303 { 1304 int ret; 1305 tsd_t *tsd; 1306 arena_t *oldarena; 1307 unsigned newind, oldind; 1308 1309 tsd = tsd_fetch(); 1310 oldarena = arena_choose(tsd, NULL); 1311 if (oldarena == NULL) 1312 return (EAGAIN); 1313 1314 malloc_mutex_lock(&ctl_mtx); 1315 newind = oldind = oldarena->ind; 1316 WRITE(newind, unsigned); 1317 READ(oldind, unsigned); 1318 if (newind != oldind) { 1319 arena_t *newarena; 1320 1321 if (newind >= ctl_stats.narenas) { 1322 /* New arena index is out of range. */ 1323 ret = EFAULT; 1324 goto label_return; 1325 } 1326 1327 /* Initialize arena if necessary. */ 1328 newarena = arena_get(newind, true); 1329 if (newarena == NULL) { 1330 ret = EAGAIN; 1331 goto label_return; 1332 } 1333 /* Set new arena/tcache associations. */ 1334 arena_migrate(tsd, oldind, newind); 1335 if (config_tcache) { 1336 tcache_t *tcache = tsd_tcache_get(tsd); 1337 if (tcache != NULL) { 1338 tcache_arena_reassociate(tcache, oldarena, 1339 newarena); 1340 } 1341 } 1342 } 1343 1344 ret = 0; 1345 label_return: 1346 malloc_mutex_unlock(&ctl_mtx); 1347 return (ret); 1348 } 1349 1350 CTL_TSD_RO_NL_CGEN(config_stats, thread_allocated, tsd_thread_allocated_get, 1351 uint64_t) 1352 CTL_TSD_RO_NL_CGEN(config_stats, thread_allocatedp, tsd_thread_allocatedp_get, 1353 uint64_t *) 1354 CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocated, tsd_thread_deallocated_get, 1355 uint64_t) 1356 CTL_TSD_RO_NL_CGEN(config_stats, thread_deallocatedp, 1357 tsd_thread_deallocatedp_get, uint64_t *) 1358 1359 static int 1360 thread_tcache_enabled_ctl(const size_t *mib, size_t miblen, void *oldp, 1361 size_t *oldlenp, void *newp, size_t newlen) 1362 { 1363 int ret; 1364 bool oldval; 1365 1366 if (!config_tcache) 1367 return (ENOENT); 1368 1369 oldval = tcache_enabled_get(); 1370 if (newp != NULL) { 1371 if (newlen != sizeof(bool)) { 1372 ret = EINVAL; 1373 goto label_return; 1374 } 1375 tcache_enabled_set(*(bool *)newp); 1376 } 1377 READ(oldval, bool); 1378 1379 ret = 0; 1380 label_return: 1381 return (ret); 1382 } 1383 1384 static int 1385 thread_tcache_flush_ctl(const size_t *mib, size_t miblen, void *oldp, 1386 size_t *oldlenp, void *newp, size_t newlen) 1387 { 1388 int ret; 1389 1390 if (!config_tcache) 1391 return (ENOENT); 1392 1393 READONLY(); 1394 WRITEONLY(); 1395 1396 tcache_flush(); 1397 1398 ret = 0; 1399 label_return: 1400 return (ret); 1401 } 1402 1403 static int 1404 thread_prof_name_ctl(const size_t *mib, size_t miblen, void *oldp, 1405 size_t *oldlenp, void *newp, size_t newlen) 1406 { 1407 int ret; 1408 1409 if (!config_prof) 1410 return (ENOENT); 1411 1412 READ_XOR_WRITE(); 1413 1414 if (newp != NULL) { 1415 tsd_t *tsd; 1416 1417 if (newlen != sizeof(const char *)) { 1418 ret = EINVAL; 1419 goto label_return; 1420 } 1421 1422 tsd = tsd_fetch(); 1423 1424 if ((ret = prof_thread_name_set(tsd, *(const char **)newp)) != 1425 0) 1426 goto label_return; 1427 } else { 1428 const char *oldname = prof_thread_name_get(); 1429 READ(oldname, const char *); 1430 } 1431 1432 ret = 0; 1433 label_return: 1434 return (ret); 1435 } 1436 1437 static int 1438 thread_prof_active_ctl(const size_t *mib, size_t miblen, void *oldp, 1439 size_t *oldlenp, void *newp, size_t newlen) 1440 { 1441 int ret; 1442 bool oldval; 1443 1444 if (!config_prof) 1445 return (ENOENT); 1446 1447 oldval = prof_thread_active_get(); 1448 if (newp != NULL) { 1449 if (newlen != sizeof(bool)) { 1450 ret = EINVAL; 1451 goto label_return; 1452 } 1453 if (prof_thread_active_set(*(bool *)newp)) { 1454 ret = EAGAIN; 1455 goto label_return; 1456 } 1457 } 1458 READ(oldval, bool); 1459 1460 ret = 0; 1461 label_return: 1462 return (ret); 1463 } 1464 1465 /******************************************************************************/ 1466 1467 static int 1468 tcache_create_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1469 void *newp, size_t newlen) 1470 { 1471 int ret; 1472 tsd_t *tsd; 1473 unsigned tcache_ind; 1474 1475 if (!config_tcache) 1476 return (ENOENT); 1477 1478 tsd = tsd_fetch(); 1479 1480 malloc_mutex_lock(&ctl_mtx); 1481 READONLY(); 1482 if (tcaches_create(tsd, &tcache_ind)) { 1483 ret = EFAULT; 1484 goto label_return; 1485 } 1486 READ(tcache_ind, unsigned); 1487 1488 ret = 0; 1489 label_return: 1490 malloc_mutex_unlock(&ctl_mtx); 1491 return (ret); 1492 } 1493 1494 static int 1495 tcache_flush_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1496 void *newp, size_t newlen) 1497 { 1498 int ret; 1499 tsd_t *tsd; 1500 unsigned tcache_ind; 1501 1502 if (!config_tcache) 1503 return (ENOENT); 1504 1505 tsd = tsd_fetch(); 1506 1507 WRITEONLY(); 1508 tcache_ind = UINT_MAX; 1509 WRITE(tcache_ind, unsigned); 1510 if (tcache_ind == UINT_MAX) { 1511 ret = EFAULT; 1512 goto label_return; 1513 } 1514 tcaches_flush(tsd, tcache_ind); 1515 1516 ret = 0; 1517 label_return: 1518 return (ret); 1519 } 1520 1521 static int 1522 tcache_destroy_ctl(const size_t *mib, size_t miblen, void *oldp, 1523 size_t *oldlenp, void *newp, size_t newlen) 1524 { 1525 int ret; 1526 tsd_t *tsd; 1527 unsigned tcache_ind; 1528 1529 if (!config_tcache) 1530 return (ENOENT); 1531 1532 tsd = tsd_fetch(); 1533 1534 WRITEONLY(); 1535 tcache_ind = UINT_MAX; 1536 WRITE(tcache_ind, unsigned); 1537 if (tcache_ind == UINT_MAX) { 1538 ret = EFAULT; 1539 goto label_return; 1540 } 1541 tcaches_destroy(tsd, tcache_ind); 1542 1543 ret = 0; 1544 label_return: 1545 return (ret); 1546 } 1547 1548 /******************************************************************************/ 1549 1550 static void 1551 arena_i_purge(unsigned arena_ind, bool all) 1552 { 1553 1554 malloc_mutex_lock(&ctl_mtx); 1555 { 1556 unsigned narenas = ctl_stats.narenas; 1557 1558 if (arena_ind == narenas) { 1559 unsigned i; 1560 VARIABLE_ARRAY(arena_t *, tarenas, narenas); 1561 1562 for (i = 0; i < narenas; i++) 1563 tarenas[i] = arena_get(i, false); 1564 1565 /* 1566 * No further need to hold ctl_mtx, since narenas and 1567 * tarenas contain everything needed below. 1568 */ 1569 malloc_mutex_unlock(&ctl_mtx); 1570 1571 for (i = 0; i < narenas; i++) { 1572 if (tarenas[i] != NULL) 1573 arena_purge(tarenas[i], all); 1574 } 1575 } else { 1576 arena_t *tarena; 1577 1578 assert(arena_ind < narenas); 1579 1580 tarena = arena_get(arena_ind, false); 1581 1582 /* No further need to hold ctl_mtx. */ 1583 malloc_mutex_unlock(&ctl_mtx); 1584 1585 if (tarena != NULL) 1586 arena_purge(tarena, all); 1587 } 1588 } 1589 } 1590 1591 static int 1592 arena_i_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1593 void *newp, size_t newlen) 1594 { 1595 int ret; 1596 1597 READONLY(); 1598 WRITEONLY(); 1599 arena_i_purge((unsigned)mib[1], true); 1600 1601 ret = 0; 1602 label_return: 1603 return (ret); 1604 } 1605 1606 static int 1607 arena_i_decay_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1608 void *newp, size_t newlen) 1609 { 1610 int ret; 1611 1612 READONLY(); 1613 WRITEONLY(); 1614 arena_i_purge((unsigned)mib[1], false); 1615 1616 ret = 0; 1617 label_return: 1618 return (ret); 1619 } 1620 1621 static int 1622 arena_i_dss_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1623 void *newp, size_t newlen) 1624 { 1625 int ret; 1626 const char *dss = NULL; 1627 unsigned arena_ind = (unsigned)mib[1]; 1628 dss_prec_t dss_prec_old = dss_prec_limit; 1629 dss_prec_t dss_prec = dss_prec_limit; 1630 1631 malloc_mutex_lock(&ctl_mtx); 1632 WRITE(dss, const char *); 1633 if (dss != NULL) { 1634 int i; 1635 bool match = false; 1636 1637 for (i = 0; i < dss_prec_limit; i++) { 1638 if (strcmp(dss_prec_names[i], dss) == 0) { 1639 dss_prec = i; 1640 match = true; 1641 break; 1642 } 1643 } 1644 1645 if (!match) { 1646 ret = EINVAL; 1647 goto label_return; 1648 } 1649 } 1650 1651 if (arena_ind < ctl_stats.narenas) { 1652 arena_t *arena = arena_get(arena_ind, false); 1653 if (arena == NULL || (dss_prec != dss_prec_limit && 1654 arena_dss_prec_set(arena, dss_prec))) { 1655 ret = EFAULT; 1656 goto label_return; 1657 } 1658 dss_prec_old = arena_dss_prec_get(arena); 1659 } else { 1660 if (dss_prec != dss_prec_limit && 1661 chunk_dss_prec_set(dss_prec)) { 1662 ret = EFAULT; 1663 goto label_return; 1664 } 1665 dss_prec_old = chunk_dss_prec_get(); 1666 } 1667 1668 dss = dss_prec_names[dss_prec_old]; 1669 READ(dss, const char *); 1670 1671 ret = 0; 1672 label_return: 1673 malloc_mutex_unlock(&ctl_mtx); 1674 return (ret); 1675 } 1676 1677 static int 1678 arena_i_lg_dirty_mult_ctl(const size_t *mib, size_t miblen, void *oldp, 1679 size_t *oldlenp, void *newp, size_t newlen) 1680 { 1681 int ret; 1682 unsigned arena_ind = (unsigned)mib[1]; 1683 arena_t *arena; 1684 1685 arena = arena_get(arena_ind, false); 1686 if (arena == NULL) { 1687 ret = EFAULT; 1688 goto label_return; 1689 } 1690 1691 if (oldp != NULL && oldlenp != NULL) { 1692 size_t oldval = arena_lg_dirty_mult_get(arena); 1693 READ(oldval, ssize_t); 1694 } 1695 if (newp != NULL) { 1696 if (newlen != sizeof(ssize_t)) { 1697 ret = EINVAL; 1698 goto label_return; 1699 } 1700 if (arena_lg_dirty_mult_set(arena, *(ssize_t *)newp)) { 1701 ret = EFAULT; 1702 goto label_return; 1703 } 1704 } 1705 1706 ret = 0; 1707 label_return: 1708 return (ret); 1709 } 1710 1711 static int 1712 arena_i_decay_time_ctl(const size_t *mib, size_t miblen, void *oldp, 1713 size_t *oldlenp, void *newp, size_t newlen) 1714 { 1715 int ret; 1716 unsigned arena_ind = (unsigned)mib[1]; 1717 arena_t *arena; 1718 1719 arena = arena_get(arena_ind, false); 1720 if (arena == NULL) { 1721 ret = EFAULT; 1722 goto label_return; 1723 } 1724 1725 if (oldp != NULL && oldlenp != NULL) { 1726 size_t oldval = arena_decay_time_get(arena); 1727 READ(oldval, ssize_t); 1728 } 1729 if (newp != NULL) { 1730 if (newlen != sizeof(ssize_t)) { 1731 ret = EINVAL; 1732 goto label_return; 1733 } 1734 if (arena_decay_time_set(arena, *(ssize_t *)newp)) { 1735 ret = EFAULT; 1736 goto label_return; 1737 } 1738 } 1739 1740 ret = 0; 1741 label_return: 1742 return (ret); 1743 } 1744 1745 static int 1746 arena_i_chunk_hooks_ctl(const size_t *mib, size_t miblen, void *oldp, 1747 size_t *oldlenp, void *newp, size_t newlen) 1748 { 1749 int ret; 1750 unsigned arena_ind = (unsigned)mib[1]; 1751 arena_t *arena; 1752 1753 malloc_mutex_lock(&ctl_mtx); 1754 if (arena_ind < narenas_total_get() && (arena = 1755 arena_get(arena_ind, false)) != NULL) { 1756 if (newp != NULL) { 1757 chunk_hooks_t old_chunk_hooks, new_chunk_hooks; 1758 WRITE(new_chunk_hooks, chunk_hooks_t); 1759 old_chunk_hooks = chunk_hooks_set(arena, 1760 &new_chunk_hooks); 1761 READ(old_chunk_hooks, chunk_hooks_t); 1762 } else { 1763 chunk_hooks_t old_chunk_hooks = chunk_hooks_get(arena); 1764 READ(old_chunk_hooks, chunk_hooks_t); 1765 } 1766 } else { 1767 ret = EFAULT; 1768 goto label_return; 1769 } 1770 ret = 0; 1771 label_return: 1772 malloc_mutex_unlock(&ctl_mtx); 1773 return (ret); 1774 } 1775 1776 static const ctl_named_node_t * 1777 arena_i_index(const size_t *mib, size_t miblen, size_t i) 1778 { 1779 const ctl_named_node_t * ret; 1780 1781 malloc_mutex_lock(&ctl_mtx); 1782 if (i > ctl_stats.narenas) { 1783 ret = NULL; 1784 goto label_return; 1785 } 1786 1787 ret = super_arena_i_node; 1788 label_return: 1789 malloc_mutex_unlock(&ctl_mtx); 1790 return (ret); 1791 } 1792 1793 /******************************************************************************/ 1794 1795 static int 1796 arenas_narenas_ctl(const size_t *mib, size_t miblen, void *oldp, 1797 size_t *oldlenp, void *newp, size_t newlen) 1798 { 1799 int ret; 1800 unsigned narenas; 1801 1802 malloc_mutex_lock(&ctl_mtx); 1803 READONLY(); 1804 if (*oldlenp != sizeof(unsigned)) { 1805 ret = EINVAL; 1806 goto label_return; 1807 } 1808 narenas = ctl_stats.narenas; 1809 READ(narenas, unsigned); 1810 1811 ret = 0; 1812 label_return: 1813 malloc_mutex_unlock(&ctl_mtx); 1814 return (ret); 1815 } 1816 1817 static int 1818 arenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp, 1819 size_t *oldlenp, void *newp, size_t newlen) 1820 { 1821 int ret; 1822 unsigned nread, i; 1823 1824 malloc_mutex_lock(&ctl_mtx); 1825 READONLY(); 1826 if (*oldlenp != ctl_stats.narenas * sizeof(bool)) { 1827 ret = EINVAL; 1828 nread = (*oldlenp < ctl_stats.narenas * sizeof(bool)) 1829 ? (unsigned)(*oldlenp / sizeof(bool)) : ctl_stats.narenas; 1830 } else { 1831 ret = 0; 1832 nread = ctl_stats.narenas; 1833 } 1834 1835 for (i = 0; i < nread; i++) 1836 ((bool *)oldp)[i] = ctl_stats.arenas[i].initialized; 1837 1838 label_return: 1839 malloc_mutex_unlock(&ctl_mtx); 1840 return (ret); 1841 } 1842 1843 static int 1844 arenas_lg_dirty_mult_ctl(const size_t *mib, size_t miblen, void *oldp, 1845 size_t *oldlenp, void *newp, size_t newlen) 1846 { 1847 int ret; 1848 1849 if (oldp != NULL && oldlenp != NULL) { 1850 size_t oldval = arena_lg_dirty_mult_default_get(); 1851 READ(oldval, ssize_t); 1852 } 1853 if (newp != NULL) { 1854 if (newlen != sizeof(ssize_t)) { 1855 ret = EINVAL; 1856 goto label_return; 1857 } 1858 if (arena_lg_dirty_mult_default_set(*(ssize_t *)newp)) { 1859 ret = EFAULT; 1860 goto label_return; 1861 } 1862 } 1863 1864 ret = 0; 1865 label_return: 1866 return (ret); 1867 } 1868 1869 static int 1870 arenas_decay_time_ctl(const size_t *mib, size_t miblen, void *oldp, 1871 size_t *oldlenp, void *newp, size_t newlen) 1872 { 1873 int ret; 1874 1875 if (oldp != NULL && oldlenp != NULL) { 1876 size_t oldval = arena_decay_time_default_get(); 1877 READ(oldval, ssize_t); 1878 } 1879 if (newp != NULL) { 1880 if (newlen != sizeof(ssize_t)) { 1881 ret = EINVAL; 1882 goto label_return; 1883 } 1884 if (arena_decay_time_default_set(*(ssize_t *)newp)) { 1885 ret = EFAULT; 1886 goto label_return; 1887 } 1888 } 1889 1890 ret = 0; 1891 label_return: 1892 return (ret); 1893 } 1894 1895 CTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t) 1896 CTL_RO_NL_GEN(arenas_page, PAGE, size_t) 1897 CTL_RO_NL_CGEN(config_tcache, arenas_tcache_max, tcache_maxclass, size_t) 1898 CTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned) 1899 CTL_RO_NL_CGEN(config_tcache, arenas_nhbins, nhbins, unsigned) 1900 CTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t) 1901 CTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t) 1902 CTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t) 1903 static const ctl_named_node_t * 1904 arenas_bin_i_index(const size_t *mib, size_t miblen, size_t i) 1905 { 1906 1907 if (i > NBINS) 1908 return (NULL); 1909 return (super_arenas_bin_i_node); 1910 } 1911 1912 CTL_RO_NL_GEN(arenas_nlruns, nlclasses, unsigned) 1913 CTL_RO_NL_GEN(arenas_lrun_i_size, index2size(NBINS+(szind_t)mib[2]), size_t) 1914 static const ctl_named_node_t * 1915 arenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i) 1916 { 1917 1918 if (i > nlclasses) 1919 return (NULL); 1920 return (super_arenas_lrun_i_node); 1921 } 1922 1923 CTL_RO_NL_GEN(arenas_nhchunks, nhclasses, unsigned) 1924 CTL_RO_NL_GEN(arenas_hchunk_i_size, index2size(NBINS+nlclasses+(szind_t)mib[2]), 1925 size_t) 1926 static const ctl_named_node_t * 1927 arenas_hchunk_i_index(const size_t *mib, size_t miblen, size_t i) 1928 { 1929 1930 if (i > nhclasses) 1931 return (NULL); 1932 return (super_arenas_hchunk_i_node); 1933 } 1934 1935 static int 1936 arenas_extend_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1937 void *newp, size_t newlen) 1938 { 1939 int ret; 1940 unsigned narenas; 1941 1942 malloc_mutex_lock(&ctl_mtx); 1943 READONLY(); 1944 if (ctl_grow()) { 1945 ret = EAGAIN; 1946 goto label_return; 1947 } 1948 narenas = ctl_stats.narenas - 1; 1949 READ(narenas, unsigned); 1950 1951 ret = 0; 1952 label_return: 1953 malloc_mutex_unlock(&ctl_mtx); 1954 return (ret); 1955 } 1956 1957 /******************************************************************************/ 1958 1959 static int 1960 prof_thread_active_init_ctl(const size_t *mib, size_t miblen, void *oldp, 1961 size_t *oldlenp, void *newp, size_t newlen) 1962 { 1963 int ret; 1964 bool oldval; 1965 1966 if (!config_prof) 1967 return (ENOENT); 1968 1969 if (newp != NULL) { 1970 if (newlen != sizeof(bool)) { 1971 ret = EINVAL; 1972 goto label_return; 1973 } 1974 oldval = prof_thread_active_init_set(*(bool *)newp); 1975 } else 1976 oldval = prof_thread_active_init_get(); 1977 READ(oldval, bool); 1978 1979 ret = 0; 1980 label_return: 1981 return (ret); 1982 } 1983 1984 static int 1985 prof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1986 void *newp, size_t newlen) 1987 { 1988 int ret; 1989 bool oldval; 1990 1991 if (!config_prof) 1992 return (ENOENT); 1993 1994 if (newp != NULL) { 1995 if (newlen != sizeof(bool)) { 1996 ret = EINVAL; 1997 goto label_return; 1998 } 1999 oldval = prof_active_set(*(bool *)newp); 2000 } else 2001 oldval = prof_active_get(); 2002 READ(oldval, bool); 2003 2004 ret = 0; 2005 label_return: 2006 return (ret); 2007 } 2008 2009 static int 2010 prof_dump_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 2011 void *newp, size_t newlen) 2012 { 2013 int ret; 2014 const char *filename = NULL; 2015 2016 if (!config_prof) 2017 return (ENOENT); 2018 2019 WRITEONLY(); 2020 WRITE(filename, const char *); 2021 2022 if (prof_mdump(filename)) { 2023 ret = EFAULT; 2024 goto label_return; 2025 } 2026 2027 ret = 0; 2028 label_return: 2029 return (ret); 2030 } 2031 2032 static int 2033 prof_gdump_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 2034 void *newp, size_t newlen) 2035 { 2036 int ret; 2037 bool oldval; 2038 2039 if (!config_prof) 2040 return (ENOENT); 2041 2042 if (newp != NULL) { 2043 if (newlen != sizeof(bool)) { 2044 ret = EINVAL; 2045 goto label_return; 2046 } 2047 oldval = prof_gdump_set(*(bool *)newp); 2048 } else 2049 oldval = prof_gdump_get(); 2050 READ(oldval, bool); 2051 2052 ret = 0; 2053 label_return: 2054 return (ret); 2055 } 2056 2057 static int 2058 prof_reset_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 2059 void *newp, size_t newlen) 2060 { 2061 int ret; 2062 size_t lg_sample = lg_prof_sample; 2063 tsd_t *tsd; 2064 2065 if (!config_prof) 2066 return (ENOENT); 2067 2068 WRITEONLY(); 2069 WRITE(lg_sample, size_t); 2070 if (lg_sample >= (sizeof(uint64_t) << 3)) 2071 lg_sample = (sizeof(uint64_t) << 3) - 1; 2072 2073 tsd = tsd_fetch(); 2074 2075 prof_reset(tsd, lg_sample); 2076 2077 ret = 0; 2078 label_return: 2079 return (ret); 2080 } 2081 2082 CTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t) 2083 CTL_RO_NL_CGEN(config_prof, lg_prof_sample, lg_prof_sample, size_t) 2084 2085 /******************************************************************************/ 2086 2087 CTL_RO_CGEN(config_stats, stats_cactive, &stats_cactive, size_t *) 2088 CTL_RO_CGEN(config_stats, stats_allocated, ctl_stats.allocated, size_t) 2089 CTL_RO_CGEN(config_stats, stats_active, ctl_stats.active, size_t) 2090 CTL_RO_CGEN(config_stats, stats_metadata, ctl_stats.metadata, size_t) 2091 CTL_RO_CGEN(config_stats, stats_resident, ctl_stats.resident, size_t) 2092 CTL_RO_CGEN(config_stats, stats_mapped, ctl_stats.mapped, size_t) 2093 2094 CTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *) 2095 CTL_RO_GEN(stats_arenas_i_lg_dirty_mult, ctl_stats.arenas[mib[2]].lg_dirty_mult, 2096 ssize_t) 2097 CTL_RO_GEN(stats_arenas_i_decay_time, ctl_stats.arenas[mib[2]].decay_time, 2098 ssize_t) 2099 CTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned) 2100 CTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t) 2101 CTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t) 2102 CTL_RO_CGEN(config_stats, stats_arenas_i_mapped, 2103 ctl_stats.arenas[mib[2]].astats.mapped, size_t) 2104 CTL_RO_CGEN(config_stats, stats_arenas_i_npurge, 2105 ctl_stats.arenas[mib[2]].astats.npurge, uint64_t) 2106 CTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise, 2107 ctl_stats.arenas[mib[2]].astats.nmadvise, uint64_t) 2108 CTL_RO_CGEN(config_stats, stats_arenas_i_purged, 2109 ctl_stats.arenas[mib[2]].astats.purged, uint64_t) 2110 CTL_RO_CGEN(config_stats, stats_arenas_i_metadata_mapped, 2111 ctl_stats.arenas[mib[2]].astats.metadata_mapped, size_t) 2112 CTL_RO_CGEN(config_stats, stats_arenas_i_metadata_allocated, 2113 ctl_stats.arenas[mib[2]].astats.metadata_allocated, size_t) 2114 2115 CTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated, 2116 ctl_stats.arenas[mib[2]].allocated_small, size_t) 2117 CTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc, 2118 ctl_stats.arenas[mib[2]].nmalloc_small, uint64_t) 2119 CTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc, 2120 ctl_stats.arenas[mib[2]].ndalloc_small, uint64_t) 2121 CTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests, 2122 ctl_stats.arenas[mib[2]].nrequests_small, uint64_t) 2123 CTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated, 2124 ctl_stats.arenas[mib[2]].astats.allocated_large, size_t) 2125 CTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc, 2126 ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t) 2127 CTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc, 2128 ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t) 2129 CTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, 2130 ctl_stats.arenas[mib[2]].astats.nrequests_large, uint64_t) 2131 CTL_RO_CGEN(config_stats, stats_arenas_i_huge_allocated, 2132 ctl_stats.arenas[mib[2]].astats.allocated_huge, size_t) 2133 CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nmalloc, 2134 ctl_stats.arenas[mib[2]].astats.nmalloc_huge, uint64_t) 2135 CTL_RO_CGEN(config_stats, stats_arenas_i_huge_ndalloc, 2136 ctl_stats.arenas[mib[2]].astats.ndalloc_huge, uint64_t) 2137 CTL_RO_CGEN(config_stats, stats_arenas_i_huge_nrequests, 2138 ctl_stats.arenas[mib[2]].astats.nmalloc_huge, uint64_t) /* Intentional. */ 2139 2140 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc, 2141 ctl_stats.arenas[mib[2]].bstats[mib[4]].nmalloc, uint64_t) 2142 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc, 2143 ctl_stats.arenas[mib[2]].bstats[mib[4]].ndalloc, uint64_t) 2144 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests, 2145 ctl_stats.arenas[mib[2]].bstats[mib[4]].nrequests, uint64_t) 2146 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curregs, 2147 ctl_stats.arenas[mib[2]].bstats[mib[4]].curregs, size_t) 2148 CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills, 2149 ctl_stats.arenas[mib[2]].bstats[mib[4]].nfills, uint64_t) 2150 CTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes, 2151 ctl_stats.arenas[mib[2]].bstats[mib[4]].nflushes, uint64_t) 2152 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nruns, 2153 ctl_stats.arenas[mib[2]].bstats[mib[4]].nruns, uint64_t) 2154 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreruns, 2155 ctl_stats.arenas[mib[2]].bstats[mib[4]].reruns, uint64_t) 2156 CTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curruns, 2157 ctl_stats.arenas[mib[2]].bstats[mib[4]].curruns, size_t) 2158 2159 static const ctl_named_node_t * 2160 stats_arenas_i_bins_j_index(const size_t *mib, size_t miblen, size_t j) 2161 { 2162 2163 if (j > NBINS) 2164 return (NULL); 2165 return (super_stats_arenas_i_bins_j_node); 2166 } 2167 2168 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nmalloc, 2169 ctl_stats.arenas[mib[2]].lstats[mib[4]].nmalloc, uint64_t) 2170 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_ndalloc, 2171 ctl_stats.arenas[mib[2]].lstats[mib[4]].ndalloc, uint64_t) 2172 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nrequests, 2173 ctl_stats.arenas[mib[2]].lstats[mib[4]].nrequests, uint64_t) 2174 CTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_curruns, 2175 ctl_stats.arenas[mib[2]].lstats[mib[4]].curruns, size_t) 2176 2177 static const ctl_named_node_t * 2178 stats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j) 2179 { 2180 2181 if (j > nlclasses) 2182 return (NULL); 2183 return (super_stats_arenas_i_lruns_j_node); 2184 } 2185 2186 CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nmalloc, 2187 ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, uint64_t) 2188 CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_ndalloc, 2189 ctl_stats.arenas[mib[2]].hstats[mib[4]].ndalloc, uint64_t) 2190 CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_nrequests, 2191 ctl_stats.arenas[mib[2]].hstats[mib[4]].nmalloc, /* Intentional. */ 2192 uint64_t) 2193 CTL_RO_CGEN(config_stats, stats_arenas_i_hchunks_j_curhchunks, 2194 ctl_stats.arenas[mib[2]].hstats[mib[4]].curhchunks, size_t) 2195 2196 static const ctl_named_node_t * 2197 stats_arenas_i_hchunks_j_index(const size_t *mib, size_t miblen, size_t j) 2198 { 2199 2200 if (j > nhclasses) 2201 return (NULL); 2202 return (super_stats_arenas_i_hchunks_j_node); 2203 } 2204 2205 static const ctl_named_node_t * 2206 stats_arenas_i_index(const size_t *mib, size_t miblen, size_t i) 2207 { 2208 const ctl_named_node_t * ret; 2209 2210 malloc_mutex_lock(&ctl_mtx); 2211 if (i > ctl_stats.narenas || !ctl_stats.arenas[i].initialized) { 2212 ret = NULL; 2213 goto label_return; 2214 } 2215 2216 ret = super_stats_arenas_i_node; 2217 label_return: 2218 malloc_mutex_unlock(&ctl_mtx); 2219 return (ret); 2220 } 2221