xref: /netbsd-src/external/bsd/jemalloc.old/include/jemalloc/internal/sz.h (revision 8e33eff89e26cf71871ead62f0d5063e1313c33a)
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