1a4bd5210SJason Evans #define JEMALLOC_TCACHE_C_ 2a4bd5210SJason Evans #include "jemalloc/internal/jemalloc_internal.h" 3a4bd5210SJason Evans 4a4bd5210SJason Evans /******************************************************************************/ 5a4bd5210SJason Evans /* Data. */ 6a4bd5210SJason Evans 7a4bd5210SJason Evans malloc_tsd_data(, tcache, tcache_t *, NULL) 8a4bd5210SJason Evans malloc_tsd_data(, tcache_enabled, tcache_enabled_t, tcache_enabled_default) 9a4bd5210SJason Evans 10a4bd5210SJason Evans bool opt_tcache = true; 11a4bd5210SJason Evans ssize_t opt_lg_tcache_max = LG_TCACHE_MAXCLASS_DEFAULT; 12a4bd5210SJason Evans 13a4bd5210SJason Evans tcache_bin_info_t *tcache_bin_info; 14a4bd5210SJason Evans static unsigned stack_nelms; /* Total stack elms per tcache. */ 15a4bd5210SJason Evans 16a4bd5210SJason Evans size_t nhbins; 17a4bd5210SJason Evans size_t tcache_maxclass; 18a4bd5210SJason Evans 19a4bd5210SJason Evans /******************************************************************************/ 20a4bd5210SJason Evans 21*8ed34ab0SJason Evans size_t tcache_salloc(const void *ptr) 22*8ed34ab0SJason Evans { 23*8ed34ab0SJason Evans 24*8ed34ab0SJason Evans return (arena_salloc(ptr, false)); 25*8ed34ab0SJason Evans } 26*8ed34ab0SJason Evans 27a4bd5210SJason Evans void * 28a4bd5210SJason Evans tcache_alloc_small_hard(tcache_t *tcache, tcache_bin_t *tbin, size_t binind) 29a4bd5210SJason Evans { 30a4bd5210SJason Evans void *ret; 31a4bd5210SJason Evans 32a4bd5210SJason Evans arena_tcache_fill_small(tcache->arena, tbin, binind, 33a4bd5210SJason Evans config_prof ? tcache->prof_accumbytes : 0); 34a4bd5210SJason Evans if (config_prof) 35a4bd5210SJason Evans tcache->prof_accumbytes = 0; 36a4bd5210SJason Evans ret = tcache_alloc_easy(tbin); 37a4bd5210SJason Evans 38a4bd5210SJason Evans return (ret); 39a4bd5210SJason Evans } 40a4bd5210SJason Evans 41a4bd5210SJason Evans void 42a4bd5210SJason Evans tcache_bin_flush_small(tcache_bin_t *tbin, size_t binind, unsigned rem, 43a4bd5210SJason Evans tcache_t *tcache) 44a4bd5210SJason Evans { 45a4bd5210SJason Evans void *ptr; 46a4bd5210SJason Evans unsigned i, nflush, ndeferred; 47a4bd5210SJason Evans bool merged_stats = false; 48a4bd5210SJason Evans 49a4bd5210SJason Evans assert(binind < NBINS); 50a4bd5210SJason Evans assert(rem <= tbin->ncached); 51a4bd5210SJason Evans 52a4bd5210SJason Evans for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) { 53a4bd5210SJason Evans /* Lock the arena bin associated with the first object. */ 54a4bd5210SJason Evans arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE( 55a4bd5210SJason Evans tbin->avail[0]); 56a4bd5210SJason Evans arena_t *arena = chunk->arena; 57a4bd5210SJason Evans arena_bin_t *bin = &arena->bins[binind]; 58a4bd5210SJason Evans 59a4bd5210SJason Evans if (config_prof && arena == tcache->arena) { 60a4bd5210SJason Evans malloc_mutex_lock(&arena->lock); 61a4bd5210SJason Evans arena_prof_accum(arena, tcache->prof_accumbytes); 62a4bd5210SJason Evans malloc_mutex_unlock(&arena->lock); 63a4bd5210SJason Evans tcache->prof_accumbytes = 0; 64a4bd5210SJason Evans } 65a4bd5210SJason Evans 66a4bd5210SJason Evans malloc_mutex_lock(&bin->lock); 67a4bd5210SJason Evans if (config_stats && arena == tcache->arena) { 68a4bd5210SJason Evans assert(merged_stats == false); 69a4bd5210SJason Evans merged_stats = true; 70a4bd5210SJason Evans bin->stats.nflushes++; 71a4bd5210SJason Evans bin->stats.nrequests += tbin->tstats.nrequests; 72a4bd5210SJason Evans tbin->tstats.nrequests = 0; 73a4bd5210SJason Evans } 74a4bd5210SJason Evans ndeferred = 0; 75a4bd5210SJason Evans for (i = 0; i < nflush; i++) { 76a4bd5210SJason Evans ptr = tbin->avail[i]; 77a4bd5210SJason Evans assert(ptr != NULL); 78a4bd5210SJason Evans chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); 79a4bd5210SJason Evans if (chunk->arena == arena) { 80a4bd5210SJason Evans size_t pageind = ((uintptr_t)ptr - 81a4bd5210SJason Evans (uintptr_t)chunk) >> LG_PAGE; 82a4bd5210SJason Evans arena_chunk_map_t *mapelm = 83a4bd5210SJason Evans &chunk->map[pageind-map_bias]; 84a4bd5210SJason Evans if (config_fill && opt_junk) { 85a4bd5210SJason Evans arena_alloc_junk_small(ptr, 86a4bd5210SJason Evans &arena_bin_info[binind], true); 87a4bd5210SJason Evans } 88a4bd5210SJason Evans arena_dalloc_bin(arena, chunk, ptr, mapelm); 89a4bd5210SJason Evans } else { 90a4bd5210SJason Evans /* 91a4bd5210SJason Evans * This object was allocated via a different 92a4bd5210SJason Evans * arena bin than the one that is currently 93a4bd5210SJason Evans * locked. Stash the object, so that it can be 94a4bd5210SJason Evans * handled in a future pass. 95a4bd5210SJason Evans */ 96a4bd5210SJason Evans tbin->avail[ndeferred] = ptr; 97a4bd5210SJason Evans ndeferred++; 98a4bd5210SJason Evans } 99a4bd5210SJason Evans } 100a4bd5210SJason Evans malloc_mutex_unlock(&bin->lock); 101a4bd5210SJason Evans } 102a4bd5210SJason Evans if (config_stats && merged_stats == false) { 103a4bd5210SJason Evans /* 104a4bd5210SJason Evans * The flush loop didn't happen to flush to this thread's 105a4bd5210SJason Evans * arena, so the stats didn't get merged. Manually do so now. 106a4bd5210SJason Evans */ 107a4bd5210SJason Evans arena_bin_t *bin = &tcache->arena->bins[binind]; 108a4bd5210SJason Evans malloc_mutex_lock(&bin->lock); 109a4bd5210SJason Evans bin->stats.nflushes++; 110a4bd5210SJason Evans bin->stats.nrequests += tbin->tstats.nrequests; 111a4bd5210SJason Evans tbin->tstats.nrequests = 0; 112a4bd5210SJason Evans malloc_mutex_unlock(&bin->lock); 113a4bd5210SJason Evans } 114a4bd5210SJason Evans 115a4bd5210SJason Evans memmove(tbin->avail, &tbin->avail[tbin->ncached - rem], 116a4bd5210SJason Evans rem * sizeof(void *)); 117a4bd5210SJason Evans tbin->ncached = rem; 118a4bd5210SJason Evans if ((int)tbin->ncached < tbin->low_water) 119a4bd5210SJason Evans tbin->low_water = tbin->ncached; 120a4bd5210SJason Evans } 121a4bd5210SJason Evans 122a4bd5210SJason Evans void 123a4bd5210SJason Evans tcache_bin_flush_large(tcache_bin_t *tbin, size_t binind, unsigned rem, 124a4bd5210SJason Evans tcache_t *tcache) 125a4bd5210SJason Evans { 126a4bd5210SJason Evans void *ptr; 127a4bd5210SJason Evans unsigned i, nflush, ndeferred; 128a4bd5210SJason Evans bool merged_stats = false; 129a4bd5210SJason Evans 130a4bd5210SJason Evans assert(binind < nhbins); 131a4bd5210SJason Evans assert(rem <= tbin->ncached); 132a4bd5210SJason Evans 133a4bd5210SJason Evans for (nflush = tbin->ncached - rem; nflush > 0; nflush = ndeferred) { 134a4bd5210SJason Evans /* Lock the arena associated with the first object. */ 135a4bd5210SJason Evans arena_chunk_t *chunk = (arena_chunk_t *)CHUNK_ADDR2BASE( 136a4bd5210SJason Evans tbin->avail[0]); 137a4bd5210SJason Evans arena_t *arena = chunk->arena; 138a4bd5210SJason Evans 139a4bd5210SJason Evans malloc_mutex_lock(&arena->lock); 140a4bd5210SJason Evans if ((config_prof || config_stats) && arena == tcache->arena) { 141a4bd5210SJason Evans if (config_prof) { 142a4bd5210SJason Evans arena_prof_accum(arena, 143a4bd5210SJason Evans tcache->prof_accumbytes); 144a4bd5210SJason Evans tcache->prof_accumbytes = 0; 145a4bd5210SJason Evans } 146a4bd5210SJason Evans if (config_stats) { 147a4bd5210SJason Evans merged_stats = true; 148a4bd5210SJason Evans arena->stats.nrequests_large += 149a4bd5210SJason Evans tbin->tstats.nrequests; 150a4bd5210SJason Evans arena->stats.lstats[binind - NBINS].nrequests += 151a4bd5210SJason Evans tbin->tstats.nrequests; 152a4bd5210SJason Evans tbin->tstats.nrequests = 0; 153a4bd5210SJason Evans } 154a4bd5210SJason Evans } 155a4bd5210SJason Evans ndeferred = 0; 156a4bd5210SJason Evans for (i = 0; i < nflush; i++) { 157a4bd5210SJason Evans ptr = tbin->avail[i]; 158a4bd5210SJason Evans assert(ptr != NULL); 159a4bd5210SJason Evans chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); 160a4bd5210SJason Evans if (chunk->arena == arena) 161a4bd5210SJason Evans arena_dalloc_large(arena, chunk, ptr); 162a4bd5210SJason Evans else { 163a4bd5210SJason Evans /* 164a4bd5210SJason Evans * This object was allocated via a different 165a4bd5210SJason Evans * arena than the one that is currently locked. 166a4bd5210SJason Evans * Stash the object, so that it can be handled 167a4bd5210SJason Evans * in a future pass. 168a4bd5210SJason Evans */ 169a4bd5210SJason Evans tbin->avail[ndeferred] = ptr; 170a4bd5210SJason Evans ndeferred++; 171a4bd5210SJason Evans } 172a4bd5210SJason Evans } 173a4bd5210SJason Evans malloc_mutex_unlock(&arena->lock); 174a4bd5210SJason Evans } 175a4bd5210SJason Evans if (config_stats && merged_stats == false) { 176a4bd5210SJason Evans /* 177a4bd5210SJason Evans * The flush loop didn't happen to flush to this thread's 178a4bd5210SJason Evans * arena, so the stats didn't get merged. Manually do so now. 179a4bd5210SJason Evans */ 180a4bd5210SJason Evans arena_t *arena = tcache->arena; 181a4bd5210SJason Evans malloc_mutex_lock(&arena->lock); 182a4bd5210SJason Evans arena->stats.nrequests_large += tbin->tstats.nrequests; 183a4bd5210SJason Evans arena->stats.lstats[binind - NBINS].nrequests += 184a4bd5210SJason Evans tbin->tstats.nrequests; 185a4bd5210SJason Evans tbin->tstats.nrequests = 0; 186a4bd5210SJason Evans malloc_mutex_unlock(&arena->lock); 187a4bd5210SJason Evans } 188a4bd5210SJason Evans 189a4bd5210SJason Evans memmove(tbin->avail, &tbin->avail[tbin->ncached - rem], 190a4bd5210SJason Evans rem * sizeof(void *)); 191a4bd5210SJason Evans tbin->ncached = rem; 192a4bd5210SJason Evans if ((int)tbin->ncached < tbin->low_water) 193a4bd5210SJason Evans tbin->low_water = tbin->ncached; 194a4bd5210SJason Evans } 195a4bd5210SJason Evans 196a4bd5210SJason Evans void 197a4bd5210SJason Evans tcache_arena_associate(tcache_t *tcache, arena_t *arena) 198a4bd5210SJason Evans { 199a4bd5210SJason Evans 200a4bd5210SJason Evans if (config_stats) { 201a4bd5210SJason Evans /* Link into list of extant tcaches. */ 202a4bd5210SJason Evans malloc_mutex_lock(&arena->lock); 203a4bd5210SJason Evans ql_elm_new(tcache, link); 204a4bd5210SJason Evans ql_tail_insert(&arena->tcache_ql, tcache, link); 205a4bd5210SJason Evans malloc_mutex_unlock(&arena->lock); 206a4bd5210SJason Evans } 207a4bd5210SJason Evans tcache->arena = arena; 208a4bd5210SJason Evans } 209a4bd5210SJason Evans 210a4bd5210SJason Evans void 211a4bd5210SJason Evans tcache_arena_dissociate(tcache_t *tcache) 212a4bd5210SJason Evans { 213a4bd5210SJason Evans 214a4bd5210SJason Evans if (config_stats) { 215a4bd5210SJason Evans /* Unlink from list of extant tcaches. */ 216a4bd5210SJason Evans malloc_mutex_lock(&tcache->arena->lock); 217a4bd5210SJason Evans ql_remove(&tcache->arena->tcache_ql, tcache, link); 218a4bd5210SJason Evans malloc_mutex_unlock(&tcache->arena->lock); 219a4bd5210SJason Evans tcache_stats_merge(tcache, tcache->arena); 220a4bd5210SJason Evans } 221a4bd5210SJason Evans } 222a4bd5210SJason Evans 223a4bd5210SJason Evans tcache_t * 224a4bd5210SJason Evans tcache_create(arena_t *arena) 225a4bd5210SJason Evans { 226a4bd5210SJason Evans tcache_t *tcache; 227a4bd5210SJason Evans size_t size, stack_offset; 228a4bd5210SJason Evans unsigned i; 229a4bd5210SJason Evans 230a4bd5210SJason Evans size = offsetof(tcache_t, tbins) + (sizeof(tcache_bin_t) * nhbins); 231a4bd5210SJason Evans /* Naturally align the pointer stacks. */ 232a4bd5210SJason Evans size = PTR_CEILING(size); 233a4bd5210SJason Evans stack_offset = size; 234a4bd5210SJason Evans size += stack_nelms * sizeof(void *); 235a4bd5210SJason Evans /* 236a4bd5210SJason Evans * Round up to the nearest multiple of the cacheline size, in order to 237a4bd5210SJason Evans * avoid the possibility of false cacheline sharing. 238a4bd5210SJason Evans * 239a4bd5210SJason Evans * That this works relies on the same logic as in ipalloc(), but we 240a4bd5210SJason Evans * cannot directly call ipalloc() here due to tcache bootstrapping 241a4bd5210SJason Evans * issues. 242a4bd5210SJason Evans */ 243a4bd5210SJason Evans size = (size + CACHELINE_MASK) & (-CACHELINE); 244a4bd5210SJason Evans 245a4bd5210SJason Evans if (size <= SMALL_MAXCLASS) 246a4bd5210SJason Evans tcache = (tcache_t *)arena_malloc_small(arena, size, true); 247a4bd5210SJason Evans else if (size <= tcache_maxclass) 248a4bd5210SJason Evans tcache = (tcache_t *)arena_malloc_large(arena, size, true); 249a4bd5210SJason Evans else 250a4bd5210SJason Evans tcache = (tcache_t *)icalloc(size); 251a4bd5210SJason Evans 252a4bd5210SJason Evans if (tcache == NULL) 253a4bd5210SJason Evans return (NULL); 254a4bd5210SJason Evans 255a4bd5210SJason Evans tcache_arena_associate(tcache, arena); 256a4bd5210SJason Evans 257a4bd5210SJason Evans assert((TCACHE_NSLOTS_SMALL_MAX & 1U) == 0); 258a4bd5210SJason Evans for (i = 0; i < nhbins; i++) { 259a4bd5210SJason Evans tcache->tbins[i].lg_fill_div = 1; 260a4bd5210SJason Evans tcache->tbins[i].avail = (void **)((uintptr_t)tcache + 261a4bd5210SJason Evans (uintptr_t)stack_offset); 262a4bd5210SJason Evans stack_offset += tcache_bin_info[i].ncached_max * sizeof(void *); 263a4bd5210SJason Evans } 264a4bd5210SJason Evans 265a4bd5210SJason Evans tcache_tsd_set(&tcache); 266a4bd5210SJason Evans 267a4bd5210SJason Evans return (tcache); 268a4bd5210SJason Evans } 269a4bd5210SJason Evans 270a4bd5210SJason Evans void 271a4bd5210SJason Evans tcache_destroy(tcache_t *tcache) 272a4bd5210SJason Evans { 273a4bd5210SJason Evans unsigned i; 274a4bd5210SJason Evans size_t tcache_size; 275a4bd5210SJason Evans 276a4bd5210SJason Evans tcache_arena_dissociate(tcache); 277a4bd5210SJason Evans 278a4bd5210SJason Evans for (i = 0; i < NBINS; i++) { 279a4bd5210SJason Evans tcache_bin_t *tbin = &tcache->tbins[i]; 280a4bd5210SJason Evans tcache_bin_flush_small(tbin, i, 0, tcache); 281a4bd5210SJason Evans 282a4bd5210SJason Evans if (config_stats && tbin->tstats.nrequests != 0) { 283a4bd5210SJason Evans arena_t *arena = tcache->arena; 284a4bd5210SJason Evans arena_bin_t *bin = &arena->bins[i]; 285a4bd5210SJason Evans malloc_mutex_lock(&bin->lock); 286a4bd5210SJason Evans bin->stats.nrequests += tbin->tstats.nrequests; 287a4bd5210SJason Evans malloc_mutex_unlock(&bin->lock); 288a4bd5210SJason Evans } 289a4bd5210SJason Evans } 290a4bd5210SJason Evans 291a4bd5210SJason Evans for (; i < nhbins; i++) { 292a4bd5210SJason Evans tcache_bin_t *tbin = &tcache->tbins[i]; 293a4bd5210SJason Evans tcache_bin_flush_large(tbin, i, 0, tcache); 294a4bd5210SJason Evans 295a4bd5210SJason Evans if (config_stats && tbin->tstats.nrequests != 0) { 296a4bd5210SJason Evans arena_t *arena = tcache->arena; 297a4bd5210SJason Evans malloc_mutex_lock(&arena->lock); 298a4bd5210SJason Evans arena->stats.nrequests_large += tbin->tstats.nrequests; 299a4bd5210SJason Evans arena->stats.lstats[i - NBINS].nrequests += 300a4bd5210SJason Evans tbin->tstats.nrequests; 301a4bd5210SJason Evans malloc_mutex_unlock(&arena->lock); 302a4bd5210SJason Evans } 303a4bd5210SJason Evans } 304a4bd5210SJason Evans 305a4bd5210SJason Evans if (config_prof && tcache->prof_accumbytes > 0) { 306a4bd5210SJason Evans malloc_mutex_lock(&tcache->arena->lock); 307a4bd5210SJason Evans arena_prof_accum(tcache->arena, tcache->prof_accumbytes); 308a4bd5210SJason Evans malloc_mutex_unlock(&tcache->arena->lock); 309a4bd5210SJason Evans } 310a4bd5210SJason Evans 311a4bd5210SJason Evans tcache_size = arena_salloc(tcache, false); 312a4bd5210SJason Evans if (tcache_size <= SMALL_MAXCLASS) { 313a4bd5210SJason Evans arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache); 314a4bd5210SJason Evans arena_t *arena = chunk->arena; 315a4bd5210SJason Evans size_t pageind = ((uintptr_t)tcache - (uintptr_t)chunk) >> 316a4bd5210SJason Evans LG_PAGE; 317a4bd5210SJason Evans arena_chunk_map_t *mapelm = &chunk->map[pageind-map_bias]; 318a4bd5210SJason Evans arena_run_t *run = (arena_run_t *)((uintptr_t)chunk + 319a4bd5210SJason Evans (uintptr_t)((pageind - (mapelm->bits >> LG_PAGE)) << 320a4bd5210SJason Evans LG_PAGE)); 321a4bd5210SJason Evans arena_bin_t *bin = run->bin; 322a4bd5210SJason Evans 323a4bd5210SJason Evans malloc_mutex_lock(&bin->lock); 324a4bd5210SJason Evans arena_dalloc_bin(arena, chunk, tcache, mapelm); 325a4bd5210SJason Evans malloc_mutex_unlock(&bin->lock); 326a4bd5210SJason Evans } else if (tcache_size <= tcache_maxclass) { 327a4bd5210SJason Evans arena_chunk_t *chunk = CHUNK_ADDR2BASE(tcache); 328a4bd5210SJason Evans arena_t *arena = chunk->arena; 329a4bd5210SJason Evans 330a4bd5210SJason Evans malloc_mutex_lock(&arena->lock); 331a4bd5210SJason Evans arena_dalloc_large(arena, chunk, tcache); 332a4bd5210SJason Evans malloc_mutex_unlock(&arena->lock); 333a4bd5210SJason Evans } else 334a4bd5210SJason Evans idalloc(tcache); 335a4bd5210SJason Evans } 336a4bd5210SJason Evans 337a4bd5210SJason Evans void 338a4bd5210SJason Evans tcache_thread_cleanup(void *arg) 339a4bd5210SJason Evans { 340a4bd5210SJason Evans tcache_t *tcache = *(tcache_t **)arg; 341a4bd5210SJason Evans 342a4bd5210SJason Evans if (tcache == TCACHE_STATE_DISABLED) { 343a4bd5210SJason Evans /* Do nothing. */ 344a4bd5210SJason Evans } else if (tcache == TCACHE_STATE_REINCARNATED) { 345a4bd5210SJason Evans /* 346a4bd5210SJason Evans * Another destructor called an allocator function after this 347a4bd5210SJason Evans * destructor was called. Reset tcache to 348a4bd5210SJason Evans * TCACHE_STATE_PURGATORY in order to receive another callback. 349a4bd5210SJason Evans */ 350a4bd5210SJason Evans tcache = TCACHE_STATE_PURGATORY; 351a4bd5210SJason Evans tcache_tsd_set(&tcache); 352a4bd5210SJason Evans } else if (tcache == TCACHE_STATE_PURGATORY) { 353a4bd5210SJason Evans /* 354a4bd5210SJason Evans * The previous time this destructor was called, we set the key 355a4bd5210SJason Evans * to TCACHE_STATE_PURGATORY so that other destructors wouldn't 356a4bd5210SJason Evans * cause re-creation of the tcache. This time, do nothing, so 357a4bd5210SJason Evans * that the destructor will not be called again. 358a4bd5210SJason Evans */ 359a4bd5210SJason Evans } else if (tcache != NULL) { 360a4bd5210SJason Evans assert(tcache != TCACHE_STATE_PURGATORY); 361a4bd5210SJason Evans tcache_destroy(tcache); 362a4bd5210SJason Evans tcache = TCACHE_STATE_PURGATORY; 363a4bd5210SJason Evans tcache_tsd_set(&tcache); 364a4bd5210SJason Evans } 365a4bd5210SJason Evans } 366a4bd5210SJason Evans 367a4bd5210SJason Evans void 368a4bd5210SJason Evans tcache_stats_merge(tcache_t *tcache, arena_t *arena) 369a4bd5210SJason Evans { 370a4bd5210SJason Evans unsigned i; 371a4bd5210SJason Evans 372a4bd5210SJason Evans /* Merge and reset tcache stats. */ 373a4bd5210SJason Evans for (i = 0; i < NBINS; i++) { 374a4bd5210SJason Evans arena_bin_t *bin = &arena->bins[i]; 375a4bd5210SJason Evans tcache_bin_t *tbin = &tcache->tbins[i]; 376a4bd5210SJason Evans malloc_mutex_lock(&bin->lock); 377a4bd5210SJason Evans bin->stats.nrequests += tbin->tstats.nrequests; 378a4bd5210SJason Evans malloc_mutex_unlock(&bin->lock); 379a4bd5210SJason Evans tbin->tstats.nrequests = 0; 380a4bd5210SJason Evans } 381a4bd5210SJason Evans 382a4bd5210SJason Evans for (; i < nhbins; i++) { 383a4bd5210SJason Evans malloc_large_stats_t *lstats = &arena->stats.lstats[i - NBINS]; 384a4bd5210SJason Evans tcache_bin_t *tbin = &tcache->tbins[i]; 385a4bd5210SJason Evans arena->stats.nrequests_large += tbin->tstats.nrequests; 386a4bd5210SJason Evans lstats->nrequests += tbin->tstats.nrequests; 387a4bd5210SJason Evans tbin->tstats.nrequests = 0; 388a4bd5210SJason Evans } 389a4bd5210SJason Evans } 390a4bd5210SJason Evans 391a4bd5210SJason Evans bool 392a4bd5210SJason Evans tcache_boot0(void) 393a4bd5210SJason Evans { 394a4bd5210SJason Evans unsigned i; 395a4bd5210SJason Evans 396a4bd5210SJason Evans /* 397a4bd5210SJason Evans * If necessary, clamp opt_lg_tcache_max, now that arena_maxclass is 398a4bd5210SJason Evans * known. 399a4bd5210SJason Evans */ 400a4bd5210SJason Evans if (opt_lg_tcache_max < 0 || (1U << opt_lg_tcache_max) < SMALL_MAXCLASS) 401a4bd5210SJason Evans tcache_maxclass = SMALL_MAXCLASS; 402a4bd5210SJason Evans else if ((1U << opt_lg_tcache_max) > arena_maxclass) 403a4bd5210SJason Evans tcache_maxclass = arena_maxclass; 404a4bd5210SJason Evans else 405a4bd5210SJason Evans tcache_maxclass = (1U << opt_lg_tcache_max); 406a4bd5210SJason Evans 407a4bd5210SJason Evans nhbins = NBINS + (tcache_maxclass >> LG_PAGE); 408a4bd5210SJason Evans 409a4bd5210SJason Evans /* Initialize tcache_bin_info. */ 410a4bd5210SJason Evans tcache_bin_info = (tcache_bin_info_t *)base_alloc(nhbins * 411a4bd5210SJason Evans sizeof(tcache_bin_info_t)); 412a4bd5210SJason Evans if (tcache_bin_info == NULL) 413a4bd5210SJason Evans return (true); 414a4bd5210SJason Evans stack_nelms = 0; 415a4bd5210SJason Evans for (i = 0; i < NBINS; i++) { 416a4bd5210SJason Evans if ((arena_bin_info[i].nregs << 1) <= TCACHE_NSLOTS_SMALL_MAX) { 417a4bd5210SJason Evans tcache_bin_info[i].ncached_max = 418a4bd5210SJason Evans (arena_bin_info[i].nregs << 1); 419a4bd5210SJason Evans } else { 420a4bd5210SJason Evans tcache_bin_info[i].ncached_max = 421a4bd5210SJason Evans TCACHE_NSLOTS_SMALL_MAX; 422a4bd5210SJason Evans } 423a4bd5210SJason Evans stack_nelms += tcache_bin_info[i].ncached_max; 424a4bd5210SJason Evans } 425a4bd5210SJason Evans for (; i < nhbins; i++) { 426a4bd5210SJason Evans tcache_bin_info[i].ncached_max = TCACHE_NSLOTS_LARGE; 427a4bd5210SJason Evans stack_nelms += tcache_bin_info[i].ncached_max; 428a4bd5210SJason Evans } 429a4bd5210SJason Evans 430a4bd5210SJason Evans return (false); 431a4bd5210SJason Evans } 432a4bd5210SJason Evans 433a4bd5210SJason Evans bool 434a4bd5210SJason Evans tcache_boot1(void) 435a4bd5210SJason Evans { 436a4bd5210SJason Evans 437a4bd5210SJason Evans if (tcache_tsd_boot() || tcache_enabled_tsd_boot()) 438a4bd5210SJason Evans return (true); 439a4bd5210SJason Evans 440a4bd5210SJason Evans return (false); 441a4bd5210SJason Evans } 442