1*8e33eff8Schristos #ifndef JEMALLOC_INTERNAL_SIZE_H 2*8e33eff8Schristos #define JEMALLOC_INTERNAL_SIZE_H 3*8e33eff8Schristos 4*8e33eff8Schristos #include "jemalloc/internal/bit_util.h" 5*8e33eff8Schristos #include "jemalloc/internal/pages.h" 6*8e33eff8Schristos #include "jemalloc/internal/size_classes.h" 7*8e33eff8Schristos #include "jemalloc/internal/util.h" 8*8e33eff8Schristos 9*8e33eff8Schristos /* 10*8e33eff8Schristos * sz module: Size computations. 11*8e33eff8Schristos * 12*8e33eff8Schristos * Some abbreviations used here: 13*8e33eff8Schristos * p: Page 14*8e33eff8Schristos * ind: Index 15*8e33eff8Schristos * s, sz: Size 16*8e33eff8Schristos * u: Usable size 17*8e33eff8Schristos * a: Aligned 18*8e33eff8Schristos * 19*8e33eff8Schristos * These are not always used completely consistently, but should be enough to 20*8e33eff8Schristos * interpret function names. E.g. sz_psz2ind converts page size to page size 21*8e33eff8Schristos * index; sz_sa2u converts a (size, alignment) allocation request to the usable 22*8e33eff8Schristos * size that would result from such an allocation. 23*8e33eff8Schristos */ 24*8e33eff8Schristos 25*8e33eff8Schristos /* 26*8e33eff8Schristos * sz_pind2sz_tab encodes the same information as could be computed by 27*8e33eff8Schristos * sz_pind2sz_compute(). 28*8e33eff8Schristos */ 29*8e33eff8Schristos extern size_t const sz_pind2sz_tab[NPSIZES+1]; 30*8e33eff8Schristos /* 31*8e33eff8Schristos * sz_index2size_tab encodes the same information as could be computed (at 32*8e33eff8Schristos * unacceptable cost in some code paths) by sz_index2size_compute(). 33*8e33eff8Schristos */ 34*8e33eff8Schristos extern size_t const sz_index2size_tab[NSIZES]; 35*8e33eff8Schristos /* 36*8e33eff8Schristos * sz_size2index_tab is a compact lookup table that rounds request sizes up to 37*8e33eff8Schristos * size classes. In order to reduce cache footprint, the table is compressed, 38*8e33eff8Schristos * and all accesses are via sz_size2index(). 39*8e33eff8Schristos */ 40*8e33eff8Schristos extern uint8_t const sz_size2index_tab[]; 41*8e33eff8Schristos 42*8e33eff8Schristos static const size_t sz_large_pad = 43*8e33eff8Schristos #ifdef JEMALLOC_CACHE_OBLIVIOUS 44*8e33eff8Schristos PAGE 45*8e33eff8Schristos #else 46*8e33eff8Schristos 0 47*8e33eff8Schristos #endif 48*8e33eff8Schristos ; 49*8e33eff8Schristos 50*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE pszind_t 51*8e33eff8Schristos sz_psz2ind(size_t psz) { 52*8e33eff8Schristos if (unlikely(psz > LARGE_MAXCLASS)) { 53*8e33eff8Schristos return NPSIZES; 54*8e33eff8Schristos } 55*8e33eff8Schristos { 56*8e33eff8Schristos pszind_t x = lg_floor((psz<<1)-1); 57*8e33eff8Schristos pszind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_PAGE) ? 0 : x - 58*8e33eff8Schristos (LG_SIZE_CLASS_GROUP + LG_PAGE); 59*8e33eff8Schristos pszind_t grp = shift << LG_SIZE_CLASS_GROUP; 60*8e33eff8Schristos 61*8e33eff8Schristos pszind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? 62*8e33eff8Schristos LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; 63*8e33eff8Schristos 64*8e33eff8Schristos size_t delta_inverse_mask = ZU(-1) << lg_delta; 65*8e33eff8Schristos pszind_t mod = ((((psz-1) & delta_inverse_mask) >> lg_delta)) & 66*8e33eff8Schristos ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); 67*8e33eff8Schristos 68*8e33eff8Schristos pszind_t ind = grp + mod; 69*8e33eff8Schristos return ind; 70*8e33eff8Schristos } 71*8e33eff8Schristos } 72*8e33eff8Schristos 73*8e33eff8Schristos static inline size_t 74*8e33eff8Schristos sz_pind2sz_compute(pszind_t pind) { 75*8e33eff8Schristos if (unlikely(pind == NPSIZES)) { 76*8e33eff8Schristos return LARGE_MAXCLASS + PAGE; 77*8e33eff8Schristos } 78*8e33eff8Schristos { 79*8e33eff8Schristos size_t grp = pind >> LG_SIZE_CLASS_GROUP; 80*8e33eff8Schristos size_t mod = pind & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); 81*8e33eff8Schristos 82*8e33eff8Schristos size_t grp_size_mask = ~((!!grp)-1); 83*8e33eff8Schristos size_t grp_size = ((ZU(1) << (LG_PAGE + 84*8e33eff8Schristos (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; 85*8e33eff8Schristos 86*8e33eff8Schristos size_t shift = (grp == 0) ? 1 : grp; 87*8e33eff8Schristos size_t lg_delta = shift + (LG_PAGE-1); 88*8e33eff8Schristos size_t mod_size = (mod+1) << lg_delta; 89*8e33eff8Schristos 90*8e33eff8Schristos size_t sz = grp_size + mod_size; 91*8e33eff8Schristos return sz; 92*8e33eff8Schristos } 93*8e33eff8Schristos } 94*8e33eff8Schristos 95*8e33eff8Schristos static inline size_t 96*8e33eff8Schristos sz_pind2sz_lookup(pszind_t pind) { 97*8e33eff8Schristos size_t ret = (size_t)sz_pind2sz_tab[pind]; 98*8e33eff8Schristos assert(ret == sz_pind2sz_compute(pind)); 99*8e33eff8Schristos return ret; 100*8e33eff8Schristos } 101*8e33eff8Schristos 102*8e33eff8Schristos static inline size_t 103*8e33eff8Schristos sz_pind2sz(pszind_t pind) { 104*8e33eff8Schristos assert(pind < NPSIZES+1); 105*8e33eff8Schristos return sz_pind2sz_lookup(pind); 106*8e33eff8Schristos } 107*8e33eff8Schristos 108*8e33eff8Schristos static inline size_t 109*8e33eff8Schristos sz_psz2u(size_t psz) { 110*8e33eff8Schristos if (unlikely(psz > LARGE_MAXCLASS)) { 111*8e33eff8Schristos return LARGE_MAXCLASS + PAGE; 112*8e33eff8Schristos } 113*8e33eff8Schristos { 114*8e33eff8Schristos size_t x = lg_floor((psz<<1)-1); 115*8e33eff8Schristos size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_PAGE + 1) ? 116*8e33eff8Schristos LG_PAGE : x - LG_SIZE_CLASS_GROUP - 1; 117*8e33eff8Schristos size_t delta = ZU(1) << lg_delta; 118*8e33eff8Schristos size_t delta_mask = delta - 1; 119*8e33eff8Schristos size_t usize = (psz + delta_mask) & ~delta_mask; 120*8e33eff8Schristos return usize; 121*8e33eff8Schristos } 122*8e33eff8Schristos } 123*8e33eff8Schristos 124*8e33eff8Schristos static inline szind_t 125*8e33eff8Schristos sz_size2index_compute(size_t size) { 126*8e33eff8Schristos if (unlikely(size > LARGE_MAXCLASS)) { 127*8e33eff8Schristos return NSIZES; 128*8e33eff8Schristos } 129*8e33eff8Schristos #if (NTBINS != 0) 130*8e33eff8Schristos if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { 131*8e33eff8Schristos szind_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; 132*8e33eff8Schristos szind_t lg_ceil = lg_floor(pow2_ceil_zu(size)); 133*8e33eff8Schristos return (lg_ceil < lg_tmin ? 0 : lg_ceil - lg_tmin); 134*8e33eff8Schristos } 135*8e33eff8Schristos #endif 136*8e33eff8Schristos { 137*8e33eff8Schristos szind_t x = lg_floor((size<<1)-1); 138*8e33eff8Schristos szind_t shift = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM) ? 0 : 139*8e33eff8Schristos x - (LG_SIZE_CLASS_GROUP + LG_QUANTUM); 140*8e33eff8Schristos szind_t grp = shift << LG_SIZE_CLASS_GROUP; 141*8e33eff8Schristos 142*8e33eff8Schristos szind_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) 143*8e33eff8Schristos ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; 144*8e33eff8Schristos 145*8e33eff8Schristos size_t delta_inverse_mask = ZU(-1) << lg_delta; 146*8e33eff8Schristos szind_t mod = ((((size-1) & delta_inverse_mask) >> lg_delta)) & 147*8e33eff8Schristos ((ZU(1) << LG_SIZE_CLASS_GROUP) - 1); 148*8e33eff8Schristos 149*8e33eff8Schristos szind_t index = NTBINS + grp + mod; 150*8e33eff8Schristos return index; 151*8e33eff8Schristos } 152*8e33eff8Schristos } 153*8e33eff8Schristos 154*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE szind_t 155*8e33eff8Schristos sz_size2index_lookup(size_t size) { 156*8e33eff8Schristos assert(size <= LOOKUP_MAXCLASS); 157*8e33eff8Schristos { 158*8e33eff8Schristos szind_t ret = (sz_size2index_tab[(size-1) >> LG_TINY_MIN]); 159*8e33eff8Schristos assert(ret == sz_size2index_compute(size)); 160*8e33eff8Schristos return ret; 161*8e33eff8Schristos } 162*8e33eff8Schristos } 163*8e33eff8Schristos 164*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE szind_t 165*8e33eff8Schristos sz_size2index(size_t size) { 166*8e33eff8Schristos assert(size > 0); 167*8e33eff8Schristos if (likely(size <= LOOKUP_MAXCLASS)) { 168*8e33eff8Schristos return sz_size2index_lookup(size); 169*8e33eff8Schristos } 170*8e33eff8Schristos return sz_size2index_compute(size); 171*8e33eff8Schristos } 172*8e33eff8Schristos 173*8e33eff8Schristos static inline size_t 174*8e33eff8Schristos sz_index2size_compute(szind_t index) { 175*8e33eff8Schristos #if (NTBINS > 0) 176*8e33eff8Schristos if (index < NTBINS) { 177*8e33eff8Schristos return (ZU(1) << (LG_TINY_MAXCLASS - NTBINS + 1 + index)); 178*8e33eff8Schristos } 179*8e33eff8Schristos #endif 180*8e33eff8Schristos { 181*8e33eff8Schristos size_t reduced_index = index - NTBINS; 182*8e33eff8Schristos size_t grp = reduced_index >> LG_SIZE_CLASS_GROUP; 183*8e33eff8Schristos size_t mod = reduced_index & ((ZU(1) << LG_SIZE_CLASS_GROUP) - 184*8e33eff8Schristos 1); 185*8e33eff8Schristos 186*8e33eff8Schristos size_t grp_size_mask = ~((!!grp)-1); 187*8e33eff8Schristos size_t grp_size = ((ZU(1) << (LG_QUANTUM + 188*8e33eff8Schristos (LG_SIZE_CLASS_GROUP-1))) << grp) & grp_size_mask; 189*8e33eff8Schristos 190*8e33eff8Schristos size_t shift = (grp == 0) ? 1 : grp; 191*8e33eff8Schristos size_t lg_delta = shift + (LG_QUANTUM-1); 192*8e33eff8Schristos size_t mod_size = (mod+1) << lg_delta; 193*8e33eff8Schristos 194*8e33eff8Schristos size_t usize = grp_size + mod_size; 195*8e33eff8Schristos return usize; 196*8e33eff8Schristos } 197*8e33eff8Schristos } 198*8e33eff8Schristos 199*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE size_t 200*8e33eff8Schristos sz_index2size_lookup(szind_t index) { 201*8e33eff8Schristos size_t ret = (size_t)sz_index2size_tab[index]; 202*8e33eff8Schristos assert(ret == sz_index2size_compute(index)); 203*8e33eff8Schristos return ret; 204*8e33eff8Schristos } 205*8e33eff8Schristos 206*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE size_t 207*8e33eff8Schristos sz_index2size(szind_t index) { 208*8e33eff8Schristos assert(index < NSIZES); 209*8e33eff8Schristos return sz_index2size_lookup(index); 210*8e33eff8Schristos } 211*8e33eff8Schristos 212*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE size_t 213*8e33eff8Schristos sz_s2u_compute(size_t size) { 214*8e33eff8Schristos if (unlikely(size > LARGE_MAXCLASS)) { 215*8e33eff8Schristos return 0; 216*8e33eff8Schristos } 217*8e33eff8Schristos #if (NTBINS > 0) 218*8e33eff8Schristos if (size <= (ZU(1) << LG_TINY_MAXCLASS)) { 219*8e33eff8Schristos size_t lg_tmin = LG_TINY_MAXCLASS - NTBINS + 1; 220*8e33eff8Schristos size_t lg_ceil = lg_floor(pow2_ceil_zu(size)); 221*8e33eff8Schristos return (lg_ceil < lg_tmin ? (ZU(1) << lg_tmin) : 222*8e33eff8Schristos (ZU(1) << lg_ceil)); 223*8e33eff8Schristos } 224*8e33eff8Schristos #endif 225*8e33eff8Schristos { 226*8e33eff8Schristos size_t x = lg_floor((size<<1)-1); 227*8e33eff8Schristos size_t lg_delta = (x < LG_SIZE_CLASS_GROUP + LG_QUANTUM + 1) 228*8e33eff8Schristos ? LG_QUANTUM : x - LG_SIZE_CLASS_GROUP - 1; 229*8e33eff8Schristos size_t delta = ZU(1) << lg_delta; 230*8e33eff8Schristos size_t delta_mask = delta - 1; 231*8e33eff8Schristos size_t usize = (size + delta_mask) & ~delta_mask; 232*8e33eff8Schristos return usize; 233*8e33eff8Schristos } 234*8e33eff8Schristos } 235*8e33eff8Schristos 236*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE size_t 237*8e33eff8Schristos sz_s2u_lookup(size_t size) { 238*8e33eff8Schristos size_t ret = sz_index2size_lookup(sz_size2index_lookup(size)); 239*8e33eff8Schristos 240*8e33eff8Schristos assert(ret == sz_s2u_compute(size)); 241*8e33eff8Schristos return ret; 242*8e33eff8Schristos } 243*8e33eff8Schristos 244*8e33eff8Schristos /* 245*8e33eff8Schristos * Compute usable size that would result from allocating an object with the 246*8e33eff8Schristos * specified size. 247*8e33eff8Schristos */ 248*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE size_t 249*8e33eff8Schristos sz_s2u(size_t size) { 250*8e33eff8Schristos assert(size > 0); 251*8e33eff8Schristos if (likely(size <= LOOKUP_MAXCLASS)) { 252*8e33eff8Schristos return sz_s2u_lookup(size); 253*8e33eff8Schristos } 254*8e33eff8Schristos return sz_s2u_compute(size); 255*8e33eff8Schristos } 256*8e33eff8Schristos 257*8e33eff8Schristos /* 258*8e33eff8Schristos * Compute usable size that would result from allocating an object with the 259*8e33eff8Schristos * specified size and alignment. 260*8e33eff8Schristos */ 261*8e33eff8Schristos JEMALLOC_ALWAYS_INLINE size_t 262*8e33eff8Schristos sz_sa2u(size_t size, size_t alignment) { 263*8e33eff8Schristos size_t usize; 264*8e33eff8Schristos 265*8e33eff8Schristos assert(alignment != 0 && ((alignment - 1) & alignment) == 0); 266*8e33eff8Schristos 267*8e33eff8Schristos /* Try for a small size class. */ 268*8e33eff8Schristos if (size <= SMALL_MAXCLASS && alignment < PAGE) { 269*8e33eff8Schristos /* 270*8e33eff8Schristos * Round size up to the nearest multiple of alignment. 271*8e33eff8Schristos * 272*8e33eff8Schristos * This done, we can take advantage of the fact that for each 273*8e33eff8Schristos * small size class, every object is aligned at the smallest 274*8e33eff8Schristos * power of two that is non-zero in the base two representation 275*8e33eff8Schristos * of the size. For example: 276*8e33eff8Schristos * 277*8e33eff8Schristos * Size | Base 2 | Minimum alignment 278*8e33eff8Schristos * -----+----------+------------------ 279*8e33eff8Schristos * 96 | 1100000 | 32 280*8e33eff8Schristos * 144 | 10100000 | 32 281*8e33eff8Schristos * 192 | 11000000 | 64 282*8e33eff8Schristos */ 283*8e33eff8Schristos usize = sz_s2u(ALIGNMENT_CEILING(size, alignment)); 284*8e33eff8Schristos if (usize < LARGE_MINCLASS) { 285*8e33eff8Schristos return usize; 286*8e33eff8Schristos } 287*8e33eff8Schristos } 288*8e33eff8Schristos 289*8e33eff8Schristos /* Large size class. Beware of overflow. */ 290*8e33eff8Schristos 291*8e33eff8Schristos if (unlikely(alignment > LARGE_MAXCLASS)) { 292*8e33eff8Schristos return 0; 293*8e33eff8Schristos } 294*8e33eff8Schristos 295*8e33eff8Schristos /* Make sure result is a large size class. */ 296*8e33eff8Schristos if (size <= LARGE_MINCLASS) { 297*8e33eff8Schristos usize = LARGE_MINCLASS; 298*8e33eff8Schristos } else { 299*8e33eff8Schristos usize = sz_s2u(size); 300*8e33eff8Schristos if (usize < size) { 301*8e33eff8Schristos /* size_t overflow. */ 302*8e33eff8Schristos return 0; 303*8e33eff8Schristos } 304*8e33eff8Schristos } 305*8e33eff8Schristos 306*8e33eff8Schristos /* 307*8e33eff8Schristos * Calculate the multi-page mapping that large_palloc() would need in 308*8e33eff8Schristos * order to guarantee the alignment. 309*8e33eff8Schristos */ 310*8e33eff8Schristos if (usize + sz_large_pad + PAGE_CEILING(alignment) - PAGE < usize) { 311*8e33eff8Schristos /* size_t overflow. */ 312*8e33eff8Schristos return 0; 313*8e33eff8Schristos } 314*8e33eff8Schristos return usize; 315*8e33eff8Schristos } 316*8e33eff8Schristos 317*8e33eff8Schristos #endif /* JEMALLOC_INTERNAL_SIZE_H */ 318