Tue Jan 28 22:20:45 2020 UTC ()
gang_lookup_scan(): if a dense scan and the first sibling doesn't match,
the scan is finished.


(ad)
diff -r1.22 -r1.23 src/common/lib/libc/gen/radixtree.c

cvs diff -r1.22 -r1.23 src/common/lib/libc/gen/radixtree.c (switch to unified diff)

--- src/common/lib/libc/gen/radixtree.c 2020/01/28 16:33:34 1.22
+++ src/common/lib/libc/gen/radixtree.c 2020/01/28 22:20:45 1.23
@@ -1,1735 +1,1717 @@ @@ -1,1735 +1,1717 @@
1/* $NetBSD: radixtree.c,v 1.22 2020/01/28 16:33:34 ad Exp $ */ 1/* $NetBSD: radixtree.c,v 1.23 2020/01/28 22:20:45 ad Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c)2011,2012,2013 YAMAMOTO Takashi, 4 * Copyright (c)2011,2012,2013 YAMAMOTO Takashi,
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
15 * 15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE. 26 * SUCH DAMAGE.
27 */ 27 */
28 28
29/* 29/*
30 * radixtree.c 30 * radixtree.c
31 * 31 *
32 * Overview: 32 * Overview:
33 * 33 *
34 * This is an implementation of radix tree, whose keys are uint64_t and leafs 34 * This is an implementation of radix tree, whose keys are uint64_t and leafs
35 * are user provided pointers. 35 * are user provided pointers.
36 * 36 *
37 * Leaf nodes are just void * and this implementation doesn't care about 37 * Leaf nodes are just void * and this implementation doesn't care about
38 * what they actually point to. However, this implementation has an assumption 38 * what they actually point to. However, this implementation has an assumption
39 * about their alignment. Specifically, this implementation assumes that their 39 * about their alignment. Specifically, this implementation assumes that their
40 * 2 LSBs are always zero and uses them for internal accounting. 40 * 2 LSBs are always zero and uses them for internal accounting.
41 * 41 *
42 * Intermediate nodes and memory allocation: 42 * Intermediate nodes and memory allocation:
43 * 43 *
44 * Intermediate nodes are automatically allocated and freed internally and 44 * Intermediate nodes are automatically allocated and freed internally and
45 * basically users don't need to care about them. The allocation is done via 45 * basically users don't need to care about them. The allocation is done via
46 * pool_cache_get(9) for _KERNEL, malloc(3) for userland, and alloc() for 46 * pool_cache_get(9) for _KERNEL, malloc(3) for userland, and alloc() for
47 * _STANDALONE environment. Only radix_tree_insert_node function can allocate 47 * _STANDALONE environment. Only radix_tree_insert_node function can allocate
48 * memory for intermediate nodes and thus can fail for ENOMEM. 48 * memory for intermediate nodes and thus can fail for ENOMEM.
49 * 49 *
50 * Memory Efficiency: 50 * Memory Efficiency:
51 * 51 *
52 * It's designed to work efficiently with dense index distribution. 52 * It's designed to work efficiently with dense index distribution.
53 * The memory consumption (number of necessary intermediate nodes) heavily 53 * The memory consumption (number of necessary intermediate nodes) heavily
54 * depends on the index distribution. Basically, more dense index distribution 54 * depends on the index distribution. Basically, more dense index distribution
55 * consumes less nodes per item. Approximately, 55 * consumes less nodes per item. Approximately,
56 * 56 *
57 * - the best case: about RADIX_TREE_PTR_PER_NODE items per intermediate node. 57 * - the best case: about RADIX_TREE_PTR_PER_NODE items per intermediate node.
58 * it would look like the following. 58 * it would look like the following.
59 * 59 *
60 * root (t_height=1) 60 * root (t_height=1)
61 * | 61 * |
62 * v 62 * v
63 * [ | | | ] (intermediate node. RADIX_TREE_PTR_PER_NODE=4 in this fig) 63 * [ | | | ] (intermediate node. RADIX_TREE_PTR_PER_NODE=4 in this fig)
64 * | | | | 64 * | | | |
65 * v v v v 65 * v v v v
66 * p p p p (items) 66 * p p p p (items)
67 * 67 *
68 * - the worst case: RADIX_TREE_MAX_HEIGHT intermediate nodes per item. 68 * - the worst case: RADIX_TREE_MAX_HEIGHT intermediate nodes per item.
69 * it would look like the following if RADIX_TREE_MAX_HEIGHT=3. 69 * it would look like the following if RADIX_TREE_MAX_HEIGHT=3.
70 * 70 *
71 * root (t_height=3) 71 * root (t_height=3)
72 * | 72 * |
73 * v 73 * v
74 * [ | | | ] 74 * [ | | | ]
75 * | 75 * |
76 * v 76 * v
77 * [ | | | ] 77 * [ | | | ]
78 * | 78 * |
79 * v 79 * v
80 * [ | | | ] 80 * [ | | | ]
81 * | 81 * |
82 * v 82 * v
83 * p 83 * p
84 * 84 *
85 * The height of tree (t_height) is dynamic. It's smaller if only small 85 * The height of tree (t_height) is dynamic. It's smaller if only small
86 * index values are used. As an extreme case, if only index 0 is used, 86 * index values are used. As an extreme case, if only index 0 is used,
87 * the corresponding value is directly stored in the root of the tree 87 * the corresponding value is directly stored in the root of the tree
88 * (struct radix_tree) without allocating any intermediate nodes. In that 88 * (struct radix_tree) without allocating any intermediate nodes. In that
89 * case, t_height=0. 89 * case, t_height=0.
90 * 90 *
91 * Gang lookup: 91 * Gang lookup:
92 * 92 *
93 * This implementation provides a way to scan many nodes quickly via 93 * This implementation provides a way to scan many nodes quickly via
94 * radix_tree_gang_lookup_node function and its varients. 94 * radix_tree_gang_lookup_node function and its varients.
95 * 95 *
96 * Tags: 96 * Tags:
97 * 97 *
98 * This implementation provides tagging functionality, which allows quick 98 * This implementation provides tagging functionality, which allows quick
99 * scanning of a subset of leaf nodes. Leaf nodes are untagged when inserted 99 * scanning of a subset of leaf nodes. Leaf nodes are untagged when inserted
100 * into the tree and can be tagged by radix_tree_set_tag function. 100 * into the tree and can be tagged by radix_tree_set_tag function.
101 * radix_tree_gang_lookup_tagged_node function and its variants returns only 101 * radix_tree_gang_lookup_tagged_node function and its variants returns only
102 * leaf nodes with the given tag. To reduce amount of nodes to visit for 102 * leaf nodes with the given tag. To reduce amount of nodes to visit for
103 * these functions, this implementation keeps tagging information in internal 103 * these functions, this implementation keeps tagging information in internal
104 * intermediate nodes and quickly skips uninterested parts of a tree. 104 * intermediate nodes and quickly skips uninterested parts of a tree.
105 * 105 *
106 * A tree has RADIX_TREE_TAG_ID_MAX independent tag spaces, each of which are 106 * A tree has RADIX_TREE_TAG_ID_MAX independent tag spaces, each of which are
107 * identified by an zero-origin numbers, tagid. For the current implementation, 107 * identified by an zero-origin numbers, tagid. For the current implementation,
108 * RADIX_TREE_TAG_ID_MAX is 2. A set of tags is described as a bitmask tagmask, 108 * RADIX_TREE_TAG_ID_MAX is 2. A set of tags is described as a bitmask tagmask,
109 * which is a bitwise OR of (1 << tagid). 109 * which is a bitwise OR of (1 << tagid).
110 */ 110 */
111 111
112#include <sys/cdefs.h> 112#include <sys/cdefs.h>
113 113
114#if defined(_KERNEL) || defined(_STANDALONE) 114#if defined(_KERNEL) || defined(_STANDALONE)
115__KERNEL_RCSID(0, "$NetBSD: radixtree.c,v 1.22 2020/01/28 16:33:34 ad Exp $"); 115__KERNEL_RCSID(0, "$NetBSD: radixtree.c,v 1.23 2020/01/28 22:20:45 ad Exp $");
116#include <sys/param.h> 116#include <sys/param.h>
117#include <sys/errno.h> 117#include <sys/errno.h>
118#include <sys/pool.h> 118#include <sys/pool.h>
119#include <sys/radixtree.h> 119#include <sys/radixtree.h>
120#include <lib/libkern/libkern.h> 120#include <lib/libkern/libkern.h>
121#if defined(_STANDALONE) 121#if defined(_STANDALONE)
122#include <lib/libsa/stand.h> 122#include <lib/libsa/stand.h>
123#endif /* defined(_STANDALONE) */ 123#endif /* defined(_STANDALONE) */
124#else /* defined(_KERNEL) || defined(_STANDALONE) */ 124#else /* defined(_KERNEL) || defined(_STANDALONE) */
125__RCSID("$NetBSD: radixtree.c,v 1.22 2020/01/28 16:33:34 ad Exp $"); 125__RCSID("$NetBSD: radixtree.c,v 1.23 2020/01/28 22:20:45 ad Exp $");
126#include <assert.h> 126#include <assert.h>
127#include <errno.h> 127#include <errno.h>
128#include <stdbool.h> 128#include <stdbool.h>
129#include <stdlib.h> 129#include <stdlib.h>
130#include <string.h> 130#include <string.h>
131#if 1 131#if 1
132#define KASSERT assert 132#define KASSERT assert
133#else 133#else
134#define KASSERT(a) /* nothing */ 134#define KASSERT(a) /* nothing */
135#endif 135#endif
136#endif /* defined(_KERNEL) || defined(_STANDALONE) */ 136#endif /* defined(_KERNEL) || defined(_STANDALONE) */
137 137
138#include <sys/radixtree.h> 138#include <sys/radixtree.h>
139 139
140#define RADIX_TREE_BITS_PER_HEIGHT 4 /* XXX tune */ 140#define RADIX_TREE_BITS_PER_HEIGHT 4 /* XXX tune */
141#define RADIX_TREE_PTR_PER_NODE (1 << RADIX_TREE_BITS_PER_HEIGHT) 141#define RADIX_TREE_PTR_PER_NODE (1 << RADIX_TREE_BITS_PER_HEIGHT)
142#define RADIX_TREE_MAX_HEIGHT (64 / RADIX_TREE_BITS_PER_HEIGHT) 142#define RADIX_TREE_MAX_HEIGHT (64 / RADIX_TREE_BITS_PER_HEIGHT)
143#define RADIX_TREE_INVALID_HEIGHT (RADIX_TREE_MAX_HEIGHT + 1) 143#define RADIX_TREE_INVALID_HEIGHT (RADIX_TREE_MAX_HEIGHT + 1)
144__CTASSERT((64 % RADIX_TREE_BITS_PER_HEIGHT) == 0); 144__CTASSERT((64 % RADIX_TREE_BITS_PER_HEIGHT) == 0);
145 145
146__CTASSERT(((1 << RADIX_TREE_TAG_ID_MAX) & (sizeof(int) - 1)) == 0); 146__CTASSERT(((1 << RADIX_TREE_TAG_ID_MAX) & (sizeof(int) - 1)) == 0);
147#define RADIX_TREE_TAG_MASK ((1 << RADIX_TREE_TAG_ID_MAX) - 1) 147#define RADIX_TREE_TAG_MASK ((1 << RADIX_TREE_TAG_ID_MAX) - 1)
148 148
149static inline void * 149static inline void *
150entry_ptr(void *p) 150entry_ptr(void *p)
151{ 151{
152 152
153 return (void *)((uintptr_t)p & ~RADIX_TREE_TAG_MASK); 153 return (void *)((uintptr_t)p & ~RADIX_TREE_TAG_MASK);
154} 154}
155 155
156static inline unsigned int 156static inline unsigned int
157entry_tagmask(void *p) 157entry_tagmask(void *p)
158{ 158{
159 159
160 return (uintptr_t)p & RADIX_TREE_TAG_MASK; 160 return (uintptr_t)p & RADIX_TREE_TAG_MASK;
161} 161}
162 162
163static inline void * 163static inline void *
164entry_compose(void *p, unsigned int tagmask) 164entry_compose(void *p, unsigned int tagmask)
165{ 165{
166 166
167 return (void *)((uintptr_t)p | tagmask); 167 return (void *)((uintptr_t)p | tagmask);
168} 168}
169 169
170static inline bool 170static inline bool
171entry_match_p(void *p, unsigned int tagmask) 171entry_match_p(void *p, unsigned int tagmask)
172{ 172{
173 173
174 KASSERT(entry_ptr(p) != NULL || entry_tagmask(p) == 0); 174 KASSERT(entry_ptr(p) != NULL || entry_tagmask(p) == 0);
175 if (p == NULL) { 175 if (p == NULL) {
176 return false; 176 return false;
177 } 177 }
178 if (tagmask == 0) { 178 if (tagmask == 0) {
179 return true; 179 return true;
180 } 180 }
181 return (entry_tagmask(p) & tagmask) != 0; 181 return (entry_tagmask(p) & tagmask) != 0;
182} 182}
183 183
184/* 184/*
185 * radix_tree_node: an intermediate node 185 * radix_tree_node: an intermediate node
186 * 186 *
187 * we don't care the type of leaf nodes. they are just void *. 187 * we don't care the type of leaf nodes. they are just void *.
188 * 188 *
189 * we used to maintain a count of non-NULL nodes in this structure, but it 189 * we used to maintain a count of non-NULL nodes in this structure, but it
190 * prevented it from being aligned to a cache line boundary; the performance 190 * prevented it from being aligned to a cache line boundary; the performance
191 * benefit from being cache friendly is greater than the benefit of having 191 * benefit from being cache friendly is greater than the benefit of having
192 * a dedicated count value, especially in multi-processor situations where 192 * a dedicated count value, especially in multi-processor situations where
193 * we need to avoid intra-pool-page false sharing. 193 * we need to avoid intra-pool-page false sharing.
194 */ 194 */
195 195
196struct radix_tree_node { 196struct radix_tree_node {
197 void *n_ptrs[RADIX_TREE_PTR_PER_NODE]; 197 void *n_ptrs[RADIX_TREE_PTR_PER_NODE];
198}; 198};
199 199
200/* 200/*
201 * any_children_tagmask: 201 * any_children_tagmask:
202 * 202 *
203 * return OR'ed tagmask of the given node's children. 203 * return OR'ed tagmask of the given node's children.
204 */ 204 */
205 205
206static unsigned int 206static unsigned int
207any_children_tagmask(const struct radix_tree_node *n) 207any_children_tagmask(const struct radix_tree_node *n)
208{ 208{
209 unsigned int mask; 209 unsigned int mask;
210 int i; 210 int i;
211 211
212 mask = 0; 212 mask = 0;
213 for (i = 0; i < RADIX_TREE_PTR_PER_NODE; i++) { 213 for (i = 0; i < RADIX_TREE_PTR_PER_NODE; i++) {
214 mask |= (unsigned int)(uintptr_t)n->n_ptrs[i]; 214 mask |= (unsigned int)(uintptr_t)n->n_ptrs[i];
215 } 215 }
216 return mask & RADIX_TREE_TAG_MASK; 216 return mask & RADIX_TREE_TAG_MASK;
217} 217}
218 218
219/* 219/*
220 * p_refs[0].pptr == &t->t_root 220 * p_refs[0].pptr == &t->t_root
221 * : 221 * :
222 * p_refs[n].pptr == &(*p_refs[n-1])->n_ptrs[x] 222 * p_refs[n].pptr == &(*p_refs[n-1])->n_ptrs[x]
223 * : 223 * :
224 * : 224 * :
225 * p_refs[t->t_height].pptr == &leaf_pointer 225 * p_refs[t->t_height].pptr == &leaf_pointer
226 */ 226 */
227 227
228struct radix_tree_path { 228struct radix_tree_path {
229 struct radix_tree_node_ref { 229 struct radix_tree_node_ref {
230 void **pptr; 230 void **pptr;
231 } p_refs[RADIX_TREE_MAX_HEIGHT + 1]; /* +1 for the root ptr */ 231 } p_refs[RADIX_TREE_MAX_HEIGHT + 1]; /* +1 for the root ptr */
232 /* 232 /*
233 * p_lastidx is either the index of the last valid element of p_refs[] 233 * p_lastidx is either the index of the last valid element of p_refs[]
234 * or RADIX_TREE_INVALID_HEIGHT. 234 * or RADIX_TREE_INVALID_HEIGHT.
235 * RADIX_TREE_INVALID_HEIGHT means that radix_tree_lookup_ptr found 235 * RADIX_TREE_INVALID_HEIGHT means that radix_tree_lookup_ptr found
236 * that the height of the tree is not enough to cover the given index. 236 * that the height of the tree is not enough to cover the given index.
237 */ 237 */
238 unsigned int p_lastidx; 238 unsigned int p_lastidx;
239}; 239};
240 240
241static inline void ** 241static inline void **
242path_pptr(const struct radix_tree *t, const struct radix_tree_path *p, 242path_pptr(const struct radix_tree *t, const struct radix_tree_path *p,
243 unsigned int height) 243 unsigned int height)
244{ 244{
245 245
246 KASSERT(height <= t->t_height); 246 KASSERT(height <= t->t_height);
247 return p->p_refs[height].pptr; 247 return p->p_refs[height].pptr;
248} 248}
249 249
250static inline struct radix_tree_node * 250static inline struct radix_tree_node *
251path_node(const struct radix_tree * t, const struct radix_tree_path *p, 251path_node(const struct radix_tree * t, const struct radix_tree_path *p,
252 unsigned int height) 252 unsigned int height)
253{ 253{
254 254
255 KASSERT(height <= t->t_height); 255 KASSERT(height <= t->t_height);
256 return entry_ptr(*path_pptr(t, p, height)); 256 return entry_ptr(*path_pptr(t, p, height));
257} 257}
258 258
259/* 259/*
260 * radix_tree_init_tree: 260 * radix_tree_init_tree:
261 * 261 *
262 * Initialize a tree. 262 * Initialize a tree.
263 */ 263 */
264 264
265void 265void
266radix_tree_init_tree(struct radix_tree *t) 266radix_tree_init_tree(struct radix_tree *t)
267{ 267{
268 268
269 t->t_height = 0; 269 t->t_height = 0;
270 t->t_root = NULL; 270 t->t_root = NULL;
271} 271}
272 272
273/* 273/*
274 * radix_tree_fini_tree: 274 * radix_tree_fini_tree:
275 * 275 *
276 * Finish using a tree. 276 * Finish using a tree.
277 */ 277 */
278 278
279void 279void
280radix_tree_fini_tree(struct radix_tree *t) 280radix_tree_fini_tree(struct radix_tree *t)
281{ 281{
282 282
283 KASSERT(t->t_root == NULL); 283 KASSERT(t->t_root == NULL);
284 KASSERT(t->t_height == 0); 284 KASSERT(t->t_height == 0);
285} 285}
286 286
287/* 287/*
288 * radix_tree_empty_tree_p: 288 * radix_tree_empty_tree_p:
289 * 289 *
290 * Return if the tree is empty. 290 * Return if the tree is empty.
291 */ 291 */
292 292
293bool 293bool
294radix_tree_empty_tree_p(struct radix_tree *t) 294radix_tree_empty_tree_p(struct radix_tree *t)
295{ 295{
296 296
297 return t->t_root == NULL; 297 return t->t_root == NULL;
298} 298}
299 299
300/* 300/*
301 * radix_tree_empty_tree_p: 301 * radix_tree_empty_tree_p:
302 * 302 *
303 * Return true if the tree has any nodes with the given tag. Otherwise 303 * Return true if the tree has any nodes with the given tag. Otherwise
304 * return false. 304 * return false.
305 * 305 *
306 * It's illegal to call this function with tagmask 0. 306 * It's illegal to call this function with tagmask 0.
307 */ 307 */
308 308
309bool 309bool
310radix_tree_empty_tagged_tree_p(struct radix_tree *t, unsigned int tagmask) 310radix_tree_empty_tagged_tree_p(struct radix_tree *t, unsigned int tagmask)
311{ 311{
312 312
313 KASSERT(tagmask != 0); 313 KASSERT(tagmask != 0);
314 return (entry_tagmask(t->t_root) & tagmask) == 0; 314 return (entry_tagmask(t->t_root) & tagmask) == 0;
315} 315}
316 316
317static void 317static void
318radix_tree_node_init(struct radix_tree_node *n) 318radix_tree_node_init(struct radix_tree_node *n)
319{ 319{
320 320
321 memset(n, 0, sizeof(*n)); 321 memset(n, 0, sizeof(*n));
322} 322}
323 323
324#if defined(_KERNEL) 324#if defined(_KERNEL)
325pool_cache_t radix_tree_node_cache __read_mostly; 325pool_cache_t radix_tree_node_cache __read_mostly;
326 326
327static int 327static int
328radix_tree_node_ctor(void *dummy, void *item, int flags) 328radix_tree_node_ctor(void *dummy, void *item, int flags)
329{ 329{
330 struct radix_tree_node *n = item; 330 struct radix_tree_node *n = item;
331 331
332 KASSERT(dummy == NULL); 332 KASSERT(dummy == NULL);
333 radix_tree_node_init(n); 333 radix_tree_node_init(n);
334 return 0; 334 return 0;
335} 335}
336 336
337/* 337/*
338 * radix_tree_init: 338 * radix_tree_init:
339 * 339 *
340 * initialize the subsystem. 340 * initialize the subsystem.
341 */ 341 */
342 342
343void 343void
344radix_tree_init(void) 344radix_tree_init(void)
345{ 345{
346 346
347 radix_tree_node_cache = pool_cache_init(sizeof(struct radix_tree_node), 347 radix_tree_node_cache = pool_cache_init(sizeof(struct radix_tree_node),
348 coherency_unit, 0, PR_LARGECACHE, "radixnode", NULL, IPL_NONE, 348 coherency_unit, 0, PR_LARGECACHE, "radixnode", NULL, IPL_NONE,
349 radix_tree_node_ctor, NULL, NULL); 349 radix_tree_node_ctor, NULL, NULL);
350 KASSERT(radix_tree_node_cache != NULL); 350 KASSERT(radix_tree_node_cache != NULL);
351} 351}
352 352
353/* 353/*
354 * radix_tree_await_memory: 354 * radix_tree_await_memory:
355 * 355 *
356 * after an insert has failed with ENOMEM, wait for memory to become 356 * after an insert has failed with ENOMEM, wait for memory to become
357 * available, so the caller can retry. 357 * available, so the caller can retry.
358 */ 358 */
359 359
360void 360void
361radix_tree_await_memory(void) 361radix_tree_await_memory(void)
362{ 362{
363 struct radix_tree_node *n; 363 struct radix_tree_node *n;
364 364
365 n = pool_cache_get(radix_tree_node_cache, PR_WAITOK); 365 n = pool_cache_get(radix_tree_node_cache, PR_WAITOK);
366 pool_cache_put(radix_tree_node_cache, n); 366 pool_cache_put(radix_tree_node_cache, n);
367} 367}
368 368
369#endif /* defined(_KERNEL) */ 369#endif /* defined(_KERNEL) */
370 370
371static bool __unused 371static bool __unused
372radix_tree_node_clean_p(const struct radix_tree_node *n) 372radix_tree_node_clean_p(const struct radix_tree_node *n)
373{ 373{
374#if RADIX_TREE_PTR_PER_NODE > 16 374#if RADIX_TREE_PTR_PER_NODE > 16
375 unsigned int i; 375 unsigned int i;
376 376
377 for (i = 0; i < RADIX_TREE_PTR_PER_NODE; i++) { 377 for (i = 0; i < RADIX_TREE_PTR_PER_NODE; i++) {
378 if (n->n_ptrs[i] != NULL) { 378 if (n->n_ptrs[i] != NULL) {
379 return false; 379 return false;
380 } 380 }
381 } 381 }
382 return true; 382 return true;
383#else /* RADIX_TREE_PTR_PER_NODE > 16 */ 383#else /* RADIX_TREE_PTR_PER_NODE > 16 */
384 uintptr_t sum; 384 uintptr_t sum;
385 385
386 /* 386 /*
387 * Unrolling the above is much better than a tight loop with two 387 * Unrolling the above is much better than a tight loop with two
388 * test+branch pairs. On x86 with gcc 5.5.0 this compiles into 19 388 * test+branch pairs. On x86 with gcc 5.5.0 this compiles into 19
389 * deterministic instructions including the "return" and prologue & 389 * deterministic instructions including the "return" and prologue &
390 * epilogue. 390 * epilogue.
391 */ 391 */
392 sum = (uintptr_t)n->n_ptrs[0]; 392 sum = (uintptr_t)n->n_ptrs[0];
393 sum |= (uintptr_t)n->n_ptrs[1]; 393 sum |= (uintptr_t)n->n_ptrs[1];
394 sum |= (uintptr_t)n->n_ptrs[2]; 394 sum |= (uintptr_t)n->n_ptrs[2];
395 sum |= (uintptr_t)n->n_ptrs[3]; 395 sum |= (uintptr_t)n->n_ptrs[3];
396#if RADIX_TREE_PTR_PER_NODE > 4 396#if RADIX_TREE_PTR_PER_NODE > 4
397 sum |= (uintptr_t)n->n_ptrs[4]; 397 sum |= (uintptr_t)n->n_ptrs[4];
398 sum |= (uintptr_t)n->n_ptrs[5]; 398 sum |= (uintptr_t)n->n_ptrs[5];
399 sum |= (uintptr_t)n->n_ptrs[6]; 399 sum |= (uintptr_t)n->n_ptrs[6];
400 sum |= (uintptr_t)n->n_ptrs[7]; 400 sum |= (uintptr_t)n->n_ptrs[7];
401#endif 401#endif
402#if RADIX_TREE_PTR_PER_NODE > 8 402#if RADIX_TREE_PTR_PER_NODE > 8
403 sum |= (uintptr_t)n->n_ptrs[8]; 403 sum |= (uintptr_t)n->n_ptrs[8];
404 sum |= (uintptr_t)n->n_ptrs[9]; 404 sum |= (uintptr_t)n->n_ptrs[9];
405 sum |= (uintptr_t)n->n_ptrs[10]; 405 sum |= (uintptr_t)n->n_ptrs[10];
406 sum |= (uintptr_t)n->n_ptrs[11]; 406 sum |= (uintptr_t)n->n_ptrs[11];
407 sum |= (uintptr_t)n->n_ptrs[12]; 407 sum |= (uintptr_t)n->n_ptrs[12];
408 sum |= (uintptr_t)n->n_ptrs[13]; 408 sum |= (uintptr_t)n->n_ptrs[13];
409 sum |= (uintptr_t)n->n_ptrs[14]; 409 sum |= (uintptr_t)n->n_ptrs[14];
410 sum |= (uintptr_t)n->n_ptrs[15]; 410 sum |= (uintptr_t)n->n_ptrs[15];
411#endif 411#endif
412 return sum == 0; 412 return sum == 0;
413#endif /* RADIX_TREE_PTR_PER_NODE > 16 */ 413#endif /* RADIX_TREE_PTR_PER_NODE > 16 */
414} 414}
415 415
416static int __unused 416static int __unused
417radix_tree_node_count_ptrs(const struct radix_tree_node *n) 417radix_tree_node_count_ptrs(const struct radix_tree_node *n)
418{ 418{
419 unsigned int i, c; 419 unsigned int i, c;
420 420
421 for (i = c = 0; i < RADIX_TREE_PTR_PER_NODE; i++) { 421 for (i = c = 0; i < RADIX_TREE_PTR_PER_NODE; i++) {
422 c += (n->n_ptrs[i] != NULL); 422 c += (n->n_ptrs[i] != NULL);
423 } 423 }
424 return c; 424 return c;
425} 425}
426 426
427static struct radix_tree_node * 427static struct radix_tree_node *
428radix_tree_alloc_node(void) 428radix_tree_alloc_node(void)
429{ 429{
430 struct radix_tree_node *n; 430 struct radix_tree_node *n;
431 431
432#if defined(_KERNEL) 432#if defined(_KERNEL)
433 /* 433 /*
434 * note that pool_cache_get can block. 434 * note that pool_cache_get can block.
435 */ 435 */
436 n = pool_cache_get(radix_tree_node_cache, PR_NOWAIT); 436 n = pool_cache_get(radix_tree_node_cache, PR_NOWAIT);
437#else /* defined(_KERNEL) */ 437#else /* defined(_KERNEL) */
438#if defined(_STANDALONE) 438#if defined(_STANDALONE)
439 n = alloc(sizeof(*n)); 439 n = alloc(sizeof(*n));
440#else /* defined(_STANDALONE) */ 440#else /* defined(_STANDALONE) */
441 n = malloc(sizeof(*n)); 441 n = malloc(sizeof(*n));
442#endif /* defined(_STANDALONE) */ 442#endif /* defined(_STANDALONE) */
443 if (n != NULL) { 443 if (n != NULL) {
444 radix_tree_node_init(n); 444 radix_tree_node_init(n);
445 } 445 }
446#endif /* defined(_KERNEL) */ 446#endif /* defined(_KERNEL) */
447 KASSERT(n == NULL || radix_tree_node_clean_p(n)); 447 KASSERT(n == NULL || radix_tree_node_clean_p(n));
448 return n; 448 return n;
449} 449}
450 450
451static void 451static void
452radix_tree_free_node(struct radix_tree_node *n) 452radix_tree_free_node(struct radix_tree_node *n)
453{ 453{
454 454
455 KASSERT(radix_tree_node_clean_p(n)); 455 KASSERT(radix_tree_node_clean_p(n));
456#if defined(_KERNEL) 456#if defined(_KERNEL)
457 pool_cache_put(radix_tree_node_cache, n); 457 pool_cache_put(radix_tree_node_cache, n);
458#elif defined(_STANDALONE) 458#elif defined(_STANDALONE)
459 dealloc(n, sizeof(*n)); 459 dealloc(n, sizeof(*n));
460#else 460#else
461 free(n); 461 free(n);
462#endif 462#endif
463} 463}
464 464
465static int 465static int
466radix_tree_grow(struct radix_tree *t, unsigned int newheight) 466radix_tree_grow(struct radix_tree *t, unsigned int newheight)
467{ 467{
468 const unsigned int tagmask = entry_tagmask(t->t_root); 468 const unsigned int tagmask = entry_tagmask(t->t_root);
469 469
470 KASSERT(newheight <= 64 / RADIX_TREE_BITS_PER_HEIGHT); 470 KASSERT(newheight <= 64 / RADIX_TREE_BITS_PER_HEIGHT);
471 if (t->t_root == NULL) { 471 if (t->t_root == NULL) {
472 t->t_height = newheight; 472 t->t_height = newheight;
473 return 0; 473 return 0;
474 } 474 }
475 while (t->t_height < newheight) { 475 while (t->t_height < newheight) {
476 struct radix_tree_node *n; 476 struct radix_tree_node *n;
477 477
478 n = radix_tree_alloc_node(); 478 n = radix_tree_alloc_node();
479 if (n == NULL) { 479 if (n == NULL) {
480 /* 480 /*
481 * don't bother to revert our changes. 481 * don't bother to revert our changes.
482 * the caller will likely retry. 482 * the caller will likely retry.
483 */ 483 */
484 return ENOMEM; 484 return ENOMEM;
485 } 485 }
486 n->n_ptrs[0] = t->t_root; 486 n->n_ptrs[0] = t->t_root;
487 t->t_root = entry_compose(n, tagmask); 487 t->t_root = entry_compose(n, tagmask);
488 t->t_height++; 488 t->t_height++;
489 } 489 }
490 return 0; 490 return 0;
491} 491}
492 492
493/* 493/*
494 * radix_tree_lookup_ptr: 494 * radix_tree_lookup_ptr:
495 * 495 *
496 * an internal helper function used for various exported functions. 496 * an internal helper function used for various exported functions.
497 * 497 *
498 * return the pointer to store the node for the given index. 498 * return the pointer to store the node for the given index.
499 * 499 *
500 * if alloc is true, try to allocate the storage. (note for _KERNEL: 500 * if alloc is true, try to allocate the storage. (note for _KERNEL:
501 * in that case, this function can block.) if the allocation failed or 501 * in that case, this function can block.) if the allocation failed or
502 * alloc is false, return NULL. 502 * alloc is false, return NULL.
503 * 503 *
504 * if path is not NULL, fill it for the caller's investigation. 504 * if path is not NULL, fill it for the caller's investigation.
505 * 505 *
506 * if tagmask is not zero, search only for nodes with the tag set. 506 * if tagmask is not zero, search only for nodes with the tag set.
507 * note that, however, this function doesn't check the tagmask for the leaf 507 * note that, however, this function doesn't check the tagmask for the leaf
508 * pointer. it's a caller's responsibility to investigate the value which 508 * pointer. it's a caller's responsibility to investigate the value which
509 * is pointed by the returned pointer if necessary. 509 * is pointed by the returned pointer if necessary.
510 * 510 *
511 * while this function is a bit large, as it's called with some constant 511 * while this function is a bit large, as it's called with some constant
512 * arguments, inlining might have benefits. anyway, a compiler will decide. 512 * arguments, inlining might have benefits. anyway, a compiler will decide.
513 */ 513 */
514 514
515static inline void ** 515static inline void **
516radix_tree_lookup_ptr(struct radix_tree *t, uint64_t idx, 516radix_tree_lookup_ptr(struct radix_tree *t, uint64_t idx,
517 struct radix_tree_path *path, bool alloc, const unsigned int tagmask) 517 struct radix_tree_path *path, bool alloc, const unsigned int tagmask)
518{ 518{
519 struct radix_tree_node *n; 519 struct radix_tree_node *n;
520 int hshift = RADIX_TREE_BITS_PER_HEIGHT * t->t_height; 520 int hshift = RADIX_TREE_BITS_PER_HEIGHT * t->t_height;
521 int shift; 521 int shift;
522 void **vpp; 522 void **vpp;
523 const uint64_t mask = (UINT64_C(1) << RADIX_TREE_BITS_PER_HEIGHT) - 1; 523 const uint64_t mask = (UINT64_C(1) << RADIX_TREE_BITS_PER_HEIGHT) - 1;
524 struct radix_tree_node_ref *refs = NULL; 524 struct radix_tree_node_ref *refs = NULL;
525 525
526 /* 526 /*
527 * check unsupported combinations 527 * check unsupported combinations
528 */ 528 */
529 KASSERT(tagmask == 0 || !alloc); 529 KASSERT(tagmask == 0 || !alloc);
530 KASSERT(path == NULL || !alloc); 530 KASSERT(path == NULL || !alloc);
531 vpp = &t->t_root; 531 vpp = &t->t_root;
532 if (path != NULL) { 532 if (path != NULL) {
533 refs = path->p_refs; 533 refs = path->p_refs;
534 refs->pptr = vpp; 534 refs->pptr = vpp;
535 } 535 }
536 n = NULL; 536 n = NULL;
537 for (shift = 64 - RADIX_TREE_BITS_PER_HEIGHT; shift >= 0;) { 537 for (shift = 64 - RADIX_TREE_BITS_PER_HEIGHT; shift >= 0;) {
538 struct radix_tree_node *c; 538 struct radix_tree_node *c;
539 void *entry; 539 void *entry;
540 const uint64_t i = (idx >> shift) & mask; 540 const uint64_t i = (idx >> shift) & mask;
541 541
542 if (shift >= hshift) { 542 if (shift >= hshift) {
543 unsigned int newheight; 543 unsigned int newheight;
544 544
545 KASSERT(vpp == &t->t_root); 545 KASSERT(vpp == &t->t_root);
546 if (i == 0) { 546 if (i == 0) {
547 shift -= RADIX_TREE_BITS_PER_HEIGHT; 547 shift -= RADIX_TREE_BITS_PER_HEIGHT;
548 continue; 548 continue;
549 } 549 }
550 if (!alloc) { 550 if (!alloc) {
551 if (path != NULL) { 551 if (path != NULL) {
552 KASSERT((refs - path->p_refs) == 0); 552 KASSERT((refs - path->p_refs) == 0);
553 path->p_lastidx = 553 path->p_lastidx =
554 RADIX_TREE_INVALID_HEIGHT; 554 RADIX_TREE_INVALID_HEIGHT;
555 } 555 }
556 return NULL; 556 return NULL;
557 } 557 }
558 newheight = shift / RADIX_TREE_BITS_PER_HEIGHT + 1; 558 newheight = shift / RADIX_TREE_BITS_PER_HEIGHT + 1;
559 if (radix_tree_grow(t, newheight)) { 559 if (radix_tree_grow(t, newheight)) {
560 return NULL; 560 return NULL;
561 } 561 }
562 hshift = RADIX_TREE_BITS_PER_HEIGHT * t->t_height; 562 hshift = RADIX_TREE_BITS_PER_HEIGHT * t->t_height;
563 } 563 }
564 entry = *vpp; 564 entry = *vpp;
565 c = entry_ptr(entry); 565 c = entry_ptr(entry);
566 if (c == NULL || 566 if (c == NULL ||
567 (tagmask != 0 && 567 (tagmask != 0 &&
568 (entry_tagmask(entry) & tagmask) == 0)) { 568 (entry_tagmask(entry) & tagmask) == 0)) {
569 if (!alloc) { 569 if (!alloc) {
570 if (path != NULL) { 570 if (path != NULL) {
571 path->p_lastidx = refs - path->p_refs; 571 path->p_lastidx = refs - path->p_refs;
572 } 572 }
573 return NULL; 573 return NULL;
574 } 574 }
575 c = radix_tree_alloc_node(); 575 c = radix_tree_alloc_node();
576 if (c == NULL) { 576 if (c == NULL) {
577 return NULL; 577 return NULL;
578 } 578 }
579 *vpp = c; 579 *vpp = c;
580 } 580 }
581 n = c; 581 n = c;
582 vpp = &n->n_ptrs[i]; 582 vpp = &n->n_ptrs[i];
583 if (path != NULL) { 583 if (path != NULL) {
584 refs++; 584 refs++;
585 refs->pptr = vpp; 585 refs->pptr = vpp;
586 } 586 }
587 shift -= RADIX_TREE_BITS_PER_HEIGHT; 587 shift -= RADIX_TREE_BITS_PER_HEIGHT;
588 } 588 }
589 if (alloc) { 589 if (alloc) {
590 KASSERT(*vpp == NULL); 590 KASSERT(*vpp == NULL);
591 } 591 }
592 if (path != NULL) { 592 if (path != NULL) {
593 path->p_lastidx = refs - path->p_refs; 593 path->p_lastidx = refs - path->p_refs;
594 } 594 }
595 return vpp; 595 return vpp;
596} 596}
597 597
598/* 598/*
599 * radix_tree_insert_node: 599 * radix_tree_insert_node:
600 * 600 *
601 * Insert the node at the given index. 601 * Insert the node at the given index.
602 * 602 *
603 * It's illegal to insert NULL. It's illegal to insert a non-aligned pointer. 603 * It's illegal to insert NULL. It's illegal to insert a non-aligned pointer.
604 * 604 *
605 * This function returns ENOMEM if necessary memory allocation failed. 605 * This function returns ENOMEM if necessary memory allocation failed.
606 * Otherwise, this function returns 0. 606 * Otherwise, this function returns 0.
607 * 607 *
608 * Note that inserting a node can involves memory allocation for intermediate 608 * Note that inserting a node can involves memory allocation for intermediate
609 * nodes. If _KERNEL, it's done with no-sleep IPL_NONE memory allocation. 609 * nodes. If _KERNEL, it's done with no-sleep IPL_NONE memory allocation.
610 * 610 *
611 * For the newly inserted node, all tags are cleared. 611 * For the newly inserted node, all tags are cleared.
612 */ 612 */
613 613
614int 614int
615radix_tree_insert_node(struct radix_tree *t, uint64_t idx, void *p) 615radix_tree_insert_node(struct radix_tree *t, uint64_t idx, void *p)
616{ 616{
617 void **vpp; 617 void **vpp;
618 618
619 KASSERT(p != NULL); 619 KASSERT(p != NULL);
620 KASSERT(entry_tagmask(entry_compose(p, 0)) == 0); 620 KASSERT(entry_tagmask(entry_compose(p, 0)) == 0);
621 vpp = radix_tree_lookup_ptr(t, idx, NULL, true, 0); 621 vpp = radix_tree_lookup_ptr(t, idx, NULL, true, 0);
622 if (vpp == NULL) { 622 if (vpp == NULL) {
623 return ENOMEM; 623 return ENOMEM;
624 } 624 }
625 KASSERT(*vpp == NULL); 625 KASSERT(*vpp == NULL);
626 *vpp = p; 626 *vpp = p;
627 return 0; 627 return 0;
628} 628}
629 629
630/* 630/*
631 * radix_tree_replace_node: 631 * radix_tree_replace_node:
632 * 632 *
633 * Replace a node at the given index with the given node and return the 633 * Replace a node at the given index with the given node and return the
634 * replaced one. 634 * replaced one.
635 * 635 *
636 * It's illegal to try to replace a node which has not been inserted. 636 * It's illegal to try to replace a node which has not been inserted.
637 * 637 *
638 * This function keeps tags intact. 638 * This function keeps tags intact.
639 */ 639 */
640 640
641void * 641void *
642radix_tree_replace_node(struct radix_tree *t, uint64_t idx, void *p) 642radix_tree_replace_node(struct radix_tree *t, uint64_t idx, void *p)
643{ 643{
644 void **vpp; 644 void **vpp;
645 void *oldp; 645 void *oldp;
646 646
647 KASSERT(p != NULL); 647 KASSERT(p != NULL);
648 KASSERT(entry_tagmask(entry_compose(p, 0)) == 0); 648 KASSERT(entry_tagmask(entry_compose(p, 0)) == 0);
649 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, 0); 649 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, 0);
650 KASSERT(vpp != NULL); 650 KASSERT(vpp != NULL);
651 oldp = *vpp; 651 oldp = *vpp;
652 KASSERT(oldp != NULL); 652 KASSERT(oldp != NULL);
653 *vpp = entry_compose(p, entry_tagmask(*vpp)); 653 *vpp = entry_compose(p, entry_tagmask(*vpp));
654 return entry_ptr(oldp); 654 return entry_ptr(oldp);
655} 655}
656 656
657/* 657/*
658 * radix_tree_remove_node: 658 * radix_tree_remove_node:
659 * 659 *
660 * Remove the node at the given index. 660 * Remove the node at the given index.
661 * 661 *
662 * It's illegal to try to remove a node which has not been inserted. 662 * It's illegal to try to remove a node which has not been inserted.
663 */ 663 */
664 664
665void * 665void *
666radix_tree_remove_node(struct radix_tree *t, uint64_t idx) 666radix_tree_remove_node(struct radix_tree *t, uint64_t idx)
667{ 667{
668 struct radix_tree_path path; 668 struct radix_tree_path path;
669 void **vpp; 669 void **vpp;
670 void *oldp; 670 void *oldp;
671 int i; 671 int i;
672 672
673 vpp = radix_tree_lookup_ptr(t, idx, &path, false, 0); 673 vpp = radix_tree_lookup_ptr(t, idx, &path, false, 0);
674 KASSERT(vpp != NULL); 674 KASSERT(vpp != NULL);
675 oldp = *vpp; 675 oldp = *vpp;
676 KASSERT(oldp != NULL); 676 KASSERT(oldp != NULL);
677 KASSERT(path.p_lastidx == t->t_height); 677 KASSERT(path.p_lastidx == t->t_height);
678 KASSERT(vpp == path_pptr(t, &path, path.p_lastidx)); 678 KASSERT(vpp == path_pptr(t, &path, path.p_lastidx));
679 *vpp = NULL; 679 *vpp = NULL;
680 for (i = t->t_height - 1; i >= 0; i--) { 680 for (i = t->t_height - 1; i >= 0; i--) {
681 void *entry; 681 void *entry;
682 struct radix_tree_node ** const pptr = 682 struct radix_tree_node ** const pptr =
683 (struct radix_tree_node **)path_pptr(t, &path, i); 683 (struct radix_tree_node **)path_pptr(t, &path, i);
684 struct radix_tree_node *n; 684 struct radix_tree_node *n;
685 685
686 KASSERT(pptr != NULL); 686 KASSERT(pptr != NULL);
687 entry = *pptr; 687 entry = *pptr;
688 n = entry_ptr(entry); 688 n = entry_ptr(entry);
689 KASSERT(n != NULL); 689 KASSERT(n != NULL);
690 if (!radix_tree_node_clean_p(n)) { 690 if (!radix_tree_node_clean_p(n)) {
691 break; 691 break;
692 } 692 }
693 radix_tree_free_node(n); 693 radix_tree_free_node(n);
694 *pptr = NULL; 694 *pptr = NULL;
695 } 695 }
696 /* 696 /*
697 * fix up height 697 * fix up height
698 */ 698 */
699 if (i < 0) { 699 if (i < 0) {
700 KASSERT(t->t_root == NULL); 700 KASSERT(t->t_root == NULL);
701 t->t_height = 0; 701 t->t_height = 0;
702 } 702 }
703 /* 703 /*
704 * update tags 704 * update tags
705 */ 705 */
706 for (; i >= 0; i--) { 706 for (; i >= 0; i--) {
707 void *entry; 707 void *entry;
708 struct radix_tree_node ** const pptr = 708 struct radix_tree_node ** const pptr =
709 (struct radix_tree_node **)path_pptr(t, &path, i); 709 (struct radix_tree_node **)path_pptr(t, &path, i);
710 struct radix_tree_node *n; 710 struct radix_tree_node *n;
711 unsigned int newmask; 711 unsigned int newmask;
712 712
713 KASSERT(pptr != NULL); 713 KASSERT(pptr != NULL);
714 entry = *pptr; 714 entry = *pptr;
715 n = entry_ptr(entry); 715 n = entry_ptr(entry);
716 KASSERT(n != NULL); 716 KASSERT(n != NULL);
717 KASSERT(!radix_tree_node_clean_p(n)); 717 KASSERT(!radix_tree_node_clean_p(n));
718 newmask = any_children_tagmask(n); 718 newmask = any_children_tagmask(n);
719 if (newmask == entry_tagmask(entry)) { 719 if (newmask == entry_tagmask(entry)) {
720 break; 720 break;
721 } 721 }
722 *pptr = entry_compose(n, newmask); 722 *pptr = entry_compose(n, newmask);
723 } 723 }
724 /* 724 /*
725 * XXX is it worth to try to reduce height? 725 * XXX is it worth to try to reduce height?
726 * if we do that, make radix_tree_grow rollback its change as well. 726 * if we do that, make radix_tree_grow rollback its change as well.
727 */ 727 */
728 return entry_ptr(oldp); 728 return entry_ptr(oldp);
729} 729}
730 730
731/* 731/*
732 * radix_tree_lookup_node: 732 * radix_tree_lookup_node:
733 * 733 *
734 * Returns the node at the given index. 734 * Returns the node at the given index.
735 * Returns NULL if nothing is found at the given index. 735 * Returns NULL if nothing is found at the given index.
736 */ 736 */
737 737
738void * 738void *
739radix_tree_lookup_node(struct radix_tree *t, uint64_t idx) 739radix_tree_lookup_node(struct radix_tree *t, uint64_t idx)
740{ 740{
741 void **vpp; 741 void **vpp;
742 742
743 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, 0); 743 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, 0);
744 if (vpp == NULL) { 744 if (vpp == NULL) {
745 return NULL; 745 return NULL;
746 } 746 }
747 return entry_ptr(*vpp); 747 return entry_ptr(*vpp);
748} 748}
749 749
750static inline void 750static inline void
751gang_lookup_init(struct radix_tree *t, uint64_t idx, 751gang_lookup_init(struct radix_tree *t, uint64_t idx,
752 struct radix_tree_path *path, const unsigned int tagmask) 752 struct radix_tree_path *path, const unsigned int tagmask)
753{ 753{
754 void **vpp __unused; 754 void **vpp __unused;
755 755
756 vpp = radix_tree_lookup_ptr(t, idx, path, false, tagmask); 756 vpp = radix_tree_lookup_ptr(t, idx, path, false, tagmask);
757 KASSERT(vpp == NULL || 757 KASSERT(vpp == NULL ||
758 vpp == path_pptr(t, path, path->p_lastidx)); 758 vpp == path_pptr(t, path, path->p_lastidx));
759 KASSERT(&t->t_root == path_pptr(t, path, 0)); 759 KASSERT(&t->t_root == path_pptr(t, path, 0));
760 KASSERT(path->p_lastidx == RADIX_TREE_INVALID_HEIGHT || 760 KASSERT(path->p_lastidx == RADIX_TREE_INVALID_HEIGHT ||
761 path->p_lastidx == t->t_height || 761 path->p_lastidx == t->t_height ||
762 !entry_match_p(*path_pptr(t, path, path->p_lastidx), tagmask)); 762 !entry_match_p(*path_pptr(t, path, path->p_lastidx), tagmask));
763} 763}
764 764
765/* 765/*
766 * gang_lookup_scan: 766 * gang_lookup_scan:
767 * 767 *
768 * a helper routine for radix_tree_gang_lookup_node and its variants. 768 * a helper routine for radix_tree_gang_lookup_node and its variants.
769 */ 769 */
770 770
771static inline unsigned int 771static inline unsigned int
772__attribute__((__always_inline__)) 772__attribute__((__always_inline__))
773gang_lookup_scan(struct radix_tree *t, struct radix_tree_path *path, 773gang_lookup_scan(struct radix_tree *t, struct radix_tree_path *path,
774 void **results, const unsigned int maxresults, const unsigned int tagmask, 774 void **results, const unsigned int maxresults, const unsigned int tagmask,
775 const bool reverse, const bool dense) 775 const bool reverse, const bool dense)
776{ 776{
777 777
778 /* 778 /*
779 * we keep the path updated only for lastidx-1. 779 * we keep the path updated only for lastidx-1.
780 * vpp is what path_pptr(t, path, lastidx) would be. 780 * vpp is what path_pptr(t, path, lastidx) would be.
781 */ 781 */
782 void **vpp; 782 void **vpp;
783 unsigned int nfound; 783 unsigned int nfound;
784 unsigned int lastidx; 784 unsigned int lastidx;
785 /* 785 /*
786 * set up scan direction dependant constants so that we can iterate 786 * set up scan direction dependant constants so that we can iterate
787 * n_ptrs as the following. 787 * n_ptrs as the following.
788 * 788 *
789 * for (i = first; i != guard; i += step) 789 * for (i = first; i != guard; i += step)
790 * visit n->n_ptrs[i]; 790 * visit n->n_ptrs[i];
791 */ 791 */
792 const int step = reverse ? -1 : 1; 792 const int step = reverse ? -1 : 1;
793 const unsigned int first = reverse ? RADIX_TREE_PTR_PER_NODE - 1 : 0; 793 const unsigned int first = reverse ? RADIX_TREE_PTR_PER_NODE - 1 : 0;
794 const unsigned int last = reverse ? 0 : RADIX_TREE_PTR_PER_NODE - 1; 794 const unsigned int last = reverse ? 0 : RADIX_TREE_PTR_PER_NODE - 1;
795 const unsigned int guard = last + step; 795 const unsigned int guard = last + step;
796 796
797 KASSERT(maxresults > 0); 797 KASSERT(maxresults > 0);
798 KASSERT(&t->t_root == path_pptr(t, path, 0)); 798 KASSERT(&t->t_root == path_pptr(t, path, 0));
799 lastidx = path->p_lastidx; 799 lastidx = path->p_lastidx;
800 KASSERT(lastidx == RADIX_TREE_INVALID_HEIGHT || 800 KASSERT(lastidx == RADIX_TREE_INVALID_HEIGHT ||
801 lastidx == t->t_height || 801 lastidx == t->t_height ||
802 !entry_match_p(*path_pptr(t, path, lastidx), tagmask)); 802 !entry_match_p(*path_pptr(t, path, lastidx), tagmask));
803 nfound = 0; 803 nfound = 0;
804 if (lastidx == RADIX_TREE_INVALID_HEIGHT) { 804 if (lastidx == RADIX_TREE_INVALID_HEIGHT) {
805 /* 805 /*
806 * requested idx is beyond the right-most node. 806 * requested idx is beyond the right-most node.
807 */ 807 */
808 if (reverse && !dense) { 808 if (reverse && !dense) {
809 lastidx = 0; 809 lastidx = 0;
810 vpp = path_pptr(t, path, lastidx); 810 vpp = path_pptr(t, path, lastidx);
811 goto descend; 811 goto descend;
812 } 812 }
813 return 0; 813 return 0;
814 } 814 }
815 vpp = path_pptr(t, path, lastidx); 815 vpp = path_pptr(t, path, lastidx);
816 while (/*CONSTCOND*/true) { 816 while (/*CONSTCOND*/true) {
817 struct radix_tree_node *n; 817 struct radix_tree_node *n;
818 unsigned int i; 818 unsigned int i;
819 819
820 if (entry_match_p(*vpp, tagmask)) { 820 if (entry_match_p(*vpp, tagmask)) {
821 KASSERT(lastidx == t->t_height); 821 KASSERT(lastidx == t->t_height);
822 /* 822 /*
823 * record the matching non-NULL leaf. 823 * record the matching non-NULL leaf.
824 */ 824 */
825 results[nfound] = entry_ptr(*vpp); 825 results[nfound] = entry_ptr(*vpp);
826 nfound++; 826 nfound++;
827 if (nfound == maxresults) { 827 if (nfound == maxresults) {
828 return nfound; 828 return nfound;
829 } 829 }
830 } else if (dense) { 830 } else if (dense) {
831 return nfound; 831 return nfound;
832 } 832 }
833scan_siblings: 833scan_siblings:
834 /* 834 /*
835 * try to find the next matching non-NULL sibling. 835 * try to find the next matching non-NULL sibling.
836 */ 836 */
837 if (lastidx == 0) { 837 if (lastidx == 0) {
838 /* 838 /*
839 * the root has no siblings. 839 * the root has no siblings.
840 * we've done. 840 * we've done.
841 */ 841 */
842 KASSERT(vpp == &t->t_root); 842 KASSERT(vpp == &t->t_root);
843 break; 843 break;
844 } 844 }
845 n = path_node(t, path, lastidx - 1); 845 n = path_node(t, path, lastidx - 1);
846 /* 
847 * we used to have an integer counter in the node, and this 
848 * optimization made sense then, even though marginal. it 
849 * no longer provides benefit with the structure cache line 
850 * aligned and the counter replaced by an unrolled sequence 
851 * testing the pointers in batch. 
852 */ 
853#if 0 
854 if (*vpp != NULL && radix_tree_node_count_ptrs(n) == 1) { 
855 /* 
856 * optimization; if the node has only a single pointer 
857 * and we've already visited it, there's no point to 
858 * keep scanning in this node. 
859 */ 
860 goto no_siblings; 
861 } 
862#endif /* 0 */ 
863 for (i = vpp - n->n_ptrs + step; i != guard; i += step) { 846 for (i = vpp - n->n_ptrs + step; i != guard; i += step) {
864 KASSERT(i < RADIX_TREE_PTR_PER_NODE); 847 KASSERT(i < RADIX_TREE_PTR_PER_NODE);
865 if (entry_match_p(n->n_ptrs[i], tagmask)) { 848 if (entry_match_p(n->n_ptrs[i], tagmask)) {
866 vpp = &n->n_ptrs[i]; 849 vpp = &n->n_ptrs[i];
867 break; 850 break;
 851 } else if (dense) {
 852 return nfound;
868 } 853 }
869 } 854 }
870 if (i == guard) { 855 if (i == guard) {
871#if 0 
872no_siblings: 
873#endif /* 0 */ 
874 /* 856 /*
875 * not found. go to parent. 857 * not found. go to parent.
876 */ 858 */
877 lastidx--; 859 lastidx--;
878 vpp = path_pptr(t, path, lastidx); 860 vpp = path_pptr(t, path, lastidx);
879 goto scan_siblings; 861 goto scan_siblings;
880 } 862 }
881descend: 863descend:
882 /* 864 /*
883 * following the left-most (or right-most in the case of 865 * following the left-most (or right-most in the case of
884 * reverse scan) child node, decend until reaching the leaf or 866 * reverse scan) child node, decend until reaching the leaf or
885 * an non-matching entry. 867 * an non-matching entry.
886 */ 868 */
887 while (entry_match_p(*vpp, tagmask) && lastidx < t->t_height) { 869 while (entry_match_p(*vpp, tagmask) && lastidx < t->t_height) {
888 /* 870 /*
889 * save vpp in the path so that we can come back to this 871 * save vpp in the path so that we can come back to this
890 * node after finishing visiting children. 872 * node after finishing visiting children.
891 */ 873 */
892 path->p_refs[lastidx].pptr = vpp; 874 path->p_refs[lastidx].pptr = vpp;
893 n = entry_ptr(*vpp); 875 n = entry_ptr(*vpp);
894 vpp = &n->n_ptrs[first]; 876 vpp = &n->n_ptrs[first];
895 lastidx++; 877 lastidx++;
896 } 878 }
897 } 879 }
898 return nfound; 880 return nfound;
899} 881}
900 882
901/* 883/*
902 * radix_tree_gang_lookup_node: 884 * radix_tree_gang_lookup_node:
903 * 885 *
904 * Scan the tree starting from the given index in the ascending order and 886 * Scan the tree starting from the given index in the ascending order and
905 * return found nodes. 887 * return found nodes.
906 * 888 *
907 * results should be an array large enough to hold maxresults pointers. 889 * results should be an array large enough to hold maxresults pointers.
908 * This function returns the number of nodes found, up to maxresults. 890 * This function returns the number of nodes found, up to maxresults.
909 * Returning less than maxresults means there are no more nodes in the tree. 891 * Returning less than maxresults means there are no more nodes in the tree.
910 * 892 *
911 * If dense == true, this function stops scanning when it founds a hole of 893 * If dense == true, this function stops scanning when it founds a hole of
912 * indexes. I.e. an index for which radix_tree_lookup_node would returns NULL. 894 * indexes. I.e. an index for which radix_tree_lookup_node would returns NULL.
913 * If dense == false, this function skips holes and continue scanning until 895 * If dense == false, this function skips holes and continue scanning until
914 * maxresults nodes are found or it reaches the limit of the index range. 896 * maxresults nodes are found or it reaches the limit of the index range.
915 * 897 *
916 * The result of this function is semantically equivalent to what could be 898 * The result of this function is semantically equivalent to what could be
917 * obtained by repeated calls of radix_tree_lookup_node with increasing index. 899 * obtained by repeated calls of radix_tree_lookup_node with increasing index.
918 * but this function is expected to be computationally cheaper when looking up 900 * but this function is expected to be computationally cheaper when looking up
919 * multiple nodes at once. Especially, it's expected to be much cheaper when 901 * multiple nodes at once. Especially, it's expected to be much cheaper when
920 * node indexes are distributed sparsely. 902 * node indexes are distributed sparsely.
921 * 903 *
922 * Note that this function doesn't return index values of found nodes. 904 * Note that this function doesn't return index values of found nodes.
923 * Thus, in the case of dense == false, if index values are important for 905 * Thus, in the case of dense == false, if index values are important for
924 * a caller, it's the caller's responsibility to check them, typically 906 * a caller, it's the caller's responsibility to check them, typically
925 * by examinining the returned nodes using some caller-specific knowledge 907 * by examinining the returned nodes using some caller-specific knowledge
926 * about them. 908 * about them.
927 * In the case of dense == true, a node returned via results[N] is always for 909 * In the case of dense == true, a node returned via results[N] is always for
928 * the index (idx + N). 910 * the index (idx + N).
929 */ 911 */
930 912
931unsigned int 913unsigned int
932radix_tree_gang_lookup_node(struct radix_tree *t, uint64_t idx, 914radix_tree_gang_lookup_node(struct radix_tree *t, uint64_t idx,
933 void **results, unsigned int maxresults, bool dense) 915 void **results, unsigned int maxresults, bool dense)
934{ 916{
935 struct radix_tree_path path; 917 struct radix_tree_path path;
936 918
937 gang_lookup_init(t, idx, &path, 0); 919 gang_lookup_init(t, idx, &path, 0);
938 return gang_lookup_scan(t, &path, results, maxresults, 0, false, dense); 920 return gang_lookup_scan(t, &path, results, maxresults, 0, false, dense);
939} 921}
940 922
941/* 923/*
942 * radix_tree_gang_lookup_node_reverse: 924 * radix_tree_gang_lookup_node_reverse:
943 * 925 *
944 * Same as radix_tree_gang_lookup_node except that this one scans the 926 * Same as radix_tree_gang_lookup_node except that this one scans the
945 * tree in the reverse order. I.e. descending index values. 927 * tree in the reverse order. I.e. descending index values.
946 */ 928 */
947 929
948unsigned int 930unsigned int
949radix_tree_gang_lookup_node_reverse(struct radix_tree *t, uint64_t idx, 931radix_tree_gang_lookup_node_reverse(struct radix_tree *t, uint64_t idx,
950 void **results, unsigned int maxresults, bool dense) 932 void **results, unsigned int maxresults, bool dense)
951{ 933{
952 struct radix_tree_path path; 934 struct radix_tree_path path;
953 935
954 gang_lookup_init(t, idx, &path, 0); 936 gang_lookup_init(t, idx, &path, 0);
955 return gang_lookup_scan(t, &path, results, maxresults, 0, true, dense); 937 return gang_lookup_scan(t, &path, results, maxresults, 0, true, dense);
956} 938}
957 939
958/* 940/*
959 * radix_tree_gang_lookup_tagged_node: 941 * radix_tree_gang_lookup_tagged_node:
960 * 942 *
961 * Same as radix_tree_gang_lookup_node except that this one only returns 943 * Same as radix_tree_gang_lookup_node except that this one only returns
962 * nodes tagged with tagid. 944 * nodes tagged with tagid.
963 * 945 *
964 * It's illegal to call this function with tagmask 0. 946 * It's illegal to call this function with tagmask 0.
965 */ 947 */
966 948
967unsigned int 949unsigned int
968radix_tree_gang_lookup_tagged_node(struct radix_tree *t, uint64_t idx, 950radix_tree_gang_lookup_tagged_node(struct radix_tree *t, uint64_t idx,
969 void **results, unsigned int maxresults, bool dense, unsigned int tagmask) 951 void **results, unsigned int maxresults, bool dense, unsigned int tagmask)
970{ 952{
971 struct radix_tree_path path; 953 struct radix_tree_path path;
972 954
973 KASSERT(tagmask != 0); 955 KASSERT(tagmask != 0);
974 gang_lookup_init(t, idx, &path, tagmask); 956 gang_lookup_init(t, idx, &path, tagmask);
975 return gang_lookup_scan(t, &path, results, maxresults, tagmask, false, 957 return gang_lookup_scan(t, &path, results, maxresults, tagmask, false,
976 dense); 958 dense);
977} 959}
978 960
979/* 961/*
980 * radix_tree_gang_lookup_tagged_node_reverse: 962 * radix_tree_gang_lookup_tagged_node_reverse:
981 * 963 *
982 * Same as radix_tree_gang_lookup_tagged_node except that this one scans the 964 * Same as radix_tree_gang_lookup_tagged_node except that this one scans the
983 * tree in the reverse order. I.e. descending index values. 965 * tree in the reverse order. I.e. descending index values.
984 */ 966 */
985 967
986unsigned int 968unsigned int
987radix_tree_gang_lookup_tagged_node_reverse(struct radix_tree *t, uint64_t idx, 969radix_tree_gang_lookup_tagged_node_reverse(struct radix_tree *t, uint64_t idx,
988 void **results, unsigned int maxresults, bool dense, unsigned int tagmask) 970 void **results, unsigned int maxresults, bool dense, unsigned int tagmask)
989{ 971{
990 struct radix_tree_path path; 972 struct radix_tree_path path;
991 973
992 KASSERT(tagmask != 0); 974 KASSERT(tagmask != 0);
993 gang_lookup_init(t, idx, &path, tagmask); 975 gang_lookup_init(t, idx, &path, tagmask);
994 return gang_lookup_scan(t, &path, results, maxresults, tagmask, true, 976 return gang_lookup_scan(t, &path, results, maxresults, tagmask, true,
995 dense); 977 dense);
996} 978}
997 979
998/* 980/*
999 * radix_tree_get_tag: 981 * radix_tree_get_tag:
1000 * 982 *
1001 * Return the tagmask for the node at the given index. 983 * Return the tagmask for the node at the given index.
1002 * 984 *
1003 * It's illegal to call this function for a node which has not been inserted. 985 * It's illegal to call this function for a node which has not been inserted.
1004 */ 986 */
1005 987
1006unsigned int 988unsigned int
1007radix_tree_get_tag(struct radix_tree *t, uint64_t idx, unsigned int tagmask) 989radix_tree_get_tag(struct radix_tree *t, uint64_t idx, unsigned int tagmask)
1008{ 990{
1009 /* 991 /*
1010 * the following two implementations should behave same. 992 * the following two implementations should behave same.
1011 * the former one was chosen because it seems faster. 993 * the former one was chosen because it seems faster.
1012 */ 994 */
1013#if 1 995#if 1
1014 void **vpp; 996 void **vpp;
1015 997
1016 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, tagmask); 998 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, tagmask);
1017 if (vpp == NULL) { 999 if (vpp == NULL) {
1018 return false; 1000 return false;
1019 } 1001 }
1020 KASSERT(*vpp != NULL); 1002 KASSERT(*vpp != NULL);
1021 return (entry_tagmask(*vpp) & tagmask); 1003 return (entry_tagmask(*vpp) & tagmask);
1022#else 1004#else
1023 void **vpp; 1005 void **vpp;
1024 1006
1025 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, 0); 1007 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, 0);
1026 KASSERT(vpp != NULL); 1008 KASSERT(vpp != NULL);
1027 return (entry_tagmask(*vpp) & tagmask); 1009 return (entry_tagmask(*vpp) & tagmask);
1028#endif 1010#endif
1029} 1011}
1030 1012
1031/* 1013/*
1032 * radix_tree_set_tag: 1014 * radix_tree_set_tag:
1033 * 1015 *
1034 * Set the tag for the node at the given index. 1016 * Set the tag for the node at the given index.
1035 * 1017 *
1036 * It's illegal to call this function for a node which has not been inserted. 1018 * It's illegal to call this function for a node which has not been inserted.
1037 * It's illegal to call this function with tagmask 0. 1019 * It's illegal to call this function with tagmask 0.
1038 */ 1020 */
1039 1021
1040void 1022void
1041radix_tree_set_tag(struct radix_tree *t, uint64_t idx, unsigned int tagmask) 1023radix_tree_set_tag(struct radix_tree *t, uint64_t idx, unsigned int tagmask)
1042{ 1024{
1043 struct radix_tree_path path; 1025 struct radix_tree_path path;
1044 void **vpp __unused; 1026 void **vpp __unused;
1045 int i; 1027 int i;
1046 1028
1047 KASSERT(tagmask != 0); 1029 KASSERT(tagmask != 0);
1048 vpp = radix_tree_lookup_ptr(t, idx, &path, false, 0); 1030 vpp = radix_tree_lookup_ptr(t, idx, &path, false, 0);
1049 KASSERT(vpp != NULL); 1031 KASSERT(vpp != NULL);
1050 KASSERT(*vpp != NULL); 1032 KASSERT(*vpp != NULL);
1051 KASSERT(path.p_lastidx == t->t_height); 1033 KASSERT(path.p_lastidx == t->t_height);
1052 KASSERT(vpp == path_pptr(t, &path, path.p_lastidx)); 1034 KASSERT(vpp == path_pptr(t, &path, path.p_lastidx));
1053 for (i = t->t_height; i >= 0; i--) { 1035 for (i = t->t_height; i >= 0; i--) {
1054 void ** const pptr = (void **)path_pptr(t, &path, i); 1036 void ** const pptr = (void **)path_pptr(t, &path, i);
1055 void *entry; 1037 void *entry;
1056 1038
1057 KASSERT(pptr != NULL); 1039 KASSERT(pptr != NULL);
1058 entry = *pptr; 1040 entry = *pptr;
1059 if ((entry_tagmask(entry) & tagmask) != 0) { 1041 if ((entry_tagmask(entry) & tagmask) != 0) {
1060 break; 1042 break;
1061 } 1043 }
1062 *pptr = (void *)((uintptr_t)entry | tagmask); 1044 *pptr = (void *)((uintptr_t)entry | tagmask);
1063 } 1045 }
1064} 1046}
1065 1047
1066/* 1048/*
1067 * radix_tree_clear_tag: 1049 * radix_tree_clear_tag:
1068 * 1050 *
1069 * Clear the tag for the node at the given index. 1051 * Clear the tag for the node at the given index.
1070 * 1052 *
1071 * It's illegal to call this function for a node which has not been inserted. 1053 * It's illegal to call this function for a node which has not been inserted.
1072 * It's illegal to call this function with tagmask 0. 1054 * It's illegal to call this function with tagmask 0.
1073 */ 1055 */
1074 1056
1075void 1057void
1076radix_tree_clear_tag(struct radix_tree *t, uint64_t idx, unsigned int tagmask) 1058radix_tree_clear_tag(struct radix_tree *t, uint64_t idx, unsigned int tagmask)
1077{ 1059{
1078 struct radix_tree_path path; 1060 struct radix_tree_path path;
1079 void **vpp; 1061 void **vpp;
1080 int i; 1062 int i;
1081 1063
1082 KASSERT(tagmask != 0); 1064 KASSERT(tagmask != 0);
1083 vpp = radix_tree_lookup_ptr(t, idx, &path, false, 0); 1065 vpp = radix_tree_lookup_ptr(t, idx, &path, false, 0);
1084 KASSERT(vpp != NULL); 1066 KASSERT(vpp != NULL);
1085 KASSERT(*vpp != NULL); 1067 KASSERT(*vpp != NULL);
1086 KASSERT(path.p_lastidx == t->t_height); 1068 KASSERT(path.p_lastidx == t->t_height);
1087 KASSERT(vpp == path_pptr(t, &path, path.p_lastidx)); 1069 KASSERT(vpp == path_pptr(t, &path, path.p_lastidx));
1088 /* 1070 /*
1089 * if already cleared, nothing to do 1071 * if already cleared, nothing to do
1090 */ 1072 */
1091 if ((entry_tagmask(*vpp) & tagmask) == 0) { 1073 if ((entry_tagmask(*vpp) & tagmask) == 0) {
1092 return; 1074 return;
1093 } 1075 }
1094 /* 1076 /*
1095 * clear the tag only if no children have the tag. 1077 * clear the tag only if no children have the tag.
1096 */ 1078 */
1097 for (i = t->t_height; i >= 0; i--) { 1079 for (i = t->t_height; i >= 0; i--) {
1098 void ** const pptr = (void **)path_pptr(t, &path, i); 1080 void ** const pptr = (void **)path_pptr(t, &path, i);
1099 void *entry; 1081 void *entry;
1100 1082
1101 KASSERT(pptr != NULL); 1083 KASSERT(pptr != NULL);
1102 entry = *pptr; 1084 entry = *pptr;
1103 KASSERT((entry_tagmask(entry) & tagmask) != 0); 1085 KASSERT((entry_tagmask(entry) & tagmask) != 0);
1104 *pptr = entry_compose(entry_ptr(entry), 1086 *pptr = entry_compose(entry_ptr(entry),
1105 entry_tagmask(entry) & ~tagmask); 1087 entry_tagmask(entry) & ~tagmask);
1106 /* 1088 /*
1107 * check if we should proceed to process the next level. 1089 * check if we should proceed to process the next level.
1108 */ 1090 */
1109 if (0 < i) { 1091 if (0 < i) {
1110 struct radix_tree_node *n = path_node(t, &path, i - 1); 1092 struct radix_tree_node *n = path_node(t, &path, i - 1);
1111 1093
1112 if ((any_children_tagmask(n) & tagmask) != 0) { 1094 if ((any_children_tagmask(n) & tagmask) != 0) {
1113 break; 1095 break;
1114 } 1096 }
1115 } 1097 }
1116 } 1098 }
1117} 1099}
1118 1100
1119#if defined(UNITTEST) 1101#if defined(UNITTEST)
1120 1102
1121#include <inttypes.h> 1103#include <inttypes.h>
1122#include <stdio.h> 1104#include <stdio.h>
1123 1105
1124static void 1106static void
1125radix_tree_dump_node(const struct radix_tree *t, void *vp, 1107radix_tree_dump_node(const struct radix_tree *t, void *vp,
1126 uint64_t offset, unsigned int height) 1108 uint64_t offset, unsigned int height)
1127{ 1109{
1128 struct radix_tree_node *n; 1110 struct radix_tree_node *n;
1129 unsigned int i; 1111 unsigned int i;
1130 1112
1131 for (i = 0; i < t->t_height - height; i++) { 1113 for (i = 0; i < t->t_height - height; i++) {
1132 printf(" "); 1114 printf(" ");
1133 } 1115 }
1134 if (entry_tagmask(vp) == 0) { 1116 if (entry_tagmask(vp) == 0) {
1135 printf("[%" PRIu64 "] %p", offset, entry_ptr(vp)); 1117 printf("[%" PRIu64 "] %p", offset, entry_ptr(vp));
1136 } else { 1118 } else {
1137 printf("[%" PRIu64 "] %p (tagmask=0x%x)", offset, entry_ptr(vp), 1119 printf("[%" PRIu64 "] %p (tagmask=0x%x)", offset, entry_ptr(vp),
1138 entry_tagmask(vp)); 1120 entry_tagmask(vp));
1139 } 1121 }
1140 if (height == 0) { 1122 if (height == 0) {
1141 printf(" (leaf)\n"); 1123 printf(" (leaf)\n");
1142 return; 1124 return;
1143 } 1125 }
1144 n = entry_ptr(vp); 1126 n = entry_ptr(vp);
1145 assert(any_children_tagmask(n) == entry_tagmask(vp)); 1127 assert(any_children_tagmask(n) == entry_tagmask(vp));
1146 printf(" (%u children)\n", radix_tree_node_count_ptrs(n)); 1128 printf(" (%u children)\n", radix_tree_node_count_ptrs(n));
1147 for (i = 0; i < __arraycount(n->n_ptrs); i++) { 1129 for (i = 0; i < __arraycount(n->n_ptrs); i++) {
1148 void *c; 1130 void *c;
1149 1131
1150 c = n->n_ptrs[i]; 1132 c = n->n_ptrs[i];
1151 if (c == NULL) { 1133 if (c == NULL) {
1152 continue; 1134 continue;
1153 } 1135 }
1154 radix_tree_dump_node(t, c, 1136 radix_tree_dump_node(t, c,
1155 offset + i * (UINT64_C(1) << 1137 offset + i * (UINT64_C(1) <<
1156 (RADIX_TREE_BITS_PER_HEIGHT * (height - 1))), height - 1); 1138 (RADIX_TREE_BITS_PER_HEIGHT * (height - 1))), height - 1);
1157 } 1139 }
1158} 1140}
1159 1141
1160void radix_tree_dump(const struct radix_tree *); 1142void radix_tree_dump(const struct radix_tree *);
1161 1143
1162void 1144void
1163radix_tree_dump(const struct radix_tree *t) 1145radix_tree_dump(const struct radix_tree *t)
1164{ 1146{
1165 1147
1166 printf("tree %p height=%u\n", t, t->t_height); 1148 printf("tree %p height=%u\n", t, t->t_height);
1167 radix_tree_dump_node(t, t->t_root, 0, t->t_height); 1149 radix_tree_dump_node(t, t->t_root, 0, t->t_height);
1168} 1150}
1169 1151
1170static void 1152static void
1171test1(void) 1153test1(void)
1172{ 1154{
1173 struct radix_tree s; 1155 struct radix_tree s;
1174 struct radix_tree *t = &s; 1156 struct radix_tree *t = &s;
1175 void *results[3]; 1157 void *results[3];
1176 1158
1177 radix_tree_init_tree(t); 1159 radix_tree_init_tree(t);
1178 radix_tree_dump(t); 1160 radix_tree_dump(t);
1179 assert(radix_tree_lookup_node(t, 0) == NULL); 1161 assert(radix_tree_lookup_node(t, 0) == NULL);
1180 assert(radix_tree_lookup_node(t, 1000) == NULL); 1162 assert(radix_tree_lookup_node(t, 1000) == NULL);
1181 assert(radix_tree_gang_lookup_node(t, 0, results, 3, false) == 0); 1163 assert(radix_tree_gang_lookup_node(t, 0, results, 3, false) == 0);
1182 assert(radix_tree_gang_lookup_node(t, 0, results, 3, true) == 0); 1164 assert(radix_tree_gang_lookup_node(t, 0, results, 3, true) == 0);
1183 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, false) == 0); 1165 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, false) == 0);
1184 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, true) == 0); 1166 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, true) == 0);
1185 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, false) == 1167 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, false) ==
1186 0); 1168 0);
1187 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, true) == 1169 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, true) ==
1188 0); 1170 0);
1189 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, false) 1171 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, false)
1190 == 0); 1172 == 0);
1191 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, true) 1173 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, true)
1192 == 0); 1174 == 0);
1193 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, false, 1) 1175 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, false, 1)
1194 == 0); 1176 == 0);
1195 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, true, 1) 1177 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, true, 1)
1196 == 0); 1178 == 0);
1197 assert(radix_tree_gang_lookup_tagged_node(t, 1000, results, 3, false, 1) 1179 assert(radix_tree_gang_lookup_tagged_node(t, 1000, results, 3, false, 1)
1198 == 0); 1180 == 0);
1199 assert(radix_tree_gang_lookup_tagged_node(t, 1000, results, 3, true, 1) 1181 assert(radix_tree_gang_lookup_tagged_node(t, 1000, results, 3, true, 1)
1200 == 0); 1182 == 0);
1201 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3, 1183 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3,
1202 false, 1) == 0); 1184 false, 1) == 0);
1203 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3, 1185 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3,
1204 true, 1) == 0); 1186 true, 1) == 0);
1205 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 1000, results, 3, 1187 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 1000, results, 3,
1206 false, 1) == 0); 1188 false, 1) == 0);
1207 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 1000, results, 3, 1189 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 1000, results, 3,
1208 true, 1) == 0); 1190 true, 1) == 0);
1209 assert(radix_tree_empty_tree_p(t)); 1191 assert(radix_tree_empty_tree_p(t));
1210 assert(radix_tree_empty_tagged_tree_p(t, 1)); 1192 assert(radix_tree_empty_tagged_tree_p(t, 1));
1211 assert(radix_tree_empty_tagged_tree_p(t, 2)); 1193 assert(radix_tree_empty_tagged_tree_p(t, 2));
1212 assert(radix_tree_insert_node(t, 0, (void *)0xdeadbea0) == 0); 1194 assert(radix_tree_insert_node(t, 0, (void *)0xdeadbea0) == 0);
1213 assert(!radix_tree_empty_tree_p(t)); 1195 assert(!radix_tree_empty_tree_p(t));
1214 assert(radix_tree_empty_tagged_tree_p(t, 1)); 1196 assert(radix_tree_empty_tagged_tree_p(t, 1));
1215 assert(radix_tree_empty_tagged_tree_p(t, 2)); 1197 assert(radix_tree_empty_tagged_tree_p(t, 2));
1216 assert(radix_tree_lookup_node(t, 0) == (void *)0xdeadbea0); 1198 assert(radix_tree_lookup_node(t, 0) == (void *)0xdeadbea0);
1217 assert(radix_tree_lookup_node(t, 1000) == NULL); 1199 assert(radix_tree_lookup_node(t, 1000) == NULL);
1218 memset(results, 0, sizeof(results)); 1200 memset(results, 0, sizeof(results));
1219 assert(radix_tree_gang_lookup_node(t, 0, results, 3, false) == 1); 1201 assert(radix_tree_gang_lookup_node(t, 0, results, 3, false) == 1);
1220 assert(results[0] == (void *)0xdeadbea0); 1202 assert(results[0] == (void *)0xdeadbea0);
1221 memset(results, 0, sizeof(results)); 1203 memset(results, 0, sizeof(results));
1222 assert(radix_tree_gang_lookup_node(t, 0, results, 3, true) == 1); 1204 assert(radix_tree_gang_lookup_node(t, 0, results, 3, true) == 1);
1223 assert(results[0] == (void *)0xdeadbea0); 1205 assert(results[0] == (void *)0xdeadbea0);
1224 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, false) == 0); 1206 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, false) == 0);
1225 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, true) == 0); 1207 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, true) == 0);
1226 memset(results, 0, sizeof(results)); 1208 memset(results, 0, sizeof(results));
1227 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, false) == 1209 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, false) ==
1228 1); 1210 1);
1229 assert(results[0] == (void *)0xdeadbea0); 1211 assert(results[0] == (void *)0xdeadbea0);
1230 memset(results, 0, sizeof(results)); 1212 memset(results, 0, sizeof(results));
1231 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, true) == 1213 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, true) ==
1232 1); 1214 1);
1233 assert(results[0] == (void *)0xdeadbea0); 1215 assert(results[0] == (void *)0xdeadbea0);
1234 memset(results, 0, sizeof(results)); 1216 memset(results, 0, sizeof(results));
1235 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, false) 1217 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, false)
1236 == 1); 1218 == 1);
1237 assert(results[0] == (void *)0xdeadbea0); 1219 assert(results[0] == (void *)0xdeadbea0);
1238 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, true) 1220 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, true)
1239 == 0); 1221 == 0);
1240 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, false, 1) 1222 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, false, 1)
1241 == 0); 1223 == 0);
1242 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, true, 1) 1224 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, true, 1)
1243 == 0); 1225 == 0);
1244 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3, 1226 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3,
1245 false, 1) == 0); 1227 false, 1) == 0);
1246 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3, 1228 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3,
1247 true, 1) == 0); 1229 true, 1) == 0);
1248 assert(radix_tree_insert_node(t, 1000, (void *)0xdeadbea0) == 0); 1230 assert(radix_tree_insert_node(t, 1000, (void *)0xdeadbea0) == 0);
1249 assert(radix_tree_remove_node(t, 0) == (void *)0xdeadbea0); 1231 assert(radix_tree_remove_node(t, 0) == (void *)0xdeadbea0);
1250 assert(!radix_tree_empty_tree_p(t)); 1232 assert(!radix_tree_empty_tree_p(t));
1251 radix_tree_dump(t); 1233 radix_tree_dump(t);
1252 assert(radix_tree_lookup_node(t, 0) == NULL); 1234 assert(radix_tree_lookup_node(t, 0) == NULL);
1253 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0); 1235 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0);
1254 memset(results, 0, sizeof(results)); 1236 memset(results, 0, sizeof(results));
1255 assert(radix_tree_gang_lookup_node(t, 0, results, 3, false) == 1); 1237 assert(radix_tree_gang_lookup_node(t, 0, results, 3, false) == 1);
1256 assert(results[0] == (void *)0xdeadbea0); 1238 assert(results[0] == (void *)0xdeadbea0);
1257 assert(radix_tree_gang_lookup_node(t, 0, results, 3, true) == 0); 1239 assert(radix_tree_gang_lookup_node(t, 0, results, 3, true) == 0);
1258 memset(results, 0, sizeof(results)); 1240 memset(results, 0, sizeof(results));
1259 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, false) == 1); 1241 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, false) == 1);
1260 assert(results[0] == (void *)0xdeadbea0); 1242 assert(results[0] == (void *)0xdeadbea0);
1261 memset(results, 0, sizeof(results)); 1243 memset(results, 0, sizeof(results));
1262 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, true) == 1); 1244 assert(radix_tree_gang_lookup_node(t, 1000, results, 3, true) == 1);
1263 assert(results[0] == (void *)0xdeadbea0); 1245 assert(results[0] == (void *)0xdeadbea0);
1264 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, false) 1246 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, false)
1265 == 0); 1247 == 0);
1266 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, true) 1248 assert(radix_tree_gang_lookup_node_reverse(t, 0, results, 3, true)
1267 == 0); 1249 == 0);
1268 memset(results, 0, sizeof(results)); 1250 memset(results, 0, sizeof(results));
1269 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, false) 1251 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, false)
1270 == 1); 1252 == 1);
1271 memset(results, 0, sizeof(results)); 1253 memset(results, 0, sizeof(results));
1272 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, true) 1254 assert(radix_tree_gang_lookup_node_reverse(t, 1000, results, 3, true)
1273 == 1); 1255 == 1);
1274 assert(results[0] == (void *)0xdeadbea0); 1256 assert(results[0] == (void *)0xdeadbea0);
1275 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, false, 1) 1257 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, false, 1)
1276 == 0); 1258 == 0);
1277 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, true, 1) 1259 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 3, true, 1)
1278 == 0); 1260 == 0);
1279 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3, 1261 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3,
1280 false, 1) == 0); 1262 false, 1) == 0);
1281 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3, 1263 assert(radix_tree_gang_lookup_tagged_node_reverse(t, 0, results, 3,
1282 true, 1) == 0); 1264 true, 1) == 0);
1283 assert(!radix_tree_get_tag(t, 1000, 1)); 1265 assert(!radix_tree_get_tag(t, 1000, 1));
1284 assert(!radix_tree_get_tag(t, 1000, 2)); 1266 assert(!radix_tree_get_tag(t, 1000, 2));
1285 assert(radix_tree_get_tag(t, 1000, 2 | 1) == 0); 1267 assert(radix_tree_get_tag(t, 1000, 2 | 1) == 0);
1286 assert(radix_tree_empty_tagged_tree_p(t, 1)); 1268 assert(radix_tree_empty_tagged_tree_p(t, 1));
1287 assert(radix_tree_empty_tagged_tree_p(t, 2)); 1269 assert(radix_tree_empty_tagged_tree_p(t, 2));
1288 radix_tree_set_tag(t, 1000, 2); 1270 radix_tree_set_tag(t, 1000, 2);
1289 assert(!radix_tree_get_tag(t, 1000, 1)); 1271 assert(!radix_tree_get_tag(t, 1000, 1));
1290 assert(radix_tree_get_tag(t, 1000, 2)); 1272 assert(radix_tree_get_tag(t, 1000, 2));
1291 assert(radix_tree_get_tag(t, 1000, 2 | 1) == 2); 1273 assert(radix_tree_get_tag(t, 1000, 2 | 1) == 2);
1292 assert(radix_tree_empty_tagged_tree_p(t, 1)); 1274 assert(radix_tree_empty_tagged_tree_p(t, 1));
1293 assert(!radix_tree_empty_tagged_tree_p(t, 2)); 1275 assert(!radix_tree_empty_tagged_tree_p(t, 2));
1294 radix_tree_dump(t); 1276 radix_tree_dump(t);
1295 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0); 1277 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0);
1296 assert(radix_tree_insert_node(t, 0, (void *)0xbea0) == 0); 1278 assert(radix_tree_insert_node(t, 0, (void *)0xbea0) == 0);
1297 radix_tree_dump(t); 1279 radix_tree_dump(t);
1298 assert(radix_tree_lookup_node(t, 0) == (void *)0xbea0); 1280 assert(radix_tree_lookup_node(t, 0) == (void *)0xbea0);
1299 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0); 1281 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0);
1300 assert(radix_tree_insert_node(t, UINT64_C(10000000000), (void *)0xdea0) 1282 assert(radix_tree_insert_node(t, UINT64_C(10000000000), (void *)0xdea0)
1301 == 0); 1283 == 0);
1302 radix_tree_dump(t); 1284 radix_tree_dump(t);
1303 assert(radix_tree_lookup_node(t, 0) == (void *)0xbea0); 1285 assert(radix_tree_lookup_node(t, 0) == (void *)0xbea0);
1304 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0); 1286 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0);
1305 assert(radix_tree_lookup_node(t, UINT64_C(10000000000)) == 1287 assert(radix_tree_lookup_node(t, UINT64_C(10000000000)) ==
1306 (void *)0xdea0); 1288 (void *)0xdea0);
1307 radix_tree_dump(t); 1289 radix_tree_dump(t);
1308 assert(!radix_tree_get_tag(t, 0, 2)); 1290 assert(!radix_tree_get_tag(t, 0, 2));
1309 assert(radix_tree_get_tag(t, 1000, 2)); 1291 assert(radix_tree_get_tag(t, 1000, 2));
1310 assert(!radix_tree_get_tag(t, UINT64_C(10000000000), 1)); 1292 assert(!radix_tree_get_tag(t, UINT64_C(10000000000), 1));
1311 radix_tree_set_tag(t, 0, 2);; 1293 radix_tree_set_tag(t, 0, 2);;
1312 radix_tree_set_tag(t, UINT64_C(10000000000), 2); 1294 radix_tree_set_tag(t, UINT64_C(10000000000), 2);
1313 radix_tree_dump(t); 1295 radix_tree_dump(t);
1314 assert(radix_tree_get_tag(t, 0, 2)); 1296 assert(radix_tree_get_tag(t, 0, 2));
1315 assert(radix_tree_get_tag(t, 1000, 2)); 1297 assert(radix_tree_get_tag(t, 1000, 2));
1316 assert(radix_tree_get_tag(t, UINT64_C(10000000000), 2)); 1298 assert(radix_tree_get_tag(t, UINT64_C(10000000000), 2));
1317 radix_tree_clear_tag(t, 0, 2);; 1299 radix_tree_clear_tag(t, 0, 2);;
1318 radix_tree_clear_tag(t, UINT64_C(10000000000), 2); 1300 radix_tree_clear_tag(t, UINT64_C(10000000000), 2);
1319 radix_tree_dump(t); 1301 radix_tree_dump(t);
1320 assert(!radix_tree_get_tag(t, 0, 2)); 1302 assert(!radix_tree_get_tag(t, 0, 2));
1321 assert(radix_tree_get_tag(t, 1000, 2)); 1303 assert(radix_tree_get_tag(t, 1000, 2));
1322 assert(!radix_tree_get_tag(t, UINT64_C(10000000000), 2)); 1304 assert(!radix_tree_get_tag(t, UINT64_C(10000000000), 2));
1323 radix_tree_dump(t); 1305 radix_tree_dump(t);
1324 assert(radix_tree_replace_node(t, 1000, (void *)0x12345678) == 1306 assert(radix_tree_replace_node(t, 1000, (void *)0x12345678) ==
1325 (void *)0xdeadbea0); 1307 (void *)0xdeadbea0);
1326 assert(!radix_tree_get_tag(t, 1000, 1)); 1308 assert(!radix_tree_get_tag(t, 1000, 1));
1327 assert(radix_tree_get_tag(t, 1000, 2)); 1309 assert(radix_tree_get_tag(t, 1000, 2));
1328 assert(radix_tree_get_tag(t, 1000, 2 | 1) == 2); 1310 assert(radix_tree_get_tag(t, 1000, 2 | 1) == 2);
1329 memset(results, 0, sizeof(results)); 1311 memset(results, 0, sizeof(results));
1330 assert(radix_tree_gang_lookup_node(t, 0, results, 3, false) == 3); 1312 assert(radix_tree_gang_lookup_node(t, 0, results, 3, false) == 3);
1331 assert(results[0] == (void *)0xbea0); 1313 assert(results[0] == (void *)0xbea0);
1332 assert(results[1] == (void *)0x12345678); 1314 assert(results[1] == (void *)0x12345678);
1333 assert(results[2] == (void *)0xdea0); 1315 assert(results[2] == (void *)0xdea0);
1334 memset(results, 0, sizeof(results)); 1316 memset(results, 0, sizeof(results));
1335 assert(radix_tree_gang_lookup_node(t, 0, results, 3, true) == 1); 1317 assert(radix_tree_gang_lookup_node(t, 0, results, 3, true) == 1);
1336 assert(results[0] == (void *)0xbea0); 1318 assert(results[0] == (void *)0xbea0);
1337 memset(results, 0, sizeof(results)); 1319 memset(results, 0, sizeof(results));
1338 assert(radix_tree_gang_lookup_node(t, 1, results, 3, false) == 2); 1320 assert(radix_tree_gang_lookup_node(t, 1, results, 3, false) == 2);
1339 assert(results[0] == (void *)0x12345678); 1321 assert(results[0] == (void *)0x12345678);
1340 assert(results[1] == (void *)0xdea0); 1322 assert(results[1] == (void *)0xdea0);
1341 assert(radix_tree_gang_lookup_node(t, 1, results, 3, true) == 0); 1323 assert(radix_tree_gang_lookup_node(t, 1, results, 3, true) == 0);
1342 memset(results, 0, sizeof(results)); 1324 memset(results, 0, sizeof(results));
1343 assert(radix_tree_gang_lookup_node(t, 1001, results, 3, false) == 1); 1325 assert(radix_tree_gang_lookup_node(t, 1001, results, 3, false) == 1);
1344 assert(results[0] == (void *)0xdea0); 1326 assert(results[0] == (void *)0xdea0);
1345 assert(radix_tree_gang_lookup_node(t, 1001, results, 3, true) == 0); 1327 assert(radix_tree_gang_lookup_node(t, 1001, results, 3, true) == 0);
1346 assert(radix_tree_gang_lookup_node(t, UINT64_C(10000000001), results, 3, 1328 assert(radix_tree_gang_lookup_node(t, UINT64_C(10000000001), results, 3,
1347 false) == 0); 1329 false) == 0);
1348 assert(radix_tree_gang_lookup_node(t, UINT64_C(10000000001), results, 3, 1330 assert(radix_tree_gang_lookup_node(t, UINT64_C(10000000001), results, 3,
1349 true) == 0); 1331 true) == 0);
1350 assert(radix_tree_gang_lookup_node(t, UINT64_C(1000000000000), results, 1332 assert(radix_tree_gang_lookup_node(t, UINT64_C(1000000000000), results,
1351 3, false) == 0); 1333 3, false) == 0);
1352 assert(radix_tree_gang_lookup_node(t, UINT64_C(1000000000000), results, 1334 assert(radix_tree_gang_lookup_node(t, UINT64_C(1000000000000), results,
1353 3, true) == 0); 1335 3, true) == 0);
1354 memset(results, 0, sizeof(results)); 1336 memset(results, 0, sizeof(results));
1355 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 100, false, 2) 1337 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 100, false, 2)
1356 == 1); 1338 == 1);
1357 assert(results[0] == (void *)0x12345678); 1339 assert(results[0] == (void *)0x12345678);
1358 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 100, true, 2) 1340 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 100, true, 2)
1359 == 0); 1341 == 0);
1360 assert(entry_tagmask(t->t_root) != 0); 1342 assert(entry_tagmask(t->t_root) != 0);
1361 assert(radix_tree_remove_node(t, 1000) == (void *)0x12345678); 1343 assert(radix_tree_remove_node(t, 1000) == (void *)0x12345678);
1362 assert(entry_tagmask(t->t_root) == 0); 1344 assert(entry_tagmask(t->t_root) == 0);
1363 radix_tree_dump(t); 1345 radix_tree_dump(t);
1364 assert(radix_tree_insert_node(t, UINT64_C(10000000001), (void *)0xfff0) 1346 assert(radix_tree_insert_node(t, UINT64_C(10000000001), (void *)0xfff0)
1365 == 0); 1347 == 0);
1366 memset(results, 0, sizeof(results)); 1348 memset(results, 0, sizeof(results));
1367 assert(radix_tree_gang_lookup_node(t, UINT64_C(10000000000), results, 3, 1349 assert(radix_tree_gang_lookup_node(t, UINT64_C(10000000000), results, 3,
1368 false) == 2); 1350 false) == 2);
1369 assert(results[0] == (void *)0xdea0); 1351 assert(results[0] == (void *)0xdea0);
1370 assert(results[1] == (void *)0xfff0); 1352 assert(results[1] == (void *)0xfff0);
1371 memset(results, 0, sizeof(results)); 1353 memset(results, 0, sizeof(results));
1372 assert(radix_tree_gang_lookup_node(t, UINT64_C(10000000000), results, 3, 1354 assert(radix_tree_gang_lookup_node(t, UINT64_C(10000000000), results, 3,
1373 true) == 2); 1355 true) == 2);
1374 assert(results[0] == (void *)0xdea0); 1356 assert(results[0] == (void *)0xdea0);
1375 assert(results[1] == (void *)0xfff0); 1357 assert(results[1] == (void *)0xfff0);
1376 memset(results, 0, sizeof(results)); 1358 memset(results, 0, sizeof(results));
1377 assert(radix_tree_gang_lookup_node_reverse(t, UINT64_C(10000000001), 1359 assert(radix_tree_gang_lookup_node_reverse(t, UINT64_C(10000000001),
1378 results, 3, false) == 3); 1360 results, 3, false) == 3);
1379 assert(results[0] == (void *)0xfff0); 1361 assert(results[0] == (void *)0xfff0);
1380 assert(results[1] == (void *)0xdea0); 1362 assert(results[1] == (void *)0xdea0);
1381 assert(results[2] == (void *)0xbea0); 1363 assert(results[2] == (void *)0xbea0);
1382 memset(results, 0, sizeof(results)); 1364 memset(results, 0, sizeof(results));
1383 assert(radix_tree_gang_lookup_node_reverse(t, UINT64_C(10000000001), 1365 assert(radix_tree_gang_lookup_node_reverse(t, UINT64_C(10000000001),
1384 results, 3, true) == 2); 1366 results, 3, true) == 2);
1385 assert(results[0] == (void *)0xfff0); 1367 assert(results[0] == (void *)0xfff0);
1386 assert(results[1] == (void *)0xdea0); 1368 assert(results[1] == (void *)0xdea0);
1387 assert(radix_tree_remove_node(t, UINT64_C(10000000000)) == 1369 assert(radix_tree_remove_node(t, UINT64_C(10000000000)) ==
1388 (void *)0xdea0); 1370 (void *)0xdea0);
1389 assert(radix_tree_remove_node(t, UINT64_C(10000000001)) == 1371 assert(radix_tree_remove_node(t, UINT64_C(10000000001)) ==
1390 (void *)0xfff0); 1372 (void *)0xfff0);
1391 radix_tree_dump(t); 1373 radix_tree_dump(t);
1392 assert(radix_tree_remove_node(t, 0) == (void *)0xbea0); 1374 assert(radix_tree_remove_node(t, 0) == (void *)0xbea0);
1393 radix_tree_dump(t); 1375 radix_tree_dump(t);
1394 radix_tree_fini_tree(t); 1376 radix_tree_fini_tree(t);
1395} 1377}
1396 1378
1397#include <sys/time.h> 1379#include <sys/time.h>
1398 1380
1399struct testnode { 1381struct testnode {
1400 uint64_t idx; 1382 uint64_t idx;
1401 bool tagged[RADIX_TREE_TAG_ID_MAX]; 1383 bool tagged[RADIX_TREE_TAG_ID_MAX];
1402}; 1384};
1403 1385
1404static void 1386static void
1405printops(const char *title, const char *name, int tag, unsigned int n, 1387printops(const char *title, const char *name, int tag, unsigned int n,
1406 const struct timeval *stv, const struct timeval *etv) 1388 const struct timeval *stv, const struct timeval *etv)
1407{ 1389{
1408 uint64_t s = stv->tv_sec * 1000000 + stv->tv_usec; 1390 uint64_t s = stv->tv_sec * 1000000 + stv->tv_usec;
1409 uint64_t e = etv->tv_sec * 1000000 + etv->tv_usec; 1391 uint64_t e = etv->tv_sec * 1000000 + etv->tv_usec;
1410 1392
1411 printf("RESULT %s %s %d %lf op/s\n", title, name, tag, 1393 printf("RESULT %s %s %d %lf op/s\n", title, name, tag,
1412 (double)n / (e - s) * 1000000); 1394 (double)n / (e - s) * 1000000);
1413} 1395}
1414 1396
1415#define TEST2_GANG_LOOKUP_NODES 16 1397#define TEST2_GANG_LOOKUP_NODES 16
1416 1398
1417static bool 1399static bool
1418test2_should_tag(unsigned int i, unsigned int tagid) 1400test2_should_tag(unsigned int i, unsigned int tagid)
1419{ 1401{
1420 1402
1421 if (tagid == 0) { 1403 if (tagid == 0) {
1422 return (i % 4) == 0; /* 25% */ 1404 return (i % 4) == 0; /* 25% */
1423 } else { 1405 } else {
1424 return (i % 7) == 0; /* 14% */ 1406 return (i % 7) == 0; /* 14% */
1425 } 1407 }
1426 return 1; 1408 return 1;
1427} 1409}
1428 1410
1429static void 1411static void
1430check_tag_count(const unsigned int *ntagged, unsigned int tagmask, 1412check_tag_count(const unsigned int *ntagged, unsigned int tagmask,
1431 unsigned int count) 1413 unsigned int count)
1432{ 1414{
1433 unsigned int tag; 1415 unsigned int tag;
1434 1416
1435 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1417 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) {
1436 if ((tagmask & (1 << tag)) == 0) { 1418 if ((tagmask & (1 << tag)) == 0) {
1437 continue; 1419 continue;
1438 } 1420 }
1439 if (((tagmask - 1) & tagmask) == 0) { 1421 if (((tagmask - 1) & tagmask) == 0) {
1440 assert(count == ntagged[tag]); 1422 assert(count == ntagged[tag]);
1441 } else { 1423 } else {
1442 assert(count >= ntagged[tag]); 1424 assert(count >= ntagged[tag]);
1443 } 1425 }
1444 } 1426 }
1445} 1427}
1446 1428
1447static void 1429static void
1448test2(const char *title, bool dense) 1430test2(const char *title, bool dense)
1449{ 1431{
1450 struct radix_tree s; 1432 struct radix_tree s;
1451 struct radix_tree *t = &s; 1433 struct radix_tree *t = &s;
1452 struct testnode *n; 1434 struct testnode *n;
1453 unsigned int i; 1435 unsigned int i;
1454 unsigned int nnodes = 100000; 1436 unsigned int nnodes = 100000;
1455 unsigned int removed; 1437 unsigned int removed;
1456 unsigned int tag; 1438 unsigned int tag;
1457 unsigned int tagmask; 1439 unsigned int tagmask;
1458 unsigned int ntagged[RADIX_TREE_TAG_ID_MAX]; 1440 unsigned int ntagged[RADIX_TREE_TAG_ID_MAX];
1459 struct testnode *nodes; 1441 struct testnode *nodes;
1460 struct timeval stv; 1442 struct timeval stv;
1461 struct timeval etv; 1443 struct timeval etv;
1462 1444
1463 nodes = malloc(nnodes * sizeof(*nodes)); 1445 nodes = malloc(nnodes * sizeof(*nodes));
1464 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1446 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) {
1465 ntagged[tag] = 0; 1447 ntagged[tag] = 0;
1466 } 1448 }
1467 radix_tree_init_tree(t); 1449 radix_tree_init_tree(t);
1468 for (i = 0; i < nnodes; i++) { 1450 for (i = 0; i < nnodes; i++) {
1469 n = &nodes[i]; 1451 n = &nodes[i];
1470 n->idx = random(); 1452 n->idx = random();
1471 if (sizeof(long) == 4) { 1453 if (sizeof(long) == 4) {
1472 n->idx <<= 32; 1454 n->idx <<= 32;
1473 n->idx |= (uint32_t)random(); 1455 n->idx |= (uint32_t)random();
1474 } 1456 }
1475 if (dense) { 1457 if (dense) {
1476 n->idx %= nnodes * 2; 1458 n->idx %= nnodes * 2;
1477 } 1459 }
1478 while (radix_tree_lookup_node(t, n->idx) != NULL) { 1460 while (radix_tree_lookup_node(t, n->idx) != NULL) {
1479 n->idx++; 1461 n->idx++;
1480 } 1462 }
1481 radix_tree_insert_node(t, n->idx, n); 1463 radix_tree_insert_node(t, n->idx, n);
1482 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1464 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) {
1483 tagmask = 1 << tag; 1465 tagmask = 1 << tag;
1484 1466
1485 n->tagged[tag] = test2_should_tag(i, tag); 1467 n->tagged[tag] = test2_should_tag(i, tag);
1486 if (n->tagged[tag]) { 1468 if (n->tagged[tag]) {
1487 radix_tree_set_tag(t, n->idx, tagmask); 1469 radix_tree_set_tag(t, n->idx, tagmask);
1488 ntagged[tag]++; 1470 ntagged[tag]++;
1489 } 1471 }
1490 assert((n->tagged[tag] ? tagmask : 0) == 1472 assert((n->tagged[tag] ? tagmask : 0) ==
1491 radix_tree_get_tag(t, n->idx, tagmask)); 1473 radix_tree_get_tag(t, n->idx, tagmask));
1492 } 1474 }
1493 } 1475 }
1494 1476
1495 gettimeofday(&stv, NULL); 1477 gettimeofday(&stv, NULL);
1496 for (i = 0; i < nnodes; i++) { 1478 for (i = 0; i < nnodes; i++) {
1497 n = &nodes[i]; 1479 n = &nodes[i];
1498 assert(radix_tree_lookup_node(t, n->idx) == n); 1480 assert(radix_tree_lookup_node(t, n->idx) == n);
1499 } 1481 }
1500 gettimeofday(&etv, NULL); 1482 gettimeofday(&etv, NULL);
1501 printops(title, "lookup", 0, nnodes, &stv, &etv); 1483 printops(title, "lookup", 0, nnodes, &stv, &etv);
1502 1484
1503 for (tagmask = 1; tagmask <= RADIX_TREE_TAG_MASK; tagmask ++) { 1485 for (tagmask = 1; tagmask <= RADIX_TREE_TAG_MASK; tagmask ++) {
1504 unsigned int count = 0; 1486 unsigned int count = 0;
1505 1487
1506 gettimeofday(&stv, NULL); 1488 gettimeofday(&stv, NULL);
1507 for (i = 0; i < nnodes; i++) { 1489 for (i = 0; i < nnodes; i++) {
1508 unsigned int tagged; 1490 unsigned int tagged;
1509 1491
1510 n = &nodes[i]; 1492 n = &nodes[i];
1511 tagged = radix_tree_get_tag(t, n->idx, tagmask); 1493 tagged = radix_tree_get_tag(t, n->idx, tagmask);
1512 assert((tagged & ~tagmask) == 0); 1494 assert((tagged & ~tagmask) == 0);
1513 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1495 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) {
1514 assert((tagmask & (1 << tag)) == 0 || 1496 assert((tagmask & (1 << tag)) == 0 ||
1515 n->tagged[tag] == !!(tagged & (1 << tag))); 1497 n->tagged[tag] == !!(tagged & (1 << tag)));
1516 } 1498 }
1517 if (tagged) { 1499 if (tagged) {
1518 count++; 1500 count++;
1519 } 1501 }
1520 } 1502 }
1521 gettimeofday(&etv, NULL); 1503 gettimeofday(&etv, NULL);
1522 check_tag_count(ntagged, tagmask, count); 1504 check_tag_count(ntagged, tagmask, count);
1523 printops(title, "get_tag", tagmask, nnodes, &stv, &etv); 1505 printops(title, "get_tag", tagmask, nnodes, &stv, &etv);
1524 } 1506 }
1525 1507
1526 gettimeofday(&stv, NULL); 1508 gettimeofday(&stv, NULL);
1527 for (i = 0; i < nnodes; i++) { 1509 for (i = 0; i < nnodes; i++) {
1528 n = &nodes[i]; 1510 n = &nodes[i];
1529 radix_tree_remove_node(t, n->idx); 1511 radix_tree_remove_node(t, n->idx);
1530 } 1512 }
1531 gettimeofday(&etv, NULL); 1513 gettimeofday(&etv, NULL);
1532 printops(title, "remove", 0, nnodes, &stv, &etv); 1514 printops(title, "remove", 0, nnodes, &stv, &etv);
1533 1515
1534 gettimeofday(&stv, NULL); 1516 gettimeofday(&stv, NULL);
1535 for (i = 0; i < nnodes; i++) { 1517 for (i = 0; i < nnodes; i++) {
1536 n = &nodes[i]; 1518 n = &nodes[i];
1537 radix_tree_insert_node(t, n->idx, n); 1519 radix_tree_insert_node(t, n->idx, n);
1538 } 1520 }
1539 gettimeofday(&etv, NULL); 1521 gettimeofday(&etv, NULL);
1540 printops(title, "insert", 0, nnodes, &stv, &etv); 1522 printops(title, "insert", 0, nnodes, &stv, &etv);
1541 1523
1542 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1524 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) {
1543 tagmask = 1 << tag; 1525 tagmask = 1 << tag;
1544 1526
1545 ntagged[tag] = 0; 1527 ntagged[tag] = 0;
1546 gettimeofday(&stv, NULL); 1528 gettimeofday(&stv, NULL);
1547 for (i = 0; i < nnodes; i++) { 1529 for (i = 0; i < nnodes; i++) {
1548 n = &nodes[i]; 1530 n = &nodes[i];
1549 if (n->tagged[tag]) { 1531 if (n->tagged[tag]) {
1550 radix_tree_set_tag(t, n->idx, tagmask); 1532 radix_tree_set_tag(t, n->idx, tagmask);
1551 ntagged[tag]++; 1533 ntagged[tag]++;
1552 } 1534 }
1553 } 1535 }
1554 gettimeofday(&etv, NULL); 1536 gettimeofday(&etv, NULL);
1555 printops(title, "set_tag", tag, ntagged[tag], &stv, &etv); 1537 printops(title, "set_tag", tag, ntagged[tag], &stv, &etv);
1556 } 1538 }
1557 1539
1558 gettimeofday(&stv, NULL); 1540 gettimeofday(&stv, NULL);
1559 { 1541 {
1560 struct testnode *results[TEST2_GANG_LOOKUP_NODES]; 1542 struct testnode *results[TEST2_GANG_LOOKUP_NODES];
1561 uint64_t nextidx; 1543 uint64_t nextidx;
1562 unsigned int nfound; 1544 unsigned int nfound;
1563 unsigned int total; 1545 unsigned int total;
1564 1546
1565 nextidx = 0; 1547 nextidx = 0;
1566 total = 0; 1548 total = 0;
1567 while ((nfound = radix_tree_gang_lookup_node(t, nextidx, 1549 while ((nfound = radix_tree_gang_lookup_node(t, nextidx,
1568 (void *)results, __arraycount(results), false)) > 0) { 1550 (void *)results, __arraycount(results), false)) > 0) {
1569 nextidx = results[nfound - 1]->idx + 1; 1551 nextidx = results[nfound - 1]->idx + 1;
1570 total += nfound; 1552 total += nfound;
1571 if (nextidx == 0) { 1553 if (nextidx == 0) {
1572 break; 1554 break;
1573 } 1555 }
1574 } 1556 }
1575 assert(total == nnodes); 1557 assert(total == nnodes);
1576 } 1558 }
1577 gettimeofday(&etv, NULL); 1559 gettimeofday(&etv, NULL);
1578 printops(title, "ganglookup", 0, nnodes, &stv, &etv); 1560 printops(title, "ganglookup", 0, nnodes, &stv, &etv);
1579 1561
1580 gettimeofday(&stv, NULL); 1562 gettimeofday(&stv, NULL);
1581 { 1563 {
1582 struct testnode *results[TEST2_GANG_LOOKUP_NODES]; 1564 struct testnode *results[TEST2_GANG_LOOKUP_NODES];
1583 uint64_t nextidx; 1565 uint64_t nextidx;
1584 unsigned int nfound; 1566 unsigned int nfound;
1585 unsigned int total; 1567 unsigned int total;
1586 1568
1587 nextidx = UINT64_MAX; 1569 nextidx = UINT64_MAX;
1588 total = 0; 1570 total = 0;
1589 while ((nfound = radix_tree_gang_lookup_node_reverse(t, nextidx, 1571 while ((nfound = radix_tree_gang_lookup_node_reverse(t, nextidx,
1590 (void *)results, __arraycount(results), false)) > 0) { 1572 (void *)results, __arraycount(results), false)) > 0) {
1591 nextidx = results[nfound - 1]->idx - 1; 1573 nextidx = results[nfound - 1]->idx - 1;
1592 total += nfound; 1574 total += nfound;
1593 if (nextidx == UINT64_MAX) { 1575 if (nextidx == UINT64_MAX) {
1594 break; 1576 break;
1595 } 1577 }
1596 } 1578 }
1597 assert(total == nnodes); 1579 assert(total == nnodes);
1598 } 1580 }
1599 gettimeofday(&etv, NULL); 1581 gettimeofday(&etv, NULL);
1600 printops(title, "ganglookup_reverse", 0, nnodes, &stv, &etv); 1582 printops(title, "ganglookup_reverse", 0, nnodes, &stv, &etv);
1601 1583
1602 for (tagmask = 1; tagmask <= RADIX_TREE_TAG_MASK; tagmask ++) { 1584 for (tagmask = 1; tagmask <= RADIX_TREE_TAG_MASK; tagmask ++) {
1603 unsigned int total = 0; 1585 unsigned int total = 0;
1604 1586
1605 gettimeofday(&stv, NULL); 1587 gettimeofday(&stv, NULL);
1606 { 1588 {
1607 struct testnode *results[TEST2_GANG_LOOKUP_NODES]; 1589 struct testnode *results[TEST2_GANG_LOOKUP_NODES];
1608 uint64_t nextidx; 1590 uint64_t nextidx;
1609 unsigned int nfound; 1591 unsigned int nfound;
1610 1592
1611 nextidx = 0; 1593 nextidx = 0;
1612 while ((nfound = radix_tree_gang_lookup_tagged_node(t, 1594 while ((nfound = radix_tree_gang_lookup_tagged_node(t,
1613 nextidx, (void *)results, __arraycount(results), 1595 nextidx, (void *)results, __arraycount(results),
1614 false, tagmask)) > 0) { 1596 false, tagmask)) > 0) {
1615 nextidx = results[nfound - 1]->idx + 1; 1597 nextidx = results[nfound - 1]->idx + 1;
1616 total += nfound; 1598 total += nfound;
1617 } 1599 }
1618 } 1600 }
1619 gettimeofday(&etv, NULL); 1601 gettimeofday(&etv, NULL);
1620 check_tag_count(ntagged, tagmask, total); 1602 check_tag_count(ntagged, tagmask, total);
1621 assert(tagmask != 0 || total == 0); 1603 assert(tagmask != 0 || total == 0);
1622 printops(title, "ganglookup_tag", tagmask, total, &stv, &etv); 1604 printops(title, "ganglookup_tag", tagmask, total, &stv, &etv);
1623 } 1605 }
1624 1606
1625 for (tagmask = 1; tagmask <= RADIX_TREE_TAG_MASK; tagmask ++) { 1607 for (tagmask = 1; tagmask <= RADIX_TREE_TAG_MASK; tagmask ++) {
1626 unsigned int total = 0; 1608 unsigned int total = 0;
1627 1609
1628 gettimeofday(&stv, NULL); 1610 gettimeofday(&stv, NULL);
1629 { 1611 {
1630 struct testnode *results[TEST2_GANG_LOOKUP_NODES]; 1612 struct testnode *results[TEST2_GANG_LOOKUP_NODES];
1631 uint64_t nextidx; 1613 uint64_t nextidx;
1632 unsigned int nfound; 1614 unsigned int nfound;
1633 1615
1634 nextidx = UINT64_MAX; 1616 nextidx = UINT64_MAX;
1635 while ((nfound = 1617 while ((nfound =
1636 radix_tree_gang_lookup_tagged_node_reverse(t, 1618 radix_tree_gang_lookup_tagged_node_reverse(t,
1637 nextidx, (void *)results, __arraycount(results), 1619 nextidx, (void *)results, __arraycount(results),
1638 false, tagmask)) > 0) { 1620 false, tagmask)) > 0) {
1639 nextidx = results[nfound - 1]->idx - 1; 1621 nextidx = results[nfound - 1]->idx - 1;
1640 total += nfound; 1622 total += nfound;
1641 if (nextidx == UINT64_MAX) { 1623 if (nextidx == UINT64_MAX) {
1642 break; 1624 break;
1643 } 1625 }
1644 } 1626 }
1645 } 1627 }
1646 gettimeofday(&etv, NULL); 1628 gettimeofday(&etv, NULL);
1647 check_tag_count(ntagged, tagmask, total); 1629 check_tag_count(ntagged, tagmask, total);
1648 assert(tagmask != 0 || total == 0); 1630 assert(tagmask != 0 || total == 0);
1649 printops(title, "ganglookup_tag_reverse", tagmask, total, 1631 printops(title, "ganglookup_tag_reverse", tagmask, total,
1650 &stv, &etv); 1632 &stv, &etv);
1651 } 1633 }
1652 1634
1653 removed = 0; 1635 removed = 0;
1654 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1636 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) {
1655 unsigned int total; 1637 unsigned int total;
1656 1638
1657 total = 0; 1639 total = 0;
1658 tagmask = 1 << tag; 1640 tagmask = 1 << tag;
1659 gettimeofday(&stv, NULL); 1641 gettimeofday(&stv, NULL);
1660 { 1642 {
1661 struct testnode *results[TEST2_GANG_LOOKUP_NODES]; 1643 struct testnode *results[TEST2_GANG_LOOKUP_NODES];
1662 uint64_t nextidx; 1644 uint64_t nextidx;
1663 unsigned int nfound; 1645 unsigned int nfound;
1664 1646
1665 nextidx = 0; 1647 nextidx = 0;
1666 while ((nfound = radix_tree_gang_lookup_tagged_node(t, 1648 while ((nfound = radix_tree_gang_lookup_tagged_node(t,
1667 nextidx, (void *)results, __arraycount(results), 1649 nextidx, (void *)results, __arraycount(results),
1668 false, tagmask)) > 0) { 1650 false, tagmask)) > 0) {
1669 for (i = 0; i < nfound; i++) { 1651 for (i = 0; i < nfound; i++) {
1670 radix_tree_remove_node(t, 1652 radix_tree_remove_node(t,
1671 results[i]->idx); 1653 results[i]->idx);
1672 } 1654 }
1673 nextidx = results[nfound - 1]->idx + 1; 1655 nextidx = results[nfound - 1]->idx + 1;
1674 total += nfound; 1656 total += nfound;
1675 if (nextidx == 0) { 1657 if (nextidx == 0) {
1676 break; 1658 break;
1677 } 1659 }
1678 } 1660 }
1679 } 1661 }
1680 gettimeofday(&etv, NULL); 1662 gettimeofday(&etv, NULL);
1681 if (tag == 0) { 1663 if (tag == 0) {
1682 check_tag_count(ntagged, tagmask, total); 1664 check_tag_count(ntagged, tagmask, total);
1683 } else { 1665 } else {
1684 assert(total <= ntagged[tag]); 1666 assert(total <= ntagged[tag]);
1685 } 1667 }
1686 printops(title, "ganglookup_tag+remove", tagmask, total, &stv, 1668 printops(title, "ganglookup_tag+remove", tagmask, total, &stv,
1687 &etv); 1669 &etv);
1688 removed += total; 1670 removed += total;
1689 } 1671 }
1690 1672
1691 gettimeofday(&stv, NULL); 1673 gettimeofday(&stv, NULL);
1692 { 1674 {
1693 struct testnode *results[TEST2_GANG_LOOKUP_NODES]; 1675 struct testnode *results[TEST2_GANG_LOOKUP_NODES];
1694 uint64_t nextidx; 1676 uint64_t nextidx;
1695 unsigned int nfound; 1677 unsigned int nfound;
1696 unsigned int total; 1678 unsigned int total;
1697 1679
1698 nextidx = 0; 1680 nextidx = 0;
1699 total = 0; 1681 total = 0;
1700 while ((nfound = radix_tree_gang_lookup_node(t, nextidx, 1682 while ((nfound = radix_tree_gang_lookup_node(t, nextidx,
1701 (void *)results, __arraycount(results), false)) > 0) { 1683 (void *)results, __arraycount(results), false)) > 0) {
1702 for (i = 0; i < nfound; i++) { 1684 for (i = 0; i < nfound; i++) {
1703 assert(results[i] == radix_tree_remove_node(t, 1685 assert(results[i] == radix_tree_remove_node(t,
1704 results[i]->idx)); 1686 results[i]->idx));
1705 } 1687 }
1706 nextidx = results[nfound - 1]->idx + 1; 1688 nextidx = results[nfound - 1]->idx + 1;
1707 total += nfound; 1689 total += nfound;
1708 if (nextidx == 0) { 1690 if (nextidx == 0) {
1709 break; 1691 break;
1710 } 1692 }
1711 } 1693 }
1712 assert(total == nnodes - removed); 1694 assert(total == nnodes - removed);
1713 } 1695 }
1714 gettimeofday(&etv, NULL); 1696 gettimeofday(&etv, NULL);
1715 printops(title, "ganglookup+remove", 0, nnodes - removed, &stv, &etv); 1697 printops(title, "ganglookup+remove", 0, nnodes - removed, &stv, &etv);
1716 1698
1717 assert(radix_tree_empty_tree_p(t)); 1699 assert(radix_tree_empty_tree_p(t));
1718 for (tagmask = 1; tagmask <= RADIX_TREE_TAG_MASK; tagmask ++) { 1700 for (tagmask = 1; tagmask <= RADIX_TREE_TAG_MASK; tagmask ++) {
1719 assert(radix_tree_empty_tagged_tree_p(t, tagmask)); 1701 assert(radix_tree_empty_tagged_tree_p(t, tagmask));
1720 } 1702 }
1721 radix_tree_fini_tree(t); 1703 radix_tree_fini_tree(t);
1722 free(nodes); 1704 free(nodes);
1723} 1705}
1724 1706
1725int 1707int
1726main(int argc, char *argv[]) 1708main(int argc, char *argv[])
1727{ 1709{
1728 1710
1729 test1(); 1711 test1();
1730 test2("dense", true); 1712 test2("dense", true);
1731 test2("sparse", false); 1713 test2("sparse", false);
1732 return 0; 1714 return 0;
1733} 1715}
1734 1716
1735#endif /* defined(UNITTEST) */ 1717#endif /* defined(UNITTEST) */