1 /* $NetBSD: radixtree.c,v 1.7 2011/05/19 10:06:56 yamt Exp $ */ 2 3 /*- 4 * Copyright (c)2011 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 * radix tree 31 * 32 * it's designed to work efficiently with dense index distribution. 33 * the memory consumption (number of necessary intermediate nodes) 34 * heavily depends on index distribution. basically, more dense index 35 * distribution consumes less nodes per item. 36 * approximately, 37 * the best case: about RADIX_TREE_PTR_PER_NODE items per node. 38 * the worst case: RADIX_TREE_MAX_HEIGHT nodes per item. 39 */ 40 41 #include <sys/cdefs.h> 42 43 #if defined(_KERNEL) || defined(_STANDALONE) 44 __KERNEL_RCSID(0, "$NetBSD: radixtree.c,v 1.7 2011/05/19 10:06:56 yamt Exp $"); 45 #include <sys/param.h> 46 #include <sys/errno.h> 47 #include <sys/pool.h> 48 #include <sys/radixtree.h> 49 #include <lib/libkern/libkern.h> 50 #if defined(_STANDALONE) 51 #include <lib/libsa/stand.h> 52 #endif /* defined(_STANDALONE) */ 53 #else /* defined(_KERNEL) || defined(_STANDALONE) */ 54 __RCSID("$NetBSD: radixtree.c,v 1.7 2011/05/19 10:06:56 yamt Exp $"); 55 #include <assert.h> 56 #include <errno.h> 57 #include <stdbool.h> 58 #include <stdlib.h> 59 #if 1 60 #define KASSERT assert 61 #else 62 #define KASSERT(a) /* nothing */ 63 #endif 64 #endif /* defined(_KERNEL) || defined(_STANDALONE) */ 65 66 #include <sys/radixtree.h> 67 68 #define RADIX_TREE_BITS_PER_HEIGHT 4 /* XXX tune */ 69 #define RADIX_TREE_PTR_PER_NODE (1 << RADIX_TREE_BITS_PER_HEIGHT) 70 #define RADIX_TREE_MAX_HEIGHT (64 / RADIX_TREE_BITS_PER_HEIGHT) 71 __CTASSERT((64 % RADIX_TREE_BITS_PER_HEIGHT) == 0); 72 73 __CTASSERT(((1 << RADIX_TREE_TAG_ID_MAX) & (sizeof(int) - 1)) == 0); 74 #define RADIX_TREE_TAG_MASK ((1 << RADIX_TREE_TAG_ID_MAX) - 1) 75 76 static inline void * 77 entry_ptr(void *p) 78 { 79 80 return (void *)((uintptr_t)p & ~RADIX_TREE_TAG_MASK); 81 } 82 83 static inline unsigned int 84 entry_tagmask(void *p) 85 { 86 87 return (uintptr_t)p & RADIX_TREE_TAG_MASK; 88 } 89 90 static inline void * 91 entry_compose(void *p, unsigned int tagmask) 92 { 93 94 return (void *)((uintptr_t)p | tagmask); 95 } 96 97 static inline bool 98 entry_match_p(void *p, unsigned int tagmask) 99 { 100 101 KASSERT(entry_ptr(p) != NULL || entry_tagmask(p) == 0); 102 if (p == NULL) { 103 return false; 104 } 105 if (tagmask == 0) { 106 return true; 107 } 108 return (entry_tagmask(p) & tagmask) != 0; 109 } 110 111 static inline unsigned int 112 tagid_to_mask(radix_tree_tagid_t id) 113 { 114 115 KASSERT(id >= 0); 116 KASSERT(id < RADIX_TREE_TAG_ID_MAX); 117 return 1U << id; 118 } 119 120 /* 121 * radix_tree_node: an intermediate node 122 * 123 * we don't care the type of leaf nodes. they are just void *. 124 */ 125 126 struct radix_tree_node { 127 void *n_ptrs[RADIX_TREE_PTR_PER_NODE]; 128 unsigned int n_nptrs; /* # of non-NULL pointers in n_ptrs */ 129 }; 130 131 /* 132 * any_children_tagmask: 133 * 134 * return OR'ed tagmask of the given node's children. 135 */ 136 137 static unsigned int 138 any_children_tagmask(struct radix_tree_node *n) 139 { 140 unsigned int mask; 141 int i; 142 143 mask = 0; 144 for (i = 0; i < RADIX_TREE_PTR_PER_NODE; i++) { 145 mask |= (unsigned int)(uintptr_t)n->n_ptrs[i]; 146 } 147 return mask & RADIX_TREE_TAG_MASK; 148 } 149 150 /* 151 * p_refs[0].pptr == &t->t_root 152 * : 153 * p_refs[n].pptr == &(*p_refs[n-1])->n_ptrs[x] 154 * : 155 * : 156 * p_refs[t->t_height].pptr == &leaf_pointer 157 */ 158 159 struct radix_tree_path { 160 struct radix_tree_node_ref { 161 void **pptr; 162 } p_refs[RADIX_TREE_MAX_HEIGHT + 1]; /* +1 for the root ptr */ 163 int p_lastidx; 164 }; 165 166 static inline void ** 167 path_pptr(struct radix_tree *t, struct radix_tree_path *p, 168 unsigned int height) 169 { 170 171 KASSERT(height <= t->t_height); 172 return p->p_refs[height].pptr; 173 } 174 175 static inline struct radix_tree_node * 176 path_node(struct radix_tree * t, struct radix_tree_path *p, unsigned int height) 177 { 178 179 KASSERT(height <= t->t_height); 180 return entry_ptr(*path_pptr(t, p, height)); 181 } 182 183 static inline unsigned int 184 path_idx(struct radix_tree * t, struct radix_tree_path *p, unsigned int height) 185 { 186 187 KASSERT(height <= t->t_height); 188 return path_pptr(t, p, height + 1) - path_node(t, p, height)->n_ptrs; 189 } 190 191 /* 192 * radix_tree_init_tree: 193 * 194 * initialize a tree. 195 */ 196 197 void 198 radix_tree_init_tree(struct radix_tree *t) 199 { 200 201 t->t_height = 0; 202 t->t_root = NULL; 203 } 204 205 /* 206 * radix_tree_init_tree: 207 * 208 * clean up a tree. 209 */ 210 211 void 212 radix_tree_fini_tree(struct radix_tree *t) 213 { 214 215 KASSERT(t->t_root == NULL); 216 KASSERT(t->t_height == 0); 217 } 218 219 static void 220 radix_tree_node_init(struct radix_tree_node *n) 221 { 222 223 memset(n, 0, sizeof(*n)); 224 } 225 226 #if defined(_KERNEL) 227 pool_cache_t radix_tree_node_cache __read_mostly; 228 229 static int 230 radix_tree_node_ctor(void *dummy, void *item, int flags) 231 { 232 struct radix_tree_node *n = item; 233 234 KASSERT(dummy == NULL); 235 radix_tree_node_init(n); 236 return 0; 237 } 238 239 /* 240 * radix_tree_init: 241 * 242 * initialize the subsystem. 243 */ 244 245 void 246 radix_tree_init(void) 247 { 248 249 radix_tree_node_cache = pool_cache_init(sizeof(struct radix_tree_node), 250 0, 0, 0, "radix_tree_node", NULL, IPL_NONE, radix_tree_node_ctor, 251 NULL, NULL); 252 KASSERT(radix_tree_node_cache != NULL); 253 } 254 #endif /* defined(_KERNEL) */ 255 256 static bool __unused 257 radix_tree_node_clean_p(const struct radix_tree_node *n) 258 { 259 unsigned int i; 260 261 if (n->n_nptrs != 0) { 262 return false; 263 } 264 for (i = 0; i < RADIX_TREE_PTR_PER_NODE; i++) { 265 if (n->n_ptrs[i] != NULL) { 266 return false; 267 } 268 } 269 return true; 270 } 271 272 static struct radix_tree_node * 273 radix_tree_alloc_node(void) 274 { 275 struct radix_tree_node *n; 276 277 #if defined(_KERNEL) 278 n = pool_cache_get(radix_tree_node_cache, PR_NOWAIT); 279 #else /* defined(_KERNEL) */ 280 #if defined(_STANDALONE) 281 n = alloc(sizeof(*n)); 282 #else /* defined(_STANDALONE) */ 283 n = malloc(sizeof(*n)); 284 #endif /* defined(_STANDALONE) */ 285 if (n != NULL) { 286 radix_tree_node_init(n); 287 } 288 #endif /* defined(_KERNEL) */ 289 KASSERT(n == NULL || radix_tree_node_clean_p(n)); 290 return n; 291 } 292 293 static void 294 radix_tree_free_node(struct radix_tree_node *n) 295 { 296 297 KASSERT(radix_tree_node_clean_p(n)); 298 #if defined(_KERNEL) 299 pool_cache_put(radix_tree_node_cache, n); 300 #elif defined(_STANDALONE) 301 dealloc(n, sizeof(*n)); 302 #else 303 free(n); 304 #endif 305 } 306 307 static int 308 radix_tree_grow(struct radix_tree *t, unsigned int newheight) 309 { 310 const unsigned int tagmask = entry_tagmask(t->t_root); 311 312 KASSERT(newheight <= 64 / RADIX_TREE_BITS_PER_HEIGHT); 313 if (t->t_root == NULL) { 314 t->t_height = newheight; 315 return 0; 316 } 317 while (t->t_height < newheight) { 318 struct radix_tree_node *n; 319 320 n = radix_tree_alloc_node(); 321 if (n == NULL) { 322 /* 323 * don't bother to revert our changes. 324 * the caller will likely retry. 325 */ 326 return ENOMEM; 327 } 328 n->n_nptrs = 1; 329 n->n_ptrs[0] = t->t_root; 330 t->t_root = entry_compose(n, tagmask); 331 t->t_height++; 332 } 333 return 0; 334 } 335 336 /* 337 * radix_tree_lookup_ptr: 338 * 339 * an internal helper function used for various exported functions. 340 * 341 * return the pointer to store the node for the given index. 342 * 343 * if alloc is true, try to allocate the storage. (note for _KERNEL: 344 * in that case, this function can block.) if the allocation failed or 345 * alloc is false, return NULL. 346 * 347 * if path is not NULL, fill it for the caller's investigation. 348 * 349 * if tagmask is not zero, search only for nodes with the tag set. 350 * 351 * while this function is a bit large, as it's called with some constant 352 * arguments, inlining might have benefits. anyway, a compiler will decide. 353 */ 354 355 static inline void ** 356 radix_tree_lookup_ptr(struct radix_tree *t, uint64_t idx, 357 struct radix_tree_path *path, bool alloc, const unsigned int tagmask) 358 { 359 struct radix_tree_node *n; 360 int hshift = RADIX_TREE_BITS_PER_HEIGHT * t->t_height; 361 int shift; 362 void **vpp; 363 const uint64_t mask = (UINT64_C(1) << RADIX_TREE_BITS_PER_HEIGHT) - 1; 364 struct radix_tree_node_ref *refs = NULL; 365 366 /* 367 * check unsupported combinations 368 */ 369 KASSERT(tagmask == 0 || !alloc); 370 KASSERT(path == NULL || !alloc); 371 vpp = &t->t_root; 372 if (path != NULL) { 373 refs = path->p_refs; 374 refs->pptr = vpp; 375 } 376 n = NULL; 377 for (shift = 64 - RADIX_TREE_BITS_PER_HEIGHT; shift >= 0;) { 378 struct radix_tree_node *c; 379 void *entry; 380 const uint64_t i = (idx >> shift) & mask; 381 382 if (shift >= hshift) { 383 unsigned int newheight; 384 385 KASSERT(vpp == &t->t_root); 386 if (i == 0) { 387 shift -= RADIX_TREE_BITS_PER_HEIGHT; 388 continue; 389 } 390 if (!alloc) { 391 if (path != NULL) { 392 KASSERT((refs - path->p_refs) == 0); 393 path->p_lastidx = 0; 394 } 395 return NULL; 396 } 397 newheight = shift / RADIX_TREE_BITS_PER_HEIGHT + 1; 398 if (radix_tree_grow(t, newheight)) { 399 return NULL; 400 } 401 hshift = RADIX_TREE_BITS_PER_HEIGHT * t->t_height; 402 } 403 entry = *vpp; 404 c = entry_ptr(entry); 405 if (c == NULL || 406 (tagmask != 0 && 407 (entry_tagmask(entry) & tagmask) == 0)) { 408 if (!alloc) { 409 if (path != NULL) { 410 path->p_lastidx = refs - path->p_refs; 411 } 412 return NULL; 413 } 414 c = radix_tree_alloc_node(); 415 if (c == NULL) { 416 return NULL; 417 } 418 *vpp = c; 419 if (n != NULL) { 420 KASSERT(n->n_nptrs < RADIX_TREE_PTR_PER_NODE); 421 n->n_nptrs++; 422 } 423 } 424 n = c; 425 vpp = &n->n_ptrs[i]; 426 if (path != NULL) { 427 refs++; 428 refs->pptr = vpp; 429 } 430 shift -= RADIX_TREE_BITS_PER_HEIGHT; 431 } 432 if (alloc) { 433 KASSERT(*vpp == NULL); 434 if (n != NULL) { 435 KASSERT(n->n_nptrs < RADIX_TREE_PTR_PER_NODE); 436 n->n_nptrs++; 437 } 438 } 439 if (path != NULL) { 440 path->p_lastidx = refs - path->p_refs; 441 } 442 return vpp; 443 } 444 445 /* 446 * radix_tree_insert_node: 447 * 448 * insert the node at idx. 449 * it's illegal to insert NULL. 450 * it's illegal to insert a non-aligned pointer. 451 * 452 * this function returns ENOMEM if necessary memory allocation failed. 453 * otherwise, this function returns 0. 454 * 455 * note that inserting a node can involves memory allocation for intermediate 456 * nodes. if _KERNEL, it's done with non-blocking IPL_NONE memory allocation. 457 * 458 * for the newly inserted node, all tags are cleared. 459 */ 460 461 int 462 radix_tree_insert_node(struct radix_tree *t, uint64_t idx, void *p) 463 { 464 void **vpp; 465 466 KASSERT(p != NULL); 467 KASSERT(entry_compose(p, 0) == p); 468 vpp = radix_tree_lookup_ptr(t, idx, NULL, true, 0); 469 if (vpp == NULL) { 470 return ENOMEM; 471 } 472 KASSERT(*vpp == NULL); 473 *vpp = p; 474 return 0; 475 } 476 477 /* 478 * radix_tree_replace_node: 479 * 480 * replace a node at the given index with the given node. 481 * return the old node. 482 * it's illegal to try to replace a node which has not been inserted. 483 * 484 * this function doesn't change tags. 485 */ 486 487 void * 488 radix_tree_replace_node(struct radix_tree *t, uint64_t idx, void *p) 489 { 490 void **vpp; 491 void *oldp; 492 493 KASSERT(p != NULL); 494 KASSERT(entry_compose(p, 0) == p); 495 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, 0); 496 KASSERT(vpp != NULL); 497 oldp = *vpp; 498 KASSERT(oldp != NULL); 499 *vpp = entry_compose(p, entry_tagmask(*vpp)); 500 return entry_ptr(oldp); 501 } 502 503 /* 504 * radix_tree_remove_node: 505 * 506 * remove the node at idx. 507 * it's illegal to try to remove a node which has not been inserted. 508 */ 509 510 void * 511 radix_tree_remove_node(struct radix_tree *t, uint64_t idx) 512 { 513 struct radix_tree_path path; 514 void **vpp; 515 void *oldp; 516 int i; 517 518 vpp = radix_tree_lookup_ptr(t, idx, &path, false, 0); 519 KASSERT(vpp != NULL); 520 oldp = *vpp; 521 KASSERT(oldp != NULL); 522 KASSERT(path.p_lastidx == t->t_height); 523 KASSERT(vpp == path_pptr(t, &path, path.p_lastidx)); 524 *vpp = NULL; 525 for (i = t->t_height - 1; i >= 0; i--) { 526 void *entry; 527 struct radix_tree_node ** const pptr = 528 (struct radix_tree_node **)path_pptr(t, &path, i); 529 struct radix_tree_node *n; 530 531 KASSERT(pptr != NULL); 532 entry = *pptr; 533 n = entry_ptr(entry); 534 KASSERT(n != NULL); 535 KASSERT(n->n_nptrs > 0); 536 n->n_nptrs--; 537 if (n->n_nptrs > 0) { 538 break; 539 } 540 radix_tree_free_node(n); 541 *pptr = NULL; 542 } 543 /* 544 * fix up height 545 */ 546 if (i < 0) { 547 KASSERT(t->t_root == NULL); 548 t->t_height = 0; 549 } 550 /* 551 * update tags 552 */ 553 for (; i >= 0; i--) { 554 void *entry; 555 struct radix_tree_node ** const pptr = 556 (struct radix_tree_node **)path_pptr(t, &path, i); 557 struct radix_tree_node *n; 558 unsigned int newmask; 559 560 KASSERT(pptr != NULL); 561 entry = *pptr; 562 n = entry_ptr(entry); 563 KASSERT(n != NULL); 564 KASSERT(n->n_nptrs > 0); 565 newmask = any_children_tagmask(n); 566 if (newmask == entry_tagmask(entry)) { 567 break; 568 } 569 *pptr = entry_compose(n, newmask); 570 } 571 /* 572 * XXX is it worth to try to reduce height? 573 * if we do that, make radix_tree_grow rollback its change as well. 574 */ 575 return entry_ptr(oldp); 576 } 577 578 /* 579 * radix_tree_lookup_node: 580 * 581 * returns the node at idx. 582 * returns NULL if nothing is found at idx. 583 */ 584 585 void * 586 radix_tree_lookup_node(struct radix_tree *t, uint64_t idx) 587 { 588 void **vpp; 589 590 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, 0); 591 if (vpp == NULL) { 592 return NULL; 593 } 594 return entry_ptr(*vpp); 595 } 596 597 static inline void 598 gang_lookup_init(struct radix_tree *t, uint64_t idx, 599 struct radix_tree_path *path, const unsigned int tagmask) 600 { 601 void **vpp; 602 603 vpp = radix_tree_lookup_ptr(t, idx, path, false, tagmask); 604 KASSERT(vpp == NULL || 605 vpp == path_pptr(t, path, path->p_lastidx)); 606 KASSERT(&t->t_root == path_pptr(t, path, 0)); 607 } 608 609 static inline unsigned int 610 gang_lookup_scan(struct radix_tree *t, struct radix_tree_path *path, 611 void **results, unsigned int maxresults, const unsigned int tagmask) 612 { 613 void **vpp; 614 int nfound; 615 unsigned int lastidx; 616 617 KASSERT(maxresults > 0); 618 lastidx = path->p_lastidx; 619 if (lastidx == 0) { 620 return 0; 621 } 622 nfound = 0; 623 vpp = path_pptr(t, path, lastidx); 624 while (/*CONSTCOND*/true) { 625 struct radix_tree_node *n; 626 int i; 627 628 if (entry_match_p(*vpp, tagmask)) { 629 KASSERT(lastidx == t->t_height); 630 /* 631 * record the non-NULL leaf. 632 */ 633 results[nfound] = entry_ptr(*vpp); 634 nfound++; 635 if (nfound == maxresults) { 636 return nfound; 637 } 638 } 639 scan_siblings: 640 /* 641 * try to find the next non-NULL sibling. 642 */ 643 n = path_node(t, path, lastidx - 1); 644 if (*vpp != NULL && n->n_nptrs == 1) { 645 /* 646 * optimization 647 */ 648 goto no_siblings; 649 } 650 for (i = path_idx(t, path, lastidx - 1) + 1; 651 i < RADIX_TREE_PTR_PER_NODE; 652 i++) { 653 if (entry_match_p(n->n_ptrs[i], tagmask)) { 654 vpp = &n->n_ptrs[i]; 655 path->p_refs[lastidx].pptr = vpp; 656 KASSERT(path_idx(t, path, lastidx - 1) 657 == i); 658 break; 659 } 660 } 661 if (i == RADIX_TREE_PTR_PER_NODE) { 662 no_siblings: 663 /* 664 * not found. go to parent. 665 */ 666 lastidx--; 667 if (lastidx == 0) { 668 return nfound; 669 } 670 vpp = path_pptr(t, path, lastidx); 671 goto scan_siblings; 672 } 673 /* 674 * descending the left-most child node, upto the leaf or NULL. 675 */ 676 while (entry_match_p(*vpp, tagmask) && lastidx < t->t_height) { 677 n = entry_ptr(*vpp); 678 vpp = &n->n_ptrs[0]; 679 lastidx++; 680 path->p_refs[lastidx].pptr = vpp; 681 } 682 } 683 } 684 685 /* 686 * radix_tree_gang_lookup_node: 687 * 688 * search nodes starting from idx in the ascending order. 689 * results should be an array large enough to hold maxresults pointers. 690 * returns the number of nodes found, up to maxresults. 691 * returning less than maxresults means there are no more nodes. 692 * 693 * the result of this function is semantically equivalent to what could be 694 * obtained by repeated calls of radix_tree_lookup_node with increasing index. 695 * but this function is much faster when node indexes are distributed sparsely. 696 * 697 * note that this function doesn't return exact values of node indexes of 698 * found nodes. if they are important for a caller, it's the caller's 699 * responsibility to check them, typically by examinining the returned nodes 700 * using some caller-specific knowledge about them. 701 */ 702 703 unsigned int 704 radix_tree_gang_lookup_node(struct radix_tree *t, uint64_t idx, 705 void **results, unsigned int maxresults) 706 { 707 struct radix_tree_path path; 708 709 gang_lookup_init(t, idx, &path, 0); 710 return gang_lookup_scan(t, &path, results, maxresults, 0); 711 } 712 713 /* 714 * radix_tree_gang_lookup_tagged_node: 715 * 716 * same as radix_tree_gang_lookup_node except that this one only returns 717 * nodes tagged with tagid. 718 */ 719 720 unsigned int 721 radix_tree_gang_lookup_tagged_node(struct radix_tree *t, uint64_t idx, 722 void **results, unsigned int maxresults, radix_tree_tagid_t tagid) 723 { 724 struct radix_tree_path path; 725 const unsigned int tagmask = tagid_to_mask(tagid); 726 727 gang_lookup_init(t, idx, &path, tagmask); 728 return gang_lookup_scan(t, &path, results, maxresults, tagmask); 729 } 730 731 /* 732 * radix_tree_get_tag: 733 * 734 * return if the tag is set for the node at the given index. (true if set) 735 * it's illegal to call this function for a node which has not been inserted. 736 */ 737 738 bool 739 radix_tree_get_tag(struct radix_tree *t, uint64_t idx, 740 radix_tree_tagid_t tagid) 741 { 742 #if 1 743 const unsigned int tagmask = tagid_to_mask(tagid); 744 void **vpp; 745 746 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, tagmask); 747 if (vpp == NULL) { 748 return false; 749 } 750 KASSERT(*vpp != NULL); 751 return (entry_tagmask(*vpp) & tagmask) != 0; 752 #else 753 const unsigned int tagmask = tagid_to_mask(tagid); 754 void **vpp; 755 756 vpp = radix_tree_lookup_ptr(t, idx, NULL, false, 0); 757 KASSERT(vpp != NULL); 758 return (entry_tagmask(*vpp) & tagmask) != 0; 759 #endif 760 } 761 762 /* 763 * radix_tree_set_tag: 764 * 765 * set the tag for the node at the given index. 766 * it's illegal to call this function for a node which has not been inserted. 767 */ 768 769 void 770 radix_tree_set_tag(struct radix_tree *t, uint64_t idx, 771 radix_tree_tagid_t tagid) 772 { 773 struct radix_tree_path path; 774 const unsigned int tagmask = tagid_to_mask(tagid); 775 void **vpp; 776 int i; 777 778 vpp = radix_tree_lookup_ptr(t, idx, &path, false, 0); 779 KASSERT(vpp != NULL); 780 KASSERT(*vpp != NULL); 781 KASSERT(path.p_lastidx == t->t_height); 782 KASSERT(vpp == path_pptr(t, &path, path.p_lastidx)); 783 for (i = t->t_height; i >= 0; i--) { 784 void ** const pptr = (void **)path_pptr(t, &path, i); 785 void *entry; 786 787 KASSERT(pptr != NULL); 788 entry = *pptr; 789 if ((entry_tagmask(entry) & tagmask) != 0) { 790 break; 791 } 792 *pptr = (void *)((uintptr_t)entry | tagmask); 793 } 794 } 795 796 /* 797 * radix_tree_clear_tag: 798 * 799 * clear the tag for the node at the given index. 800 * it's illegal to call this function for a node which has not been inserted. 801 */ 802 803 void 804 radix_tree_clear_tag(struct radix_tree *t, uint64_t idx, 805 radix_tree_tagid_t tagid) 806 { 807 struct radix_tree_path path; 808 const unsigned int tagmask = tagid_to_mask(tagid); 809 void **vpp; 810 int i; 811 812 vpp = radix_tree_lookup_ptr(t, idx, &path, false, 0); 813 KASSERT(vpp != NULL); 814 KASSERT(*vpp != NULL); 815 KASSERT(path.p_lastidx == t->t_height); 816 KASSERT(vpp == path_pptr(t, &path, path.p_lastidx)); 817 /* 818 * if already cleared, nothing to do 819 */ 820 if ((entry_tagmask(*vpp) & tagmask) == 0) { 821 return; 822 } 823 /* 824 * clear the tag only if no children have the tag. 825 */ 826 for (i = t->t_height; i >= 0; i--) { 827 void ** const pptr = (void **)path_pptr(t, &path, i); 828 void *entry; 829 830 KASSERT(pptr != NULL); 831 entry = *pptr; 832 KASSERT((entry_tagmask(entry) & tagmask) != 0); 833 *pptr = entry_compose(entry_ptr(entry), 834 entry_tagmask(entry) & ~tagmask); 835 /* 836 * check if we should proceed to process the next level. 837 */ 838 if (0 < i) { 839 struct radix_tree_node *n = path_node(t, &path, i - 1); 840 841 if ((any_children_tagmask(n) & tagmask) != 0) { 842 break; 843 } 844 } 845 } 846 } 847 848 #if defined(UNITTEST) 849 850 #include <inttypes.h> 851 #include <stdio.h> 852 853 static void 854 radix_tree_dump_node(const struct radix_tree *t, void *vp, 855 uint64_t offset, unsigned int height) 856 { 857 struct radix_tree_node *n; 858 unsigned int i; 859 860 for (i = 0; i < t->t_height - height; i++) { 861 printf(" "); 862 } 863 if (entry_tagmask(vp) == 0) { 864 printf("[%" PRIu64 "] %p", offset, entry_ptr(vp)); 865 } else { 866 printf("[%" PRIu64 "] %p (tagmask=0x%x)", offset, entry_ptr(vp), 867 entry_tagmask(vp)); 868 } 869 if (height == 0) { 870 printf(" (leaf)\n"); 871 return; 872 } 873 n = entry_ptr(vp); 874 assert(any_children_tagmask(n) == entry_tagmask(vp)); 875 printf(" (%u children)\n", n->n_nptrs); 876 for (i = 0; i < __arraycount(n->n_ptrs); i++) { 877 void *c; 878 879 c = n->n_ptrs[i]; 880 if (c == NULL) { 881 continue; 882 } 883 radix_tree_dump_node(t, c, 884 offset + i * (UINT64_C(1) << 885 (RADIX_TREE_BITS_PER_HEIGHT * (height - 1))), height - 1); 886 } 887 } 888 889 void radix_tree_dump(const struct radix_tree *); 890 891 void 892 radix_tree_dump(const struct radix_tree *t) 893 { 894 895 printf("tree %p height=%u\n", t, t->t_height); 896 radix_tree_dump_node(t, t->t_root, 0, t->t_height); 897 } 898 899 static void 900 test1(void) 901 { 902 struct radix_tree s; 903 struct radix_tree *t = &s; 904 void *results[3]; 905 906 radix_tree_init_tree(t); 907 radix_tree_dump(t); 908 assert(radix_tree_lookup_node(t, 0) == NULL); 909 assert(radix_tree_lookup_node(t, 1000) == NULL); 910 assert(radix_tree_insert_node(t, 1000, (void *)0xdeadbea0) == 0); 911 radix_tree_dump(t); 912 assert(!radix_tree_get_tag(t, 1000, 0)); 913 assert(!radix_tree_get_tag(t, 1000, 1)); 914 radix_tree_set_tag(t, 1000, 1); 915 assert(!radix_tree_get_tag(t, 1000, 0)); 916 assert(radix_tree_get_tag(t, 1000, 1)); 917 radix_tree_dump(t); 918 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0); 919 assert(radix_tree_insert_node(t, 0, (void *)0xbea0) == 0); 920 radix_tree_dump(t); 921 assert(radix_tree_lookup_node(t, 0) == (void *)0xbea0); 922 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0); 923 assert(radix_tree_insert_node(t, UINT64_C(10000000000), (void *)0xdea0) 924 == 0); 925 radix_tree_dump(t); 926 assert(radix_tree_lookup_node(t, 0) == (void *)0xbea0); 927 assert(radix_tree_lookup_node(t, 1000) == (void *)0xdeadbea0); 928 assert(radix_tree_lookup_node(t, UINT64_C(10000000000)) == 929 (void *)0xdea0); 930 radix_tree_dump(t); 931 assert(!radix_tree_get_tag(t, 0, 1)); 932 assert(radix_tree_get_tag(t, 1000, 1)); 933 assert(!radix_tree_get_tag(t, UINT64_C(10000000000), 1)); 934 radix_tree_set_tag(t, 0, 1);; 935 radix_tree_set_tag(t, UINT64_C(10000000000), 1); 936 radix_tree_dump(t); 937 assert(radix_tree_get_tag(t, 0, 1)); 938 assert(radix_tree_get_tag(t, 1000, 1)); 939 assert(radix_tree_get_tag(t, UINT64_C(10000000000), 1)); 940 radix_tree_clear_tag(t, 0, 1);; 941 radix_tree_clear_tag(t, UINT64_C(10000000000), 1); 942 radix_tree_dump(t); 943 assert(!radix_tree_get_tag(t, 0, 1)); 944 assert(radix_tree_get_tag(t, 1000, 1)); 945 assert(!radix_tree_get_tag(t, UINT64_C(10000000000), 1)); 946 radix_tree_dump(t); 947 assert(radix_tree_replace_node(t, 1000, (void *)0x12345678) == 948 (void *)0xdeadbea0); 949 assert(!radix_tree_get_tag(t, 1000, 0)); 950 assert(radix_tree_get_tag(t, 1000, 1)); 951 assert(radix_tree_gang_lookup_node(t, 0, results, 3) == 3); 952 assert(results[0] == (void *)0xbea0); 953 assert(results[1] == (void *)0x12345678); 954 assert(results[2] == (void *)0xdea0); 955 assert(radix_tree_gang_lookup_node(t, 1, results, 3) == 2); 956 assert(results[0] == (void *)0x12345678); 957 assert(results[1] == (void *)0xdea0); 958 assert(radix_tree_gang_lookup_node(t, 1001, results, 3) == 1); 959 assert(results[0] == (void *)0xdea0); 960 assert(radix_tree_gang_lookup_node(t, UINT64_C(10000000001), results, 3) 961 == 0); 962 assert(radix_tree_gang_lookup_node(t, UINT64_C(1000000000000), results, 963 3) == 0); 964 assert(radix_tree_gang_lookup_tagged_node(t, 0, results, 100, 1) == 1); 965 assert(results[0] == (void *)0x12345678); 966 assert(entry_tagmask(t->t_root) != 0); 967 assert(radix_tree_remove_node(t, 1000) == (void *)0x12345678); 968 assert(entry_tagmask(t->t_root) == 0); 969 radix_tree_dump(t); 970 assert(radix_tree_remove_node(t, UINT64_C(10000000000)) == 971 (void *)0xdea0); 972 radix_tree_dump(t); 973 assert(radix_tree_remove_node(t, 0) == (void *)0xbea0); 974 radix_tree_dump(t); 975 radix_tree_fini_tree(t); 976 } 977 978 #include <sys/time.h> 979 980 struct testnode { 981 uint64_t idx; 982 }; 983 984 static void 985 printops(const char *name, unsigned int n, const struct timeval *stv, 986 const struct timeval *etv) 987 { 988 uint64_t s = stv->tv_sec * 1000000 + stv->tv_usec; 989 uint64_t e = etv->tv_sec * 1000000 + etv->tv_usec; 990 991 printf("%lf %s/s\n", (double)n / (e - s) * 1000000, name); 992 } 993 994 #define TEST2_GANG_LOOKUP_NODES 16 995 996 static bool 997 test2_should_tag(unsigned int i, radix_tree_tagid_t tagid) 998 { 999 1000 if (tagid == 0) { 1001 return (i & 0x3) == 0; 1002 } else { 1003 return (i % 7) == 0; 1004 } 1005 } 1006 1007 static void 1008 test2(bool dense) 1009 { 1010 struct radix_tree s; 1011 struct radix_tree *t = &s; 1012 struct testnode *n; 1013 unsigned int i; 1014 unsigned int nnodes = 100000; 1015 unsigned int removed; 1016 radix_tree_tagid_t tag; 1017 unsigned int ntagged[RADIX_TREE_TAG_ID_MAX]; 1018 struct testnode *nodes; 1019 struct timeval stv; 1020 struct timeval etv; 1021 1022 nodes = malloc(nnodes * sizeof(*nodes)); 1023 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1024 ntagged[tag] = 0; 1025 } 1026 radix_tree_init_tree(t); 1027 for (i = 0; i < nnodes; i++) { 1028 n = &nodes[i]; 1029 n->idx = random(); 1030 if (sizeof(long) == 4) { 1031 n->idx <<= 32; 1032 n->idx |= (uint32_t)random(); 1033 } 1034 if (dense) { 1035 n->idx %= nnodes * 2; 1036 } 1037 while (radix_tree_lookup_node(t, n->idx) != NULL) { 1038 n->idx++; 1039 } 1040 radix_tree_insert_node(t, n->idx, n); 1041 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1042 if (test2_should_tag(i, tag)) { 1043 radix_tree_set_tag(t, n->idx, tag); 1044 ntagged[tag]++; 1045 } 1046 assert(test2_should_tag(i, tag) == 1047 radix_tree_get_tag(t, n->idx, tag)); 1048 } 1049 } 1050 1051 gettimeofday(&stv, NULL); 1052 for (i = 0; i < nnodes; i++) { 1053 n = &nodes[i]; 1054 assert(radix_tree_lookup_node(t, n->idx) == n); 1055 } 1056 gettimeofday(&etv, NULL); 1057 printops("lookup", nnodes, &stv, &etv); 1058 1059 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1060 gettimeofday(&stv, NULL); 1061 for (i = 0; i < nnodes; i++) { 1062 n = &nodes[i]; 1063 assert(test2_should_tag(i, tag) == 1064 radix_tree_get_tag(t, n->idx, tag)); 1065 } 1066 gettimeofday(&etv, NULL); 1067 printops("get_tag", ntagged[tag], &stv, &etv); 1068 } 1069 1070 gettimeofday(&stv, NULL); 1071 for (i = 0; i < nnodes; i++) { 1072 n = &nodes[i]; 1073 radix_tree_remove_node(t, n->idx); 1074 } 1075 gettimeofday(&etv, NULL); 1076 printops("remove", nnodes, &stv, &etv); 1077 1078 gettimeofday(&stv, NULL); 1079 for (i = 0; i < nnodes; i++) { 1080 n = &nodes[i]; 1081 radix_tree_insert_node(t, n->idx, n); 1082 } 1083 gettimeofday(&etv, NULL); 1084 printops("insert", nnodes, &stv, &etv); 1085 1086 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1087 ntagged[tag] = 0; 1088 gettimeofday(&stv, NULL); 1089 for (i = 0; i < nnodes; i++) { 1090 n = &nodes[i]; 1091 if (test2_should_tag(i, tag)) { 1092 radix_tree_set_tag(t, n->idx, tag); 1093 ntagged[tag]++; 1094 } 1095 } 1096 gettimeofday(&etv, NULL); 1097 printops("set_tag", ntagged[tag], &stv, &etv); 1098 } 1099 1100 gettimeofday(&stv, NULL); 1101 { 1102 struct testnode *results[TEST2_GANG_LOOKUP_NODES]; 1103 uint64_t nextidx; 1104 unsigned int nfound; 1105 unsigned int total; 1106 1107 nextidx = 0; 1108 total = 0; 1109 while ((nfound = radix_tree_gang_lookup_node(t, nextidx, 1110 (void *)results, __arraycount(results))) > 0) { 1111 nextidx = results[nfound - 1]->idx + 1; 1112 total += nfound; 1113 } 1114 assert(total == nnodes); 1115 } 1116 gettimeofday(&etv, NULL); 1117 printops("ganglookup", nnodes, &stv, &etv); 1118 1119 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1120 gettimeofday(&stv, NULL); 1121 { 1122 struct testnode *results[TEST2_GANG_LOOKUP_NODES]; 1123 uint64_t nextidx; 1124 unsigned int nfound; 1125 unsigned int total; 1126 1127 nextidx = 0; 1128 total = 0; 1129 while ((nfound = radix_tree_gang_lookup_tagged_node(t, 1130 nextidx, (void *)results, __arraycount(results), 1131 tag)) > 0) { 1132 nextidx = results[nfound - 1]->idx + 1; 1133 total += nfound; 1134 } 1135 assert(total == ntagged[tag]); 1136 } 1137 gettimeofday(&etv, NULL); 1138 printops("ganglookup_tag", ntagged[tag], &stv, &etv); 1139 } 1140 1141 removed = 0; 1142 for (tag = 0; tag < RADIX_TREE_TAG_ID_MAX; tag++) { 1143 unsigned int total; 1144 1145 total = 0; 1146 gettimeofday(&stv, NULL); 1147 { 1148 struct testnode *results[TEST2_GANG_LOOKUP_NODES]; 1149 uint64_t nextidx; 1150 unsigned int nfound; 1151 1152 nextidx = 0; 1153 while ((nfound = radix_tree_gang_lookup_tagged_node(t, 1154 nextidx, (void *)results, __arraycount(results), 1155 tag)) > 0) { 1156 for (i = 0; i < nfound; i++) { 1157 radix_tree_remove_node(t, 1158 results[i]->idx); 1159 } 1160 nextidx = results[nfound - 1]->idx + 1; 1161 total += nfound; 1162 } 1163 assert(tag != 0 || total == ntagged[tag]); 1164 assert(total <= ntagged[tag]); 1165 } 1166 gettimeofday(&etv, NULL); 1167 printops("ganglookup_tag+remove", total, &stv, &etv); 1168 removed += total; 1169 } 1170 1171 gettimeofday(&stv, NULL); 1172 { 1173 struct testnode *results[TEST2_GANG_LOOKUP_NODES]; 1174 uint64_t nextidx; 1175 unsigned int nfound; 1176 unsigned int total; 1177 1178 nextidx = 0; 1179 total = 0; 1180 while ((nfound = radix_tree_gang_lookup_node(t, nextidx, 1181 (void *)results, __arraycount(results))) > 0) { 1182 for (i = 0; i < nfound; i++) { 1183 assert(results[i] == radix_tree_remove_node(t, 1184 results[i]->idx)); 1185 } 1186 nextidx = results[nfound - 1]->idx + 1; 1187 total += nfound; 1188 } 1189 assert(total == nnodes - removed); 1190 } 1191 gettimeofday(&etv, NULL); 1192 printops("ganglookup+remove", nnodes - removed, &stv, &etv); 1193 1194 radix_tree_fini_tree(t); 1195 free(nodes); 1196 } 1197 1198 int 1199 main(int argc, char *argv[]) 1200 { 1201 1202 test1(); 1203 printf("dense distribution:\n"); 1204 test2(true); 1205 printf("sparse distribution:\n"); 1206 test2(false); 1207 return 0; 1208 } 1209 1210 #endif /* defined(UNITTEST) */ 1211