Home | History | Annotate | Line # | Download | only in internal
tcache_inlines.h revision 1.1.1.3
      1 #ifndef JEMALLOC_INTERNAL_TCACHE_INLINES_H
      2 #define JEMALLOC_INTERNAL_TCACHE_INLINES_H
      3 
      4 #include "jemalloc/internal/jemalloc_preamble.h"
      5 #include "jemalloc/internal/arena_externs.h"
      6 #include "jemalloc/internal/bin.h"
      7 #include "jemalloc/internal/jemalloc_internal_inlines_b.h"
      8 #include "jemalloc/internal/jemalloc_internal_types.h"
      9 #include "jemalloc/internal/large_externs.h"
     10 #include "jemalloc/internal/san.h"
     11 #include "jemalloc/internal/sc.h"
     12 #include "jemalloc/internal/sz.h"
     13 #include "jemalloc/internal/tcache_externs.h"
     14 #include "jemalloc/internal/util.h"
     15 
     16 static inline bool
     17 tcache_enabled_get(tsd_t *tsd) {
     18 	return tsd_tcache_enabled_get(tsd);
     19 }
     20 
     21 static inline unsigned
     22 tcache_nbins_get(tcache_slow_t *tcache_slow) {
     23 	assert(tcache_slow != NULL);
     24 	unsigned nbins = tcache_slow->tcache_nbins;
     25 	assert(nbins <= TCACHE_NBINS_MAX);
     26 	return nbins;
     27 }
     28 
     29 static inline size_t
     30 tcache_max_get(tcache_slow_t *tcache_slow) {
     31 	assert(tcache_slow != NULL);
     32 	size_t tcache_max = sz_index2size(tcache_nbins_get(tcache_slow) - 1);
     33 	assert(tcache_max <= TCACHE_MAXCLASS_LIMIT);
     34 	return tcache_max;
     35 }
     36 
     37 static inline void
     38 tcache_max_set(tcache_slow_t *tcache_slow, size_t tcache_max) {
     39 	assert(tcache_slow != NULL);
     40 	assert(tcache_max <= TCACHE_MAXCLASS_LIMIT);
     41 	tcache_slow->tcache_nbins = sz_size2index(tcache_max) + 1;
     42 }
     43 
     44 static inline void
     45 tcache_bin_settings_backup(
     46     tcache_t *tcache, cache_bin_info_t tcache_bin_info[TCACHE_NBINS_MAX]) {
     47 	for (unsigned i = 0; i < TCACHE_NBINS_MAX; i++) {
     48 		cache_bin_info_init(&tcache_bin_info[i],
     49 		    cache_bin_ncached_max_get_unsafe(&tcache->bins[i]));
     50 	}
     51 }
     52 
     53 JEMALLOC_ALWAYS_INLINE bool
     54 tcache_bin_disabled(szind_t ind, cache_bin_t *bin, tcache_slow_t *tcache_slow) {
     55 	assert(bin != NULL);
     56 	assert(ind < TCACHE_NBINS_MAX);
     57 	bool disabled = cache_bin_disabled(bin);
     58 
     59 	/*
     60 	 * If a bin's ind >= nbins or ncached_max == 0, it must be disabled.
     61 	 * However, when ind < nbins, it could be either enabled
     62 	 * (ncached_max > 0) or disabled (ncached_max == 0). Similarly, when
     63 	 * ncached_max > 0, it could be either enabled (ind < nbins) or
     64 	 * disabled (ind >= nbins).  Thus, if a bin is disabled, it has either
     65 	 * ind >= nbins or ncached_max == 0.  If a bin is enabled, it has
     66 	 * ind < nbins and ncached_max > 0.
     67 	 */
     68 	unsigned       nbins = tcache_nbins_get(tcache_slow);
     69 	cache_bin_sz_t ncached_max = cache_bin_ncached_max_get_unsafe(bin);
     70 	if (ind >= nbins) {
     71 		assert(disabled);
     72 	} else {
     73 		assert(!disabled || ncached_max == 0);
     74 	}
     75 	if (ncached_max == 0) {
     76 		assert(disabled);
     77 	} else {
     78 		assert(!disabled || ind >= nbins);
     79 	}
     80 	if (disabled) {
     81 		assert(ind >= nbins || ncached_max == 0);
     82 	} else {
     83 		assert(ind < nbins && ncached_max > 0);
     84 	}
     85 
     86 	return disabled;
     87 }
     88 
     89 JEMALLOC_ALWAYS_INLINE void *
     90 tcache_alloc_small(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size,
     91     szind_t binind, bool zero, bool slow_path) {
     92 	void *ret;
     93 	bool  tcache_success;
     94 
     95 	assert(binind < SC_NBINS);
     96 	cache_bin_t *bin = &tcache->bins[binind];
     97 	ret = cache_bin_alloc(bin, &tcache_success);
     98 	assert(tcache_success == (ret != NULL));
     99 	if (unlikely(!tcache_success)) {
    100 		bool tcache_hard_success;
    101 		arena = arena_choose(tsd, arena);
    102 		if (unlikely(arena == NULL)) {
    103 			return NULL;
    104 		}
    105 		if (unlikely(tcache_bin_disabled(
    106 		        binind, bin, tcache->tcache_slow))) {
    107 			/* stats and zero are handled directly by the arena. */
    108 			return arena_malloc_hard(tsd_tsdn(tsd), arena, size,
    109 			    binind, zero, /* slab */ true);
    110 		}
    111 		tcache_bin_flush_stashed(tsd, tcache, bin, binind,
    112 		    /* is_small */ true);
    113 
    114 		ret = tcache_alloc_small_hard(tsd_tsdn(tsd), arena, tcache, bin,
    115 		    binind, &tcache_hard_success);
    116 		if (tcache_hard_success == false) {
    117 			return NULL;
    118 		}
    119 	}
    120 
    121 	assert(ret);
    122 	if (unlikely(zero)) {
    123 		size_t usize = sz_index2size(binind);
    124 		assert(tcache_salloc(tsd_tsdn(tsd), ret) == usize);
    125 		memset(ret, 0, usize);
    126 	}
    127 	if (config_stats) {
    128 		bin->tstats.nrequests++;
    129 	}
    130 	return ret;
    131 }
    132 
    133 JEMALLOC_ALWAYS_INLINE void *
    134 tcache_alloc_large(tsd_t *tsd, arena_t *arena, tcache_t *tcache, size_t size,
    135     szind_t binind, bool zero, bool slow_path) {
    136 	void *ret;
    137 	bool  tcache_success;
    138 
    139 	cache_bin_t *bin = &tcache->bins[binind];
    140 	assert(binind >= SC_NBINS
    141 	    && !tcache_bin_disabled(binind, bin, tcache->tcache_slow));
    142 	ret = cache_bin_alloc(bin, &tcache_success);
    143 	assert(tcache_success == (ret != NULL));
    144 	if (unlikely(!tcache_success)) {
    145 		/*
    146 		 * Only allocate one large object at a time, because it's quite
    147 		 * expensive to create one and not use it.
    148 		 */
    149 		arena = arena_choose(tsd, arena);
    150 		if (unlikely(arena == NULL)) {
    151 			return NULL;
    152 		}
    153 		tcache_bin_flush_stashed(tsd, tcache, bin, binind,
    154 		    /* is_small */ false);
    155 
    156 		ret = large_malloc(tsd_tsdn(tsd), arena, sz_s2u(size), zero);
    157 		if (ret == NULL) {
    158 			return NULL;
    159 		}
    160 	} else {
    161 		if (unlikely(zero)) {
    162 			size_t usize = sz_index2size(binind);
    163 			assert(usize <= tcache_max_get(tcache->tcache_slow));
    164 			memset(ret, 0, usize);
    165 		}
    166 	}
    167 
    168 	if (config_stats) {
    169 		bin->tstats.nrequests++;
    170 	}
    171 
    172 	return ret;
    173 }
    174 
    175 JEMALLOC_ALWAYS_INLINE void
    176 tcache_dalloc_small(
    177     tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, bool slow_path) {
    178 	assert(tcache_salloc(tsd_tsdn(tsd), ptr) <= SC_SMALL_MAXCLASS);
    179 
    180 	cache_bin_t *bin = &tcache->bins[binind];
    181 	/*
    182 	 * Not marking the branch unlikely because this is past free_fastpath()
    183 	 * (which handles the most common cases), i.e. at this point it's often
    184 	 * uncommon cases.
    185 	 */
    186 	if (cache_bin_nonfast_aligned(ptr)) {
    187 		/* Junk unconditionally, even if bin is full. */
    188 		san_junk_ptr(ptr, sz_index2size(binind));
    189 		if (cache_bin_stash(bin, ptr)) {
    190 			return;
    191 		}
    192 		assert(cache_bin_full(bin));
    193 		/* Bin full; fall through into the flush branch. */
    194 	}
    195 
    196 	if (unlikely(!cache_bin_dalloc_easy(bin, ptr))) {
    197 		if (unlikely(tcache_bin_disabled(
    198 		        binind, bin, tcache->tcache_slow))) {
    199 			arena_dalloc_small(tsd_tsdn(tsd), ptr);
    200 			return;
    201 		}
    202 		cache_bin_sz_t max = cache_bin_ncached_max_get(bin);
    203 		unsigned       remain = max >> opt_lg_tcache_flush_small_div;
    204 		tcache_bin_flush_small(tsd, tcache, bin, binind, remain);
    205 		bool ret = cache_bin_dalloc_easy(bin, ptr);
    206 		assert(ret);
    207 	}
    208 }
    209 
    210 JEMALLOC_ALWAYS_INLINE void
    211 tcache_dalloc_large(
    212     tsd_t *tsd, tcache_t *tcache, void *ptr, szind_t binind, bool slow_path) {
    213 	assert(tcache_salloc(tsd_tsdn(tsd), ptr) > SC_SMALL_MAXCLASS);
    214 	assert(tcache_salloc(tsd_tsdn(tsd), ptr)
    215 	    <= tcache_max_get(tcache->tcache_slow));
    216 	assert(!tcache_bin_disabled(
    217 	    binind, &tcache->bins[binind], tcache->tcache_slow));
    218 
    219 	cache_bin_t *bin = &tcache->bins[binind];
    220 	if (unlikely(!cache_bin_dalloc_easy(bin, ptr))) {
    221 		unsigned remain = cache_bin_ncached_max_get(bin)
    222 		    >> opt_lg_tcache_flush_large_div;
    223 		tcache_bin_flush_large(tsd, tcache, bin, binind, remain);
    224 		bool ret = cache_bin_dalloc_easy(bin, ptr);
    225 		assert(ret);
    226 	}
    227 }
    228 
    229 JEMALLOC_ALWAYS_INLINE tcache_t *
    230 tcaches_get(tsd_t *tsd, unsigned ind) {
    231 	tcaches_t *elm = &tcaches[ind];
    232 	if (unlikely(elm->tcache == NULL)) {
    233 		malloc_printf("<jemalloc>: invalid tcache id (%u).\n", ind);
    234 		abort();
    235 	} else if (unlikely(elm->tcache == TCACHES_ELM_NEED_REINIT)) {
    236 		elm->tcache = tcache_create_explicit(tsd);
    237 	}
    238 	return elm->tcache;
    239 }
    240 
    241 #endif /* JEMALLOC_INTERNAL_TCACHE_INLINES_H */
    242