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