1#ifndef JEMALLOC_INTERNAL_CACHE_BIN_H 2#define JEMALLOC_INTERNAL_CACHE_BIN_H 3 4#include "jemalloc/internal/ql.h" 5 6/* 7 * The cache_bins are the mechanism that the tcache and the arena use to 8 * communicate. The tcache fills from and flushes to the arena by passing a 9 * cache_bin_t to fill/flush. When the arena needs to pull stats from the 10 * tcaches associated with it, it does so by iterating over its 11 * cache_bin_array_descriptor_t objects and reading out per-bin stats it 12 * contains. This makes it so that the arena need not know about the existence 13 * of the tcache at all. 14 */ 15 16 17/* 18 * The count of the number of cached allocations in a bin. We make this signed 19 * so that negative numbers can encode "invalid" states (e.g. a low water mark 20 * of -1 for a cache that has been depleted). 21 */ 22typedef int32_t cache_bin_sz_t; 23 24typedef struct cache_bin_stats_s cache_bin_stats_t; 25struct cache_bin_stats_s { 26 /* 27 * Number of allocation requests that corresponded to the size of this 28 * bin. 29 */ 30 uint64_t nrequests; 31}; 32 33/* 34 * Read-only information associated with each element of tcache_t's tbins array 35 * is stored separately, mainly to reduce memory usage. 36 */ 37typedef struct cache_bin_info_s cache_bin_info_t; 38struct cache_bin_info_s { 39 /* Upper limit on ncached. */ 40 cache_bin_sz_t ncached_max; 41}; 42 43typedef struct cache_bin_s cache_bin_t; 44struct cache_bin_s { 45 /* Min # cached since last GC. */ 46 cache_bin_sz_t low_water; 47 /* # of cached objects. */ 48 cache_bin_sz_t ncached; 49 /* 50 * ncached and stats are both modified frequently. Let's keep them 51 * close so that they have a higher chance of being on the same 52 * cacheline, thus less write-backs. 53 */ 54 cache_bin_stats_t tstats; 55 /* 56 * Stack of available objects. 57 * 58 * To make use of adjacent cacheline prefetch, the items in the avail 59 * stack goes to higher address for newer allocations. avail points 60 * just above the available space, which means that 61 * avail[-ncached, ... -1] are available items and the lowest item will 62 * be allocated first. 63 */ 64 void **avail; 65}; 66 67typedef struct cache_bin_array_descriptor_s cache_bin_array_descriptor_t; 68struct cache_bin_array_descriptor_s { 69 /* 70 * The arena keeps a list of the cache bins associated with it, for 71 * stats collection. 72 */ 73 ql_elm(cache_bin_array_descriptor_t) link; 74 /* Pointers to the tcache bins. */ 75 cache_bin_t *bins_small; 76 cache_bin_t *bins_large; 77}; 78 79static inline void 80cache_bin_array_descriptor_init(cache_bin_array_descriptor_t *descriptor, 81 cache_bin_t *bins_small, cache_bin_t *bins_large) { 82 ql_elm_new(descriptor, link); 83 descriptor->bins_small = bins_small; 84 descriptor->bins_large = bins_large; 85} 86 87JEMALLOC_ALWAYS_INLINE void * 88cache_bin_alloc_easy(cache_bin_t *bin, bool *success) { 89 void *ret; 90 91 bin->ncached--; 92 93 /* 94 * Check for both bin->ncached == 0 and ncached < low_water 95 * in a single branch. 96 */ 97 if (unlikely(bin->ncached <= bin->low_water)) { 98 bin->low_water = bin->ncached; 99 if (bin->ncached == -1) { 100 bin->ncached = 0; 101 *success = false; 102 return NULL; 103 } 104 } 105 106 /* 107 * success (instead of ret) should be checked upon the return of this 108 * function. We avoid checking (ret == NULL) because there is never a 109 * null stored on the avail stack (which is unknown to the compiler), 110 * and eagerly checking ret would cause pipeline stall (waiting for the 111 * cacheline). 112 */ 113 *success = true; 114 ret = *(bin->avail - (bin->ncached + 1)); 115 116 return ret; 117} 118 119JEMALLOC_ALWAYS_INLINE bool 120cache_bin_dalloc_easy(cache_bin_t *bin, cache_bin_info_t *bin_info, void *ptr) { 121 if (unlikely(bin->ncached == bin_info->ncached_max)) { 122 return false; 123 } 124 assert(bin->ncached < bin_info->ncached_max); 125 bin->ncached++; 126 *(bin->avail - bin->ncached) = ptr; 127 128 return true; 129} 130 131#endif /* JEMALLOC_INTERNAL_CACHE_BIN_H */ 132