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