6 #include <linux/slab.h>
7 #include <linux/radix-tree.h>
13 __simple_checks(struct radix_tree_root *tree, unsigned long index, int tag)
17 item_check_absent(tree, index);
18 assert(item_tag_get(tree, index, tag) == 0);
20 item_insert(tree, index);
21 assert(item_tag_get(tree, index, tag) == 0);
22 item_tag_set(tree, index, tag);
23 ret = item_tag_get(tree, index, tag);
25 ret = item_delete(tree, index);
27 item_insert(tree, index);
28 ret = item_tag_get(tree, index, tag);
30 ret = item_delete(tree, index);
32 ret = item_delete(tree, index);
36 void simple_checks(void)
39 RADIX_TREE(tree, GFP_KERNEL);
41 for (index = 0; index < 10000; index++) {
42 __simple_checks(&tree, index, 0);
43 __simple_checks(&tree, index, 1);
45 verify_tag_consistency(&tree, 0);
46 verify_tag_consistency(&tree, 1);
47 printf("before item_kill_tree: %d allocated\n", nr_allocated);
48 item_kill_tree(&tree);
49 printf("after item_kill_tree: %d allocated\n", nr_allocated);
53 * Check that tags propagate correctly when extending a tree.
55 static void extend_checks(void)
57 RADIX_TREE(tree, GFP_KERNEL);
59 item_insert(&tree, 43);
60 assert(item_tag_get(&tree, 43, 0) == 0);
61 item_tag_set(&tree, 43, 0);
62 assert(item_tag_get(&tree, 43, 0) == 1);
63 item_insert(&tree, 1000000);
64 assert(item_tag_get(&tree, 43, 0) == 1);
66 item_insert(&tree, 0);
67 item_tag_set(&tree, 0, 0);
68 item_delete(&tree, 1000000);
69 assert(item_tag_get(&tree, 43, 0) != 0);
70 item_delete(&tree, 43);
71 assert(item_tag_get(&tree, 43, 0) == 0); /* crash */
72 assert(item_tag_get(&tree, 0, 0) == 1);
74 verify_tag_consistency(&tree, 0);
76 item_kill_tree(&tree);
80 * Check that tags propagate correctly when contracting a tree.
82 static void contract_checks(void)
86 RADIX_TREE(tree, GFP_KERNEL);
88 tmp = 1<<RADIX_TREE_MAP_SHIFT;
89 item_insert(&tree, tmp);
90 item_insert(&tree, tmp+1);
91 item_tag_set(&tree, tmp, 0);
92 item_tag_set(&tree, tmp, 1);
93 item_tag_set(&tree, tmp+1, 0);
94 item_delete(&tree, tmp+1);
95 item_tag_clear(&tree, tmp, 1);
97 assert(radix_tree_gang_lookup_tag(&tree, (void **)&item, 0, 1, 0) == 1);
98 assert(radix_tree_gang_lookup_tag(&tree, (void **)&item, 0, 1, 1) == 0);
100 assert(item_tag_get(&tree, tmp, 0) == 1);
101 assert(item_tag_get(&tree, tmp, 1) == 0);
103 verify_tag_consistency(&tree, 0);
104 item_kill_tree(&tree);
108 * Stupid tag thrasher
110 * Create a large linear array corresponding to the tree. Each element in
111 * the array is coherent with each node in the tree
120 #define THRASH_SIZE 1000 * 1000
124 static void gang_check(struct radix_tree_root *tree,
125 char *thrash_state, int tag)
127 struct item *items[BATCH];
129 unsigned long index = 0;
130 unsigned long last_index = 0;
132 while ((nr_found = radix_tree_gang_lookup_tag(tree, (void **)items,
133 index, BATCH, tag))) {
136 for (i = 0; i < nr_found; i++) {
137 struct item *item = items[i];
139 while (last_index < item->index) {
140 assert(thrash_state[last_index] != NODE_TAGGED);
143 assert(thrash_state[last_index] == NODE_TAGGED);
146 index = items[nr_found - 1]->index + 1;
150 static void do_thrash(struct radix_tree_root *tree, char *thrash_state, int tag)
156 int total_tagged = 0;
157 int total_present = 0;
159 for (insert_chunk = 1; insert_chunk < THRASH_SIZE; insert_chunk *= N)
160 for (delete_chunk = 1; delete_chunk < THRASH_SIZE; delete_chunk *= N)
161 for (tag_chunk = 1; tag_chunk < THRASH_SIZE; tag_chunk *= N)
162 for (untag_chunk = 1; untag_chunk < THRASH_SIZE; untag_chunk *= N) {
169 int actual_total_tagged;
170 int actual_total_present;
172 for (i = 0; i < insert_chunk; i++) {
173 index = rand() % THRASH_SIZE;
174 if (thrash_state[index] != NODE_ABSENT)
176 item_check_absent(tree, index);
177 item_insert(tree, index);
178 assert(thrash_state[index] != NODE_PRESENT);
179 thrash_state[index] = NODE_PRESENT;
184 for (i = 0; i < delete_chunk; i++) {
185 index = rand() % THRASH_SIZE;
186 if (thrash_state[index] == NODE_ABSENT)
188 item_check_present(tree, index);
189 if (item_tag_get(tree, index, tag)) {
190 assert(thrash_state[index] == NODE_TAGGED);
193 assert(thrash_state[index] == NODE_PRESENT);
195 item_delete(tree, index);
196 assert(thrash_state[index] != NODE_ABSENT);
197 thrash_state[index] = NODE_ABSENT;
202 for (i = 0; i < tag_chunk; i++) {
203 index = rand() % THRASH_SIZE;
204 if (thrash_state[index] != NODE_PRESENT) {
205 if (item_lookup(tree, index))
206 assert(item_tag_get(tree, index, tag));
209 item_tag_set(tree, index, tag);
210 item_tag_set(tree, index, tag);
211 assert(thrash_state[index] != NODE_TAGGED);
212 thrash_state[index] = NODE_TAGGED;
217 for (i = 0; i < untag_chunk; i++) {
218 index = rand() % THRASH_SIZE;
219 if (thrash_state[index] != NODE_TAGGED)
221 item_check_present(tree, index);
222 assert(item_tag_get(tree, index, tag));
223 item_tag_clear(tree, index, tag);
224 item_tag_clear(tree, index, tag);
225 assert(thrash_state[index] != NODE_PRESENT);
226 thrash_state[index] = NODE_PRESENT;
231 actual_total_tagged = 0;
232 actual_total_present = 0;
233 for (index = 0; index < THRASH_SIZE; index++) {
234 switch (thrash_state[index]) {
236 item_check_absent(tree, index);
239 item_check_present(tree, index);
240 assert(!item_tag_get(tree, index, tag));
241 actual_total_present++;
244 item_check_present(tree, index);
245 assert(item_tag_get(tree, index, tag));
246 actual_total_present++;
247 actual_total_tagged++;
252 gang_check(tree, thrash_state, tag);
254 printf("%d(%d) %d(%d) %d(%d) %d(%d) / "
255 "%d(%d) present, %d(%d) tagged\n",
256 insert_chunk, nr_inserted,
257 delete_chunk, nr_deleted,
258 tag_chunk, nr_tagged,
259 untag_chunk, nr_untagged,
260 total_present, actual_total_present,
261 total_tagged, actual_total_tagged);
265 static void thrash_tags(void)
267 RADIX_TREE(tree, GFP_KERNEL);
270 thrash_state = malloc(THRASH_SIZE);
271 memset(thrash_state, 0, THRASH_SIZE);
273 do_thrash(&tree, thrash_state, 0);
275 verify_tag_consistency(&tree, 0);
276 item_kill_tree(&tree);
280 static void leak_check(void)
282 RADIX_TREE(tree, GFP_KERNEL);
284 item_insert(&tree, 1000000);
285 item_delete(&tree, 1000000);
286 item_kill_tree(&tree);
289 static void __leak_check(void)
291 RADIX_TREE(tree, GFP_KERNEL);
293 printf("%d: nr_allocated=%d\n", __LINE__, nr_allocated);
294 item_insert(&tree, 1000000);
295 printf("%d: nr_allocated=%d\n", __LINE__, nr_allocated);
296 item_delete(&tree, 1000000);
297 printf("%d: nr_allocated=%d\n", __LINE__, nr_allocated);
298 item_kill_tree(&tree);
299 printf("%d: nr_allocated=%d\n", __LINE__, nr_allocated);
302 static void single_check(void)
304 struct item *items[BATCH];
305 RADIX_TREE(tree, GFP_KERNEL);
308 item_insert(&tree, 0);
309 item_tag_set(&tree, 0, 0);
310 ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 0);
312 ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 1, BATCH, 0);
314 verify_tag_consistency(&tree, 0);
315 verify_tag_consistency(&tree, 1);
316 item_kill_tree(&tree);
324 printf("after extend_checks: %d allocated\n", nr_allocated);
327 printf("after leak_check: %d allocated\n", nr_allocated);
329 printf("after simple_checks: %d allocated\n", nr_allocated);
331 printf("after thrash_tags: %d allocated\n", nr_allocated);