diff options
| author | Michel Lespinasse <walken@google.com> | 2012-10-08 19:31:15 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-09 03:22:37 -0400 |
| commit | dadf93534f125b9eda486b471446a8456a603d27 (patch) | |
| tree | 4d796ac97a940683d008fdcb2040dc84d1405970 /lib | |
| parent | 4f035ad67f4633c233cb3642711d49b4efc9c82d (diff) | |
rbtree: augmented rbtree test
Small test to measure the performance of augmented rbtrees.
Signed-off-by: Michel Lespinasse <walken@google.com>
Acked-by: Rik van Riel <riel@redhat.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/rbtree_test.c | 103 |
1 files changed, 101 insertions, 2 deletions
diff --git a/lib/rbtree_test.c b/lib/rbtree_test.c index fd09465d82ca..66e41d4bfc39 100644 --- a/lib/rbtree_test.c +++ b/lib/rbtree_test.c | |||
| @@ -10,6 +10,10 @@ | |||
| 10 | struct test_node { | 10 | struct test_node { |
| 11 | struct rb_node rb; | 11 | struct rb_node rb; |
| 12 | u32 key; | 12 | u32 key; |
| 13 | |||
| 14 | /* following fields used for testing augmented rbtree functionality */ | ||
| 15 | u32 val; | ||
| 16 | u32 augmented; | ||
| 13 | }; | 17 | }; |
| 14 | 18 | ||
| 15 | static struct rb_root root = RB_ROOT; | 19 | static struct rb_root root = RB_ROOT; |
| @@ -20,10 +24,11 @@ static struct rnd_state rnd; | |||
| 20 | static void insert(struct test_node *node, struct rb_root *root) | 24 | static void insert(struct test_node *node, struct rb_root *root) |
| 21 | { | 25 | { |
| 22 | struct rb_node **new = &root->rb_node, *parent = NULL; | 26 | struct rb_node **new = &root->rb_node, *parent = NULL; |
| 27 | u32 key = node->key; | ||
| 23 | 28 | ||
| 24 | while (*new) { | 29 | while (*new) { |
| 25 | parent = *new; | 30 | parent = *new; |
| 26 | if (node->key < rb_entry(parent, struct test_node, rb)->key) | 31 | if (key < rb_entry(parent, struct test_node, rb)->key) |
| 27 | new = &parent->rb_left; | 32 | new = &parent->rb_left; |
| 28 | else | 33 | else |
| 29 | new = &parent->rb_right; | 34 | new = &parent->rb_right; |
| @@ -38,11 +43,62 @@ static inline void erase(struct test_node *node, struct rb_root *root) | |||
| 38 | rb_erase(&node->rb, root); | 43 | rb_erase(&node->rb, root); |
| 39 | } | 44 | } |
| 40 | 45 | ||
| 46 | static inline u32 augment_recompute(struct test_node *node) | ||
| 47 | { | ||
| 48 | u32 max = node->val, child_augmented; | ||
| 49 | if (node->rb.rb_left) { | ||
| 50 | child_augmented = rb_entry(node->rb.rb_left, struct test_node, | ||
| 51 | rb)->augmented; | ||
| 52 | if (max < child_augmented) | ||
| 53 | max = child_augmented; | ||
| 54 | } | ||
| 55 | if (node->rb.rb_right) { | ||
| 56 | child_augmented = rb_entry(node->rb.rb_right, struct test_node, | ||
| 57 | rb)->augmented; | ||
| 58 | if (max < child_augmented) | ||
| 59 | max = child_augmented; | ||
| 60 | } | ||
| 61 | return max; | ||
| 62 | } | ||
| 63 | |||
| 64 | static void augment_callback(struct rb_node *rb, void *unused) | ||
| 65 | { | ||
| 66 | struct test_node *node = rb_entry(rb, struct test_node, rb); | ||
| 67 | node->augmented = augment_recompute(node); | ||
| 68 | } | ||
| 69 | |||
| 70 | static void insert_augmented(struct test_node *node, struct rb_root *root) | ||
| 71 | { | ||
| 72 | struct rb_node **new = &root->rb_node, *parent = NULL; | ||
| 73 | u32 key = node->key; | ||
| 74 | |||
| 75 | while (*new) { | ||
| 76 | parent = *new; | ||
| 77 | if (key < rb_entry(parent, struct test_node, rb)->key) | ||
| 78 | new = &parent->rb_left; | ||
| 79 | else | ||
| 80 | new = &parent->rb_right; | ||
| 81 | } | ||
| 82 | |||
| 83 | rb_link_node(&node->rb, parent, new); | ||
| 84 | rb_insert_color(&node->rb, root); | ||
| 85 | rb_augment_insert(&node->rb, augment_callback, NULL); | ||
| 86 | } | ||
| 87 | |||
| 88 | static void erase_augmented(struct test_node *node, struct rb_root *root) | ||
| 89 | { | ||
| 90 | struct rb_node *deepest = rb_augment_erase_begin(&node->rb); | ||
| 91 | rb_erase(&node->rb, root); | ||
| 92 | rb_augment_erase_end(deepest, augment_callback, NULL); | ||
| 93 | } | ||
| 94 | |||
| 41 | static void init(void) | 95 | static void init(void) |
| 42 | { | 96 | { |
| 43 | int i; | 97 | int i; |
| 44 | for (i = 0; i < NODES; i++) | 98 | for (i = 0; i < NODES; i++) { |
| 45 | nodes[i].key = prandom32(&rnd); | 99 | nodes[i].key = prandom32(&rnd); |
| 100 | nodes[i].val = prandom32(&rnd); | ||
| 101 | } | ||
| 46 | } | 102 | } |
| 47 | 103 | ||
| 48 | static bool is_red(struct rb_node *rb) | 104 | static bool is_red(struct rb_node *rb) |
| @@ -81,6 +137,17 @@ static void check(int nr_nodes) | |||
| 81 | WARN_ON_ONCE(count != nr_nodes); | 137 | WARN_ON_ONCE(count != nr_nodes); |
| 82 | } | 138 | } |
| 83 | 139 | ||
| 140 | static void check_augmented(int nr_nodes) | ||
| 141 | { | ||
| 142 | struct rb_node *rb; | ||
| 143 | |||
| 144 | check(nr_nodes); | ||
| 145 | for (rb = rb_first(&root); rb; rb = rb_next(rb)) { | ||
| 146 | struct test_node *node = rb_entry(rb, struct test_node, rb); | ||
| 147 | WARN_ON_ONCE(node->augmented != augment_recompute(node)); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 84 | static int rbtree_test_init(void) | 151 | static int rbtree_test_init(void) |
| 85 | { | 152 | { |
| 86 | int i, j; | 153 | int i, j; |
| @@ -119,6 +186,38 @@ static int rbtree_test_init(void) | |||
| 119 | check(0); | 186 | check(0); |
| 120 | } | 187 | } |
| 121 | 188 | ||
| 189 | printk(KERN_ALERT "augmented rbtree testing"); | ||
| 190 | |||
| 191 | init(); | ||
| 192 | |||
| 193 | time1 = get_cycles(); | ||
| 194 | |||
| 195 | for (i = 0; i < PERF_LOOPS; i++) { | ||
| 196 | for (j = 0; j < NODES; j++) | ||
| 197 | insert_augmented(nodes + j, &root); | ||
| 198 | for (j = 0; j < NODES; j++) | ||
| 199 | erase_augmented(nodes + j, &root); | ||
| 200 | } | ||
| 201 | |||
| 202 | time2 = get_cycles(); | ||
| 203 | time = time2 - time1; | ||
| 204 | |||
| 205 | time = div_u64(time, PERF_LOOPS); | ||
| 206 | printk(" -> %llu cycles\n", (unsigned long long)time); | ||
| 207 | |||
| 208 | for (i = 0; i < CHECK_LOOPS; i++) { | ||
| 209 | init(); | ||
| 210 | for (j = 0; j < NODES; j++) { | ||
| 211 | check_augmented(j); | ||
| 212 | insert_augmented(nodes + j, &root); | ||
| 213 | } | ||
| 214 | for (j = 0; j < NODES; j++) { | ||
| 215 | check_augmented(NODES - j); | ||
| 216 | erase_augmented(nodes + j, &root); | ||
| 217 | } | ||
| 218 | check_augmented(0); | ||
| 219 | } | ||
| 220 | |||
| 122 | return -EAGAIN; /* Fail will directly unload the module */ | 221 | return -EAGAIN; /* Fail will directly unload the module */ |
| 123 | } | 222 | } |
| 124 | 223 | ||
