Blame view

lib/rbtree_test.c 9.36 KB
09c434b8a   Thomas Gleixner   treewide: Add SPD...
1
  // SPDX-License-Identifier: GPL-2.0-only
910a742d4   Michel Lespinasse   rbtree: performan...
2
  #include <linux/module.h>
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
3
  #include <linux/moduleparam.h>
9c079add0   Michel Lespinasse   rbtree: move augm...
4
  #include <linux/rbtree_augmented.h>
910a742d4   Michel Lespinasse   rbtree: performan...
5
  #include <linux/random.h>
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
6
  #include <linux/slab.h>
910a742d4   Michel Lespinasse   rbtree: performan...
7
  #include <asm/timex.h>
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
8
9
10
11
12
13
  #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: ...
14
  __param(int, perf_loops, 1000, "Number of iterations modifying the rb-tree");
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
15
  __param(int, check_loops, 100, "Number of iterations modifying and verifying the rb-tree");
910a742d4   Michel Lespinasse   rbtree: performan...
16
17
  
  struct test_node {
910a742d4   Michel Lespinasse   rbtree: performan...
18
  	u32 key;
dbf128cbf   Cody P Schafer   rbtree/test: move...
19
  	struct rb_node rb;
dadf93534   Michel Lespinasse   rbtree: augmented...
20
21
22
23
  
  	/* following fields used for testing augmented rbtree functionality */
  	u32 val;
  	u32 augmented;
910a742d4   Michel Lespinasse   rbtree: performan...
24
  };
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
25
  static struct rb_root_cached root = RB_ROOT_CACHED;
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
26
  static struct test_node *nodes = NULL;
910a742d4   Michel Lespinasse   rbtree: performan...
27
28
  
  static struct rnd_state rnd;
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
29
  static void insert(struct test_node *node, struct rb_root_cached *root)
910a742d4   Michel Lespinasse   rbtree: performan...
30
  {
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
31
  	struct rb_node **new = &root->rb_root.rb_node, *parent = NULL;
dadf93534   Michel Lespinasse   rbtree: augmented...
32
  	u32 key = node->key;
910a742d4   Michel Lespinasse   rbtree: performan...
33
34
35
  
  	while (*new) {
  		parent = *new;
dadf93534   Michel Lespinasse   rbtree: augmented...
36
  		if (key < rb_entry(parent, struct test_node, rb)->key)
910a742d4   Michel Lespinasse   rbtree: performan...
37
38
39
40
41
42
  			new = &parent->rb_left;
  		else
  			new = &parent->rb_right;
  	}
  
  	rb_link_node(&node->rb, parent, new);
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
43
  	rb_insert_color(&node->rb, &root->rb_root);
910a742d4   Michel Lespinasse   rbtree: performan...
44
  }
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
45
  static void insert_cached(struct test_node *node, struct rb_root_cached *root)
910a742d4   Michel Lespinasse   rbtree: performan...
46
  {
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  	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...
63
  }
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
64
65
66
67
68
69
70
71
72
  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);
  }
315cc066b   Michel Lespinasse   augmented rbtree:...
73
  #define NODE_VAL(node) ((node)->val)
dadf93534   Michel Lespinasse   rbtree: augmented...
74

315cc066b   Michel Lespinasse   augmented rbtree:...
75
76
  RB_DECLARE_CALLBACKS_MAX(static, augment_callbacks,
  			 struct test_node, rb, u32, augmented, NODE_VAL)
14b94af0b   Michel Lespinasse   rbtree: faster au...
77

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

910a742d4   Michel Lespinasse   rbtree: performan...
197
  	WARN_ON_ONCE(count != nr_nodes);
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
198
  	WARN_ON_ONCE(count < (1 << black_path_count(rb_last(&root.rb_root))) - 1);
a791a62fd   Cody P Schafer   rbtree_test: add ...
199
200
  
  	check_postorder(nr_nodes);
964fe94d7   Cody P Schafer   rbtree/test: test...
201
  	check_postorder_foreach(nr_nodes);
910a742d4   Michel Lespinasse   rbtree: performan...
202
  }
dadf93534   Michel Lespinasse   rbtree: augmented...
203
204
205
206
207
  static void check_augmented(int nr_nodes)
  {
  	struct rb_node *rb;
  
  	check(nr_nodes);
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
208
  	for (rb = rb_first(&root.rb_root); rb; rb = rb_next(rb)) {
dadf93534   Michel Lespinasse   rbtree: augmented...
209
  		struct test_node *node = rb_entry(rb, struct test_node, rb);
315cc066b   Michel Lespinasse   augmented rbtree:...
210
211
212
213
214
215
216
217
218
219
220
221
222
223
  		u32 subtree, max = node->val;
  		if (node->rb.rb_left) {
  			subtree = rb_entry(node->rb.rb_left, struct test_node,
  					   rb)->augmented;
  			if (max < subtree)
  				max = subtree;
  		}
  		if (node->rb.rb_right) {
  			subtree = rb_entry(node->rb.rb_right, struct test_node,
  					   rb)->augmented;
  			if (max < subtree)
  				max = subtree;
  		}
  		WARN_ON_ONCE(node->augmented != max);
dadf93534   Michel Lespinasse   rbtree: augmented...
224
225
  	}
  }
c75aaa8ed   Davidlohr Bueso   rbtree_test: add ...
226
  static int __init rbtree_test_init(void)
910a742d4   Michel Lespinasse   rbtree: performan...
227
228
229
  {
  	int i, j;
  	cycles_t time1, time2, time;
977bd8d5e   Davidlohr Bueso   lib/rbtree_test.c...
230
  	struct rb_node *node;
910a742d4   Michel Lespinasse   rbtree: performan...
231

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

977bd8d5e   Davidlohr Bueso   lib/rbtree_test.c...
271
272
273
274
275
276
  	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...
277
  		for (node = rb_first(&root.rb_root); node; node = rb_next(node))
977bd8d5e   Davidlohr Bueso   lib/rbtree_test.c...
278
279
280
281
282
283
284
  			;
  	}
  
  	time2 = get_cycles();
  	time = time2 - time1;
  
  	time = div_u64(time, perf_loops);
b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
285
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
  	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...
314
315
316
317
318
  
  	for (i = 0; i < nnodes; i++)
  		erase(nodes + i, &root);
  
  	/* run checks */
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
319
  	for (i = 0; i < check_loops; i++) {
910a742d4   Michel Lespinasse   rbtree: performan...
320
  		init();
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
321
  		for (j = 0; j < nnodes; j++) {
910a742d4   Michel Lespinasse   rbtree: performan...
322
323
324
  			check(j);
  			insert(nodes + j, &root);
  		}
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
325
326
  		for (j = 0; j < nnodes; j++) {
  			check(nnodes - j);
910a742d4   Michel Lespinasse   rbtree: performan...
327
328
329
330
  			erase(nodes + j, &root);
  		}
  		check(0);
  	}
dadf93534   Michel Lespinasse   rbtree: augmented...
331
332
333
334
335
  	printk(KERN_ALERT "augmented rbtree testing");
  
  	init();
  
  	time1 = get_cycles();
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
336
337
  	for (i = 0; i < perf_loops; i++) {
  		for (j = 0; j < nnodes; j++)
dadf93534   Michel Lespinasse   rbtree: augmented...
338
  			insert_augmented(nodes + j, &root);
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
339
  		for (j = 0; j < nnodes; j++)
dadf93534   Michel Lespinasse   rbtree: augmented...
340
341
342
343
344
  			erase_augmented(nodes + j, &root);
  	}
  
  	time2 = get_cycles();
  	time = time2 - time1;
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
345
  	time = div_u64(time, perf_loops);
977bd8d5e   Davidlohr Bueso   lib/rbtree_test.c...
346
347
  	printk(" -> test 1 (latency of nnodes insert+delete): %llu cycles
  ", (unsigned long long)time);
dadf93534   Michel Lespinasse   rbtree: augmented...
348

b10d43f98   Davidlohr Bueso   lib/rbtree_test.c...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
  	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...
364
  	for (i = 0; i < check_loops; i++) {
dadf93534   Michel Lespinasse   rbtree: augmented...
365
  		init();
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
366
  		for (j = 0; j < nnodes; j++) {
dadf93534   Michel Lespinasse   rbtree: augmented...
367
368
369
  			check_augmented(j);
  			insert_augmented(nodes + j, &root);
  		}
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
370
371
  		for (j = 0; j < nnodes; j++) {
  			check_augmented(nnodes - j);
dadf93534   Michel Lespinasse   rbtree: augmented...
372
373
374
375
  			erase_augmented(nodes + j, &root);
  		}
  		check_augmented(0);
  	}
223f8911e   Davidlohr Bueso   lib/rbtree_test.c...
376
  	kfree(nodes);
910a742d4   Michel Lespinasse   rbtree: performan...
377
378
  	return -EAGAIN; /* Fail will directly unload the module */
  }
c75aaa8ed   Davidlohr Bueso   rbtree_test: add ...
379
  static void __exit rbtree_test_exit(void)
910a742d4   Michel Lespinasse   rbtree: performan...
380
381
382
383
384
385
386
387
388
389
390
  {
  	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");