main.c 8.6 KB
Newer Older
M
Matthew Wilcox 已提交
1 2 3 4 5
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <assert.h>
6
#include <limits.h>
M
Matthew Wilcox 已提交
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64

#include <linux/slab.h>
#include <linux/radix-tree.h>

#include "test.h"
#include "regression.h"

void __gang_check(unsigned long middle, long down, long up, int chunk, int hop)
{
	long idx;
	RADIX_TREE(tree, GFP_KERNEL);

	middle = 1 << 30;

	for (idx = -down; idx < up; idx++)
		item_insert(&tree, middle + idx);

	item_check_absent(&tree, middle - down - 1);
	for (idx = -down; idx < up; idx++)
		item_check_present(&tree, middle + idx);
	item_check_absent(&tree, middle + up);

	item_gang_check_present(&tree, middle - down,
			up + down, chunk, hop);
	item_full_scan(&tree, middle - down, down + up, chunk);
	item_kill_tree(&tree);
}

void gang_check(void)
{
	__gang_check(1 << 30, 128, 128, 35, 2);
	__gang_check(1 << 31, 128, 128, 32, 32);
	__gang_check(1 << 31, 128, 128, 32, 100);
	__gang_check(1 << 31, 128, 128, 17, 7);
	__gang_check(0xffff0000, 0, 65536, 17, 7);
	__gang_check(0xfffffffe, 1, 1, 17, 7);
}

void __big_gang_check(void)
{
	unsigned long start;
	int wrapped = 0;

	start = 0;
	do {
		unsigned long old_start;

//		printf("0x%08lx\n", start);
		__gang_check(start, rand() % 113 + 1, rand() % 71,
				rand() % 157, rand() % 91 + 1);
		old_start = start;
		start += rand() % 1000000;
		start %= 1ULL << 33;
		if (start < old_start)
			wrapped = 1;
	} while (!wrapped);
}

65
void big_gang_check(bool long_run)
M
Matthew Wilcox 已提交
66 67 68
{
	int i;

69
	for (i = 0; i < (long_run ? 1000 : 3); i++) {
M
Matthew Wilcox 已提交
70
		__big_gang_check();
71
		printv(2, "%d ", i);
M
Matthew Wilcox 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 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
		fflush(stdout);
	}
}

void add_and_check(void)
{
	RADIX_TREE(tree, GFP_KERNEL);

	item_insert(&tree, 44);
	item_check_present(&tree, 44);
	item_check_absent(&tree, 43);
	item_kill_tree(&tree);
}

void dynamic_height_check(void)
{
	int i;
	RADIX_TREE(tree, GFP_KERNEL);
	tree_verify_min_height(&tree, 0);

	item_insert(&tree, 42);
	tree_verify_min_height(&tree, 42);

	item_insert(&tree, 1000000);
	tree_verify_min_height(&tree, 1000000);

	assert(item_delete(&tree, 1000000));
	tree_verify_min_height(&tree, 42);

	assert(item_delete(&tree, 42));
	tree_verify_min_height(&tree, 0);

	for (i = 0; i < 1000; i++) {
		item_insert(&tree, i);
		tree_verify_min_height(&tree, i);
	}

	i--;
	for (;;) {
		assert(item_delete(&tree, i));
		if (i == 0) {
			tree_verify_min_height(&tree, 0);
			break;
		}
		i--;
		tree_verify_min_height(&tree, i);
	}

	item_kill_tree(&tree);
}

void check_copied_tags(struct radix_tree_root *tree, unsigned long start, unsigned long end, unsigned long *idx, int count, int fromtag, int totag)
{
	int i;

	for (i = 0; i < count; i++) {
/*		if (i % 1000 == 0)
			putchar('.'); */
		if (idx[i] < start || idx[i] > end) {
			if (item_tag_get(tree, idx[i], totag)) {
132 133 134 135
				printv(2, "%lu-%lu: %lu, tags %d-%d\n", start,
				       end, idx[i], item_tag_get(tree, idx[i],
								 fromtag),
				       item_tag_get(tree, idx[i], totag));
M
Matthew Wilcox 已提交
136 137 138 139 140 141
			}
			assert(!item_tag_get(tree, idx[i], totag));
			continue;
		}
		if (item_tag_get(tree, idx[i], fromtag) ^
			item_tag_get(tree, idx[i], totag)) {
142 143 144
			printv(2, "%lu-%lu: %lu, tags %d-%d\n", start, end,
			       idx[i], item_tag_get(tree, idx[i], fromtag),
			       item_tag_get(tree, idx[i], totag));
M
Matthew Wilcox 已提交
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
		}
		assert(!(item_tag_get(tree, idx[i], fromtag) ^
			 item_tag_get(tree, idx[i], totag)));
	}
}

#define ITEMS 50000

void copy_tag_check(void)
{
	RADIX_TREE(tree, GFP_KERNEL);
	unsigned long idx[ITEMS];
	unsigned long start, end, count = 0, tagged, cur, tmp;
	int i;

//	printf("generating radix tree indices...\n");
	start = rand();
	end = rand();
	if (start > end && (rand() % 10)) {
		cur = start;
		start = end;
		end = cur;
	}
	/* Specifically create items around the start and the end of the range
	 * with high probability to check for off by one errors */
	cur = rand();
	if (cur & 1) {
		item_insert(&tree, start);
		if (cur & 2) {
			if (start <= end)
				count++;
			item_tag_set(&tree, start, 0);
		}
	}
	if (cur & 4) {
		item_insert(&tree, start-1);
		if (cur & 8)
			item_tag_set(&tree, start-1, 0);
	}
	if (cur & 16) {
		item_insert(&tree, end);
		if (cur & 32) {
			if (start <= end)
				count++;
			item_tag_set(&tree, end, 0);
		}
	}
	if (cur & 64) {
		item_insert(&tree, end+1);
		if (cur & 128)
			item_tag_set(&tree, end+1, 0);
	}

	for (i = 0; i < ITEMS; i++) {
		do {
			idx[i] = rand();
		} while (item_lookup(&tree, idx[i]));

		item_insert(&tree, idx[i]);
		if (rand() & 1) {
			item_tag_set(&tree, idx[i], 0);
			if (idx[i] >= start && idx[i] <= end)
				count++;
		}
/*		if (i % 1000 == 0)
			putchar('.'); */
	}

//	printf("\ncopying tags...\n");
214
	tagged = tag_tagged_items(&tree, NULL, start, end, ITEMS, 0, 1);
M
Matthew Wilcox 已提交
215 216 217 218 219 220 221

//	printf("checking copied tags\n");
	assert(tagged == count);
	check_copied_tags(&tree, start, end, idx, ITEMS, 0, 1);

	/* Copy tags in several rounds */
//	printf("\ncopying tags...\n");
222 223 224
	tmp = rand() % (count / 10 + 2);
	tagged = tag_tagged_items(&tree, NULL, start, end, tmp, 0, 2);
	assert(tagged == count);
M
Matthew Wilcox 已提交
225 226 227 228 229 230 231 232 233 234 235

//	printf("%lu %lu %lu\n", tagged, tmp, count);
//	printf("checking copied tags\n");
	check_copied_tags(&tree, start, end, idx, ITEMS, 0, 2);
	verify_tag_consistency(&tree, 0);
	verify_tag_consistency(&tree, 1);
	verify_tag_consistency(&tree, 2);
//	printf("\n");
	item_kill_tree(&tree);
}

236
static void __locate_check(struct radix_tree_root *tree, unsigned long index,
237
			unsigned order)
238 239 240 241
{
	struct item *item;
	unsigned long index2;

242
	item_insert_order(tree, index, order);
243
	item = item_lookup(tree, index);
244
	index2 = find_item(tree, item);
245
	if (index != index2) {
246
		printv(2, "index %ld order %d inserted; found %ld\n",
247
			index, order, index2);
248 249 250 251
		abort();
	}
}

252 253 254 255 256 257 258 259 260 261 262
static void __order_0_locate_check(void)
{
	RADIX_TREE(tree, GFP_KERNEL);
	int i;

	for (i = 0; i < 50; i++)
		__locate_check(&tree, rand() % INT_MAX, 0);

	item_kill_tree(&tree);
}

263 264 265
static void locate_check(void)
{
	RADIX_TREE(tree, GFP_KERNEL);
266
	unsigned order;
267 268
	unsigned long offset, index;

269 270
	__order_0_locate_check();

271 272 273 274 275 276 277
	for (order = 0; order < 20; order++) {
		for (offset = 0; offset < (1 << (order + 3));
		     offset += (1UL << order)) {
			for (index = 0; index < (1UL << (order + 5));
			     index += (1UL << order)) {
				__locate_check(&tree, index + offset, order);
			}
278
			if (find_item(&tree, &tree) != -1)
279
				abort();
280

281 282
			item_kill_tree(&tree);
		}
283 284
	}

285
	if (find_item(&tree, &tree) != -1)
286
		abort();
287
	__locate_check(&tree, -1, 0);
288
	if (find_item(&tree, &tree) != -1)
289 290 291 292
		abort();
	item_kill_tree(&tree);
}

293
static void single_thread_tests(bool long_run)
M
Matthew Wilcox 已提交
294 295 296
{
	int i;

297
	printv(1, "starting single_thread_tests: %d allocated, preempt %d\n",
298
		nr_allocated, preempt_count);
299
	multiorder_checks();
300
	rcu_barrier();
301
	printv(2, "after multiorder_check: %d allocated, preempt %d\n",
302
		nr_allocated, preempt_count);
303
	locate_check();
304
	rcu_barrier();
305
	printv(2, "after locate_check: %d allocated, preempt %d\n",
306
		nr_allocated, preempt_count);
M
Matthew Wilcox 已提交
307
	tag_check();
308
	rcu_barrier();
309
	printv(2, "after tag_check: %d allocated, preempt %d\n",
310
		nr_allocated, preempt_count);
M
Matthew Wilcox 已提交
311
	gang_check();
312
	rcu_barrier();
313
	printv(2, "after gang_check: %d allocated, preempt %d\n",
314
		nr_allocated, preempt_count);
M
Matthew Wilcox 已提交
315
	add_and_check();
316
	rcu_barrier();
317
	printv(2, "after add_and_check: %d allocated, preempt %d\n",
318
		nr_allocated, preempt_count);
M
Matthew Wilcox 已提交
319
	dynamic_height_check();
320
	rcu_barrier();
321
	printv(2, "after dynamic_height_check: %d allocated, preempt %d\n",
322
		nr_allocated, preempt_count);
323 324 325
	idr_checks();
	ida_checks();
	rcu_barrier();
326
	printv(2, "after idr_checks: %d allocated, preempt %d\n",
327
		nr_allocated, preempt_count);
328
	big_gang_check(long_run);
329
	rcu_barrier();
330
	printv(2, "after big_gang_check: %d allocated, preempt %d\n",
331
		nr_allocated, preempt_count);
332
	for (i = 0; i < (long_run ? 2000 : 3); i++) {
M
Matthew Wilcox 已提交
333
		copy_tag_check();
334
		printv(2, "%d ", i);
M
Matthew Wilcox 已提交
335 336
		fflush(stdout);
	}
337
	rcu_barrier();
338
	printv(2, "after copy_tag_check: %d allocated, preempt %d\n",
339
		nr_allocated, preempt_count);
M
Matthew Wilcox 已提交
340 341
}

342
int main(int argc, char **argv)
M
Matthew Wilcox 已提交
343
{
344 345
	bool long_run = false;
	int opt;
346
	unsigned int seed = time(NULL);
347

348
	while ((opt = getopt(argc, argv, "ls:v")) != -1) {
349 350
		if (opt == 'l')
			long_run = true;
351 352
		else if (opt == 's')
			seed = strtoul(optarg, NULL, 0);
353 354
		else if (opt == 'v')
			test_verbose++;
355 356
	}

357 358 359
	printf("random seed %u\n", seed);
	srand(seed);

360 361
	printf("running tests\n");

M
Matthew Wilcox 已提交
362 363 364 365 366
	rcu_register_thread();
	radix_tree_init();

	regression1_test();
	regression2_test();
367
	regression3_test();
368 369
	iteration_test(0, 10 + 90 * long_run);
	iteration_test(7, 10 + 90 * long_run);
370
	single_thread_tests(long_run);
M
Matthew Wilcox 已提交
371

372 373 374
	/* Free any remaining preallocated nodes */
	radix_tree_cpu_dead(0);

375 376
	benchmark();

377
	rcu_barrier();
378
	printv(2, "after rcu_barrier: %d allocated, preempt %d\n",
379
		nr_allocated, preempt_count);
M
Matthew Wilcox 已提交
380 381
	rcu_unregister_thread();

382 383
	printf("tests completed\n");

M
Matthew Wilcox 已提交
384 385
	exit(0);
}