xref: /freebsd/contrib/jemalloc/include/jemalloc/internal/rtree.h (revision c5ad81420c495d1d5de04209b0ec4fcb435c322c)
1b7eaed25SJason Evans #ifndef JEMALLOC_INTERNAL_RTREE_H
2b7eaed25SJason Evans #define JEMALLOC_INTERNAL_RTREE_H
3b7eaed25SJason Evans 
4b7eaed25SJason Evans #include "jemalloc/internal/atomic.h"
5b7eaed25SJason Evans #include "jemalloc/internal/mutex.h"
6b7eaed25SJason Evans #include "jemalloc/internal/rtree_tsd.h"
7*c5ad8142SEric van Gyzen #include "jemalloc/internal/sc.h"
8b7eaed25SJason Evans #include "jemalloc/internal/tsd.h"
9b7eaed25SJason Evans 
10a4bd5210SJason Evans /*
11a4bd5210SJason Evans  * This radix tree implementation is tailored to the singular purpose of
12b7eaed25SJason Evans  * associating metadata with extents that are currently owned by jemalloc.
13a4bd5210SJason Evans  *
14a4bd5210SJason Evans  *******************************************************************************
15a4bd5210SJason Evans  */
16b7eaed25SJason Evans 
17b7eaed25SJason Evans /* Number of high insignificant bits. */
18b7eaed25SJason Evans #define RTREE_NHIB ((1U << (LG_SIZEOF_PTR+3)) - LG_VADDR)
19b7eaed25SJason Evans /* Number of low insigificant bits. */
20b7eaed25SJason Evans #define RTREE_NLIB LG_PAGE
21b7eaed25SJason Evans /* Number of significant bits. */
22b7eaed25SJason Evans #define RTREE_NSB (LG_VADDR - RTREE_NLIB)
23b7eaed25SJason Evans /* Number of levels in radix tree. */
24b7eaed25SJason Evans #if RTREE_NSB <= 10
25b7eaed25SJason Evans #  define RTREE_HEIGHT 1
26b7eaed25SJason Evans #elif RTREE_NSB <= 36
27b7eaed25SJason Evans #  define RTREE_HEIGHT 2
28b7eaed25SJason Evans #elif RTREE_NSB <= 52
29b7eaed25SJason Evans #  define RTREE_HEIGHT 3
30b7eaed25SJason Evans #else
31b7eaed25SJason Evans #  error Unsupported number of significant virtual address bits
32b7eaed25SJason Evans #endif
33b7eaed25SJason Evans /* Use compact leaf representation if virtual address encoding allows. */
34*c5ad8142SEric van Gyzen #if RTREE_NHIB >= LG_CEIL(SC_NSIZES)
35b7eaed25SJason Evans #  define RTREE_LEAF_COMPACT
36b7eaed25SJason Evans #endif
37b7eaed25SJason Evans 
38b7eaed25SJason Evans /* Needed for initialization only. */
39b7eaed25SJason Evans #define RTREE_LEAFKEY_INVALID ((uintptr_t)1)
40a4bd5210SJason Evans 
41d0e79aa3SJason Evans typedef struct rtree_node_elm_s rtree_node_elm_t;
42d0e79aa3SJason Evans struct rtree_node_elm_s {
43b7eaed25SJason Evans 	atomic_p_t	child; /* (rtree_{node,leaf}_elm_t *) */
44d0e79aa3SJason Evans };
45d0e79aa3SJason Evans 
46b7eaed25SJason Evans struct rtree_leaf_elm_s {
47b7eaed25SJason Evans #ifdef RTREE_LEAF_COMPACT
48d0e79aa3SJason Evans 	/*
49b7eaed25SJason Evans 	 * Single pointer-width field containing all three leaf element fields.
50b7eaed25SJason Evans 	 * For example, on a 64-bit x64 system with 48 significant virtual
51b7eaed25SJason Evans 	 * memory address bits, the index, extent, and slab fields are packed as
52b7eaed25SJason Evans 	 * such:
53d0e79aa3SJason Evans 	 *
54b7eaed25SJason Evans 	 * x: index
55b7eaed25SJason Evans 	 * e: extent
56b7eaed25SJason Evans 	 * b: slab
57d0e79aa3SJason Evans 	 *
58b7eaed25SJason Evans 	 *   00000000 xxxxxxxx eeeeeeee [...] eeeeeeee eeee000b
59d0e79aa3SJason Evans 	 */
60b7eaed25SJason Evans 	atomic_p_t	le_bits;
61b7eaed25SJason Evans #else
62b7eaed25SJason Evans 	atomic_p_t	le_extent; /* (extent_t *) */
63b7eaed25SJason Evans 	atomic_u_t	le_szind; /* (szind_t) */
64b7eaed25SJason Evans 	atomic_b_t	le_slab; /* (bool) */
65b7eaed25SJason Evans #endif
66d0e79aa3SJason Evans };
67b7eaed25SJason Evans 
68b7eaed25SJason Evans typedef struct rtree_level_s rtree_level_t;
69b7eaed25SJason Evans struct rtree_level_s {
70d0e79aa3SJason Evans 	/* Number of key bits distinguished by this level. */
71d0e79aa3SJason Evans 	unsigned		bits;
72d0e79aa3SJason Evans 	/*
73d0e79aa3SJason Evans 	 * Cumulative number of key bits distinguished by traversing to
74d0e79aa3SJason Evans 	 * corresponding tree level.
75d0e79aa3SJason Evans 	 */
76d0e79aa3SJason Evans 	unsigned		cumbits;
77d0e79aa3SJason Evans };
78d0e79aa3SJason Evans 
79b7eaed25SJason Evans typedef struct rtree_s rtree_t;
80a4bd5210SJason Evans struct rtree_s {
81b7eaed25SJason Evans 	malloc_mutex_t		init_lock;
82b7eaed25SJason Evans 	/* Number of elements based on rtree_levels[0].bits. */
83b7eaed25SJason Evans #if RTREE_HEIGHT > 1
84b7eaed25SJason Evans 	rtree_node_elm_t	root[1U << (RTREE_NSB/RTREE_HEIGHT)];
85b7eaed25SJason Evans #else
86b7eaed25SJason Evans 	rtree_leaf_elm_t	root[1U << (RTREE_NSB/RTREE_HEIGHT)];
87b7eaed25SJason Evans #endif
88a4bd5210SJason Evans };
89a4bd5210SJason Evans 
90b7eaed25SJason Evans /*
91b7eaed25SJason Evans  * Split the bits into one to three partitions depending on number of
92b7eaed25SJason Evans  * significant bits.  It the number of bits does not divide evenly into the
93b7eaed25SJason Evans  * number of levels, place one remainder bit per level starting at the leaf
94b7eaed25SJason Evans  * level.
95b7eaed25SJason Evans  */
96b7eaed25SJason Evans static const rtree_level_t rtree_levels[] = {
97b7eaed25SJason Evans #if RTREE_HEIGHT == 1
98b7eaed25SJason Evans 	{RTREE_NSB, RTREE_NHIB + RTREE_NSB}
99b7eaed25SJason Evans #elif RTREE_HEIGHT == 2
100b7eaed25SJason Evans 	{RTREE_NSB/2, RTREE_NHIB + RTREE_NSB/2},
101b7eaed25SJason Evans 	{RTREE_NSB/2 + RTREE_NSB%2, RTREE_NHIB + RTREE_NSB}
102b7eaed25SJason Evans #elif RTREE_HEIGHT == 3
103b7eaed25SJason Evans 	{RTREE_NSB/3, RTREE_NHIB + RTREE_NSB/3},
104b7eaed25SJason Evans 	{RTREE_NSB/3 + RTREE_NSB%3/2,
105b7eaed25SJason Evans 	    RTREE_NHIB + RTREE_NSB/3*2 + RTREE_NSB%3/2},
106b7eaed25SJason Evans 	{RTREE_NSB/3 + RTREE_NSB%3 - RTREE_NSB%3/2, RTREE_NHIB + RTREE_NSB}
107b7eaed25SJason Evans #else
108b7eaed25SJason Evans #  error Unsupported rtree height
109a4bd5210SJason Evans #endif
110b7eaed25SJason Evans };
111a4bd5210SJason Evans 
112b7eaed25SJason Evans bool rtree_new(rtree_t *rtree, bool zeroed);
113d0e79aa3SJason Evans 
114b7eaed25SJason Evans typedef rtree_node_elm_t *(rtree_node_alloc_t)(tsdn_t *, rtree_t *, size_t);
115b7eaed25SJason Evans extern rtree_node_alloc_t *JET_MUTABLE rtree_node_alloc;
116d0e79aa3SJason Evans 
117b7eaed25SJason Evans typedef rtree_leaf_elm_t *(rtree_leaf_alloc_t)(tsdn_t *, rtree_t *, size_t);
118b7eaed25SJason Evans extern rtree_leaf_alloc_t *JET_MUTABLE rtree_leaf_alloc;
119b7eaed25SJason Evans 
120b7eaed25SJason Evans typedef void (rtree_node_dalloc_t)(tsdn_t *, rtree_t *, rtree_node_elm_t *);
121b7eaed25SJason Evans extern rtree_node_dalloc_t *JET_MUTABLE rtree_node_dalloc;
122b7eaed25SJason Evans 
123b7eaed25SJason Evans typedef void (rtree_leaf_dalloc_t)(tsdn_t *, rtree_t *, rtree_leaf_elm_t *);
124b7eaed25SJason Evans extern rtree_leaf_dalloc_t *JET_MUTABLE rtree_leaf_dalloc;
125b7eaed25SJason Evans #ifdef JEMALLOC_JET
126b7eaed25SJason Evans void rtree_delete(tsdn_t *tsdn, rtree_t *rtree);
127b7eaed25SJason Evans #endif
128b7eaed25SJason Evans rtree_leaf_elm_t *rtree_leaf_elm_lookup_hard(tsdn_t *tsdn, rtree_t *rtree,
129b7eaed25SJason Evans     rtree_ctx_t *rtree_ctx, uintptr_t key, bool dependent, bool init_missing);
130b7eaed25SJason Evans 
131b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE uintptr_t
rtree_leafkey(uintptr_t key)132b7eaed25SJason Evans rtree_leafkey(uintptr_t key) {
133b7eaed25SJason Evans 	unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3);
134b7eaed25SJason Evans 	unsigned cumbits = (rtree_levels[RTREE_HEIGHT-1].cumbits -
135b7eaed25SJason Evans 	    rtree_levels[RTREE_HEIGHT-1].bits);
136b7eaed25SJason Evans 	unsigned maskbits = ptrbits - cumbits;
137b7eaed25SJason Evans 	uintptr_t mask = ~((ZU(1) << maskbits) - 1);
138b7eaed25SJason Evans 	return (key & mask);
139b7eaed25SJason Evans }
140b7eaed25SJason Evans 
141b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE size_t
rtree_cache_direct_map(uintptr_t key)142b7eaed25SJason Evans rtree_cache_direct_map(uintptr_t key) {
143b7eaed25SJason Evans 	unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3);
144b7eaed25SJason Evans 	unsigned cumbits = (rtree_levels[RTREE_HEIGHT-1].cumbits -
145b7eaed25SJason Evans 	    rtree_levels[RTREE_HEIGHT-1].bits);
146b7eaed25SJason Evans 	unsigned maskbits = ptrbits - cumbits;
147b7eaed25SJason Evans 	return (size_t)((key >> maskbits) & (RTREE_CTX_NCACHE - 1));
148a4bd5210SJason Evans }
149a4bd5210SJason Evans 
1501f0a49e8SJason Evans JEMALLOC_ALWAYS_INLINE uintptr_t
rtree_subkey(uintptr_t key,unsigned level)151b7eaed25SJason Evans rtree_subkey(uintptr_t key, unsigned level) {
152b7eaed25SJason Evans 	unsigned ptrbits = ZU(1) << (LG_SIZEOF_PTR+3);
153b7eaed25SJason Evans 	unsigned cumbits = rtree_levels[level].cumbits;
154b7eaed25SJason Evans 	unsigned shiftbits = ptrbits - cumbits;
155b7eaed25SJason Evans 	unsigned maskbits = rtree_levels[level].bits;
156b7eaed25SJason Evans 	uintptr_t mask = (ZU(1) << maskbits) - 1;
157b7eaed25SJason Evans 	return ((key >> shiftbits) & mask);
158d0e79aa3SJason Evans }
159a4bd5210SJason Evans 
160d0e79aa3SJason Evans /*
161b7eaed25SJason Evans  * Atomic getters.
162b7eaed25SJason Evans  *
163b7eaed25SJason Evans  * dependent: Reading a value on behalf of a pointer to a valid allocation
164b7eaed25SJason Evans  *            is guaranteed to be a clean read even without synchronization,
165d0e79aa3SJason Evans  *            because the rtree update became visible in memory before the
166d0e79aa3SJason Evans  *            pointer came into existence.
167b7eaed25SJason Evans  * !dependent: An arbitrary read, e.g. on behalf of ivsalloc(), may not be
168d0e79aa3SJason Evans  *             dependent on a previous rtree write, which means a stale read
169d0e79aa3SJason Evans  *             could result if synchronization were omitted here.
170d0e79aa3SJason Evans  */
171b7eaed25SJason Evans #  ifdef RTREE_LEAF_COMPACT
172b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE uintptr_t
rtree_leaf_elm_bits_read(tsdn_t * tsdn,rtree_t * rtree,rtree_leaf_elm_t * elm,bool dependent)173*c5ad8142SEric van Gyzen rtree_leaf_elm_bits_read(tsdn_t *tsdn, rtree_t *rtree,
174*c5ad8142SEric van Gyzen     rtree_leaf_elm_t *elm, bool dependent) {
175b7eaed25SJason Evans 	return (uintptr_t)atomic_load_p(&elm->le_bits, dependent
176b7eaed25SJason Evans 	    ? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
177d0e79aa3SJason Evans }
178d0e79aa3SJason Evans 
179b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE extent_t *
rtree_leaf_elm_bits_extent_get(uintptr_t bits)180b7eaed25SJason Evans rtree_leaf_elm_bits_extent_get(uintptr_t bits) {
1810ef50b4eSJason Evans #    ifdef __aarch64__
1820ef50b4eSJason Evans 	/*
1830ef50b4eSJason Evans 	 * aarch64 doesn't sign extend the highest virtual address bit to set
1840ef50b4eSJason Evans 	 * the higher ones.  Instead, the high bits gets zeroed.
1850ef50b4eSJason Evans 	 */
1860ef50b4eSJason Evans 	uintptr_t high_bit_mask = ((uintptr_t)1 << LG_VADDR) - 1;
1870ef50b4eSJason Evans 	/* Mask off the slab bit. */
1880ef50b4eSJason Evans 	uintptr_t low_bit_mask = ~(uintptr_t)1;
1890ef50b4eSJason Evans 	uintptr_t mask = high_bit_mask & low_bit_mask;
1900ef50b4eSJason Evans 	return (extent_t *)(bits & mask);
1910ef50b4eSJason Evans #    else
192b7eaed25SJason Evans 	/* Restore sign-extended high bits, mask slab bit. */
193b7eaed25SJason Evans 	return (extent_t *)((uintptr_t)((intptr_t)(bits << RTREE_NHIB) >>
194b7eaed25SJason Evans 	    RTREE_NHIB) & ~((uintptr_t)0x1));
1950ef50b4eSJason Evans #    endif
196d0e79aa3SJason Evans }
197d0e79aa3SJason Evans 
198b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE szind_t
rtree_leaf_elm_bits_szind_get(uintptr_t bits)199b7eaed25SJason Evans rtree_leaf_elm_bits_szind_get(uintptr_t bits) {
200b7eaed25SJason Evans 	return (szind_t)(bits >> LG_VADDR);
201d0e79aa3SJason Evans }
202d0e79aa3SJason Evans 
203b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool
rtree_leaf_elm_bits_slab_get(uintptr_t bits)204b7eaed25SJason Evans rtree_leaf_elm_bits_slab_get(uintptr_t bits) {
205b7eaed25SJason Evans 	return (bool)(bits & (uintptr_t)0x1);
206d0e79aa3SJason Evans }
207d0e79aa3SJason Evans 
208b7eaed25SJason Evans #  endif
209a4bd5210SJason Evans 
210b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE extent_t *
rtree_leaf_elm_extent_read(tsdn_t * tsdn,rtree_t * rtree,rtree_leaf_elm_t * elm,bool dependent)211*c5ad8142SEric van Gyzen rtree_leaf_elm_extent_read(tsdn_t *tsdn, rtree_t *rtree,
2120ef50b4eSJason Evans     rtree_leaf_elm_t *elm, bool dependent) {
213b7eaed25SJason Evans #ifdef RTREE_LEAF_COMPACT
214b7eaed25SJason Evans 	uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
215b7eaed25SJason Evans 	return rtree_leaf_elm_bits_extent_get(bits);
216b7eaed25SJason Evans #else
217b7eaed25SJason Evans 	extent_t *extent = (extent_t *)atomic_load_p(&elm->le_extent, dependent
218b7eaed25SJason Evans 	    ? ATOMIC_RELAXED : ATOMIC_ACQUIRE);
219b7eaed25SJason Evans 	return extent;
2201f0a49e8SJason Evans #endif
221d0e79aa3SJason Evans }
222d0e79aa3SJason Evans 
223b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE szind_t
rtree_leaf_elm_szind_read(tsdn_t * tsdn,rtree_t * rtree,rtree_leaf_elm_t * elm,bool dependent)224*c5ad8142SEric van Gyzen rtree_leaf_elm_szind_read(tsdn_t *tsdn, rtree_t *rtree,
2250ef50b4eSJason Evans     rtree_leaf_elm_t *elm, bool dependent) {
226b7eaed25SJason Evans #ifdef RTREE_LEAF_COMPACT
227b7eaed25SJason Evans 	uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
228b7eaed25SJason Evans 	return rtree_leaf_elm_bits_szind_get(bits);
229b7eaed25SJason Evans #else
230b7eaed25SJason Evans 	return (szind_t)atomic_load_u(&elm->le_szind, dependent ? ATOMIC_RELAXED
231b7eaed25SJason Evans 	    : ATOMIC_ACQUIRE);
232b7eaed25SJason Evans #endif
233b7eaed25SJason Evans }
234d0e79aa3SJason Evans 
235b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool
rtree_leaf_elm_slab_read(tsdn_t * tsdn,rtree_t * rtree,rtree_leaf_elm_t * elm,bool dependent)236*c5ad8142SEric van Gyzen rtree_leaf_elm_slab_read(tsdn_t *tsdn, rtree_t *rtree,
2370ef50b4eSJason Evans     rtree_leaf_elm_t *elm, bool dependent) {
238b7eaed25SJason Evans #ifdef RTREE_LEAF_COMPACT
239b7eaed25SJason Evans 	uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
240b7eaed25SJason Evans 	return rtree_leaf_elm_bits_slab_get(bits);
241b7eaed25SJason Evans #else
242b7eaed25SJason Evans 	return atomic_load_b(&elm->le_slab, dependent ? ATOMIC_RELAXED :
243b7eaed25SJason Evans 	    ATOMIC_ACQUIRE);
244b7eaed25SJason Evans #endif
245b7eaed25SJason Evans }
246d0e79aa3SJason Evans 
247b7eaed25SJason Evans static inline void
rtree_leaf_elm_extent_write(tsdn_t * tsdn,rtree_t * rtree,rtree_leaf_elm_t * elm,extent_t * extent)248*c5ad8142SEric van Gyzen rtree_leaf_elm_extent_write(tsdn_t *tsdn, rtree_t *rtree,
2490ef50b4eSJason Evans     rtree_leaf_elm_t *elm, extent_t *extent) {
250b7eaed25SJason Evans #ifdef RTREE_LEAF_COMPACT
251b7eaed25SJason Evans 	uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, true);
252b7eaed25SJason Evans 	uintptr_t bits = ((uintptr_t)rtree_leaf_elm_bits_szind_get(old_bits) <<
253b7eaed25SJason Evans 	    LG_VADDR) | ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1))
254b7eaed25SJason Evans 	    | ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits));
255b7eaed25SJason Evans 	atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE);
256b7eaed25SJason Evans #else
257b7eaed25SJason Evans 	atomic_store_p(&elm->le_extent, extent, ATOMIC_RELEASE);
258b7eaed25SJason Evans #endif
259b7eaed25SJason Evans }
260b7eaed25SJason Evans 
261b7eaed25SJason Evans static inline void
rtree_leaf_elm_szind_write(tsdn_t * tsdn,rtree_t * rtree,rtree_leaf_elm_t * elm,szind_t szind)262*c5ad8142SEric van Gyzen rtree_leaf_elm_szind_write(tsdn_t *tsdn, rtree_t *rtree,
2630ef50b4eSJason Evans     rtree_leaf_elm_t *elm, szind_t szind) {
264*c5ad8142SEric van Gyzen 	assert(szind <= SC_NSIZES);
265b7eaed25SJason Evans 
266b7eaed25SJason Evans #ifdef RTREE_LEAF_COMPACT
267b7eaed25SJason Evans 	uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm,
268b7eaed25SJason Evans 	    true);
269b7eaed25SJason Evans 	uintptr_t bits = ((uintptr_t)szind << LG_VADDR) |
270b7eaed25SJason Evans 	    ((uintptr_t)rtree_leaf_elm_bits_extent_get(old_bits) &
271b7eaed25SJason Evans 	    (((uintptr_t)0x1 << LG_VADDR) - 1)) |
272b7eaed25SJason Evans 	    ((uintptr_t)rtree_leaf_elm_bits_slab_get(old_bits));
273b7eaed25SJason Evans 	atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE);
274b7eaed25SJason Evans #else
275b7eaed25SJason Evans 	atomic_store_u(&elm->le_szind, szind, ATOMIC_RELEASE);
276b7eaed25SJason Evans #endif
277b7eaed25SJason Evans }
278b7eaed25SJason Evans 
279b7eaed25SJason Evans static inline void
rtree_leaf_elm_slab_write(tsdn_t * tsdn,rtree_t * rtree,rtree_leaf_elm_t * elm,bool slab)280*c5ad8142SEric van Gyzen rtree_leaf_elm_slab_write(tsdn_t *tsdn, rtree_t *rtree,
2810ef50b4eSJason Evans     rtree_leaf_elm_t *elm, bool slab) {
282b7eaed25SJason Evans #ifdef RTREE_LEAF_COMPACT
283b7eaed25SJason Evans 	uintptr_t old_bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm,
284b7eaed25SJason Evans 	    true);
285b7eaed25SJason Evans 	uintptr_t bits = ((uintptr_t)rtree_leaf_elm_bits_szind_get(old_bits) <<
286b7eaed25SJason Evans 	    LG_VADDR) | ((uintptr_t)rtree_leaf_elm_bits_extent_get(old_bits) &
287b7eaed25SJason Evans 	    (((uintptr_t)0x1 << LG_VADDR) - 1)) | ((uintptr_t)slab);
288b7eaed25SJason Evans 	atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE);
289b7eaed25SJason Evans #else
290b7eaed25SJason Evans 	atomic_store_b(&elm->le_slab, slab, ATOMIC_RELEASE);
291b7eaed25SJason Evans #endif
292b7eaed25SJason Evans }
293b7eaed25SJason Evans 
294b7eaed25SJason Evans static inline void
rtree_leaf_elm_write(tsdn_t * tsdn,rtree_t * rtree,rtree_leaf_elm_t * elm,extent_t * extent,szind_t szind,bool slab)295*c5ad8142SEric van Gyzen rtree_leaf_elm_write(tsdn_t *tsdn, rtree_t *rtree,
296*c5ad8142SEric van Gyzen     rtree_leaf_elm_t *elm, extent_t *extent, szind_t szind, bool slab) {
297b7eaed25SJason Evans #ifdef RTREE_LEAF_COMPACT
298b7eaed25SJason Evans 	uintptr_t bits = ((uintptr_t)szind << LG_VADDR) |
299b7eaed25SJason Evans 	    ((uintptr_t)extent & (((uintptr_t)0x1 << LG_VADDR) - 1)) |
300b7eaed25SJason Evans 	    ((uintptr_t)slab);
301b7eaed25SJason Evans 	atomic_store_p(&elm->le_bits, (void *)bits, ATOMIC_RELEASE);
302b7eaed25SJason Evans #else
303b7eaed25SJason Evans 	rtree_leaf_elm_slab_write(tsdn, rtree, elm, slab);
304b7eaed25SJason Evans 	rtree_leaf_elm_szind_write(tsdn, rtree, elm, szind);
305d0e79aa3SJason Evans 	/*
306b7eaed25SJason Evans 	 * Write extent last, since the element is atomically considered valid
307b7eaed25SJason Evans 	 * as soon as the extent field is non-NULL.
308d0e79aa3SJason Evans 	 */
309b7eaed25SJason Evans 	rtree_leaf_elm_extent_write(tsdn, rtree, elm, extent);
310a4bd5210SJason Evans #endif
311b7eaed25SJason Evans }
312a4bd5210SJason Evans 
313b7eaed25SJason Evans static inline void
rtree_leaf_elm_szind_slab_update(tsdn_t * tsdn,rtree_t * rtree,rtree_leaf_elm_t * elm,szind_t szind,bool slab)314b7eaed25SJason Evans rtree_leaf_elm_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree,
315b7eaed25SJason Evans     rtree_leaf_elm_t *elm, szind_t szind, bool slab) {
316*c5ad8142SEric van Gyzen 	assert(!slab || szind < SC_NBINS);
317b7eaed25SJason Evans 
318b7eaed25SJason Evans 	/*
319b7eaed25SJason Evans 	 * The caller implicitly assures that it is the only writer to the szind
320b7eaed25SJason Evans 	 * and slab fields, and that the extent field cannot currently change.
321b7eaed25SJason Evans 	 */
322b7eaed25SJason Evans 	rtree_leaf_elm_slab_write(tsdn, rtree, elm, slab);
323b7eaed25SJason Evans 	rtree_leaf_elm_szind_write(tsdn, rtree, elm, szind);
324b7eaed25SJason Evans }
325b7eaed25SJason Evans 
326b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t *
rtree_leaf_elm_lookup(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key,bool dependent,bool init_missing)327b7eaed25SJason Evans rtree_leaf_elm_lookup(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
328b7eaed25SJason Evans     uintptr_t key, bool dependent, bool init_missing) {
329b7eaed25SJason Evans 	assert(key != 0);
330b7eaed25SJason Evans 	assert(!dependent || !init_missing);
331b7eaed25SJason Evans 
332b7eaed25SJason Evans 	size_t slot = rtree_cache_direct_map(key);
333b7eaed25SJason Evans 	uintptr_t leafkey = rtree_leafkey(key);
334b7eaed25SJason Evans 	assert(leafkey != RTREE_LEAFKEY_INVALID);
335b7eaed25SJason Evans 
336b7eaed25SJason Evans 	/* Fast path: L1 direct mapped cache. */
337b7eaed25SJason Evans 	if (likely(rtree_ctx->cache[slot].leafkey == leafkey)) {
338b7eaed25SJason Evans 		rtree_leaf_elm_t *leaf = rtree_ctx->cache[slot].leaf;
339b7eaed25SJason Evans 		assert(leaf != NULL);
340b7eaed25SJason Evans 		uintptr_t subkey = rtree_subkey(key, RTREE_HEIGHT-1);
341b7eaed25SJason Evans 		return &leaf[subkey];
342b7eaed25SJason Evans 	}
343b7eaed25SJason Evans 	/*
344b7eaed25SJason Evans 	 * Search the L2 LRU cache.  On hit, swap the matching element into the
345b7eaed25SJason Evans 	 * slot in L1 cache, and move the position in L2 up by 1.
346b7eaed25SJason Evans 	 */
347b7eaed25SJason Evans #define RTREE_CACHE_CHECK_L2(i) do {					\
348b7eaed25SJason Evans 	if (likely(rtree_ctx->l2_cache[i].leafkey == leafkey)) {	\
349b7eaed25SJason Evans 		rtree_leaf_elm_t *leaf = rtree_ctx->l2_cache[i].leaf;	\
350b7eaed25SJason Evans 		assert(leaf != NULL);					\
351b7eaed25SJason Evans 		if (i > 0) {						\
352b7eaed25SJason Evans 			/* Bubble up by one. */				\
353b7eaed25SJason Evans 			rtree_ctx->l2_cache[i].leafkey =		\
354b7eaed25SJason Evans 				rtree_ctx->l2_cache[i - 1].leafkey;	\
355b7eaed25SJason Evans 			rtree_ctx->l2_cache[i].leaf =			\
356b7eaed25SJason Evans 				rtree_ctx->l2_cache[i - 1].leaf;	\
357b7eaed25SJason Evans 			rtree_ctx->l2_cache[i - 1].leafkey =		\
358b7eaed25SJason Evans 			    rtree_ctx->cache[slot].leafkey;		\
359b7eaed25SJason Evans 			rtree_ctx->l2_cache[i - 1].leaf =		\
360b7eaed25SJason Evans 			    rtree_ctx->cache[slot].leaf;		\
361b7eaed25SJason Evans 		} else {						\
362b7eaed25SJason Evans 			rtree_ctx->l2_cache[0].leafkey =		\
363b7eaed25SJason Evans 			    rtree_ctx->cache[slot].leafkey;		\
364b7eaed25SJason Evans 			rtree_ctx->l2_cache[0].leaf =			\
365b7eaed25SJason Evans 			    rtree_ctx->cache[slot].leaf;		\
366b7eaed25SJason Evans 		}							\
367b7eaed25SJason Evans 		rtree_ctx->cache[slot].leafkey = leafkey;		\
368b7eaed25SJason Evans 		rtree_ctx->cache[slot].leaf = leaf;			\
369b7eaed25SJason Evans 		uintptr_t subkey = rtree_subkey(key, RTREE_HEIGHT-1);	\
370b7eaed25SJason Evans 		return &leaf[subkey];					\
371b7eaed25SJason Evans 	}								\
372b7eaed25SJason Evans } while (0)
373b7eaed25SJason Evans 	/* Check the first cache entry. */
374b7eaed25SJason Evans 	RTREE_CACHE_CHECK_L2(0);
375b7eaed25SJason Evans 	/* Search the remaining cache elements. */
376b7eaed25SJason Evans 	for (unsigned i = 1; i < RTREE_CTX_NCACHE_L2; i++) {
377b7eaed25SJason Evans 		RTREE_CACHE_CHECK_L2(i);
378b7eaed25SJason Evans 	}
379b7eaed25SJason Evans #undef RTREE_CACHE_CHECK_L2
380b7eaed25SJason Evans 
381b7eaed25SJason Evans 	return rtree_leaf_elm_lookup_hard(tsdn, rtree, rtree_ctx, key,
382b7eaed25SJason Evans 	    dependent, init_missing);
383b7eaed25SJason Evans }
384b7eaed25SJason Evans 
385b7eaed25SJason Evans static inline bool
rtree_write(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key,extent_t * extent,szind_t szind,bool slab)386b7eaed25SJason Evans rtree_write(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key,
387b7eaed25SJason Evans     extent_t *extent, szind_t szind, bool slab) {
388b7eaed25SJason Evans 	/* Use rtree_clear() to set the extent to NULL. */
389b7eaed25SJason Evans 	assert(extent != NULL);
390b7eaed25SJason Evans 
391b7eaed25SJason Evans 	rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
392b7eaed25SJason Evans 	    key, false, true);
393b7eaed25SJason Evans 	if (elm == NULL) {
394b7eaed25SJason Evans 		return true;
395b7eaed25SJason Evans 	}
396b7eaed25SJason Evans 
397b7eaed25SJason Evans 	assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false) == NULL);
398b7eaed25SJason Evans 	rtree_leaf_elm_write(tsdn, rtree, elm, extent, szind, slab);
399b7eaed25SJason Evans 
400b7eaed25SJason Evans 	return false;
401b7eaed25SJason Evans }
402b7eaed25SJason Evans 
403b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE rtree_leaf_elm_t *
rtree_read(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key,bool dependent)404b7eaed25SJason Evans rtree_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx, uintptr_t key,
405b7eaed25SJason Evans     bool dependent) {
406b7eaed25SJason Evans 	rtree_leaf_elm_t *elm = rtree_leaf_elm_lookup(tsdn, rtree, rtree_ctx,
407b7eaed25SJason Evans 	    key, dependent, false);
408b7eaed25SJason Evans 	if (!dependent && elm == NULL) {
409b7eaed25SJason Evans 		return NULL;
410b7eaed25SJason Evans 	}
411b7eaed25SJason Evans 	assert(elm != NULL);
412b7eaed25SJason Evans 	return elm;
413b7eaed25SJason Evans }
414b7eaed25SJason Evans 
415b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE extent_t *
rtree_extent_read(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key,bool dependent)416b7eaed25SJason Evans rtree_extent_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
417b7eaed25SJason Evans     uintptr_t key, bool dependent) {
418b7eaed25SJason Evans 	rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key,
419b7eaed25SJason Evans 	    dependent);
420b7eaed25SJason Evans 	if (!dependent && elm == NULL) {
421b7eaed25SJason Evans 		return NULL;
422b7eaed25SJason Evans 	}
423b7eaed25SJason Evans 	return rtree_leaf_elm_extent_read(tsdn, rtree, elm, dependent);
424b7eaed25SJason Evans }
425b7eaed25SJason Evans 
426b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE szind_t
rtree_szind_read(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key,bool dependent)427b7eaed25SJason Evans rtree_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
428b7eaed25SJason Evans     uintptr_t key, bool dependent) {
429b7eaed25SJason Evans 	rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key,
430b7eaed25SJason Evans 	    dependent);
431b7eaed25SJason Evans 	if (!dependent && elm == NULL) {
432*c5ad8142SEric van Gyzen 		return SC_NSIZES;
433b7eaed25SJason Evans 	}
434b7eaed25SJason Evans 	return rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent);
435b7eaed25SJason Evans }
436b7eaed25SJason Evans 
437b7eaed25SJason Evans /*
438b7eaed25SJason Evans  * rtree_slab_read() is intentionally omitted because slab is always read in
439b7eaed25SJason Evans  * conjunction with szind, which makes rtree_szind_slab_read() a better choice.
440b7eaed25SJason Evans  */
441b7eaed25SJason Evans 
442b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool
rtree_extent_szind_read(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key,bool dependent,extent_t ** r_extent,szind_t * r_szind)443b7eaed25SJason Evans rtree_extent_szind_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
444b7eaed25SJason Evans     uintptr_t key, bool dependent, extent_t **r_extent, szind_t *r_szind) {
445b7eaed25SJason Evans 	rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key,
446b7eaed25SJason Evans 	    dependent);
447b7eaed25SJason Evans 	if (!dependent && elm == NULL) {
448b7eaed25SJason Evans 		return true;
449b7eaed25SJason Evans 	}
450b7eaed25SJason Evans 	*r_extent = rtree_leaf_elm_extent_read(tsdn, rtree, elm, dependent);
451b7eaed25SJason Evans 	*r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent);
452b7eaed25SJason Evans 	return false;
453b7eaed25SJason Evans }
454b7eaed25SJason Evans 
455*c5ad8142SEric van Gyzen /*
456*c5ad8142SEric van Gyzen  * Try to read szind_slab from the L1 cache.  Returns true on a hit,
457*c5ad8142SEric van Gyzen  * and fills in r_szind and r_slab.  Otherwise returns false.
458*c5ad8142SEric van Gyzen  *
459*c5ad8142SEric van Gyzen  * Key is allowed to be NULL in order to save an extra branch on the
460*c5ad8142SEric van Gyzen  * fastpath.  returns false in this case.
461*c5ad8142SEric van Gyzen  */
462*c5ad8142SEric van Gyzen JEMALLOC_ALWAYS_INLINE bool
rtree_szind_slab_read_fast(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key,szind_t * r_szind,bool * r_slab)463*c5ad8142SEric van Gyzen rtree_szind_slab_read_fast(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
464*c5ad8142SEric van Gyzen 			    uintptr_t key, szind_t *r_szind, bool *r_slab) {
465*c5ad8142SEric van Gyzen 	rtree_leaf_elm_t *elm;
466*c5ad8142SEric van Gyzen 
467*c5ad8142SEric van Gyzen 	size_t slot = rtree_cache_direct_map(key);
468*c5ad8142SEric van Gyzen 	uintptr_t leafkey = rtree_leafkey(key);
469*c5ad8142SEric van Gyzen 	assert(leafkey != RTREE_LEAFKEY_INVALID);
470*c5ad8142SEric van Gyzen 
471*c5ad8142SEric van Gyzen 	if (likely(rtree_ctx->cache[slot].leafkey == leafkey)) {
472*c5ad8142SEric van Gyzen 		rtree_leaf_elm_t *leaf = rtree_ctx->cache[slot].leaf;
473*c5ad8142SEric van Gyzen 		assert(leaf != NULL);
474*c5ad8142SEric van Gyzen 		uintptr_t subkey = rtree_subkey(key, RTREE_HEIGHT-1);
475*c5ad8142SEric van Gyzen 		elm = &leaf[subkey];
476*c5ad8142SEric van Gyzen 
477*c5ad8142SEric van Gyzen #ifdef RTREE_LEAF_COMPACT
478*c5ad8142SEric van Gyzen 		uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree,
479*c5ad8142SEric van Gyzen 							  elm, true);
480*c5ad8142SEric van Gyzen 		*r_szind = rtree_leaf_elm_bits_szind_get(bits);
481*c5ad8142SEric van Gyzen 		*r_slab = rtree_leaf_elm_bits_slab_get(bits);
482*c5ad8142SEric van Gyzen #else
483*c5ad8142SEric van Gyzen 		*r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, true);
484*c5ad8142SEric van Gyzen 		*r_slab = rtree_leaf_elm_slab_read(tsdn, rtree, elm, true);
485*c5ad8142SEric van Gyzen #endif
486*c5ad8142SEric van Gyzen 		return true;
487*c5ad8142SEric van Gyzen 	} else {
488*c5ad8142SEric van Gyzen 		return false;
489*c5ad8142SEric van Gyzen 	}
490*c5ad8142SEric van Gyzen }
491b7eaed25SJason Evans JEMALLOC_ALWAYS_INLINE bool
rtree_szind_slab_read(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key,bool dependent,szind_t * r_szind,bool * r_slab)492b7eaed25SJason Evans rtree_szind_slab_read(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
493b7eaed25SJason Evans     uintptr_t key, bool dependent, szind_t *r_szind, bool *r_slab) {
494b7eaed25SJason Evans 	rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key,
495b7eaed25SJason Evans 	    dependent);
496b7eaed25SJason Evans 	if (!dependent && elm == NULL) {
497b7eaed25SJason Evans 		return true;
498b7eaed25SJason Evans 	}
4990ef50b4eSJason Evans #ifdef RTREE_LEAF_COMPACT
5000ef50b4eSJason Evans 	uintptr_t bits = rtree_leaf_elm_bits_read(tsdn, rtree, elm, dependent);
5010ef50b4eSJason Evans 	*r_szind = rtree_leaf_elm_bits_szind_get(bits);
5020ef50b4eSJason Evans 	*r_slab = rtree_leaf_elm_bits_slab_get(bits);
5030ef50b4eSJason Evans #else
504b7eaed25SJason Evans 	*r_szind = rtree_leaf_elm_szind_read(tsdn, rtree, elm, dependent);
505b7eaed25SJason Evans 	*r_slab = rtree_leaf_elm_slab_read(tsdn, rtree, elm, dependent);
5060ef50b4eSJason Evans #endif
507b7eaed25SJason Evans 	return false;
508b7eaed25SJason Evans }
509b7eaed25SJason Evans 
510b7eaed25SJason Evans static inline void
rtree_szind_slab_update(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key,szind_t szind,bool slab)511b7eaed25SJason Evans rtree_szind_slab_update(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
512b7eaed25SJason Evans     uintptr_t key, szind_t szind, bool slab) {
513*c5ad8142SEric van Gyzen 	assert(!slab || szind < SC_NBINS);
514b7eaed25SJason Evans 
515b7eaed25SJason Evans 	rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true);
516b7eaed25SJason Evans 	rtree_leaf_elm_szind_slab_update(tsdn, rtree, elm, szind, slab);
517b7eaed25SJason Evans }
518b7eaed25SJason Evans 
519b7eaed25SJason Evans static inline void
rtree_clear(tsdn_t * tsdn,rtree_t * rtree,rtree_ctx_t * rtree_ctx,uintptr_t key)520b7eaed25SJason Evans rtree_clear(tsdn_t *tsdn, rtree_t *rtree, rtree_ctx_t *rtree_ctx,
521b7eaed25SJason Evans     uintptr_t key) {
522b7eaed25SJason Evans 	rtree_leaf_elm_t *elm = rtree_read(tsdn, rtree, rtree_ctx, key, true);
523b7eaed25SJason Evans 	assert(rtree_leaf_elm_extent_read(tsdn, rtree, elm, false) !=
524b7eaed25SJason Evans 	    NULL);
525*c5ad8142SEric van Gyzen 	rtree_leaf_elm_write(tsdn, rtree, elm, NULL, SC_NSIZES, false);
526b7eaed25SJason Evans }
527b7eaed25SJason Evans 
528b7eaed25SJason Evans #endif /* JEMALLOC_INTERNAL_RTREE_H */
529