summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavidlohr Bueso <dave@stgolabs.net>2017-09-08 19:14:52 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-09-08 21:26:48 -0400
commitb10d43f9898e0b56f6cf2375093dbd2c5db54486 (patch)
tree9a0b1da6a0972dd877ea5c36f05e9267a5554420
parent977bd8d5e1e61dc877c468e8937a4ab3094e53eb (diff)
lib/rbtree_test.c: support rb_root_cached
We can work with a single rb_root_cached root to test both cached and non-cached rbtrees. In addition, also add a test to measure latencies between rb_first and its fast counterpart. Link: http://lkml.kernel.org/r/20170719014603.19029-7-dave@stgolabs.net Signed-off-by: Davidlohr Bueso <dbueso@suse.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--lib/rbtree_test.c156
1 files changed, 137 insertions, 19 deletions
diff --git a/lib/rbtree_test.c b/lib/rbtree_test.c
index 967999ff46db..191a238e5a9d 100644
--- a/lib/rbtree_test.c
+++ b/lib/rbtree_test.c
@@ -23,14 +23,14 @@ struct test_node {
23 u32 augmented; 23 u32 augmented;
24}; 24};
25 25
26static struct rb_root root = RB_ROOT; 26static struct rb_root_cached root = RB_ROOT_CACHED;
27static struct test_node *nodes = NULL; 27static struct test_node *nodes = NULL;
28 28
29static struct rnd_state rnd; 29static struct rnd_state rnd;
30 30
31static void insert(struct test_node *node, struct rb_root *root) 31static void insert(struct test_node *node, struct rb_root_cached *root)
32{ 32{
33 struct rb_node **new = &root->rb_node, *parent = NULL; 33 struct rb_node **new = &root->rb_root.rb_node, *parent = NULL;
34 u32 key = node->key; 34 u32 key = node->key;
35 35
36 while (*new) { 36 while (*new) {
@@ -42,14 +42,40 @@ static void insert(struct test_node *node, struct rb_root *root)
42 } 42 }
43 43
44 rb_link_node(&node->rb, parent, new); 44 rb_link_node(&node->rb, parent, new);
45 rb_insert_color(&node->rb, root); 45 rb_insert_color(&node->rb, &root->rb_root);
46} 46}
47 47
48static inline void erase(struct test_node *node, struct rb_root *root) 48static void insert_cached(struct test_node *node, struct rb_root_cached *root)
49{ 49{
50 rb_erase(&node->rb, root); 50 struct rb_node **new = &root->rb_root.rb_node, *parent = NULL;
51 u32 key = node->key;
52 bool leftmost = true;
53
54 while (*new) {
55 parent = *new;
56 if (key < rb_entry(parent, struct test_node, rb)->key)
57 new = &parent->rb_left;
58 else {
59 new = &parent->rb_right;
60 leftmost = false;
61 }
62 }
63
64 rb_link_node(&node->rb, parent, new);
65 rb_insert_color_cached(&node->rb, root, leftmost);
51} 66}
52 67
68static inline void erase(struct test_node *node, struct rb_root_cached *root)
69{
70 rb_erase(&node->rb, &root->rb_root);
71}
72
73static inline void erase_cached(struct test_node *node, struct rb_root_cached *root)
74{
75 rb_erase_cached(&node->rb, root);
76}
77
78
53static inline u32 augment_recompute(struct test_node *node) 79static inline u32 augment_recompute(struct test_node *node)
54{ 80{
55 u32 max = node->val, child_augmented; 81 u32 max = node->val, child_augmented;
@@ -71,9 +97,10 @@ static inline u32 augment_recompute(struct test_node *node)
71RB_DECLARE_CALLBACKS(static, augment_callbacks, struct test_node, rb, 97RB_DECLARE_CALLBACKS(static, augment_callbacks, struct test_node, rb,
72 u32, augmented, augment_recompute) 98 u32, augmented, augment_recompute)
73 99
74static void insert_augmented(struct test_node *node, struct rb_root *root) 100static void insert_augmented(struct test_node *node,
101 struct rb_root_cached *root)
75{ 102{
76 struct rb_node **new = &root->rb_node, *rb_parent = NULL; 103 struct rb_node **new = &root->rb_root.rb_node, *rb_parent = NULL;
77 u32 key = node->key; 104 u32 key = node->key;
78 u32 val = node->val; 105 u32 val = node->val;
79 struct test_node *parent; 106 struct test_node *parent;
@@ -91,12 +118,47 @@ static void insert_augmented(struct test_node *node, struct rb_root *root)
91 118
92 node->augmented = val; 119 node->augmented = val;
93 rb_link_node(&node->rb, rb_parent, new); 120 rb_link_node(&node->rb, rb_parent, new);
94 rb_insert_augmented(&node->rb, root, &augment_callbacks); 121 rb_insert_augmented(&node->rb, &root->rb_root, &augment_callbacks);
122}
123
124static void insert_augmented_cached(struct test_node *node,
125 struct rb_root_cached *root)
126{
127 struct rb_node **new = &root->rb_root.rb_node, *rb_parent = NULL;
128 u32 key = node->key;
129 u32 val = node->val;
130 struct test_node *parent;
131 bool leftmost = true;
132
133 while (*new) {
134 rb_parent = *new;
135 parent = rb_entry(rb_parent, struct test_node, rb);
136 if (parent->augmented < val)
137 parent->augmented = val;
138 if (key < parent->key)
139 new = &parent->rb.rb_left;
140 else {
141 new = &parent->rb.rb_right;
142 leftmost = false;
143 }
144 }
145
146 node->augmented = val;
147 rb_link_node(&node->rb, rb_parent, new);
148 rb_insert_augmented_cached(&node->rb, root,
149 leftmost, &augment_callbacks);
150}
151
152
153static void erase_augmented(struct test_node *node, struct rb_root_cached *root)
154{
155 rb_erase_augmented(&node->rb, &root->rb_root, &augment_callbacks);
95} 156}
96 157
97static void erase_augmented(struct test_node *node, struct rb_root *root) 158static void erase_augmented_cached(struct test_node *node,
159 struct rb_root_cached *root)
98{ 160{
99 rb_erase_augmented(&node->rb, root, &augment_callbacks); 161 rb_erase_augmented_cached(&node->rb, root, &augment_callbacks);
100} 162}
101 163
102static void init(void) 164static void init(void)
@@ -125,7 +187,7 @@ static void check_postorder_foreach(int nr_nodes)
125{ 187{
126 struct test_node *cur, *n; 188 struct test_node *cur, *n;
127 int count = 0; 189 int count = 0;
128 rbtree_postorder_for_each_entry_safe(cur, n, &root, rb) 190 rbtree_postorder_for_each_entry_safe(cur, n, &root.rb_root, rb)
129 count++; 191 count++;
130 192
131 WARN_ON_ONCE(count != nr_nodes); 193 WARN_ON_ONCE(count != nr_nodes);
@@ -135,7 +197,7 @@ static void check_postorder(int nr_nodes)
135{ 197{
136 struct rb_node *rb; 198 struct rb_node *rb;
137 int count = 0; 199 int count = 0;
138 for (rb = rb_first_postorder(&root); rb; rb = rb_next_postorder(rb)) 200 for (rb = rb_first_postorder(&root.rb_root); rb; rb = rb_next_postorder(rb))
139 count++; 201 count++;
140 202
141 WARN_ON_ONCE(count != nr_nodes); 203 WARN_ON_ONCE(count != nr_nodes);
@@ -147,7 +209,7 @@ static void check(int nr_nodes)
147 int count = 0, blacks = 0; 209 int count = 0, blacks = 0;
148 u32 prev_key = 0; 210 u32 prev_key = 0;
149 211
150 for (rb = rb_first(&root); rb; rb = rb_next(rb)) { 212 for (rb = rb_first(&root.rb_root); rb; rb = rb_next(rb)) {
151 struct test_node *node = rb_entry(rb, struct test_node, rb); 213 struct test_node *node = rb_entry(rb, struct test_node, rb);
152 WARN_ON_ONCE(node->key < prev_key); 214 WARN_ON_ONCE(node->key < prev_key);
153 WARN_ON_ONCE(is_red(rb) && 215 WARN_ON_ONCE(is_red(rb) &&
@@ -162,7 +224,7 @@ static void check(int nr_nodes)
162 } 224 }
163 225
164 WARN_ON_ONCE(count != nr_nodes); 226 WARN_ON_ONCE(count != nr_nodes);
165 WARN_ON_ONCE(count < (1 << black_path_count(rb_last(&root))) - 1); 227 WARN_ON_ONCE(count < (1 << black_path_count(rb_last(&root.rb_root))) - 1);
166 228
167 check_postorder(nr_nodes); 229 check_postorder(nr_nodes);
168 check_postorder_foreach(nr_nodes); 230 check_postorder_foreach(nr_nodes);
@@ -173,7 +235,7 @@ static void check_augmented(int nr_nodes)
173 struct rb_node *rb; 235 struct rb_node *rb;
174 236
175 check(nr_nodes); 237 check(nr_nodes);
176 for (rb = rb_first(&root); rb; rb = rb_next(rb)) { 238 for (rb = rb_first(&root.rb_root); rb; rb = rb_next(rb)) {
177 struct test_node *node = rb_entry(rb, struct test_node, rb); 239 struct test_node *node = rb_entry(rb, struct test_node, rb);
178 WARN_ON_ONCE(node->augmented != augment_recompute(node)); 240 WARN_ON_ONCE(node->augmented != augment_recompute(node));
179 } 241 }
@@ -207,7 +269,24 @@ static int __init rbtree_test_init(void)
207 time = time2 - time1; 269 time = time2 - time1;
208 270
209 time = div_u64(time, perf_loops); 271 time = div_u64(time, perf_loops);
210 printk(" -> test 1 (latency of nnodes insert+delete): %llu cycles\n", (unsigned long long)time); 272 printk(" -> test 1 (latency of nnodes insert+delete): %llu cycles\n",
273 (unsigned long long)time);
274
275 time1 = get_cycles();
276
277 for (i = 0; i < perf_loops; i++) {
278 for (j = 0; j < nnodes; j++)
279 insert_cached(nodes + j, &root);
280 for (j = 0; j < nnodes; j++)
281 erase_cached(nodes + j, &root);
282 }
283
284 time2 = get_cycles();
285 time = time2 - time1;
286
287 time = div_u64(time, perf_loops);
288 printk(" -> test 2 (latency of nnodes cached insert+delete): %llu cycles\n",
289 (unsigned long long)time);
211 290
212 for (i = 0; i < nnodes; i++) 291 for (i = 0; i < nnodes; i++)
213 insert(nodes + i, &root); 292 insert(nodes + i, &root);
@@ -215,7 +294,7 @@ static int __init rbtree_test_init(void)
215 time1 = get_cycles(); 294 time1 = get_cycles();
216 295
217 for (i = 0; i < perf_loops; i++) { 296 for (i = 0; i < perf_loops; i++) {
218 for (node = rb_first(&root); node; node = rb_next(node)) 297 for (node = rb_first(&root.rb_root); node; node = rb_next(node))
219 ; 298 ;
220 } 299 }
221 300
@@ -223,7 +302,31 @@ static int __init rbtree_test_init(void)
223 time = time2 - time1; 302 time = time2 - time1;
224 303
225 time = div_u64(time, perf_loops); 304 time = div_u64(time, perf_loops);
226 printk(" -> test 2 (latency of inorder traversal): %llu cycles\n", (unsigned long long)time); 305 printk(" -> test 3 (latency of inorder traversal): %llu cycles\n",
306 (unsigned long long)time);
307
308 time1 = get_cycles();
309
310 for (i = 0; i < perf_loops; i++)
311 node = rb_first(&root.rb_root);
312
313 time2 = get_cycles();
314 time = time2 - time1;
315
316 time = div_u64(time, perf_loops);
317 printk(" -> test 4 (latency to fetch first node)\n");
318 printk(" non-cached: %llu cycles\n", (unsigned long long)time);
319
320 time1 = get_cycles();
321
322 for (i = 0; i < perf_loops; i++)
323 node = rb_first_cached(&root);
324
325 time2 = get_cycles();
326 time = time2 - time1;
327
328 time = div_u64(time, perf_loops);
329 printk(" cached: %llu cycles\n", (unsigned long long)time);
227 330
228 for (i = 0; i < nnodes; i++) 331 for (i = 0; i < nnodes; i++)
229 erase(nodes + i, &root); 332 erase(nodes + i, &root);
@@ -261,6 +364,21 @@ static int __init rbtree_test_init(void)
261 time = div_u64(time, perf_loops); 364 time = div_u64(time, perf_loops);
262 printk(" -> test 1 (latency of nnodes insert+delete): %llu cycles\n", (unsigned long long)time); 365 printk(" -> test 1 (latency of nnodes insert+delete): %llu cycles\n", (unsigned long long)time);
263 366
367 time1 = get_cycles();
368
369 for (i = 0; i < perf_loops; i++) {
370 for (j = 0; j < nnodes; j++)
371 insert_augmented_cached(nodes + j, &root);
372 for (j = 0; j < nnodes; j++)
373 erase_augmented_cached(nodes + j, &root);
374 }
375
376 time2 = get_cycles();
377 time = time2 - time1;
378
379 time = div_u64(time, perf_loops);
380 printk(" -> test 2 (latency of nnodes cached insert+delete): %llu cycles\n", (unsigned long long)time);
381
264 for (i = 0; i < check_loops; i++) { 382 for (i = 0; i < check_loops; i++) {
265 init(); 383 init();
266 for (j = 0; j < nnodes; j++) { 384 for (j = 0; j < nnodes; j++) {