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 | ||