ctl.c revision 261071
1234370Sjasone#define JEMALLOC_CTL_C_ 2234370Sjasone#include "jemalloc/internal/jemalloc_internal.h" 3234370Sjasone 4234370Sjasone/******************************************************************************/ 5234370Sjasone/* Data. */ 6234370Sjasone 7234370Sjasone/* 8234370Sjasone * ctl_mtx protects the following: 9234370Sjasone * - ctl_stats.* 10234370Sjasone * - opt_prof_active 11234370Sjasone */ 12234370Sjasonestatic malloc_mutex_t ctl_mtx; 13234370Sjasonestatic bool ctl_initialized; 14234370Sjasonestatic uint64_t ctl_epoch; 15234370Sjasonestatic ctl_stats_t ctl_stats; 16234370Sjasone 17234370Sjasone/******************************************************************************/ 18235238Sjasone/* Helpers for named and indexed nodes. */ 19235238Sjasone 20235238Sjasonestatic inline const ctl_named_node_t * 21235238Sjasonectl_named_node(const ctl_node_t *node) 22235238Sjasone{ 23235238Sjasone 24235238Sjasone return ((node->named) ? (const ctl_named_node_t *)node : NULL); 25235238Sjasone} 26235238Sjasone 27235238Sjasonestatic inline const ctl_named_node_t * 28235238Sjasonectl_named_children(const ctl_named_node_t *node, int index) 29235238Sjasone{ 30235238Sjasone const ctl_named_node_t *children = ctl_named_node(node->children); 31235238Sjasone 32235238Sjasone return (children ? &children[index] : NULL); 33235238Sjasone} 34235238Sjasone 35235238Sjasonestatic inline const ctl_indexed_node_t * 36235238Sjasonectl_indexed_node(const ctl_node_t *node) 37235238Sjasone{ 38235238Sjasone 39235238Sjasone return ((node->named == false) ? (const ctl_indexed_node_t *)node : 40235238Sjasone NULL); 41235238Sjasone} 42235238Sjasone 43235238Sjasone/******************************************************************************/ 44234370Sjasone/* Function prototypes for non-inline static functions. */ 45234370Sjasone 46234370Sjasone#define CTL_PROTO(n) \ 47234370Sjasonestatic int n##_ctl(const size_t *mib, size_t miblen, void *oldp, \ 48234370Sjasone size_t *oldlenp, void *newp, size_t newlen); 49234370Sjasone 50234370Sjasone#define INDEX_PROTO(n) \ 51242844Sjasonestatic const ctl_named_node_t *n##_index(const size_t *mib, \ 52242844Sjasone size_t miblen, size_t i); 53234370Sjasone 54234370Sjasonestatic bool ctl_arena_init(ctl_arena_stats_t *astats); 55234370Sjasonestatic void ctl_arena_clear(ctl_arena_stats_t *astats); 56234370Sjasonestatic void ctl_arena_stats_amerge(ctl_arena_stats_t *cstats, 57234370Sjasone arena_t *arena); 58234370Sjasonestatic void ctl_arena_stats_smerge(ctl_arena_stats_t *sstats, 59234370Sjasone ctl_arena_stats_t *astats); 60234370Sjasonestatic void ctl_arena_refresh(arena_t *arena, unsigned i); 61242844Sjasonestatic bool ctl_grow(void); 62234370Sjasonestatic void ctl_refresh(void); 63234370Sjasonestatic bool ctl_init(void); 64234370Sjasonestatic int ctl_lookup(const char *name, ctl_node_t const **nodesp, 65234370Sjasone size_t *mibp, size_t *depthp); 66234370Sjasone 67234370SjasoneCTL_PROTO(version) 68234370SjasoneCTL_PROTO(epoch) 69234370SjasoneCTL_PROTO(thread_tcache_enabled) 70234370SjasoneCTL_PROTO(thread_tcache_flush) 71234370SjasoneCTL_PROTO(thread_arena) 72234370SjasoneCTL_PROTO(thread_allocated) 73234370SjasoneCTL_PROTO(thread_allocatedp) 74234370SjasoneCTL_PROTO(thread_deallocated) 75234370SjasoneCTL_PROTO(thread_deallocatedp) 76234370SjasoneCTL_PROTO(config_debug) 77234370SjasoneCTL_PROTO(config_dss) 78234370SjasoneCTL_PROTO(config_fill) 79234370SjasoneCTL_PROTO(config_lazy_lock) 80235238SjasoneCTL_PROTO(config_mremap) 81234370SjasoneCTL_PROTO(config_munmap) 82234370SjasoneCTL_PROTO(config_prof) 83234370SjasoneCTL_PROTO(config_prof_libgcc) 84234370SjasoneCTL_PROTO(config_prof_libunwind) 85234370SjasoneCTL_PROTO(config_stats) 86234370SjasoneCTL_PROTO(config_tcache) 87234370SjasoneCTL_PROTO(config_tls) 88234370SjasoneCTL_PROTO(config_utrace) 89234370SjasoneCTL_PROTO(config_valgrind) 90234370SjasoneCTL_PROTO(config_xmalloc) 91234370SjasoneCTL_PROTO(opt_abort) 92242844SjasoneCTL_PROTO(opt_dss) 93234370SjasoneCTL_PROTO(opt_lg_chunk) 94234370SjasoneCTL_PROTO(opt_narenas) 95234370SjasoneCTL_PROTO(opt_lg_dirty_mult) 96234370SjasoneCTL_PROTO(opt_stats_print) 97234370SjasoneCTL_PROTO(opt_junk) 98234370SjasoneCTL_PROTO(opt_zero) 99234370SjasoneCTL_PROTO(opt_quarantine) 100234370SjasoneCTL_PROTO(opt_redzone) 101234370SjasoneCTL_PROTO(opt_utrace) 102234370SjasoneCTL_PROTO(opt_valgrind) 103234370SjasoneCTL_PROTO(opt_xmalloc) 104234370SjasoneCTL_PROTO(opt_tcache) 105234370SjasoneCTL_PROTO(opt_lg_tcache_max) 106234370SjasoneCTL_PROTO(opt_prof) 107234370SjasoneCTL_PROTO(opt_prof_prefix) 108234370SjasoneCTL_PROTO(opt_prof_active) 109234370SjasoneCTL_PROTO(opt_lg_prof_sample) 110234370SjasoneCTL_PROTO(opt_lg_prof_interval) 111234370SjasoneCTL_PROTO(opt_prof_gdump) 112234543SjasoneCTL_PROTO(opt_prof_final) 113234370SjasoneCTL_PROTO(opt_prof_leak) 114234370SjasoneCTL_PROTO(opt_prof_accum) 115242844SjasoneCTL_PROTO(arena_i_purge) 116242844Sjasonestatic void arena_purge(unsigned arena_ind); 117242844SjasoneCTL_PROTO(arena_i_dss) 118242844SjasoneINDEX_PROTO(arena_i) 119234370SjasoneCTL_PROTO(arenas_bin_i_size) 120234370SjasoneCTL_PROTO(arenas_bin_i_nregs) 121234370SjasoneCTL_PROTO(arenas_bin_i_run_size) 122234370SjasoneINDEX_PROTO(arenas_bin_i) 123234370SjasoneCTL_PROTO(arenas_lrun_i_size) 124234370SjasoneINDEX_PROTO(arenas_lrun_i) 125234370SjasoneCTL_PROTO(arenas_narenas) 126234370SjasoneCTL_PROTO(arenas_initialized) 127234370SjasoneCTL_PROTO(arenas_quantum) 128234370SjasoneCTL_PROTO(arenas_page) 129234370SjasoneCTL_PROTO(arenas_tcache_max) 130234370SjasoneCTL_PROTO(arenas_nbins) 131234370SjasoneCTL_PROTO(arenas_nhbins) 132234370SjasoneCTL_PROTO(arenas_nlruns) 133234370SjasoneCTL_PROTO(arenas_purge) 134242844SjasoneCTL_PROTO(arenas_extend) 135234370SjasoneCTL_PROTO(prof_active) 136234370SjasoneCTL_PROTO(prof_dump) 137234370SjasoneCTL_PROTO(prof_interval) 138234370SjasoneCTL_PROTO(stats_chunks_current) 139234370SjasoneCTL_PROTO(stats_chunks_total) 140234370SjasoneCTL_PROTO(stats_chunks_high) 141234370SjasoneCTL_PROTO(stats_huge_allocated) 142234370SjasoneCTL_PROTO(stats_huge_nmalloc) 143234370SjasoneCTL_PROTO(stats_huge_ndalloc) 144234370SjasoneCTL_PROTO(stats_arenas_i_small_allocated) 145234370SjasoneCTL_PROTO(stats_arenas_i_small_nmalloc) 146234370SjasoneCTL_PROTO(stats_arenas_i_small_ndalloc) 147234370SjasoneCTL_PROTO(stats_arenas_i_small_nrequests) 148234370SjasoneCTL_PROTO(stats_arenas_i_large_allocated) 149234370SjasoneCTL_PROTO(stats_arenas_i_large_nmalloc) 150234370SjasoneCTL_PROTO(stats_arenas_i_large_ndalloc) 151234370SjasoneCTL_PROTO(stats_arenas_i_large_nrequests) 152234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_allocated) 153234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nmalloc) 154234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_ndalloc) 155234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nrequests) 156234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nfills) 157234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nflushes) 158234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nruns) 159234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_nreruns) 160234370SjasoneCTL_PROTO(stats_arenas_i_bins_j_curruns) 161234370SjasoneINDEX_PROTO(stats_arenas_i_bins_j) 162234370SjasoneCTL_PROTO(stats_arenas_i_lruns_j_nmalloc) 163234370SjasoneCTL_PROTO(stats_arenas_i_lruns_j_ndalloc) 164234370SjasoneCTL_PROTO(stats_arenas_i_lruns_j_nrequests) 165234370SjasoneCTL_PROTO(stats_arenas_i_lruns_j_curruns) 166234370SjasoneINDEX_PROTO(stats_arenas_i_lruns_j) 167234370SjasoneCTL_PROTO(stats_arenas_i_nthreads) 168242844SjasoneCTL_PROTO(stats_arenas_i_dss) 169234370SjasoneCTL_PROTO(stats_arenas_i_pactive) 170234370SjasoneCTL_PROTO(stats_arenas_i_pdirty) 171234370SjasoneCTL_PROTO(stats_arenas_i_mapped) 172234370SjasoneCTL_PROTO(stats_arenas_i_npurge) 173234370SjasoneCTL_PROTO(stats_arenas_i_nmadvise) 174234370SjasoneCTL_PROTO(stats_arenas_i_purged) 175234370SjasoneINDEX_PROTO(stats_arenas_i) 176234370SjasoneCTL_PROTO(stats_cactive) 177234370SjasoneCTL_PROTO(stats_allocated) 178234370SjasoneCTL_PROTO(stats_active) 179234370SjasoneCTL_PROTO(stats_mapped) 180234370Sjasone 181234370Sjasone/******************************************************************************/ 182234370Sjasone/* mallctl tree. */ 183234370Sjasone 184234370Sjasone/* Maximum tree depth. */ 185234370Sjasone#define CTL_MAX_DEPTH 6 186234370Sjasone 187235238Sjasone#define NAME(n) {true}, n 188235238Sjasone#define CHILD(t, c) \ 189235238Sjasone sizeof(c##_node) / sizeof(ctl_##t##_node_t), \ 190235238Sjasone (ctl_node_t *)c##_node, \ 191235238Sjasone NULL 192235238Sjasone#define CTL(c) 0, NULL, c##_ctl 193234370Sjasone 194234370Sjasone/* 195234370Sjasone * Only handles internal indexed nodes, since there are currently no external 196234370Sjasone * ones. 197234370Sjasone */ 198235238Sjasone#define INDEX(i) {false}, i##_index 199234370Sjasone 200235238Sjasonestatic const ctl_named_node_t tcache_node[] = { 201234370Sjasone {NAME("enabled"), CTL(thread_tcache_enabled)}, 202234370Sjasone {NAME("flush"), CTL(thread_tcache_flush)} 203234370Sjasone}; 204234370Sjasone 205235238Sjasonestatic const ctl_named_node_t thread_node[] = { 206234370Sjasone {NAME("arena"), CTL(thread_arena)}, 207234370Sjasone {NAME("allocated"), CTL(thread_allocated)}, 208234370Sjasone {NAME("allocatedp"), CTL(thread_allocatedp)}, 209234370Sjasone {NAME("deallocated"), CTL(thread_deallocated)}, 210234370Sjasone {NAME("deallocatedp"), CTL(thread_deallocatedp)}, 211235238Sjasone {NAME("tcache"), CHILD(named, tcache)} 212234370Sjasone}; 213234370Sjasone 214235238Sjasonestatic const ctl_named_node_t config_node[] = { 215234370Sjasone {NAME("debug"), CTL(config_debug)}, 216234370Sjasone {NAME("dss"), CTL(config_dss)}, 217234370Sjasone {NAME("fill"), CTL(config_fill)}, 218234370Sjasone {NAME("lazy_lock"), CTL(config_lazy_lock)}, 219235238Sjasone {NAME("mremap"), CTL(config_mremap)}, 220234370Sjasone {NAME("munmap"), CTL(config_munmap)}, 221234370Sjasone {NAME("prof"), CTL(config_prof)}, 222234370Sjasone {NAME("prof_libgcc"), CTL(config_prof_libgcc)}, 223234370Sjasone {NAME("prof_libunwind"), CTL(config_prof_libunwind)}, 224234370Sjasone {NAME("stats"), CTL(config_stats)}, 225234370Sjasone {NAME("tcache"), CTL(config_tcache)}, 226234370Sjasone {NAME("tls"), CTL(config_tls)}, 227234370Sjasone {NAME("utrace"), CTL(config_utrace)}, 228234370Sjasone {NAME("valgrind"), CTL(config_valgrind)}, 229234370Sjasone {NAME("xmalloc"), CTL(config_xmalloc)} 230234370Sjasone}; 231234370Sjasone 232235238Sjasonestatic const ctl_named_node_t opt_node[] = { 233234370Sjasone {NAME("abort"), CTL(opt_abort)}, 234242844Sjasone {NAME("dss"), CTL(opt_dss)}, 235234370Sjasone {NAME("lg_chunk"), CTL(opt_lg_chunk)}, 236234370Sjasone {NAME("narenas"), CTL(opt_narenas)}, 237234370Sjasone {NAME("lg_dirty_mult"), CTL(opt_lg_dirty_mult)}, 238234370Sjasone {NAME("stats_print"), CTL(opt_stats_print)}, 239234370Sjasone {NAME("junk"), CTL(opt_junk)}, 240234370Sjasone {NAME("zero"), CTL(opt_zero)}, 241234370Sjasone {NAME("quarantine"), CTL(opt_quarantine)}, 242234370Sjasone {NAME("redzone"), CTL(opt_redzone)}, 243234370Sjasone {NAME("utrace"), CTL(opt_utrace)}, 244234370Sjasone {NAME("valgrind"), CTL(opt_valgrind)}, 245234370Sjasone {NAME("xmalloc"), CTL(opt_xmalloc)}, 246234370Sjasone {NAME("tcache"), CTL(opt_tcache)}, 247234370Sjasone {NAME("lg_tcache_max"), CTL(opt_lg_tcache_max)}, 248234370Sjasone {NAME("prof"), CTL(opt_prof)}, 249234370Sjasone {NAME("prof_prefix"), CTL(opt_prof_prefix)}, 250234370Sjasone {NAME("prof_active"), CTL(opt_prof_active)}, 251234370Sjasone {NAME("lg_prof_sample"), CTL(opt_lg_prof_sample)}, 252234370Sjasone {NAME("lg_prof_interval"), CTL(opt_lg_prof_interval)}, 253234370Sjasone {NAME("prof_gdump"), CTL(opt_prof_gdump)}, 254234543Sjasone {NAME("prof_final"), CTL(opt_prof_final)}, 255234370Sjasone {NAME("prof_leak"), CTL(opt_prof_leak)}, 256234370Sjasone {NAME("prof_accum"), CTL(opt_prof_accum)} 257234370Sjasone}; 258234370Sjasone 259242844Sjasonestatic const ctl_named_node_t arena_i_node[] = { 260242844Sjasone {NAME("purge"), CTL(arena_i_purge)}, 261242844Sjasone {NAME("dss"), CTL(arena_i_dss)} 262242844Sjasone}; 263242844Sjasonestatic const ctl_named_node_t super_arena_i_node[] = { 264242844Sjasone {NAME(""), CHILD(named, arena_i)} 265242844Sjasone}; 266242844Sjasone 267242844Sjasonestatic const ctl_indexed_node_t arena_node[] = { 268242844Sjasone {INDEX(arena_i)} 269242844Sjasone}; 270242844Sjasone 271235238Sjasonestatic const ctl_named_node_t arenas_bin_i_node[] = { 272234370Sjasone {NAME("size"), CTL(arenas_bin_i_size)}, 273234370Sjasone {NAME("nregs"), CTL(arenas_bin_i_nregs)}, 274234370Sjasone {NAME("run_size"), CTL(arenas_bin_i_run_size)} 275234370Sjasone}; 276235238Sjasonestatic const ctl_named_node_t super_arenas_bin_i_node[] = { 277235238Sjasone {NAME(""), CHILD(named, arenas_bin_i)} 278234370Sjasone}; 279234370Sjasone 280235238Sjasonestatic const ctl_indexed_node_t arenas_bin_node[] = { 281234370Sjasone {INDEX(arenas_bin_i)} 282234370Sjasone}; 283234370Sjasone 284235238Sjasonestatic const ctl_named_node_t arenas_lrun_i_node[] = { 285234370Sjasone {NAME("size"), CTL(arenas_lrun_i_size)} 286234370Sjasone}; 287235238Sjasonestatic const ctl_named_node_t super_arenas_lrun_i_node[] = { 288235238Sjasone {NAME(""), CHILD(named, arenas_lrun_i)} 289234370Sjasone}; 290234370Sjasone 291235238Sjasonestatic const ctl_indexed_node_t arenas_lrun_node[] = { 292234370Sjasone {INDEX(arenas_lrun_i)} 293234370Sjasone}; 294234370Sjasone 295235238Sjasonestatic const ctl_named_node_t arenas_node[] = { 296234370Sjasone {NAME("narenas"), CTL(arenas_narenas)}, 297234370Sjasone {NAME("initialized"), CTL(arenas_initialized)}, 298234370Sjasone {NAME("quantum"), CTL(arenas_quantum)}, 299234370Sjasone {NAME("page"), CTL(arenas_page)}, 300234370Sjasone {NAME("tcache_max"), CTL(arenas_tcache_max)}, 301234370Sjasone {NAME("nbins"), CTL(arenas_nbins)}, 302234370Sjasone {NAME("nhbins"), CTL(arenas_nhbins)}, 303235238Sjasone {NAME("bin"), CHILD(indexed, arenas_bin)}, 304234370Sjasone {NAME("nlruns"), CTL(arenas_nlruns)}, 305235238Sjasone {NAME("lrun"), CHILD(indexed, arenas_lrun)}, 306242844Sjasone {NAME("purge"), CTL(arenas_purge)}, 307242844Sjasone {NAME("extend"), CTL(arenas_extend)} 308234370Sjasone}; 309234370Sjasone 310235238Sjasonestatic const ctl_named_node_t prof_node[] = { 311234370Sjasone {NAME("active"), CTL(prof_active)}, 312234370Sjasone {NAME("dump"), CTL(prof_dump)}, 313234370Sjasone {NAME("interval"), CTL(prof_interval)} 314234370Sjasone}; 315234370Sjasone 316235238Sjasonestatic const ctl_named_node_t stats_chunks_node[] = { 317234370Sjasone {NAME("current"), CTL(stats_chunks_current)}, 318234370Sjasone {NAME("total"), CTL(stats_chunks_total)}, 319234370Sjasone {NAME("high"), CTL(stats_chunks_high)} 320234370Sjasone}; 321234370Sjasone 322235238Sjasonestatic const ctl_named_node_t stats_huge_node[] = { 323234370Sjasone {NAME("allocated"), CTL(stats_huge_allocated)}, 324234370Sjasone {NAME("nmalloc"), CTL(stats_huge_nmalloc)}, 325234370Sjasone {NAME("ndalloc"), CTL(stats_huge_ndalloc)} 326234370Sjasone}; 327234370Sjasone 328235238Sjasonestatic const ctl_named_node_t stats_arenas_i_small_node[] = { 329234370Sjasone {NAME("allocated"), CTL(stats_arenas_i_small_allocated)}, 330234370Sjasone {NAME("nmalloc"), CTL(stats_arenas_i_small_nmalloc)}, 331234370Sjasone {NAME("ndalloc"), CTL(stats_arenas_i_small_ndalloc)}, 332234370Sjasone {NAME("nrequests"), CTL(stats_arenas_i_small_nrequests)} 333234370Sjasone}; 334234370Sjasone 335235238Sjasonestatic const ctl_named_node_t stats_arenas_i_large_node[] = { 336234370Sjasone {NAME("allocated"), CTL(stats_arenas_i_large_allocated)}, 337234370Sjasone {NAME("nmalloc"), CTL(stats_arenas_i_large_nmalloc)}, 338234370Sjasone {NAME("ndalloc"), CTL(stats_arenas_i_large_ndalloc)}, 339234370Sjasone {NAME("nrequests"), CTL(stats_arenas_i_large_nrequests)} 340234370Sjasone}; 341234370Sjasone 342235238Sjasonestatic const ctl_named_node_t stats_arenas_i_bins_j_node[] = { 343234370Sjasone {NAME("allocated"), CTL(stats_arenas_i_bins_j_allocated)}, 344234370Sjasone {NAME("nmalloc"), CTL(stats_arenas_i_bins_j_nmalloc)}, 345234370Sjasone {NAME("ndalloc"), CTL(stats_arenas_i_bins_j_ndalloc)}, 346234370Sjasone {NAME("nrequests"), CTL(stats_arenas_i_bins_j_nrequests)}, 347234370Sjasone {NAME("nfills"), CTL(stats_arenas_i_bins_j_nfills)}, 348234370Sjasone {NAME("nflushes"), CTL(stats_arenas_i_bins_j_nflushes)}, 349234370Sjasone {NAME("nruns"), CTL(stats_arenas_i_bins_j_nruns)}, 350234370Sjasone {NAME("nreruns"), CTL(stats_arenas_i_bins_j_nreruns)}, 351234370Sjasone {NAME("curruns"), CTL(stats_arenas_i_bins_j_curruns)} 352234370Sjasone}; 353235238Sjasonestatic const ctl_named_node_t super_stats_arenas_i_bins_j_node[] = { 354235238Sjasone {NAME(""), CHILD(named, stats_arenas_i_bins_j)} 355234370Sjasone}; 356234370Sjasone 357235238Sjasonestatic const ctl_indexed_node_t stats_arenas_i_bins_node[] = { 358234370Sjasone {INDEX(stats_arenas_i_bins_j)} 359234370Sjasone}; 360234370Sjasone 361235238Sjasonestatic const ctl_named_node_t stats_arenas_i_lruns_j_node[] = { 362234370Sjasone {NAME("nmalloc"), CTL(stats_arenas_i_lruns_j_nmalloc)}, 363234370Sjasone {NAME("ndalloc"), CTL(stats_arenas_i_lruns_j_ndalloc)}, 364234370Sjasone {NAME("nrequests"), CTL(stats_arenas_i_lruns_j_nrequests)}, 365234370Sjasone {NAME("curruns"), CTL(stats_arenas_i_lruns_j_curruns)} 366234370Sjasone}; 367235238Sjasonestatic const ctl_named_node_t super_stats_arenas_i_lruns_j_node[] = { 368235238Sjasone {NAME(""), CHILD(named, stats_arenas_i_lruns_j)} 369234370Sjasone}; 370234370Sjasone 371235238Sjasonestatic const ctl_indexed_node_t stats_arenas_i_lruns_node[] = { 372234370Sjasone {INDEX(stats_arenas_i_lruns_j)} 373234370Sjasone}; 374234370Sjasone 375235238Sjasonestatic const ctl_named_node_t stats_arenas_i_node[] = { 376234370Sjasone {NAME("nthreads"), CTL(stats_arenas_i_nthreads)}, 377242844Sjasone {NAME("dss"), CTL(stats_arenas_i_dss)}, 378234370Sjasone {NAME("pactive"), CTL(stats_arenas_i_pactive)}, 379234370Sjasone {NAME("pdirty"), CTL(stats_arenas_i_pdirty)}, 380234370Sjasone {NAME("mapped"), CTL(stats_arenas_i_mapped)}, 381234370Sjasone {NAME("npurge"), CTL(stats_arenas_i_npurge)}, 382234370Sjasone {NAME("nmadvise"), CTL(stats_arenas_i_nmadvise)}, 383234370Sjasone {NAME("purged"), CTL(stats_arenas_i_purged)}, 384235238Sjasone {NAME("small"), CHILD(named, stats_arenas_i_small)}, 385235238Sjasone {NAME("large"), CHILD(named, stats_arenas_i_large)}, 386235238Sjasone {NAME("bins"), CHILD(indexed, stats_arenas_i_bins)}, 387235238Sjasone {NAME("lruns"), CHILD(indexed, stats_arenas_i_lruns)} 388234370Sjasone}; 389235238Sjasonestatic const ctl_named_node_t super_stats_arenas_i_node[] = { 390235238Sjasone {NAME(""), CHILD(named, stats_arenas_i)} 391234370Sjasone}; 392234370Sjasone 393235238Sjasonestatic const ctl_indexed_node_t stats_arenas_node[] = { 394234370Sjasone {INDEX(stats_arenas_i)} 395234370Sjasone}; 396234370Sjasone 397235238Sjasonestatic const ctl_named_node_t stats_node[] = { 398234370Sjasone {NAME("cactive"), CTL(stats_cactive)}, 399234370Sjasone {NAME("allocated"), CTL(stats_allocated)}, 400234370Sjasone {NAME("active"), CTL(stats_active)}, 401234370Sjasone {NAME("mapped"), CTL(stats_mapped)}, 402235238Sjasone {NAME("chunks"), CHILD(named, stats_chunks)}, 403235238Sjasone {NAME("huge"), CHILD(named, stats_huge)}, 404235238Sjasone {NAME("arenas"), CHILD(indexed, stats_arenas)} 405234370Sjasone}; 406234370Sjasone 407235238Sjasonestatic const ctl_named_node_t root_node[] = { 408234370Sjasone {NAME("version"), CTL(version)}, 409234370Sjasone {NAME("epoch"), CTL(epoch)}, 410235238Sjasone {NAME("thread"), CHILD(named, thread)}, 411235238Sjasone {NAME("config"), CHILD(named, config)}, 412235238Sjasone {NAME("opt"), CHILD(named, opt)}, 413242844Sjasone {NAME("arena"), CHILD(indexed, arena)}, 414235238Sjasone {NAME("arenas"), CHILD(named, arenas)}, 415235238Sjasone {NAME("prof"), CHILD(named, prof)}, 416235238Sjasone {NAME("stats"), CHILD(named, stats)} 417234370Sjasone}; 418235238Sjasonestatic const ctl_named_node_t super_root_node[] = { 419235238Sjasone {NAME(""), CHILD(named, root)} 420234370Sjasone}; 421234370Sjasone 422234370Sjasone#undef NAME 423234370Sjasone#undef CHILD 424234370Sjasone#undef CTL 425234370Sjasone#undef INDEX 426234370Sjasone 427234370Sjasone/******************************************************************************/ 428234370Sjasone 429234370Sjasonestatic bool 430234370Sjasonectl_arena_init(ctl_arena_stats_t *astats) 431234370Sjasone{ 432234370Sjasone 433234370Sjasone if (astats->lstats == NULL) { 434234370Sjasone astats->lstats = (malloc_large_stats_t *)base_alloc(nlclasses * 435234370Sjasone sizeof(malloc_large_stats_t)); 436234370Sjasone if (astats->lstats == NULL) 437234370Sjasone return (true); 438234370Sjasone } 439234370Sjasone 440234370Sjasone return (false); 441234370Sjasone} 442234370Sjasone 443234370Sjasonestatic void 444234370Sjasonectl_arena_clear(ctl_arena_stats_t *astats) 445234370Sjasone{ 446234370Sjasone 447242844Sjasone astats->dss = dss_prec_names[dss_prec_limit]; 448234370Sjasone astats->pactive = 0; 449234370Sjasone astats->pdirty = 0; 450234370Sjasone if (config_stats) { 451234370Sjasone memset(&astats->astats, 0, sizeof(arena_stats_t)); 452234370Sjasone astats->allocated_small = 0; 453234370Sjasone astats->nmalloc_small = 0; 454234370Sjasone astats->ndalloc_small = 0; 455234370Sjasone astats->nrequests_small = 0; 456234370Sjasone memset(astats->bstats, 0, NBINS * sizeof(malloc_bin_stats_t)); 457234370Sjasone memset(astats->lstats, 0, nlclasses * 458234370Sjasone sizeof(malloc_large_stats_t)); 459234370Sjasone } 460234370Sjasone} 461234370Sjasone 462234370Sjasonestatic void 463234370Sjasonectl_arena_stats_amerge(ctl_arena_stats_t *cstats, arena_t *arena) 464234370Sjasone{ 465234370Sjasone unsigned i; 466234370Sjasone 467242844Sjasone arena_stats_merge(arena, &cstats->dss, &cstats->pactive, 468242844Sjasone &cstats->pdirty, &cstats->astats, cstats->bstats, cstats->lstats); 469234370Sjasone 470234370Sjasone for (i = 0; i < NBINS; i++) { 471234370Sjasone cstats->allocated_small += cstats->bstats[i].allocated; 472234370Sjasone cstats->nmalloc_small += cstats->bstats[i].nmalloc; 473234370Sjasone cstats->ndalloc_small += cstats->bstats[i].ndalloc; 474234370Sjasone cstats->nrequests_small += cstats->bstats[i].nrequests; 475234370Sjasone } 476234370Sjasone} 477234370Sjasone 478234370Sjasonestatic void 479234370Sjasonectl_arena_stats_smerge(ctl_arena_stats_t *sstats, ctl_arena_stats_t *astats) 480234370Sjasone{ 481234370Sjasone unsigned i; 482234370Sjasone 483234370Sjasone sstats->pactive += astats->pactive; 484234370Sjasone sstats->pdirty += astats->pdirty; 485234370Sjasone 486234370Sjasone sstats->astats.mapped += astats->astats.mapped; 487234370Sjasone sstats->astats.npurge += astats->astats.npurge; 488234370Sjasone sstats->astats.nmadvise += astats->astats.nmadvise; 489234370Sjasone sstats->astats.purged += astats->astats.purged; 490234370Sjasone 491234370Sjasone sstats->allocated_small += astats->allocated_small; 492234370Sjasone sstats->nmalloc_small += astats->nmalloc_small; 493234370Sjasone sstats->ndalloc_small += astats->ndalloc_small; 494234370Sjasone sstats->nrequests_small += astats->nrequests_small; 495234370Sjasone 496234370Sjasone sstats->astats.allocated_large += astats->astats.allocated_large; 497234370Sjasone sstats->astats.nmalloc_large += astats->astats.nmalloc_large; 498234370Sjasone sstats->astats.ndalloc_large += astats->astats.ndalloc_large; 499234370Sjasone sstats->astats.nrequests_large += astats->astats.nrequests_large; 500234370Sjasone 501234370Sjasone for (i = 0; i < nlclasses; i++) { 502234370Sjasone sstats->lstats[i].nmalloc += astats->lstats[i].nmalloc; 503234370Sjasone sstats->lstats[i].ndalloc += astats->lstats[i].ndalloc; 504234370Sjasone sstats->lstats[i].nrequests += astats->lstats[i].nrequests; 505234370Sjasone sstats->lstats[i].curruns += astats->lstats[i].curruns; 506234370Sjasone } 507234370Sjasone 508234370Sjasone for (i = 0; i < NBINS; i++) { 509234370Sjasone sstats->bstats[i].allocated += astats->bstats[i].allocated; 510234370Sjasone sstats->bstats[i].nmalloc += astats->bstats[i].nmalloc; 511234370Sjasone sstats->bstats[i].ndalloc += astats->bstats[i].ndalloc; 512234370Sjasone sstats->bstats[i].nrequests += astats->bstats[i].nrequests; 513234370Sjasone if (config_tcache) { 514234370Sjasone sstats->bstats[i].nfills += astats->bstats[i].nfills; 515234370Sjasone sstats->bstats[i].nflushes += 516234370Sjasone astats->bstats[i].nflushes; 517234370Sjasone } 518234370Sjasone sstats->bstats[i].nruns += astats->bstats[i].nruns; 519234370Sjasone sstats->bstats[i].reruns += astats->bstats[i].reruns; 520234370Sjasone sstats->bstats[i].curruns += astats->bstats[i].curruns; 521234370Sjasone } 522234370Sjasone} 523234370Sjasone 524234370Sjasonestatic void 525234370Sjasonectl_arena_refresh(arena_t *arena, unsigned i) 526234370Sjasone{ 527234370Sjasone ctl_arena_stats_t *astats = &ctl_stats.arenas[i]; 528242844Sjasone ctl_arena_stats_t *sstats = &ctl_stats.arenas[ctl_stats.narenas]; 529234370Sjasone 530234370Sjasone ctl_arena_clear(astats); 531234370Sjasone 532234370Sjasone sstats->nthreads += astats->nthreads; 533234370Sjasone if (config_stats) { 534234370Sjasone ctl_arena_stats_amerge(astats, arena); 535234370Sjasone /* Merge into sum stats as well. */ 536234370Sjasone ctl_arena_stats_smerge(sstats, astats); 537234370Sjasone } else { 538234370Sjasone astats->pactive += arena->nactive; 539234370Sjasone astats->pdirty += arena->ndirty; 540234370Sjasone /* Merge into sum stats as well. */ 541234370Sjasone sstats->pactive += arena->nactive; 542234370Sjasone sstats->pdirty += arena->ndirty; 543234370Sjasone } 544234370Sjasone} 545234370Sjasone 546242844Sjasonestatic bool 547242844Sjasonectl_grow(void) 548242844Sjasone{ 549242844Sjasone ctl_arena_stats_t *astats; 550242844Sjasone arena_t **tarenas; 551242844Sjasone 552256823Sjasone /* Allocate extended arena stats and arenas arrays. */ 553256823Sjasone astats = (ctl_arena_stats_t *)imalloc((ctl_stats.narenas + 2) * 554256823Sjasone sizeof(ctl_arena_stats_t)); 555256823Sjasone if (astats == NULL) 556256823Sjasone return (true); 557256823Sjasone tarenas = (arena_t **)imalloc((ctl_stats.narenas + 1) * 558256823Sjasone sizeof(arena_t *)); 559256823Sjasone if (tarenas == NULL) { 560256823Sjasone idalloc(astats); 561256823Sjasone return (true); 562256823Sjasone } 563242844Sjasone 564256823Sjasone /* Initialize the new astats element. */ 565256823Sjasone memcpy(astats, ctl_stats.arenas, (ctl_stats.narenas + 1) * 566256823Sjasone sizeof(ctl_arena_stats_t)); 567242844Sjasone memset(&astats[ctl_stats.narenas + 1], 0, sizeof(ctl_arena_stats_t)); 568256823Sjasone if (ctl_arena_init(&astats[ctl_stats.narenas + 1])) { 569256823Sjasone idalloc(tarenas); 570256823Sjasone idalloc(astats); 571242844Sjasone return (true); 572256823Sjasone } 573242844Sjasone /* Swap merged stats to their new location. */ 574242844Sjasone { 575242844Sjasone ctl_arena_stats_t tstats; 576242844Sjasone memcpy(&tstats, &astats[ctl_stats.narenas], 577242844Sjasone sizeof(ctl_arena_stats_t)); 578242844Sjasone memcpy(&astats[ctl_stats.narenas], 579242844Sjasone &astats[ctl_stats.narenas + 1], sizeof(ctl_arena_stats_t)); 580242844Sjasone memcpy(&astats[ctl_stats.narenas + 1], &tstats, 581242844Sjasone sizeof(ctl_arena_stats_t)); 582242844Sjasone } 583256823Sjasone /* Initialize the new arenas element. */ 584256823Sjasone tarenas[ctl_stats.narenas] = NULL; 585256823Sjasone { 586256823Sjasone arena_t **arenas_old = arenas; 587256823Sjasone /* 588256823Sjasone * Swap extended arenas array into place. Although ctl_mtx 589256823Sjasone * protects this function from other threads extending the 590256823Sjasone * array, it does not protect from other threads mutating it 591256823Sjasone * (i.e. initializing arenas and setting array elements to 592256823Sjasone * point to them). Therefore, array copying must happen under 593256823Sjasone * the protection of arenas_lock. 594256823Sjasone */ 595256823Sjasone malloc_mutex_lock(&arenas_lock); 596256823Sjasone arenas = tarenas; 597256823Sjasone memcpy(arenas, arenas_old, ctl_stats.narenas * 598256823Sjasone sizeof(arena_t *)); 599256823Sjasone narenas_total++; 600256823Sjasone arenas_extend(narenas_total - 1); 601256823Sjasone malloc_mutex_unlock(&arenas_lock); 602256823Sjasone /* 603256823Sjasone * Deallocate arenas_old only if it came from imalloc() (not 604256823Sjasone * base_alloc()). 605256823Sjasone */ 606256823Sjasone if (ctl_stats.narenas != narenas_auto) 607256823Sjasone idalloc(arenas_old); 608256823Sjasone } 609242844Sjasone ctl_stats.arenas = astats; 610242844Sjasone ctl_stats.narenas++; 611242844Sjasone 612242844Sjasone return (false); 613242844Sjasone} 614242844Sjasone 615234370Sjasonestatic void 616234370Sjasonectl_refresh(void) 617234370Sjasone{ 618234370Sjasone unsigned i; 619242844Sjasone VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas); 620234370Sjasone 621234370Sjasone if (config_stats) { 622234370Sjasone malloc_mutex_lock(&chunks_mtx); 623234370Sjasone ctl_stats.chunks.current = stats_chunks.curchunks; 624234370Sjasone ctl_stats.chunks.total = stats_chunks.nchunks; 625234370Sjasone ctl_stats.chunks.high = stats_chunks.highchunks; 626234370Sjasone malloc_mutex_unlock(&chunks_mtx); 627234370Sjasone 628234370Sjasone malloc_mutex_lock(&huge_mtx); 629234370Sjasone ctl_stats.huge.allocated = huge_allocated; 630234370Sjasone ctl_stats.huge.nmalloc = huge_nmalloc; 631234370Sjasone ctl_stats.huge.ndalloc = huge_ndalloc; 632234370Sjasone malloc_mutex_unlock(&huge_mtx); 633234370Sjasone } 634234370Sjasone 635234370Sjasone /* 636234370Sjasone * Clear sum stats, since they will be merged into by 637234370Sjasone * ctl_arena_refresh(). 638234370Sjasone */ 639242844Sjasone ctl_stats.arenas[ctl_stats.narenas].nthreads = 0; 640242844Sjasone ctl_arena_clear(&ctl_stats.arenas[ctl_stats.narenas]); 641234370Sjasone 642234370Sjasone malloc_mutex_lock(&arenas_lock); 643242844Sjasone memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas); 644242844Sjasone for (i = 0; i < ctl_stats.narenas; i++) { 645234370Sjasone if (arenas[i] != NULL) 646234370Sjasone ctl_stats.arenas[i].nthreads = arenas[i]->nthreads; 647234370Sjasone else 648234370Sjasone ctl_stats.arenas[i].nthreads = 0; 649234370Sjasone } 650234370Sjasone malloc_mutex_unlock(&arenas_lock); 651242844Sjasone for (i = 0; i < ctl_stats.narenas; i++) { 652234370Sjasone bool initialized = (tarenas[i] != NULL); 653234370Sjasone 654234370Sjasone ctl_stats.arenas[i].initialized = initialized; 655234370Sjasone if (initialized) 656234370Sjasone ctl_arena_refresh(tarenas[i], i); 657234370Sjasone } 658234370Sjasone 659234370Sjasone if (config_stats) { 660242844Sjasone ctl_stats.allocated = 661242844Sjasone ctl_stats.arenas[ctl_stats.narenas].allocated_small 662242844Sjasone + ctl_stats.arenas[ctl_stats.narenas].astats.allocated_large 663234370Sjasone + ctl_stats.huge.allocated; 664242844Sjasone ctl_stats.active = 665242844Sjasone (ctl_stats.arenas[ctl_stats.narenas].pactive << LG_PAGE) 666242844Sjasone + ctl_stats.huge.allocated; 667234370Sjasone ctl_stats.mapped = (ctl_stats.chunks.current << opt_lg_chunk); 668234370Sjasone } 669234370Sjasone 670234370Sjasone ctl_epoch++; 671234370Sjasone} 672234370Sjasone 673234370Sjasonestatic bool 674234370Sjasonectl_init(void) 675234370Sjasone{ 676234370Sjasone bool ret; 677234370Sjasone 678234370Sjasone malloc_mutex_lock(&ctl_mtx); 679234370Sjasone if (ctl_initialized == false) { 680234370Sjasone /* 681234370Sjasone * Allocate space for one extra arena stats element, which 682234370Sjasone * contains summed stats across all arenas. 683234370Sjasone */ 684242844Sjasone assert(narenas_auto == narenas_total_get()); 685242844Sjasone ctl_stats.narenas = narenas_auto; 686234370Sjasone ctl_stats.arenas = (ctl_arena_stats_t *)base_alloc( 687242844Sjasone (ctl_stats.narenas + 1) * sizeof(ctl_arena_stats_t)); 688234370Sjasone if (ctl_stats.arenas == NULL) { 689234370Sjasone ret = true; 690234370Sjasone goto label_return; 691234370Sjasone } 692242844Sjasone memset(ctl_stats.arenas, 0, (ctl_stats.narenas + 1) * 693234370Sjasone sizeof(ctl_arena_stats_t)); 694234370Sjasone 695234370Sjasone /* 696234370Sjasone * Initialize all stats structures, regardless of whether they 697234370Sjasone * ever get used. Lazy initialization would allow errors to 698234370Sjasone * cause inconsistent state to be viewable by the application. 699234370Sjasone */ 700234370Sjasone if (config_stats) { 701234370Sjasone unsigned i; 702242844Sjasone for (i = 0; i <= ctl_stats.narenas; i++) { 703234370Sjasone if (ctl_arena_init(&ctl_stats.arenas[i])) { 704234370Sjasone ret = true; 705234370Sjasone goto label_return; 706234370Sjasone } 707234370Sjasone } 708234370Sjasone } 709242844Sjasone ctl_stats.arenas[ctl_stats.narenas].initialized = true; 710234370Sjasone 711234370Sjasone ctl_epoch = 0; 712234370Sjasone ctl_refresh(); 713234370Sjasone ctl_initialized = true; 714234370Sjasone } 715234370Sjasone 716234370Sjasone ret = false; 717234370Sjasonelabel_return: 718234370Sjasone malloc_mutex_unlock(&ctl_mtx); 719234370Sjasone return (ret); 720234370Sjasone} 721234370Sjasone 722234370Sjasonestatic int 723234370Sjasonectl_lookup(const char *name, ctl_node_t const **nodesp, size_t *mibp, 724234370Sjasone size_t *depthp) 725234370Sjasone{ 726234370Sjasone int ret; 727234370Sjasone const char *elm, *tdot, *dot; 728234370Sjasone size_t elen, i, j; 729235238Sjasone const ctl_named_node_t *node; 730234370Sjasone 731234370Sjasone elm = name; 732234370Sjasone /* Equivalent to strchrnul(). */ 733234370Sjasone dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot : strchr(elm, '\0'); 734234370Sjasone elen = (size_t)((uintptr_t)dot - (uintptr_t)elm); 735234370Sjasone if (elen == 0) { 736234370Sjasone ret = ENOENT; 737234370Sjasone goto label_return; 738234370Sjasone } 739234370Sjasone node = super_root_node; 740234370Sjasone for (i = 0; i < *depthp; i++) { 741235238Sjasone assert(node); 742235238Sjasone assert(node->nchildren > 0); 743235238Sjasone if (ctl_named_node(node->children) != NULL) { 744235238Sjasone const ctl_named_node_t *pnode = node; 745234370Sjasone 746234370Sjasone /* Children are named. */ 747235238Sjasone for (j = 0; j < node->nchildren; j++) { 748235238Sjasone const ctl_named_node_t *child = 749235238Sjasone ctl_named_children(node, j); 750235238Sjasone if (strlen(child->name) == elen && 751235238Sjasone strncmp(elm, child->name, elen) == 0) { 752234370Sjasone node = child; 753234370Sjasone if (nodesp != NULL) 754235238Sjasone nodesp[i] = 755235238Sjasone (const ctl_node_t *)node; 756234370Sjasone mibp[i] = j; 757234370Sjasone break; 758234370Sjasone } 759234370Sjasone } 760234370Sjasone if (node == pnode) { 761234370Sjasone ret = ENOENT; 762234370Sjasone goto label_return; 763234370Sjasone } 764234370Sjasone } else { 765234370Sjasone uintmax_t index; 766235238Sjasone const ctl_indexed_node_t *inode; 767234370Sjasone 768234370Sjasone /* Children are indexed. */ 769234370Sjasone index = malloc_strtoumax(elm, NULL, 10); 770234370Sjasone if (index == UINTMAX_MAX || index > SIZE_T_MAX) { 771234370Sjasone ret = ENOENT; 772234370Sjasone goto label_return; 773234370Sjasone } 774234370Sjasone 775235238Sjasone inode = ctl_indexed_node(node->children); 776235238Sjasone node = inode->index(mibp, *depthp, (size_t)index); 777234370Sjasone if (node == NULL) { 778234370Sjasone ret = ENOENT; 779234370Sjasone goto label_return; 780234370Sjasone } 781234370Sjasone 782234370Sjasone if (nodesp != NULL) 783235238Sjasone nodesp[i] = (const ctl_node_t *)node; 784234370Sjasone mibp[i] = (size_t)index; 785234370Sjasone } 786234370Sjasone 787234370Sjasone if (node->ctl != NULL) { 788234370Sjasone /* Terminal node. */ 789234370Sjasone if (*dot != '\0') { 790234370Sjasone /* 791234370Sjasone * The name contains more elements than are 792234370Sjasone * in this path through the tree. 793234370Sjasone */ 794234370Sjasone ret = ENOENT; 795234370Sjasone goto label_return; 796234370Sjasone } 797234370Sjasone /* Complete lookup successful. */ 798234370Sjasone *depthp = i + 1; 799234370Sjasone break; 800234370Sjasone } 801234370Sjasone 802234370Sjasone /* Update elm. */ 803234370Sjasone if (*dot == '\0') { 804234370Sjasone /* No more elements. */ 805234370Sjasone ret = ENOENT; 806234370Sjasone goto label_return; 807234370Sjasone } 808234370Sjasone elm = &dot[1]; 809234370Sjasone dot = ((tdot = strchr(elm, '.')) != NULL) ? tdot : 810234370Sjasone strchr(elm, '\0'); 811234370Sjasone elen = (size_t)((uintptr_t)dot - (uintptr_t)elm); 812234370Sjasone } 813234370Sjasone 814234370Sjasone ret = 0; 815234370Sjasonelabel_return: 816234370Sjasone return (ret); 817234370Sjasone} 818234370Sjasone 819234370Sjasoneint 820234370Sjasonectl_byname(const char *name, void *oldp, size_t *oldlenp, void *newp, 821234370Sjasone size_t newlen) 822234370Sjasone{ 823234370Sjasone int ret; 824234370Sjasone size_t depth; 825234370Sjasone ctl_node_t const *nodes[CTL_MAX_DEPTH]; 826234370Sjasone size_t mib[CTL_MAX_DEPTH]; 827235238Sjasone const ctl_named_node_t *node; 828234370Sjasone 829234370Sjasone if (ctl_initialized == false && ctl_init()) { 830234370Sjasone ret = EAGAIN; 831234370Sjasone goto label_return; 832234370Sjasone } 833234370Sjasone 834234370Sjasone depth = CTL_MAX_DEPTH; 835234370Sjasone ret = ctl_lookup(name, nodes, mib, &depth); 836234370Sjasone if (ret != 0) 837234370Sjasone goto label_return; 838234370Sjasone 839235238Sjasone node = ctl_named_node(nodes[depth-1]); 840235238Sjasone if (node != NULL && node->ctl) 841235238Sjasone ret = node->ctl(mib, depth, oldp, oldlenp, newp, newlen); 842235238Sjasone else { 843234370Sjasone /* The name refers to a partial path through the ctl tree. */ 844234370Sjasone ret = ENOENT; 845234370Sjasone } 846234370Sjasone 847234370Sjasonelabel_return: 848234370Sjasone return(ret); 849234370Sjasone} 850234370Sjasone 851234370Sjasoneint 852234370Sjasonectl_nametomib(const char *name, size_t *mibp, size_t *miblenp) 853234370Sjasone{ 854234370Sjasone int ret; 855234370Sjasone 856234370Sjasone if (ctl_initialized == false && ctl_init()) { 857234370Sjasone ret = EAGAIN; 858234370Sjasone goto label_return; 859234370Sjasone } 860234370Sjasone 861234370Sjasone ret = ctl_lookup(name, NULL, mibp, miblenp); 862234370Sjasonelabel_return: 863234370Sjasone return(ret); 864234370Sjasone} 865234370Sjasone 866234370Sjasoneint 867234370Sjasonectl_bymib(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 868234370Sjasone void *newp, size_t newlen) 869234370Sjasone{ 870234370Sjasone int ret; 871235238Sjasone const ctl_named_node_t *node; 872234370Sjasone size_t i; 873234370Sjasone 874234370Sjasone if (ctl_initialized == false && ctl_init()) { 875234370Sjasone ret = EAGAIN; 876234370Sjasone goto label_return; 877234370Sjasone } 878234370Sjasone 879234370Sjasone /* Iterate down the tree. */ 880234370Sjasone node = super_root_node; 881234370Sjasone for (i = 0; i < miblen; i++) { 882235238Sjasone assert(node); 883235238Sjasone assert(node->nchildren > 0); 884235238Sjasone if (ctl_named_node(node->children) != NULL) { 885234370Sjasone /* Children are named. */ 886235238Sjasone if (node->nchildren <= mib[i]) { 887234370Sjasone ret = ENOENT; 888234370Sjasone goto label_return; 889234370Sjasone } 890235238Sjasone node = ctl_named_children(node, mib[i]); 891234370Sjasone } else { 892235238Sjasone const ctl_indexed_node_t *inode; 893234370Sjasone 894234370Sjasone /* Indexed element. */ 895235238Sjasone inode = ctl_indexed_node(node->children); 896235238Sjasone node = inode->index(mib, miblen, mib[i]); 897234370Sjasone if (node == NULL) { 898234370Sjasone ret = ENOENT; 899234370Sjasone goto label_return; 900234370Sjasone } 901234370Sjasone } 902234370Sjasone } 903234370Sjasone 904234370Sjasone /* Call the ctl function. */ 905235238Sjasone if (node && node->ctl) 906235238Sjasone ret = node->ctl(mib, miblen, oldp, oldlenp, newp, newlen); 907235238Sjasone else { 908234370Sjasone /* Partial MIB. */ 909234370Sjasone ret = ENOENT; 910234370Sjasone } 911234370Sjasone 912234370Sjasonelabel_return: 913234370Sjasone return(ret); 914234370Sjasone} 915234370Sjasone 916234370Sjasonebool 917234370Sjasonectl_boot(void) 918234370Sjasone{ 919234370Sjasone 920234370Sjasone if (malloc_mutex_init(&ctl_mtx)) 921234370Sjasone return (true); 922234370Sjasone 923234370Sjasone ctl_initialized = false; 924234370Sjasone 925234370Sjasone return (false); 926234370Sjasone} 927234370Sjasone 928242844Sjasonevoid 929242844Sjasonectl_prefork(void) 930242844Sjasone{ 931242844Sjasone 932261071Sjasone malloc_mutex_prefork(&ctl_mtx); 933242844Sjasone} 934242844Sjasone 935242844Sjasonevoid 936242844Sjasonectl_postfork_parent(void) 937242844Sjasone{ 938242844Sjasone 939242844Sjasone malloc_mutex_postfork_parent(&ctl_mtx); 940242844Sjasone} 941242844Sjasone 942242844Sjasonevoid 943242844Sjasonectl_postfork_child(void) 944242844Sjasone{ 945242844Sjasone 946242844Sjasone malloc_mutex_postfork_child(&ctl_mtx); 947242844Sjasone} 948242844Sjasone 949234370Sjasone/******************************************************************************/ 950234370Sjasone/* *_ctl() functions. */ 951234370Sjasone 952234370Sjasone#define READONLY() do { \ 953234370Sjasone if (newp != NULL || newlen != 0) { \ 954234370Sjasone ret = EPERM; \ 955235238Sjasone goto label_return; \ 956234370Sjasone } \ 957234370Sjasone} while (0) 958234370Sjasone 959234370Sjasone#define WRITEONLY() do { \ 960234370Sjasone if (oldp != NULL || oldlenp != NULL) { \ 961234370Sjasone ret = EPERM; \ 962235238Sjasone goto label_return; \ 963234370Sjasone } \ 964234370Sjasone} while (0) 965234370Sjasone 966234370Sjasone#define READ(v, t) do { \ 967234370Sjasone if (oldp != NULL && oldlenp != NULL) { \ 968234370Sjasone if (*oldlenp != sizeof(t)) { \ 969234370Sjasone size_t copylen = (sizeof(t) <= *oldlenp) \ 970234370Sjasone ? sizeof(t) : *oldlenp; \ 971245868Sjasone memcpy(oldp, (void *)&(v), copylen); \ 972234370Sjasone ret = EINVAL; \ 973235238Sjasone goto label_return; \ 974234370Sjasone } else \ 975245868Sjasone *(t *)oldp = (v); \ 976234370Sjasone } \ 977234370Sjasone} while (0) 978234370Sjasone 979234370Sjasone#define WRITE(v, t) do { \ 980234370Sjasone if (newp != NULL) { \ 981234370Sjasone if (newlen != sizeof(t)) { \ 982234370Sjasone ret = EINVAL; \ 983235238Sjasone goto label_return; \ 984234370Sjasone } \ 985245868Sjasone (v) = *(t *)newp; \ 986234370Sjasone } \ 987234370Sjasone} while (0) 988234370Sjasone 989234370Sjasone/* 990234370Sjasone * There's a lot of code duplication in the following macros due to limitations 991234370Sjasone * in how nested cpp macros are expanded. 992234370Sjasone */ 993234370Sjasone#define CTL_RO_CLGEN(c, l, n, v, t) \ 994234370Sjasonestatic int \ 995234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 996234370Sjasone void *newp, size_t newlen) \ 997234370Sjasone{ \ 998234370Sjasone int ret; \ 999234370Sjasone t oldval; \ 1000234370Sjasone \ 1001234370Sjasone if ((c) == false) \ 1002234370Sjasone return (ENOENT); \ 1003234370Sjasone if (l) \ 1004234370Sjasone malloc_mutex_lock(&ctl_mtx); \ 1005234370Sjasone READONLY(); \ 1006245868Sjasone oldval = (v); \ 1007234370Sjasone READ(oldval, t); \ 1008234370Sjasone \ 1009234370Sjasone ret = 0; \ 1010235238Sjasonelabel_return: \ 1011234370Sjasone if (l) \ 1012234370Sjasone malloc_mutex_unlock(&ctl_mtx); \ 1013234370Sjasone return (ret); \ 1014234370Sjasone} 1015234370Sjasone 1016234370Sjasone#define CTL_RO_CGEN(c, n, v, t) \ 1017234370Sjasonestatic int \ 1018234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1019234370Sjasone void *newp, size_t newlen) \ 1020234370Sjasone{ \ 1021234370Sjasone int ret; \ 1022234370Sjasone t oldval; \ 1023234370Sjasone \ 1024234370Sjasone if ((c) == false) \ 1025234370Sjasone return (ENOENT); \ 1026234370Sjasone malloc_mutex_lock(&ctl_mtx); \ 1027234370Sjasone READONLY(); \ 1028245868Sjasone oldval = (v); \ 1029234370Sjasone READ(oldval, t); \ 1030234370Sjasone \ 1031234370Sjasone ret = 0; \ 1032235238Sjasonelabel_return: \ 1033234370Sjasone malloc_mutex_unlock(&ctl_mtx); \ 1034234370Sjasone return (ret); \ 1035234370Sjasone} 1036234370Sjasone 1037234370Sjasone#define CTL_RO_GEN(n, v, t) \ 1038234370Sjasonestatic int \ 1039234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1040234370Sjasone void *newp, size_t newlen) \ 1041234370Sjasone{ \ 1042234370Sjasone int ret; \ 1043234370Sjasone t oldval; \ 1044234370Sjasone \ 1045234370Sjasone malloc_mutex_lock(&ctl_mtx); \ 1046234370Sjasone READONLY(); \ 1047245868Sjasone oldval = (v); \ 1048234370Sjasone READ(oldval, t); \ 1049234370Sjasone \ 1050234370Sjasone ret = 0; \ 1051235238Sjasonelabel_return: \ 1052234370Sjasone malloc_mutex_unlock(&ctl_mtx); \ 1053234370Sjasone return (ret); \ 1054234370Sjasone} 1055234370Sjasone 1056234370Sjasone/* 1057234370Sjasone * ctl_mtx is not acquired, under the assumption that no pertinent data will 1058234370Sjasone * mutate during the call. 1059234370Sjasone */ 1060234370Sjasone#define CTL_RO_NL_CGEN(c, n, v, t) \ 1061234370Sjasonestatic int \ 1062234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1063234370Sjasone void *newp, size_t newlen) \ 1064234370Sjasone{ \ 1065234370Sjasone int ret; \ 1066234370Sjasone t oldval; \ 1067234370Sjasone \ 1068234370Sjasone if ((c) == false) \ 1069234370Sjasone return (ENOENT); \ 1070234370Sjasone READONLY(); \ 1071245868Sjasone oldval = (v); \ 1072234370Sjasone READ(oldval, t); \ 1073234370Sjasone \ 1074234370Sjasone ret = 0; \ 1075235238Sjasonelabel_return: \ 1076234370Sjasone return (ret); \ 1077234370Sjasone} 1078234370Sjasone 1079234370Sjasone#define CTL_RO_NL_GEN(n, v, t) \ 1080234370Sjasonestatic int \ 1081234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1082234370Sjasone void *newp, size_t newlen) \ 1083234370Sjasone{ \ 1084234370Sjasone int ret; \ 1085234370Sjasone t oldval; \ 1086234370Sjasone \ 1087234370Sjasone READONLY(); \ 1088245868Sjasone oldval = (v); \ 1089234370Sjasone READ(oldval, t); \ 1090234370Sjasone \ 1091234370Sjasone ret = 0; \ 1092235238Sjasonelabel_return: \ 1093234370Sjasone return (ret); \ 1094234370Sjasone} 1095234370Sjasone 1096234370Sjasone#define CTL_RO_BOOL_CONFIG_GEN(n) \ 1097234370Sjasonestatic int \ 1098234370Sjasonen##_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, \ 1099234370Sjasone void *newp, size_t newlen) \ 1100234370Sjasone{ \ 1101234370Sjasone int ret; \ 1102234370Sjasone bool oldval; \ 1103234370Sjasone \ 1104234370Sjasone READONLY(); \ 1105234370Sjasone oldval = n; \ 1106234370Sjasone READ(oldval, bool); \ 1107234370Sjasone \ 1108234370Sjasone ret = 0; \ 1109235238Sjasonelabel_return: \ 1110234370Sjasone return (ret); \ 1111234370Sjasone} 1112234370Sjasone 1113261071Sjasone/******************************************************************************/ 1114261071Sjasone 1115234370SjasoneCTL_RO_NL_GEN(version, JEMALLOC_VERSION, const char *) 1116234370Sjasone 1117234370Sjasonestatic int 1118234370Sjasoneepoch_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1119234370Sjasone void *newp, size_t newlen) 1120234370Sjasone{ 1121234370Sjasone int ret; 1122256823Sjasone UNUSED uint64_t newval; 1123234370Sjasone 1124234370Sjasone malloc_mutex_lock(&ctl_mtx); 1125234370Sjasone WRITE(newval, uint64_t); 1126235238Sjasone if (newp != NULL) 1127234370Sjasone ctl_refresh(); 1128234370Sjasone READ(ctl_epoch, uint64_t); 1129234370Sjasone 1130234370Sjasone ret = 0; 1131234370Sjasonelabel_return: 1132234370Sjasone malloc_mutex_unlock(&ctl_mtx); 1133234370Sjasone return (ret); 1134234370Sjasone} 1135234370Sjasone 1136261071Sjasone/******************************************************************************/ 1137234370Sjasone 1138261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_debug) 1139261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_dss) 1140261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_fill) 1141261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_lazy_lock) 1142261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_mremap) 1143261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_munmap) 1144261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_prof) 1145261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_prof_libgcc) 1146261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_prof_libunwind) 1147261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_stats) 1148261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_tcache) 1149261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_tls) 1150261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_utrace) 1151261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_valgrind) 1152261071SjasoneCTL_RO_BOOL_CONFIG_GEN(config_xmalloc) 1153234370Sjasone 1154261071Sjasone/******************************************************************************/ 1155234370Sjasone 1156261071SjasoneCTL_RO_NL_GEN(opt_abort, opt_abort, bool) 1157261071SjasoneCTL_RO_NL_GEN(opt_dss, opt_dss, const char *) 1158261071SjasoneCTL_RO_NL_GEN(opt_lg_chunk, opt_lg_chunk, size_t) 1159261071SjasoneCTL_RO_NL_GEN(opt_narenas, opt_narenas, size_t) 1160261071SjasoneCTL_RO_NL_GEN(opt_lg_dirty_mult, opt_lg_dirty_mult, ssize_t) 1161261071SjasoneCTL_RO_NL_GEN(opt_stats_print, opt_stats_print, bool) 1162261071SjasoneCTL_RO_NL_CGEN(config_fill, opt_junk, opt_junk, bool) 1163261071SjasoneCTL_RO_NL_CGEN(config_fill, opt_quarantine, opt_quarantine, size_t) 1164261071SjasoneCTL_RO_NL_CGEN(config_fill, opt_redzone, opt_redzone, bool) 1165261071SjasoneCTL_RO_NL_CGEN(config_fill, opt_zero, opt_zero, bool) 1166261071SjasoneCTL_RO_NL_CGEN(config_utrace, opt_utrace, opt_utrace, bool) 1167261071SjasoneCTL_RO_NL_CGEN(config_valgrind, opt_valgrind, opt_valgrind, bool) 1168261071SjasoneCTL_RO_NL_CGEN(config_xmalloc, opt_xmalloc, opt_xmalloc, bool) 1169261071SjasoneCTL_RO_NL_CGEN(config_tcache, opt_tcache, opt_tcache, bool) 1170261071SjasoneCTL_RO_NL_CGEN(config_tcache, opt_lg_tcache_max, opt_lg_tcache_max, ssize_t) 1171261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof, opt_prof, bool) 1172261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_prefix, opt_prof_prefix, const char *) 1173261071SjasoneCTL_RO_CGEN(config_prof, opt_prof_active, opt_prof_active, bool) /* Mutable. */ 1174261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_lg_prof_sample, opt_lg_prof_sample, size_t) 1175261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_accum, opt_prof_accum, bool) 1176261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_lg_prof_interval, opt_lg_prof_interval, ssize_t) 1177261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_gdump, opt_prof_gdump, bool) 1178261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_final, opt_prof_final, bool) 1179261071SjasoneCTL_RO_NL_CGEN(config_prof, opt_prof_leak, opt_prof_leak, bool) 1180234370Sjasone 1181261071Sjasone/******************************************************************************/ 1182234370Sjasone 1183234370Sjasonestatic int 1184234370Sjasonethread_arena_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1185234370Sjasone void *newp, size_t newlen) 1186234370Sjasone{ 1187234370Sjasone int ret; 1188234370Sjasone unsigned newind, oldind; 1189234370Sjasone 1190242844Sjasone malloc_mutex_lock(&ctl_mtx); 1191234370Sjasone newind = oldind = choose_arena(NULL)->ind; 1192234370Sjasone WRITE(newind, unsigned); 1193234370Sjasone READ(oldind, unsigned); 1194234370Sjasone if (newind != oldind) { 1195234370Sjasone arena_t *arena; 1196234370Sjasone 1197242844Sjasone if (newind >= ctl_stats.narenas) { 1198234370Sjasone /* New arena index is out of range. */ 1199234370Sjasone ret = EFAULT; 1200234370Sjasone goto label_return; 1201234370Sjasone } 1202234370Sjasone 1203234370Sjasone /* Initialize arena if necessary. */ 1204234370Sjasone malloc_mutex_lock(&arenas_lock); 1205234370Sjasone if ((arena = arenas[newind]) == NULL && (arena = 1206234370Sjasone arenas_extend(newind)) == NULL) { 1207234370Sjasone malloc_mutex_unlock(&arenas_lock); 1208234370Sjasone ret = EAGAIN; 1209234370Sjasone goto label_return; 1210234370Sjasone } 1211234370Sjasone assert(arena == arenas[newind]); 1212234370Sjasone arenas[oldind]->nthreads--; 1213234370Sjasone arenas[newind]->nthreads++; 1214234370Sjasone malloc_mutex_unlock(&arenas_lock); 1215234370Sjasone 1216234370Sjasone /* Set new arena association. */ 1217234370Sjasone if (config_tcache) { 1218234370Sjasone tcache_t *tcache; 1219234370Sjasone if ((uintptr_t)(tcache = *tcache_tsd_get()) > 1220234370Sjasone (uintptr_t)TCACHE_STATE_MAX) { 1221234370Sjasone tcache_arena_dissociate(tcache); 1222234370Sjasone tcache_arena_associate(tcache, arena); 1223234370Sjasone } 1224234370Sjasone } 1225234370Sjasone arenas_tsd_set(&arena); 1226234370Sjasone } 1227234370Sjasone 1228234370Sjasone ret = 0; 1229234370Sjasonelabel_return: 1230242844Sjasone malloc_mutex_unlock(&ctl_mtx); 1231234370Sjasone return (ret); 1232234370Sjasone} 1233234370Sjasone 1234234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_allocated, 1235234370Sjasone thread_allocated_tsd_get()->allocated, uint64_t) 1236234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_allocatedp, 1237234370Sjasone &thread_allocated_tsd_get()->allocated, uint64_t *) 1238234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_deallocated, 1239234370Sjasone thread_allocated_tsd_get()->deallocated, uint64_t) 1240234370SjasoneCTL_RO_NL_CGEN(config_stats, thread_deallocatedp, 1241234370Sjasone &thread_allocated_tsd_get()->deallocated, uint64_t *) 1242234370Sjasone 1243261071Sjasonestatic int 1244261071Sjasonethread_tcache_enabled_ctl(const size_t *mib, size_t miblen, void *oldp, 1245261071Sjasone size_t *oldlenp, void *newp, size_t newlen) 1246261071Sjasone{ 1247261071Sjasone int ret; 1248261071Sjasone bool oldval; 1249234370Sjasone 1250261071Sjasone if (config_tcache == false) 1251261071Sjasone return (ENOENT); 1252234370Sjasone 1253261071Sjasone oldval = tcache_enabled_get(); 1254261071Sjasone if (newp != NULL) { 1255261071Sjasone if (newlen != sizeof(bool)) { 1256261071Sjasone ret = EINVAL; 1257261071Sjasone goto label_return; 1258261071Sjasone } 1259261071Sjasone tcache_enabled_set(*(bool *)newp); 1260261071Sjasone } 1261261071Sjasone READ(oldval, bool); 1262234370Sjasone 1263261071Sjasone ret = 0; 1264261071Sjasonelabel_return: 1265261071Sjasone return (ret); 1266261071Sjasone} 1267234370Sjasone 1268261071Sjasonestatic int 1269261071Sjasonethread_tcache_flush_ctl(const size_t *mib, size_t miblen, void *oldp, 1270261071Sjasone size_t *oldlenp, void *newp, size_t newlen) 1271261071Sjasone{ 1272261071Sjasone int ret; 1273261071Sjasone 1274261071Sjasone if (config_tcache == false) 1275261071Sjasone return (ENOENT); 1276261071Sjasone 1277261071Sjasone READONLY(); 1278261071Sjasone WRITEONLY(); 1279261071Sjasone 1280261071Sjasone tcache_flush(); 1281261071Sjasone 1282261071Sjasone ret = 0; 1283261071Sjasonelabel_return: 1284261071Sjasone return (ret); 1285261071Sjasone} 1286261071Sjasone 1287234370Sjasone/******************************************************************************/ 1288234370Sjasone 1289242844Sjasone/* ctl_mutex must be held during execution of this function. */ 1290242844Sjasonestatic void 1291242844Sjasonearena_purge(unsigned arena_ind) 1292242844Sjasone{ 1293242844Sjasone VARIABLE_ARRAY(arena_t *, tarenas, ctl_stats.narenas); 1294242844Sjasone 1295242844Sjasone malloc_mutex_lock(&arenas_lock); 1296242844Sjasone memcpy(tarenas, arenas, sizeof(arena_t *) * ctl_stats.narenas); 1297242844Sjasone malloc_mutex_unlock(&arenas_lock); 1298242844Sjasone 1299242844Sjasone if (arena_ind == ctl_stats.narenas) { 1300242844Sjasone unsigned i; 1301242844Sjasone for (i = 0; i < ctl_stats.narenas; i++) { 1302242844Sjasone if (tarenas[i] != NULL) 1303242844Sjasone arena_purge_all(tarenas[i]); 1304242844Sjasone } 1305242844Sjasone } else { 1306242844Sjasone assert(arena_ind < ctl_stats.narenas); 1307242844Sjasone if (tarenas[arena_ind] != NULL) 1308242844Sjasone arena_purge_all(tarenas[arena_ind]); 1309242844Sjasone } 1310242844Sjasone} 1311242844Sjasone 1312242844Sjasonestatic int 1313242844Sjasonearena_i_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1314242844Sjasone void *newp, size_t newlen) 1315242844Sjasone{ 1316242844Sjasone int ret; 1317242844Sjasone 1318242844Sjasone READONLY(); 1319242844Sjasone WRITEONLY(); 1320242844Sjasone malloc_mutex_lock(&ctl_mtx); 1321242844Sjasone arena_purge(mib[1]); 1322242844Sjasone malloc_mutex_unlock(&ctl_mtx); 1323242844Sjasone 1324242844Sjasone ret = 0; 1325242844Sjasonelabel_return: 1326242844Sjasone return (ret); 1327242844Sjasone} 1328242844Sjasone 1329242844Sjasonestatic int 1330242844Sjasonearena_i_dss_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1331242844Sjasone void *newp, size_t newlen) 1332242844Sjasone{ 1333242844Sjasone int ret, i; 1334242844Sjasone bool match, err; 1335242844Sjasone const char *dss; 1336242844Sjasone unsigned arena_ind = mib[1]; 1337242844Sjasone dss_prec_t dss_prec_old = dss_prec_limit; 1338242844Sjasone dss_prec_t dss_prec = dss_prec_limit; 1339242844Sjasone 1340242844Sjasone malloc_mutex_lock(&ctl_mtx); 1341242844Sjasone WRITE(dss, const char *); 1342242844Sjasone match = false; 1343242844Sjasone for (i = 0; i < dss_prec_limit; i++) { 1344242844Sjasone if (strcmp(dss_prec_names[i], dss) == 0) { 1345242844Sjasone dss_prec = i; 1346242844Sjasone match = true; 1347242844Sjasone break; 1348242844Sjasone } 1349242844Sjasone } 1350242844Sjasone if (match == false) { 1351242844Sjasone ret = EINVAL; 1352242844Sjasone goto label_return; 1353242844Sjasone } 1354242844Sjasone 1355242844Sjasone if (arena_ind < ctl_stats.narenas) { 1356242844Sjasone arena_t *arena = arenas[arena_ind]; 1357242844Sjasone if (arena != NULL) { 1358242844Sjasone dss_prec_old = arena_dss_prec_get(arena); 1359242844Sjasone arena_dss_prec_set(arena, dss_prec); 1360242844Sjasone err = false; 1361242844Sjasone } else 1362242844Sjasone err = true; 1363242844Sjasone } else { 1364242844Sjasone dss_prec_old = chunk_dss_prec_get(); 1365242844Sjasone err = chunk_dss_prec_set(dss_prec); 1366242844Sjasone } 1367242844Sjasone dss = dss_prec_names[dss_prec_old]; 1368242844Sjasone READ(dss, const char *); 1369242844Sjasone if (err) { 1370242844Sjasone ret = EFAULT; 1371242844Sjasone goto label_return; 1372242844Sjasone } 1373242844Sjasone 1374242844Sjasone ret = 0; 1375242844Sjasonelabel_return: 1376242844Sjasone malloc_mutex_unlock(&ctl_mtx); 1377242844Sjasone return (ret); 1378242844Sjasone} 1379242844Sjasone 1380242844Sjasonestatic const ctl_named_node_t * 1381242844Sjasonearena_i_index(const size_t *mib, size_t miblen, size_t i) 1382242844Sjasone{ 1383242844Sjasone const ctl_named_node_t * ret; 1384242844Sjasone 1385242844Sjasone malloc_mutex_lock(&ctl_mtx); 1386242844Sjasone if (i > ctl_stats.narenas) { 1387242844Sjasone ret = NULL; 1388242844Sjasone goto label_return; 1389242844Sjasone } 1390242844Sjasone 1391242844Sjasone ret = super_arena_i_node; 1392242844Sjasonelabel_return: 1393242844Sjasone malloc_mutex_unlock(&ctl_mtx); 1394242844Sjasone return (ret); 1395242844Sjasone} 1396242844Sjasone 1397242844Sjasone/******************************************************************************/ 1398242844Sjasone 1399242844Sjasonestatic int 1400242844Sjasonearenas_narenas_ctl(const size_t *mib, size_t miblen, void *oldp, 1401242844Sjasone size_t *oldlenp, void *newp, size_t newlen) 1402242844Sjasone{ 1403242844Sjasone int ret; 1404242844Sjasone unsigned narenas; 1405234370Sjasone 1406242844Sjasone malloc_mutex_lock(&ctl_mtx); 1407242844Sjasone READONLY(); 1408242844Sjasone if (*oldlenp != sizeof(unsigned)) { 1409242844Sjasone ret = EINVAL; 1410242844Sjasone goto label_return; 1411242844Sjasone } 1412242844Sjasone narenas = ctl_stats.narenas; 1413242844Sjasone READ(narenas, unsigned); 1414242844Sjasone 1415242844Sjasone ret = 0; 1416242844Sjasonelabel_return: 1417242844Sjasone malloc_mutex_unlock(&ctl_mtx); 1418242844Sjasone return (ret); 1419242844Sjasone} 1420242844Sjasone 1421234370Sjasonestatic int 1422234370Sjasonearenas_initialized_ctl(const size_t *mib, size_t miblen, void *oldp, 1423234370Sjasone size_t *oldlenp, void *newp, size_t newlen) 1424234370Sjasone{ 1425234370Sjasone int ret; 1426234370Sjasone unsigned nread, i; 1427234370Sjasone 1428234370Sjasone malloc_mutex_lock(&ctl_mtx); 1429234370Sjasone READONLY(); 1430242844Sjasone if (*oldlenp != ctl_stats.narenas * sizeof(bool)) { 1431234370Sjasone ret = EINVAL; 1432242844Sjasone nread = (*oldlenp < ctl_stats.narenas * sizeof(bool)) 1433242844Sjasone ? (*oldlenp / sizeof(bool)) : ctl_stats.narenas; 1434234370Sjasone } else { 1435234370Sjasone ret = 0; 1436242844Sjasone nread = ctl_stats.narenas; 1437234370Sjasone } 1438234370Sjasone 1439234370Sjasone for (i = 0; i < nread; i++) 1440234370Sjasone ((bool *)oldp)[i] = ctl_stats.arenas[i].initialized; 1441234370Sjasone 1442234370Sjasonelabel_return: 1443234370Sjasone malloc_mutex_unlock(&ctl_mtx); 1444234370Sjasone return (ret); 1445234370Sjasone} 1446234370Sjasone 1447234370SjasoneCTL_RO_NL_GEN(arenas_quantum, QUANTUM, size_t) 1448234370SjasoneCTL_RO_NL_GEN(arenas_page, PAGE, size_t) 1449234370SjasoneCTL_RO_NL_CGEN(config_tcache, arenas_tcache_max, tcache_maxclass, size_t) 1450234370SjasoneCTL_RO_NL_GEN(arenas_nbins, NBINS, unsigned) 1451234370SjasoneCTL_RO_NL_CGEN(config_tcache, arenas_nhbins, nhbins, unsigned) 1452261071SjasoneCTL_RO_NL_GEN(arenas_bin_i_size, arena_bin_info[mib[2]].reg_size, size_t) 1453261071SjasoneCTL_RO_NL_GEN(arenas_bin_i_nregs, arena_bin_info[mib[2]].nregs, uint32_t) 1454261071SjasoneCTL_RO_NL_GEN(arenas_bin_i_run_size, arena_bin_info[mib[2]].run_size, size_t) 1455261071Sjasonestatic const ctl_named_node_t * 1456261071Sjasonearenas_bin_i_index(const size_t *mib, size_t miblen, size_t i) 1457261071Sjasone{ 1458261071Sjasone 1459261071Sjasone if (i > NBINS) 1460261071Sjasone return (NULL); 1461261071Sjasone return (super_arenas_bin_i_node); 1462261071Sjasone} 1463261071Sjasone 1464234370SjasoneCTL_RO_NL_GEN(arenas_nlruns, nlclasses, size_t) 1465261071SjasoneCTL_RO_NL_GEN(arenas_lrun_i_size, ((mib[2]+1) << LG_PAGE), size_t) 1466261071Sjasonestatic const ctl_named_node_t * 1467261071Sjasonearenas_lrun_i_index(const size_t *mib, size_t miblen, size_t i) 1468261071Sjasone{ 1469234370Sjasone 1470261071Sjasone if (i > nlclasses) 1471261071Sjasone return (NULL); 1472261071Sjasone return (super_arenas_lrun_i_node); 1473261071Sjasone} 1474261071Sjasone 1475234370Sjasonestatic int 1476234370Sjasonearenas_purge_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1477234370Sjasone void *newp, size_t newlen) 1478234370Sjasone{ 1479234370Sjasone int ret; 1480242844Sjasone unsigned arena_ind; 1481234370Sjasone 1482242844Sjasone malloc_mutex_lock(&ctl_mtx); 1483234370Sjasone WRITEONLY(); 1484242844Sjasone arena_ind = UINT_MAX; 1485242844Sjasone WRITE(arena_ind, unsigned); 1486242844Sjasone if (newp != NULL && arena_ind >= ctl_stats.narenas) 1487234370Sjasone ret = EFAULT; 1488242844Sjasone else { 1489242844Sjasone if (arena_ind == UINT_MAX) 1490242844Sjasone arena_ind = ctl_stats.narenas; 1491242844Sjasone arena_purge(arena_ind); 1492242844Sjasone ret = 0; 1493242844Sjasone } 1494234370Sjasone 1495242844Sjasonelabel_return: 1496242844Sjasone malloc_mutex_unlock(&ctl_mtx); 1497242844Sjasone return (ret); 1498242844Sjasone} 1499234370Sjasone 1500242844Sjasonestatic int 1501242844Sjasonearenas_extend_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1502242844Sjasone void *newp, size_t newlen) 1503242844Sjasone{ 1504242844Sjasone int ret; 1505245868Sjasone unsigned narenas; 1506242844Sjasone 1507242844Sjasone malloc_mutex_lock(&ctl_mtx); 1508242844Sjasone READONLY(); 1509242844Sjasone if (ctl_grow()) { 1510242844Sjasone ret = EAGAIN; 1511242844Sjasone goto label_return; 1512234370Sjasone } 1513245868Sjasone narenas = ctl_stats.narenas - 1; 1514245868Sjasone READ(narenas, unsigned); 1515234370Sjasone 1516234370Sjasone ret = 0; 1517234370Sjasonelabel_return: 1518242844Sjasone malloc_mutex_unlock(&ctl_mtx); 1519234370Sjasone return (ret); 1520234370Sjasone} 1521234370Sjasone 1522234370Sjasone/******************************************************************************/ 1523234370Sjasone 1524234370Sjasonestatic int 1525234370Sjasoneprof_active_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1526234370Sjasone void *newp, size_t newlen) 1527234370Sjasone{ 1528234370Sjasone int ret; 1529234370Sjasone bool oldval; 1530234370Sjasone 1531234370Sjasone if (config_prof == false) 1532234370Sjasone return (ENOENT); 1533234370Sjasone 1534234370Sjasone malloc_mutex_lock(&ctl_mtx); /* Protect opt_prof_active. */ 1535234370Sjasone oldval = opt_prof_active; 1536234370Sjasone if (newp != NULL) { 1537234370Sjasone /* 1538234370Sjasone * The memory barriers will tend to make opt_prof_active 1539234370Sjasone * propagate faster on systems with weak memory ordering. 1540234370Sjasone */ 1541234370Sjasone mb_write(); 1542234370Sjasone WRITE(opt_prof_active, bool); 1543234370Sjasone mb_write(); 1544234370Sjasone } 1545234370Sjasone READ(oldval, bool); 1546234370Sjasone 1547234370Sjasone ret = 0; 1548234370Sjasonelabel_return: 1549234370Sjasone malloc_mutex_unlock(&ctl_mtx); 1550234370Sjasone return (ret); 1551234370Sjasone} 1552234370Sjasone 1553234370Sjasonestatic int 1554234370Sjasoneprof_dump_ctl(const size_t *mib, size_t miblen, void *oldp, size_t *oldlenp, 1555234370Sjasone void *newp, size_t newlen) 1556234370Sjasone{ 1557234370Sjasone int ret; 1558234370Sjasone const char *filename = NULL; 1559234370Sjasone 1560234370Sjasone if (config_prof == false) 1561234370Sjasone return (ENOENT); 1562234370Sjasone 1563234370Sjasone WRITEONLY(); 1564234370Sjasone WRITE(filename, const char *); 1565234370Sjasone 1566234370Sjasone if (prof_mdump(filename)) { 1567234370Sjasone ret = EFAULT; 1568234370Sjasone goto label_return; 1569234370Sjasone } 1570234370Sjasone 1571234370Sjasone ret = 0; 1572234370Sjasonelabel_return: 1573234370Sjasone return (ret); 1574234370Sjasone} 1575234370Sjasone 1576234370SjasoneCTL_RO_NL_CGEN(config_prof, prof_interval, prof_interval, uint64_t) 1577234370Sjasone 1578234370Sjasone/******************************************************************************/ 1579234370Sjasone 1580261071SjasoneCTL_RO_CGEN(config_stats, stats_cactive, &stats_cactive, size_t *) 1581261071SjasoneCTL_RO_CGEN(config_stats, stats_allocated, ctl_stats.allocated, size_t) 1582261071SjasoneCTL_RO_CGEN(config_stats, stats_active, ctl_stats.active, size_t) 1583261071SjasoneCTL_RO_CGEN(config_stats, stats_mapped, ctl_stats.mapped, size_t) 1584261071Sjasone 1585234370SjasoneCTL_RO_CGEN(config_stats, stats_chunks_current, ctl_stats.chunks.current, 1586234370Sjasone size_t) 1587234370SjasoneCTL_RO_CGEN(config_stats, stats_chunks_total, ctl_stats.chunks.total, uint64_t) 1588234370SjasoneCTL_RO_CGEN(config_stats, stats_chunks_high, ctl_stats.chunks.high, size_t) 1589234370SjasoneCTL_RO_CGEN(config_stats, stats_huge_allocated, huge_allocated, size_t) 1590234370SjasoneCTL_RO_CGEN(config_stats, stats_huge_nmalloc, huge_nmalloc, uint64_t) 1591234370SjasoneCTL_RO_CGEN(config_stats, stats_huge_ndalloc, huge_ndalloc, uint64_t) 1592261071Sjasone 1593261071SjasoneCTL_RO_GEN(stats_arenas_i_dss, ctl_stats.arenas[mib[2]].dss, const char *) 1594261071SjasoneCTL_RO_GEN(stats_arenas_i_nthreads, ctl_stats.arenas[mib[2]].nthreads, unsigned) 1595261071SjasoneCTL_RO_GEN(stats_arenas_i_pactive, ctl_stats.arenas[mib[2]].pactive, size_t) 1596261071SjasoneCTL_RO_GEN(stats_arenas_i_pdirty, ctl_stats.arenas[mib[2]].pdirty, size_t) 1597261071SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_mapped, 1598261071Sjasone ctl_stats.arenas[mib[2]].astats.mapped, size_t) 1599261071SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_npurge, 1600261071Sjasone ctl_stats.arenas[mib[2]].astats.npurge, uint64_t) 1601261071SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_nmadvise, 1602261071Sjasone ctl_stats.arenas[mib[2]].astats.nmadvise, uint64_t) 1603261071SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_purged, 1604261071Sjasone ctl_stats.arenas[mib[2]].astats.purged, uint64_t) 1605261071Sjasone 1606234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_allocated, 1607234370Sjasone ctl_stats.arenas[mib[2]].allocated_small, size_t) 1608234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_nmalloc, 1609234370Sjasone ctl_stats.arenas[mib[2]].nmalloc_small, uint64_t) 1610234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_ndalloc, 1611234370Sjasone ctl_stats.arenas[mib[2]].ndalloc_small, uint64_t) 1612234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_small_nrequests, 1613234370Sjasone ctl_stats.arenas[mib[2]].nrequests_small, uint64_t) 1614234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_allocated, 1615234370Sjasone ctl_stats.arenas[mib[2]].astats.allocated_large, size_t) 1616234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_nmalloc, 1617234370Sjasone ctl_stats.arenas[mib[2]].astats.nmalloc_large, uint64_t) 1618234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_ndalloc, 1619234370Sjasone ctl_stats.arenas[mib[2]].astats.ndalloc_large, uint64_t) 1620234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_large_nrequests, 1621234370Sjasone ctl_stats.arenas[mib[2]].astats.nrequests_large, uint64_t) 1622234370Sjasone 1623234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_allocated, 1624234370Sjasone ctl_stats.arenas[mib[2]].bstats[mib[4]].allocated, size_t) 1625234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nmalloc, 1626234370Sjasone ctl_stats.arenas[mib[2]].bstats[mib[4]].nmalloc, uint64_t) 1627234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_ndalloc, 1628234370Sjasone ctl_stats.arenas[mib[2]].bstats[mib[4]].ndalloc, uint64_t) 1629234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nrequests, 1630234370Sjasone ctl_stats.arenas[mib[2]].bstats[mib[4]].nrequests, uint64_t) 1631234370SjasoneCTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nfills, 1632234370Sjasone ctl_stats.arenas[mib[2]].bstats[mib[4]].nfills, uint64_t) 1633234370SjasoneCTL_RO_CGEN(config_stats && config_tcache, stats_arenas_i_bins_j_nflushes, 1634234370Sjasone ctl_stats.arenas[mib[2]].bstats[mib[4]].nflushes, uint64_t) 1635234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nruns, 1636234370Sjasone ctl_stats.arenas[mib[2]].bstats[mib[4]].nruns, uint64_t) 1637234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_nreruns, 1638234370Sjasone ctl_stats.arenas[mib[2]].bstats[mib[4]].reruns, uint64_t) 1639234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_bins_j_curruns, 1640234370Sjasone ctl_stats.arenas[mib[2]].bstats[mib[4]].curruns, size_t) 1641234370Sjasone 1642242844Sjasonestatic const ctl_named_node_t * 1643234370Sjasonestats_arenas_i_bins_j_index(const size_t *mib, size_t miblen, size_t j) 1644234370Sjasone{ 1645234370Sjasone 1646234370Sjasone if (j > NBINS) 1647234370Sjasone return (NULL); 1648234370Sjasone return (super_stats_arenas_i_bins_j_node); 1649234370Sjasone} 1650234370Sjasone 1651234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nmalloc, 1652234370Sjasone ctl_stats.arenas[mib[2]].lstats[mib[4]].nmalloc, uint64_t) 1653234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_ndalloc, 1654234370Sjasone ctl_stats.arenas[mib[2]].lstats[mib[4]].ndalloc, uint64_t) 1655234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_nrequests, 1656234370Sjasone ctl_stats.arenas[mib[2]].lstats[mib[4]].nrequests, uint64_t) 1657234370SjasoneCTL_RO_CGEN(config_stats, stats_arenas_i_lruns_j_curruns, 1658234370Sjasone ctl_stats.arenas[mib[2]].lstats[mib[4]].curruns, size_t) 1659234370Sjasone 1660242844Sjasonestatic const ctl_named_node_t * 1661234370Sjasonestats_arenas_i_lruns_j_index(const size_t *mib, size_t miblen, size_t j) 1662234370Sjasone{ 1663234370Sjasone 1664234370Sjasone if (j > nlclasses) 1665234370Sjasone return (NULL); 1666234370Sjasone return (super_stats_arenas_i_lruns_j_node); 1667234370Sjasone} 1668234370Sjasone 1669242844Sjasonestatic const ctl_named_node_t * 1670234370Sjasonestats_arenas_i_index(const size_t *mib, size_t miblen, size_t i) 1671234370Sjasone{ 1672235238Sjasone const ctl_named_node_t * ret; 1673234370Sjasone 1674234370Sjasone malloc_mutex_lock(&ctl_mtx); 1675242844Sjasone if (i > ctl_stats.narenas || ctl_stats.arenas[i].initialized == false) { 1676234370Sjasone ret = NULL; 1677234370Sjasone goto label_return; 1678234370Sjasone } 1679234370Sjasone 1680234370Sjasone ret = super_stats_arenas_i_node; 1681234370Sjasonelabel_return: 1682234370Sjasone malloc_mutex_unlock(&ctl_mtx); 1683234370Sjasone return (ret); 1684234370Sjasone} 1685