Tue Mar 25 16:21:08 2014 UTC ()
comments.  some ascii arts to explain memory consumption.


(yamt)
diff -r1.17.2.4 -r1.17.2.5 src/common/lib/libc/gen/radixtree.c

cvs diff -r1.17.2.4 -r1.17.2.5 src/common/lib/libc/gen/radixtree.c (expand / switch to unified diff)

--- src/common/lib/libc/gen/radixtree.c 2012/08/01 21:09:27 1.17.2.4
+++ src/common/lib/libc/gen/radixtree.c 2014/03/25 16:21:08 1.17.2.5
@@ -1,17 +1,17 @@ @@ -1,17 +1,17 @@
1/* $NetBSD: radixtree.c,v 1.17.2.4 2012/08/01 21:09:27 yamt Exp $ */ 1/* $NetBSD: radixtree.c,v 1.17.2.5 2014/03/25 16:21:08 yamt Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c)2011,2012 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
@@ -34,78 +34,105 @@ @@ -34,78 +34,105 @@
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 allocatei 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 * 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 * - 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.
 59 *
 60 * root (t_height=1)
 61 * |
 62 * v
 63 * [ | | | ] (intermediate node. RADIX_TREE_PTR_PER_NODE=4 in this fig)
 64 * | | | |
 65 * v v v v
 66 * p p p p (items)
 67 *
57 * - 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.
58 * 70 *
59 * The height of tree is dynamic. It's smaller if only small index values are 71 * root (t_height=3)
60 * used. As an extreme case, if only index 0 is used, the corresponding value 72 * |
61 * is directly stored in the root of the tree (struct radix_tree) without 73 * v
62 * allocating any intermediate nodes. 74 * [ | | | ]
 75 * |
 76 * v
 77 * [ | | | ]
 78 * |
 79 * v
 80 * [ | | | ]
 81 * |
 82 * v
 83 * p
 84 *
 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,
 87 * the corresponding value is directly stored in the root of the tree
 88 * (struct radix_tree) without allocating any intermediate nodes. In that
 89 * case, t_height=0.
63 * 90 *
64 * Gang lookup: 91 * Gang lookup:
65 * 92 *
66 * This implementation provides a way to scan many nodes quickly via 93 * This implementation provides a way to scan many nodes quickly via
67 * radix_tree_gang_lookup_node function and its varients. 94 * radix_tree_gang_lookup_node function and its varients.
68 * 95 *
69 * Tags: 96 * Tags:
70 * 97 *
71 * This implementation provides tagging functionality, which allows quick 98 * This implementation provides tagging functionality, which allows quick
72 * 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
73 * 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.
74 * 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
75 * 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
76 * these functions, this implementation keeps tagging information in internal 103 * these functions, this implementation keeps tagging information in internal
77 * intermediate nodes and quickly skips uninterested parts of a tree. 104 * intermediate nodes and quickly skips uninterested parts of a tree.
78 * 105 *
79 * 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
80 * identified by an zero-origin numbers, tagid. For the current implementation, 107 * identified by an zero-origin numbers, tagid. For the current implementation,
81 * 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,
82 * which is a bitwise OR of (1 << tagid). 109 * which is a bitwise OR of (1 << tagid).
83 */ 110 */
84 111
85#include <sys/cdefs.h> 112#include <sys/cdefs.h>
86 113
87#if defined(_KERNEL) || defined(_STANDALONE) 114#if defined(_KERNEL) || defined(_STANDALONE)
88__KERNEL_RCSID(0, "$NetBSD: radixtree.c,v 1.17.2.4 2012/08/01 21:09:27 yamt Exp $"); 115__KERNEL_RCSID(0, "$NetBSD: radixtree.c,v 1.17.2.5 2014/03/25 16:21:08 yamt Exp $");
89#include <sys/param.h> 116#include <sys/param.h>
90#include <sys/errno.h> 117#include <sys/errno.h>
91#include <sys/pool.h> 118#include <sys/pool.h>
92#include <sys/radixtree.h> 119#include <sys/radixtree.h>
93#include <lib/libkern/libkern.h> 120#include <lib/libkern/libkern.h>
94#if defined(_STANDALONE) 121#if defined(_STANDALONE)
95#include <lib/libsa/stand.h> 122#include <lib/libsa/stand.h>
96#endif /* defined(_STANDALONE) */ 123#endif /* defined(_STANDALONE) */
97#else /* defined(_KERNEL) || defined(_STANDALONE) */ 124#else /* defined(_KERNEL) || defined(_STANDALONE) */
98__RCSID("$NetBSD: radixtree.c,v 1.17.2.4 2012/08/01 21:09:27 yamt Exp $"); 125__RCSID("$NetBSD: radixtree.c,v 1.17.2.5 2014/03/25 16:21:08 yamt Exp $");
99#include <assert.h> 126#include <assert.h>
100#include <errno.h> 127#include <errno.h>
101#include <stdbool.h> 128#include <stdbool.h>
102#include <stdlib.h> 129#include <stdlib.h>
103#include <string.h> 130#include <string.h>
104#if 1 131#if 1
105#define KASSERT assert 132#define KASSERT assert
106#else 133#else
107#define KASSERT(a) /* nothing */ 134#define KASSERT(a) /* nothing */
108#endif 135#endif
109#endif /* defined(_KERNEL) || defined(_STANDALONE) */ 136#endif /* defined(_KERNEL) || defined(_STANDALONE) */
110 137
111#include <sys/radixtree.h> 138#include <sys/radixtree.h>