Blame view

lib/rbtree_test.c 9.43 KB
910a742d4   Michel Lespinasse   rbtree: performan...
1
  #include <linux/module.h>
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
2
  #include <linux/moduleparam.h>
9c079add0   Michel Lespinasse   rbtree: move augm...
3
  #include <linux/rbtree_augmented.h>
910a742d4   Michel Lespinasse   rbtree: performan...
4
  #include <linux/random.h>
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
5
  #include <linux/slab.h>
910a742d4   Michel Lespinasse   rbtree: performan...
6
  #include <asm/timex.h>
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
7
8
9
10
11
12
  #define __param(type, name, init, msg)		\
  	static type name = init;		\
  	module_param(name, type, 0444);		\
  	MODULE_PARM_DESC(name, msg);
  
  __param(int, nnodes, 100, "Number of nodes in the rb-tree");
0b548e33e   Davidlohr Bueso   lib/rbtree-test: ...
13
  __param(int, perf_loops, 1000, "Number of iterations modifying the rb-tree");
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
14
  __param(int, check_loops, 100, "Number of iterations modifying and verifying the rb-tree");
910a742d4   Michel Lespinasse   rbtree: performan...
15
16
  
  struct test_node {
910a742d4   Michel Lespinasse   rbtree: performan...
17
  	u32 key;
dbf128cbf   Cody P Schafer   rbtree/test: move...
18
  	struct rb_node rb;
dadf93534   Michel Lespinasse   rbtree: augmented...
19
20
21
22
  
  	/* following fields used for testing augmented rbtree functionality */
  	u32 val;
  	u32 augmented;
910a742d4   Michel Lespinasse   rbtree: performan...
23
  };
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
24
  static struct rb_root_cached root = RB_ROOT_CACHED;
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
25
  static struct test_node *nodes = NULL;
910a742d4   Michel Lespinasse   rbtree: performan...
26
27
  
  static struct rnd_state rnd;
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
28
  static void insert(struct test_node *node, struct rb_root_cached *root)
910a742d4   Michel Lespinasse   rbtree: performan...
29
  {
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
30
  	struct rb_node **new = &root->rb_root.rb_node, *parent = NULL;
dadf93534   Michel Lespinasse   rbtree: augmented...
31
  	u32 key = node->key;
910a742d4   Michel Lespinasse   rbtree: performan...
32
33
34
  
  	while (*new) {
  		parent = *new;
dadf93534   Michel Lespinasse   rbtree: augmented...
35
  		if (key < rb_entry(parent, struct test_node, rb)->key)
910a742d4   Michel Lespinasse   rbtree: performan...
36
37
38
39
40
41
  			new = &parent->rb_left;
  		else
  			new = &parent->rb_right;
  	}
  
  	rb_link_node(&node->rb, parent, new);
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
42
  	rb_insert_color(&node->rb, &root->rb_root);
910a742d4   Michel Lespinasse   rbtree: performan...
43
  }
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
44
  static void insert_cached(struct test_node *node, struct rb_root_cached *root)
910a742d4   Michel Lespinasse   rbtree: performan...
45
  {
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
  	struct rb_node **new = &root->rb_root.rb_node, *parent = NULL;
  	u32 key = node->key;
  	bool leftmost = true;
  
  	while (*new) {
  		parent = *new;
  		if (key < rb_entry(parent, struct test_node, rb)->key)
  			new = &parent->rb_left;
  		else {
  			new = &parent->rb_right;
  			leftmost = false;
  		}
  	}
  
  	rb_link_node(&node->rb, parent, new);
  	rb_insert_color_cached(&node->rb, root, leftmost);
910a742d4   Michel Lespinasse   rbtree: performan...
62
  }
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
63
64
65
66
67
68
69
70
71
  static inline void erase(struct test_node *node, struct rb_root_cached *root)
  {
  	rb_erase(&node->rb, &root->rb_root);
  }
  
  static inline void erase_cached(struct test_node *node, struct rb_root_cached *root)
  {
  	rb_erase_cached(&node->rb, root);
  }
dadf93534   Michel Lespinasse   rbtree: augmented...
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  static inline u32 augment_recompute(struct test_node *node)
  {
  	u32 max = node->val, child_augmented;
  	if (node->rb.rb_left) {
  		child_augmented = rb_entry(node->rb.rb_left, struct test_node,
  					   rb)->augmented;
  		if (max < child_augmented)
  			max = child_augmented;
  	}
  	if (node->rb.rb_right) {
  		child_augmented = rb_entry(node->rb.rb_right, struct test_node,
  					   rb)->augmented;
  		if (max < child_augmented)
  			max = child_augmented;
  	}
  	return max;
  }
3908836aa   Michel Lespinasse   rbtree: add RB_DE...
89
90
  RB_DECLARE_CALLBACKS(static, augment_callbacks, struct test_node, rb,
  		     u32, augmented, augment_recompute)
14b94af0b   Michel Lespinasse   rbtree: faster au...
91

b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
92
93
  static void insert_augmented(struct test_node *node,
  			     struct rb_root_cached *root)
dadf93534   Michel Lespinasse   rbtree: augmented...
94
  {
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
95
  	struct rb_node **new = &root->rb_root.rb_node, *rb_parent = NULL;
dadf93534   Michel Lespinasse   rbtree: augmented...
96
  	u32 key = node->key;
14b94af0b   Michel Lespinasse   rbtree: faster au...
97
98
  	u32 val = node->val;
  	struct test_node *parent;
dadf93534   Michel Lespinasse   rbtree: augmented...
99
100
  
  	while (*new) {
14b94af0b   Michel Lespinasse   rbtree: faster au...
101
102
103
104
105
106
  		rb_parent = *new;
  		parent = rb_entry(rb_parent, struct test_node, rb);
  		if (parent->augmented < val)
  			parent->augmented = val;
  		if (key < parent->key)
  			new = &parent->rb.rb_left;
dadf93534   Michel Lespinasse   rbtree: augmented...
107
  		else
14b94af0b   Michel Lespinasse   rbtree: faster au...
108
  			new = &parent->rb.rb_right;
dadf93534   Michel Lespinasse   rbtree: augmented...
109
  	}
14b94af0b   Michel Lespinasse   rbtree: faster au...
110
111
  	node->augmented = val;
  	rb_link_node(&node->rb, rb_parent, new);
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  	rb_insert_augmented(&node->rb, &root->rb_root, &augment_callbacks);
  }
  
  static void insert_augmented_cached(struct test_node *node,
  				    struct rb_root_cached *root)
  {
  	struct rb_node **new = &root->rb_root.rb_node, *rb_parent = NULL;
  	u32 key = node->key;
  	u32 val = node->val;
  	struct test_node *parent;
  	bool leftmost = true;
  
  	while (*new) {
  		rb_parent = *new;
  		parent = rb_entry(rb_parent, struct test_node, rb);
  		if (parent->augmented < val)
  			parent->augmented = val;
  		if (key < parent->key)
  			new = &parent->rb.rb_left;
  		else {
  			new = &parent->rb.rb_right;
  			leftmost = false;
  		}
  	}
  
  	node->augmented = val;
  	rb_link_node(&node->rb, rb_parent, new);
  	rb_insert_augmented_cached(&node->rb, root,
  				   leftmost, &augment_callbacks);
  }
  
  
  static void erase_augmented(struct test_node *node, struct rb_root_cached *root)
  {
  	rb_erase_augmented(&node->rb, &root->rb_root, &augment_callbacks);
dadf93534   Michel Lespinasse   rbtree: augmented...
147
  }
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
148
149
  static void erase_augmented_cached(struct test_node *node,
  				   struct rb_root_cached *root)
dadf93534   Michel Lespinasse   rbtree: augmented...
150
  {
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
151
  	rb_erase_augmented_cached(&node->rb, root, &augment_callbacks);
dadf93534   Michel Lespinasse   rbtree: augmented...
152
  }
910a742d4   Michel Lespinasse   rbtree: performan...
153
154
155
  static void init(void)
  {
  	int i;
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
156
  	for (i = 0; i < nnodes; i++) {
496f2f93b   Akinobu Mita   random32: rename ...
157
158
  		nodes[i].key = prandom_u32_state(&rnd);
  		nodes[i].val = prandom_u32_state(&rnd);
dadf93534   Michel Lespinasse   rbtree: augmented...
159
  	}
910a742d4   Michel Lespinasse   rbtree: performan...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  }
  
  static bool is_red(struct rb_node *rb)
  {
  	return !(rb->__rb_parent_color & 1);
  }
  
  static int black_path_count(struct rb_node *rb)
  {
  	int count;
  	for (count = 0; rb; rb = rb_parent(rb))
  		count += !is_red(rb);
  	return count;
  }
964fe94d7   Cody P Schafer   rbtree/test: test...
174
175
176
177
  static void check_postorder_foreach(int nr_nodes)
  {
  	struct test_node *cur, *n;
  	int count = 0;
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
178
  	rbtree_postorder_for_each_entry_safe(cur, n, &root.rb_root, rb)
964fe94d7   Cody P Schafer   rbtree/test: test...
179
180
181
182
  		count++;
  
  	WARN_ON_ONCE(count != nr_nodes);
  }
a791a62fd   Cody P Schafer   rbtree_test: add ...
183
184
185
186
  static void check_postorder(int nr_nodes)
  {
  	struct rb_node *rb;
  	int count = 0;
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
187
  	for (rb = rb_first_postorder(&root.rb_root); rb; rb = rb_next_postorder(rb))
a791a62fd   Cody P Schafer   rbtree_test: add ...
188
189
190
191
  		count++;
  
  	WARN_ON_ONCE(count != nr_nodes);
  }
910a742d4   Michel Lespinasse   rbtree: performan...
192
193
194
  static void check(int nr_nodes)
  {
  	struct rb_node *rb;
4130f0efb   Davidlohr Bueso   rbtree_test: add ...
195
  	int count = 0, blacks = 0;
910a742d4   Michel Lespinasse   rbtree: performan...
196
  	u32 prev_key = 0;
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
197
  	for (rb = rb_first(&root.rb_root); rb; rb = rb_next(rb)) {
910a742d4   Michel Lespinasse   rbtree: performan...
198
199
200
201
202
203
204
205
206
207
208
209
  		struct test_node *node = rb_entry(rb, struct test_node, rb);
  		WARN_ON_ONCE(node->key < prev_key);
  		WARN_ON_ONCE(is_red(rb) &&
  			     (!rb_parent(rb) || is_red(rb_parent(rb))));
  		if (!count)
  			blacks = black_path_count(rb);
  		else
  			WARN_ON_ONCE((!rb->rb_left || !rb->rb_right) &&
  				     blacks != black_path_count(rb));
  		prev_key = node->key;
  		count++;
  	}
4130f0efb   Davidlohr Bueso   rbtree_test: add ...
210

910a742d4   Michel Lespinasse   rbtree: performan...
211
  	WARN_ON_ONCE(count != nr_nodes);
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
212
  	WARN_ON_ONCE(count < (1 << black_path_count(rb_last(&root.rb_root))) - 1);
a791a62fd   Cody P Schafer   rbtree_test: add ...
213
214
  
  	check_postorder(nr_nodes);
964fe94d7   Cody P Schafer   rbtree/test: test...
215
  	check_postorder_foreach(nr_nodes);
910a742d4   Michel Lespinasse   rbtree: performan...
216
  }
dadf93534   Michel Lespinasse   rbtree: augmented...
217
218
219
220
221
  static void check_augmented(int nr_nodes)
  {
  	struct rb_node *rb;
  
  	check(nr_nodes);
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
222
  	for (rb = rb_first(&root.rb_root); rb; rb = rb_next(rb)) {
dadf93534   Michel Lespinasse   rbtree: augmented...
223
224
225
226
  		struct test_node *node = rb_entry(rb, struct test_node, rb);
  		WARN_ON_ONCE(node->augmented != augment_recompute(node));
  	}
  }
c75aaa8ed   Davidlohr Bueso   rbtree_test: add ...
227
  static int __init rbtree_test_init(void)
910a742d4   Michel Lespinasse   rbtree: performan...
228
229
230
  {
  	int i, j;
  	cycles_t time1, time2, time;
977bd8d5e   Davidlohr Bueso   lib/rbtree_test.c...
231
  	struct rb_node *node;
910a742d4   Michel Lespinasse   rbtree: performan...
232

6da2ec560   Kees Cook   treewide: kmalloc...
233
  	nodes = kmalloc_array(nnodes, sizeof(*nodes), GFP_KERNEL);
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
234
235
  	if (!nodes)
  		return -ENOMEM;
910a742d4   Michel Lespinasse   rbtree: performan...
236
  	printk(KERN_ALERT "rbtree testing");
496f2f93b   Akinobu Mita   random32: rename ...
237
  	prandom_seed_state(&rnd, 3141592653589793238ULL);
910a742d4   Michel Lespinasse   rbtree: performan...
238
239
240
  	init();
  
  	time1 = get_cycles();
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
241
242
  	for (i = 0; i < perf_loops; i++) {
  		for (j = 0; j < nnodes; j++)
910a742d4   Michel Lespinasse   rbtree: performan...
243
  			insert(nodes + j, &root);
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
244
  		for (j = 0; j < nnodes; j++)
910a742d4   Michel Lespinasse   rbtree: performan...
245
246
247
248
249
  			erase(nodes + j, &root);
  	}
  
  	time2 = get_cycles();
  	time = time2 - time1;
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
250
  	time = div_u64(time, perf_loops);
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
  	printk(" -> test 1 (latency of nnodes insert+delete): %llu cycles
  ",
  	       (unsigned long long)time);
  
  	time1 = get_cycles();
  
  	for (i = 0; i < perf_loops; i++) {
  		for (j = 0; j < nnodes; j++)
  			insert_cached(nodes + j, &root);
  		for (j = 0; j < nnodes; j++)
  			erase_cached(nodes + j, &root);
  	}
  
  	time2 = get_cycles();
  	time = time2 - time1;
  
  	time = div_u64(time, perf_loops);
  	printk(" -> test 2 (latency of nnodes cached insert+delete): %llu cycles
  ",
  	       (unsigned long long)time);
910a742d4   Michel Lespinasse   rbtree: performan...
271

977bd8d5e   Davidlohr Bueso   lib/rbtree_test.c...
272
273
274
275
276
277
  	for (i = 0; i < nnodes; i++)
  		insert(nodes + i, &root);
  
  	time1 = get_cycles();
  
  	for (i = 0; i < perf_loops; i++) {
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
278
  		for (node = rb_first(&root.rb_root); node; node = rb_next(node))
977bd8d5e   Davidlohr Bueso   lib/rbtree_test.c...
279
280
281
282
283
284
285
  			;
  	}
  
  	time2 = get_cycles();
  	time = time2 - time1;
  
  	time = div_u64(time, perf_loops);
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
  	printk(" -> test 3 (latency of inorder traversal): %llu cycles
  ",
  	       (unsigned long long)time);
  
  	time1 = get_cycles();
  
  	for (i = 0; i < perf_loops; i++)
  		node = rb_first(&root.rb_root);
  
  	time2 = get_cycles();
  	time = time2 - time1;
  
  	time = div_u64(time, perf_loops);
  	printk(" -> test 4 (latency to fetch first node)
  ");
  	printk("        non-cached: %llu cycles
  ", (unsigned long long)time);
  
  	time1 = get_cycles();
  
  	for (i = 0; i < perf_loops; i++)
  		node = rb_first_cached(&root);
  
  	time2 = get_cycles();
  	time = time2 - time1;
  
  	time = div_u64(time, perf_loops);
  	printk("        cached: %llu cycles
  ", (unsigned long long)time);
977bd8d5e   Davidlohr Bueso   lib/rbtree_test.c...
315
316
317
318
319
  
  	for (i = 0; i < nnodes; i++)
  		erase(nodes + i, &root);
  
  	/* run checks */
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
320
  	for (i = 0; i < check_loops; i++) {
910a742d4   Michel Lespinasse   rbtree: performan...
321
  		init();
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
322
  		for (j = 0; j < nnodes; j++) {
910a742d4   Michel Lespinasse   rbtree: performan...
323
324
325
  			check(j);
  			insert(nodes + j, &root);
  		}
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
326
327
  		for (j = 0; j < nnodes; j++) {
  			check(nnodes - j);
910a742d4   Michel Lespinasse   rbtree: performan...
328
329
330
331
  			erase(nodes + j, &root);
  		}
  		check(0);
  	}
dadf93534   Michel Lespinasse   rbtree: augmented...
332
333
334
335
336
  	printk(KERN_ALERT "augmented rbtree testing");
  
  	init();
  
  	time1 = get_cycles();
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
337
338
  	for (i = 0; i < perf_loops; i++) {
  		for (j = 0; j < nnodes; j++)
dadf93534   Michel Lespinasse   rbtree: augmented...
339
  			insert_augmented(nodes + j, &root);
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
340
  		for (j = 0; j < nnodes; j++)
dadf93534   Michel Lespinasse   rbtree: augmented...
341
342
343
344
345
  			erase_augmented(nodes + j, &root);
  	}
  
  	time2 = get_cycles();
  	time = time2 - time1;
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
346
  	time = div_u64(time, perf_loops);
977bd8d5e   Davidlohr Bueso   lib/rbtree_test.c...
347
348
  	printk(" -> test 1 (latency of nnodes insert+delete): %llu cycles
  ", (unsigned long long)time);
dadf93534   Michel Lespinasse   rbtree: augmented...
349

b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  	time1 = get_cycles();
  
  	for (i = 0; i < perf_loops; i++) {
  		for (j = 0; j < nnodes; j++)
  			insert_augmented_cached(nodes + j, &root);
  		for (j = 0; j < nnodes; j++)
  			erase_augmented_cached(nodes + j, &root);
  	}
  
  	time2 = get_cycles();
  	time = time2 - time1;
  
  	time = div_u64(time, perf_loops);
  	printk(" -> test 2 (latency of nnodes cached insert+delete): %llu cycles
  ", (unsigned long long)time);
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
365
  	for (i = 0; i < check_loops; i++) {
dadf93534   Michel Lespinasse   rbtree: augmented...
366
  		init();
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
367
  		for (j = 0; j < nnodes; j++) {
dadf93534   Michel Lespinasse   rbtree: augmented...
368
369
370
  			check_augmented(j);
  			insert_augmented(nodes + j, &root);
  		}
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
371
372
  		for (j = 0; j < nnodes; j++) {
  			check_augmented(nnodes - j);
dadf93534   Michel Lespinasse   rbtree: augmented...
373
374
375
376
  			erase_augmented(nodes + j, &root);
  		}
  		check_augmented(0);
  	}
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
377
  	kfree(nodes);
910a742d4   Michel Lespinasse   rbtree: performan...
378
379
  	return -EAGAIN; /* Fail will directly unload the module */
  }
c75aaa8ed   Davidlohr Bueso   rbtree_test: add ...
380
  static void __exit rbtree_test_exit(void)
910a742d4   Michel Lespinasse   rbtree: performan...
381
382
383
384
385
386
387
388
389
390
391
  {
  	printk(KERN_ALERT "test exit
  ");
  }
  
  module_init(rbtree_test_init)
  module_exit(rbtree_test_exit)
  
  MODULE_LICENSE("GPL");
  MODULE_AUTHOR("Michel Lespinasse");
  MODULE_DESCRIPTION("Red Black Tree test");