xref: /OK3568_Linux_fs/kernel/tools/testing/radix-tree/main.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <stdio.h>
3*4882a593Smuzhiyun #include <stdlib.h>
4*4882a593Smuzhiyun #include <unistd.h>
5*4882a593Smuzhiyun #include <time.h>
6*4882a593Smuzhiyun #include <assert.h>
7*4882a593Smuzhiyun #include <limits.h>
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/slab.h>
10*4882a593Smuzhiyun #include <linux/radix-tree.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include "test.h"
13*4882a593Smuzhiyun #include "regression.h"
14*4882a593Smuzhiyun 
__gang_check(unsigned long middle,long down,long up,int chunk,int hop)15*4882a593Smuzhiyun void __gang_check(unsigned long middle, long down, long up, int chunk, int hop)
16*4882a593Smuzhiyun {
17*4882a593Smuzhiyun 	long idx;
18*4882a593Smuzhiyun 	RADIX_TREE(tree, GFP_KERNEL);
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 	middle = 1 << 30;
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun 	for (idx = -down; idx < up; idx++)
23*4882a593Smuzhiyun 		item_insert(&tree, middle + idx);
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	item_check_absent(&tree, middle - down - 1);
26*4882a593Smuzhiyun 	for (idx = -down; idx < up; idx++)
27*4882a593Smuzhiyun 		item_check_present(&tree, middle + idx);
28*4882a593Smuzhiyun 	item_check_absent(&tree, middle + up);
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	if (chunk > 0) {
31*4882a593Smuzhiyun 		item_gang_check_present(&tree, middle - down, up + down,
32*4882a593Smuzhiyun 				chunk, hop);
33*4882a593Smuzhiyun 		item_full_scan(&tree, middle - down, down + up, chunk);
34*4882a593Smuzhiyun 	}
35*4882a593Smuzhiyun 	item_kill_tree(&tree);
36*4882a593Smuzhiyun }
37*4882a593Smuzhiyun 
gang_check(void)38*4882a593Smuzhiyun void gang_check(void)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	__gang_check(1UL << 30, 128, 128, 35, 2);
41*4882a593Smuzhiyun 	__gang_check(1UL << 31, 128, 128, 32, 32);
42*4882a593Smuzhiyun 	__gang_check(1UL << 31, 128, 128, 32, 100);
43*4882a593Smuzhiyun 	__gang_check(1UL << 31, 128, 128, 17, 7);
44*4882a593Smuzhiyun 	__gang_check(0xffff0000UL, 0, 65536, 17, 7);
45*4882a593Smuzhiyun 	__gang_check(0xfffffffeUL, 1, 1, 17, 7);
46*4882a593Smuzhiyun }
47*4882a593Smuzhiyun 
__big_gang_check(void)48*4882a593Smuzhiyun void __big_gang_check(void)
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 	unsigned long start;
51*4882a593Smuzhiyun 	int wrapped = 0;
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun 	start = 0;
54*4882a593Smuzhiyun 	do {
55*4882a593Smuzhiyun 		unsigned long old_start;
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun //		printf("0x%08lx\n", start);
58*4882a593Smuzhiyun 		__gang_check(start, rand() % 113 + 1, rand() % 71,
59*4882a593Smuzhiyun 				rand() % 157, rand() % 91 + 1);
60*4882a593Smuzhiyun 		old_start = start;
61*4882a593Smuzhiyun 		start += rand() % 1000000;
62*4882a593Smuzhiyun 		start %= 1ULL << 33;
63*4882a593Smuzhiyun 		if (start < old_start)
64*4882a593Smuzhiyun 			wrapped = 1;
65*4882a593Smuzhiyun 	} while (!wrapped);
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
big_gang_check(bool long_run)68*4882a593Smuzhiyun void big_gang_check(bool long_run)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	int i;
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun 	for (i = 0; i < (long_run ? 1000 : 3); i++) {
73*4882a593Smuzhiyun 		__big_gang_check();
74*4882a593Smuzhiyun 		printv(2, "%d ", i);
75*4882a593Smuzhiyun 		fflush(stdout);
76*4882a593Smuzhiyun 	}
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
add_and_check(void)79*4882a593Smuzhiyun void add_and_check(void)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	RADIX_TREE(tree, GFP_KERNEL);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	item_insert(&tree, 44);
84*4882a593Smuzhiyun 	item_check_present(&tree, 44);
85*4882a593Smuzhiyun 	item_check_absent(&tree, 43);
86*4882a593Smuzhiyun 	item_kill_tree(&tree);
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun 
dynamic_height_check(void)89*4882a593Smuzhiyun void dynamic_height_check(void)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	int i;
92*4882a593Smuzhiyun 	RADIX_TREE(tree, GFP_KERNEL);
93*4882a593Smuzhiyun 	tree_verify_min_height(&tree, 0);
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	item_insert(&tree, 42);
96*4882a593Smuzhiyun 	tree_verify_min_height(&tree, 42);
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	item_insert(&tree, 1000000);
99*4882a593Smuzhiyun 	tree_verify_min_height(&tree, 1000000);
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	assert(item_delete(&tree, 1000000));
102*4882a593Smuzhiyun 	tree_verify_min_height(&tree, 42);
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	assert(item_delete(&tree, 42));
105*4882a593Smuzhiyun 	tree_verify_min_height(&tree, 0);
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	for (i = 0; i < 1000; i++) {
108*4882a593Smuzhiyun 		item_insert(&tree, i);
109*4882a593Smuzhiyun 		tree_verify_min_height(&tree, i);
110*4882a593Smuzhiyun 	}
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun 	i--;
113*4882a593Smuzhiyun 	for (;;) {
114*4882a593Smuzhiyun 		assert(item_delete(&tree, i));
115*4882a593Smuzhiyun 		if (i == 0) {
116*4882a593Smuzhiyun 			tree_verify_min_height(&tree, 0);
117*4882a593Smuzhiyun 			break;
118*4882a593Smuzhiyun 		}
119*4882a593Smuzhiyun 		i--;
120*4882a593Smuzhiyun 		tree_verify_min_height(&tree, i);
121*4882a593Smuzhiyun 	}
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	item_kill_tree(&tree);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
check_copied_tags(struct radix_tree_root * tree,unsigned long start,unsigned long end,unsigned long * idx,int count,int fromtag,int totag)126*4882a593Smuzhiyun void check_copied_tags(struct radix_tree_root *tree, unsigned long start, unsigned long end, unsigned long *idx, int count, int fromtag, int totag)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	int i;
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	for (i = 0; i < count; i++) {
131*4882a593Smuzhiyun /*		if (i % 1000 == 0)
132*4882a593Smuzhiyun 			putchar('.'); */
133*4882a593Smuzhiyun 		if (idx[i] < start || idx[i] > end) {
134*4882a593Smuzhiyun 			if (item_tag_get(tree, idx[i], totag)) {
135*4882a593Smuzhiyun 				printv(2, "%lu-%lu: %lu, tags %d-%d\n", start,
136*4882a593Smuzhiyun 				       end, idx[i], item_tag_get(tree, idx[i],
137*4882a593Smuzhiyun 								 fromtag),
138*4882a593Smuzhiyun 				       item_tag_get(tree, idx[i], totag));
139*4882a593Smuzhiyun 			}
140*4882a593Smuzhiyun 			assert(!item_tag_get(tree, idx[i], totag));
141*4882a593Smuzhiyun 			continue;
142*4882a593Smuzhiyun 		}
143*4882a593Smuzhiyun 		if (item_tag_get(tree, idx[i], fromtag) ^
144*4882a593Smuzhiyun 			item_tag_get(tree, idx[i], totag)) {
145*4882a593Smuzhiyun 			printv(2, "%lu-%lu: %lu, tags %d-%d\n", start, end,
146*4882a593Smuzhiyun 			       idx[i], item_tag_get(tree, idx[i], fromtag),
147*4882a593Smuzhiyun 			       item_tag_get(tree, idx[i], totag));
148*4882a593Smuzhiyun 		}
149*4882a593Smuzhiyun 		assert(!(item_tag_get(tree, idx[i], fromtag) ^
150*4882a593Smuzhiyun 			 item_tag_get(tree, idx[i], totag)));
151*4882a593Smuzhiyun 	}
152*4882a593Smuzhiyun }
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun #define ITEMS 50000
155*4882a593Smuzhiyun 
copy_tag_check(void)156*4882a593Smuzhiyun void copy_tag_check(void)
157*4882a593Smuzhiyun {
158*4882a593Smuzhiyun 	RADIX_TREE(tree, GFP_KERNEL);
159*4882a593Smuzhiyun 	unsigned long idx[ITEMS];
160*4882a593Smuzhiyun 	unsigned long start, end, count = 0, tagged, cur, tmp;
161*4882a593Smuzhiyun 	int i;
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun //	printf("generating radix tree indices...\n");
164*4882a593Smuzhiyun 	start = rand();
165*4882a593Smuzhiyun 	end = rand();
166*4882a593Smuzhiyun 	if (start > end && (rand() % 10)) {
167*4882a593Smuzhiyun 		cur = start;
168*4882a593Smuzhiyun 		start = end;
169*4882a593Smuzhiyun 		end = cur;
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun 	/* Specifically create items around the start and the end of the range
172*4882a593Smuzhiyun 	 * with high probability to check for off by one errors */
173*4882a593Smuzhiyun 	cur = rand();
174*4882a593Smuzhiyun 	if (cur & 1) {
175*4882a593Smuzhiyun 		item_insert(&tree, start);
176*4882a593Smuzhiyun 		if (cur & 2) {
177*4882a593Smuzhiyun 			if (start <= end)
178*4882a593Smuzhiyun 				count++;
179*4882a593Smuzhiyun 			item_tag_set(&tree, start, 0);
180*4882a593Smuzhiyun 		}
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 	if (cur & 4) {
183*4882a593Smuzhiyun 		item_insert(&tree, start-1);
184*4882a593Smuzhiyun 		if (cur & 8)
185*4882a593Smuzhiyun 			item_tag_set(&tree, start-1, 0);
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 	if (cur & 16) {
188*4882a593Smuzhiyun 		item_insert(&tree, end);
189*4882a593Smuzhiyun 		if (cur & 32) {
190*4882a593Smuzhiyun 			if (start <= end)
191*4882a593Smuzhiyun 				count++;
192*4882a593Smuzhiyun 			item_tag_set(&tree, end, 0);
193*4882a593Smuzhiyun 		}
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 	if (cur & 64) {
196*4882a593Smuzhiyun 		item_insert(&tree, end+1);
197*4882a593Smuzhiyun 		if (cur & 128)
198*4882a593Smuzhiyun 			item_tag_set(&tree, end+1, 0);
199*4882a593Smuzhiyun 	}
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	for (i = 0; i < ITEMS; i++) {
202*4882a593Smuzhiyun 		do {
203*4882a593Smuzhiyun 			idx[i] = rand();
204*4882a593Smuzhiyun 		} while (item_lookup(&tree, idx[i]));
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 		item_insert(&tree, idx[i]);
207*4882a593Smuzhiyun 		if (rand() & 1) {
208*4882a593Smuzhiyun 			item_tag_set(&tree, idx[i], 0);
209*4882a593Smuzhiyun 			if (idx[i] >= start && idx[i] <= end)
210*4882a593Smuzhiyun 				count++;
211*4882a593Smuzhiyun 		}
212*4882a593Smuzhiyun /*		if (i % 1000 == 0)
213*4882a593Smuzhiyun 			putchar('.'); */
214*4882a593Smuzhiyun 	}
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun //	printf("\ncopying tags...\n");
217*4882a593Smuzhiyun 	tagged = tag_tagged_items(&tree, start, end, ITEMS, XA_MARK_0, XA_MARK_1);
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun //	printf("checking copied tags\n");
220*4882a593Smuzhiyun 	assert(tagged == count);
221*4882a593Smuzhiyun 	check_copied_tags(&tree, start, end, idx, ITEMS, 0, 1);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	/* Copy tags in several rounds */
224*4882a593Smuzhiyun //	printf("\ncopying tags...\n");
225*4882a593Smuzhiyun 	tmp = rand() % (count / 10 + 2);
226*4882a593Smuzhiyun 	tagged = tag_tagged_items(&tree, start, end, tmp, XA_MARK_0, XA_MARK_2);
227*4882a593Smuzhiyun 	assert(tagged == count);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun //	printf("%lu %lu %lu\n", tagged, tmp, count);
230*4882a593Smuzhiyun //	printf("checking copied tags\n");
231*4882a593Smuzhiyun 	check_copied_tags(&tree, start, end, idx, ITEMS, 0, 2);
232*4882a593Smuzhiyun 	verify_tag_consistency(&tree, 0);
233*4882a593Smuzhiyun 	verify_tag_consistency(&tree, 1);
234*4882a593Smuzhiyun 	verify_tag_consistency(&tree, 2);
235*4882a593Smuzhiyun //	printf("\n");
236*4882a593Smuzhiyun 	item_kill_tree(&tree);
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun 
single_thread_tests(bool long_run)239*4882a593Smuzhiyun static void single_thread_tests(bool long_run)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun 	int i;
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 	printv(1, "starting single_thread_tests: %d allocated, preempt %d\n",
244*4882a593Smuzhiyun 		nr_allocated, preempt_count);
245*4882a593Smuzhiyun 	multiorder_checks();
246*4882a593Smuzhiyun 	rcu_barrier();
247*4882a593Smuzhiyun 	printv(2, "after multiorder_check: %d allocated, preempt %d\n",
248*4882a593Smuzhiyun 		nr_allocated, preempt_count);
249*4882a593Smuzhiyun 	tag_check();
250*4882a593Smuzhiyun 	rcu_barrier();
251*4882a593Smuzhiyun 	printv(2, "after tag_check: %d allocated, preempt %d\n",
252*4882a593Smuzhiyun 		nr_allocated, preempt_count);
253*4882a593Smuzhiyun 	gang_check();
254*4882a593Smuzhiyun 	rcu_barrier();
255*4882a593Smuzhiyun 	printv(2, "after gang_check: %d allocated, preempt %d\n",
256*4882a593Smuzhiyun 		nr_allocated, preempt_count);
257*4882a593Smuzhiyun 	add_and_check();
258*4882a593Smuzhiyun 	rcu_barrier();
259*4882a593Smuzhiyun 	printv(2, "after add_and_check: %d allocated, preempt %d\n",
260*4882a593Smuzhiyun 		nr_allocated, preempt_count);
261*4882a593Smuzhiyun 	dynamic_height_check();
262*4882a593Smuzhiyun 	rcu_barrier();
263*4882a593Smuzhiyun 	printv(2, "after dynamic_height_check: %d allocated, preempt %d\n",
264*4882a593Smuzhiyun 		nr_allocated, preempt_count);
265*4882a593Smuzhiyun 	idr_checks();
266*4882a593Smuzhiyun 	ida_tests();
267*4882a593Smuzhiyun 	rcu_barrier();
268*4882a593Smuzhiyun 	printv(2, "after idr_checks: %d allocated, preempt %d\n",
269*4882a593Smuzhiyun 		nr_allocated, preempt_count);
270*4882a593Smuzhiyun 	big_gang_check(long_run);
271*4882a593Smuzhiyun 	rcu_barrier();
272*4882a593Smuzhiyun 	printv(2, "after big_gang_check: %d allocated, preempt %d\n",
273*4882a593Smuzhiyun 		nr_allocated, preempt_count);
274*4882a593Smuzhiyun 	for (i = 0; i < (long_run ? 2000 : 3); i++) {
275*4882a593Smuzhiyun 		copy_tag_check();
276*4882a593Smuzhiyun 		printv(2, "%d ", i);
277*4882a593Smuzhiyun 		fflush(stdout);
278*4882a593Smuzhiyun 	}
279*4882a593Smuzhiyun 	rcu_barrier();
280*4882a593Smuzhiyun 	printv(2, "after copy_tag_check: %d allocated, preempt %d\n",
281*4882a593Smuzhiyun 		nr_allocated, preempt_count);
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun 
main(int argc,char ** argv)284*4882a593Smuzhiyun int main(int argc, char **argv)
285*4882a593Smuzhiyun {
286*4882a593Smuzhiyun 	bool long_run = false;
287*4882a593Smuzhiyun 	int opt;
288*4882a593Smuzhiyun 	unsigned int seed = time(NULL);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	while ((opt = getopt(argc, argv, "ls:v")) != -1) {
291*4882a593Smuzhiyun 		if (opt == 'l')
292*4882a593Smuzhiyun 			long_run = true;
293*4882a593Smuzhiyun 		else if (opt == 's')
294*4882a593Smuzhiyun 			seed = strtoul(optarg, NULL, 0);
295*4882a593Smuzhiyun 		else if (opt == 'v')
296*4882a593Smuzhiyun 			test_verbose++;
297*4882a593Smuzhiyun 	}
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	printf("random seed %u\n", seed);
300*4882a593Smuzhiyun 	srand(seed);
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	printf("running tests\n");
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	rcu_register_thread();
305*4882a593Smuzhiyun 	radix_tree_init();
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	xarray_tests();
308*4882a593Smuzhiyun 	regression1_test();
309*4882a593Smuzhiyun 	regression2_test();
310*4882a593Smuzhiyun 	regression3_test();
311*4882a593Smuzhiyun 	regression4_test();
312*4882a593Smuzhiyun 	iteration_test(0, 10 + 90 * long_run);
313*4882a593Smuzhiyun 	iteration_test(7, 10 + 90 * long_run);
314*4882a593Smuzhiyun 	iteration_test2(10 + 90 * long_run);
315*4882a593Smuzhiyun 	single_thread_tests(long_run);
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	/* Free any remaining preallocated nodes */
318*4882a593Smuzhiyun 	radix_tree_cpu_dead(0);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	benchmark();
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	rcu_barrier();
323*4882a593Smuzhiyun 	printv(2, "after rcu_barrier: %d allocated, preempt %d\n",
324*4882a593Smuzhiyun 		nr_allocated, preempt_count);
325*4882a593Smuzhiyun 	rcu_unregister_thread();
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 	printf("tests completed\n");
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 	exit(0);
330*4882a593Smuzhiyun }
331