aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-03-07 13:52:26 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-03-07 13:52:26 -0500
commit9e91c144e689bb780b412c2c7908b9cf7b96f31f (patch)
tree8fe573a54384a1ff54fc0022fa6285ac9f557779
parentf7d6a7283aa1de430c6323a9714d1a787bc2d1ea (diff)
parentf0f3f2d0a3e0f7c48163fd8b45f5909d46e7f371 (diff)
Merge branch 'idr-4.11' of git://git.infradead.org/users/willy/linux-dax
Pull idr fix (and new tests) from Matthew Wilcox: "One urgent patch in here; freeing the correct IDA bitmap. Everything else is changes to the test suite" * 'idr-4.11' of git://git.infradead.org/users/willy/linux-dax: radix tree test suite: Specify -m32 in LDFLAGS too ida: Free correct IDA bitmap radix tree test suite: Depend on Makefile and quieten grep radix tree test suite: Fix build with --as-needed radix tree test suite: Build 32 bit binaries radix tree test suite: Add performance test for radix_tree_join() radix tree test suite: Add performance test for radix_tree_split() radix tree test suite: Add performance benchmarks radix tree test suite: Add test for radix_tree_clear_tags() radix tree test suite: Add tests for ida_simple_get() and ida_simple_remove() radix tree test suite: Add test for idr_get_next()
-rw-r--r--lib/radix-tree.c4
-rw-r--r--tools/testing/radix-tree/Makefile15
-rw-r--r--tools/testing/radix-tree/benchmark.c173
-rw-r--r--tools/testing/radix-tree/idr-test.c78
-rw-r--r--tools/testing/radix-tree/main.c1
-rw-r--r--tools/testing/radix-tree/tag_check.c29
-rw-r--r--tools/testing/radix-tree/test.h1
7 files changed, 283 insertions, 18 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 5ed506d648c4..691a9ad48497 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -2129,8 +2129,8 @@ int ida_pre_get(struct ida *ida, gfp_t gfp)
2129 struct ida_bitmap *bitmap = kmalloc(sizeof(*bitmap), gfp); 2129 struct ida_bitmap *bitmap = kmalloc(sizeof(*bitmap), gfp);
2130 if (!bitmap) 2130 if (!bitmap)
2131 return 0; 2131 return 0;
2132 bitmap = this_cpu_cmpxchg(ida_bitmap, NULL, bitmap); 2132 if (this_cpu_cmpxchg(ida_bitmap, NULL, bitmap))
2133 kfree(bitmap); 2133 kfree(bitmap);
2134 } 2134 }
2135 2135
2136 return 1; 2136 return 1;
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile
index f11315bedefc..6a9480c03cbd 100644
--- a/tools/testing/radix-tree/Makefile
+++ b/tools/testing/radix-tree/Makefile
@@ -1,6 +1,7 @@
1 1
2CFLAGS += -I. -I../../include -g -O2 -Wall -D_LGPL_SOURCE -fsanitize=address 2CFLAGS += -I. -I../../include -g -O2 -Wall -D_LGPL_SOURCE -fsanitize=address
3LDFLAGS += -lpthread -lurcu 3LDFLAGS += -fsanitize=address
4LDLIBS+= -lpthread -lurcu
4TARGETS = main idr-test multiorder 5TARGETS = main idr-test multiorder
5CORE_OFILES := radix-tree.o idr.o linux.o test.o find_bit.o 6CORE_OFILES := radix-tree.o idr.o linux.o test.o find_bit.o
6OFILES = main.o $(CORE_OFILES) regression1.o regression2.o regression3.o \ 7OFILES = main.o $(CORE_OFILES) regression1.o regression2.o regression3.o \
@@ -10,23 +11,25 @@ ifndef SHIFT
10 SHIFT=3 11 SHIFT=3
11endif 12endif
12 13
14ifeq ($(BUILD), 32)
15 CFLAGS += -m32
16 LDFLAGS += -m32
17endif
18
13targets: mapshift $(TARGETS) 19targets: mapshift $(TARGETS)
14 20
15main: $(OFILES) 21main: $(OFILES)
16 $(CC) $(CFLAGS) $(LDFLAGS) $^ -o main
17 22
18idr-test: idr-test.o $(CORE_OFILES) 23idr-test: idr-test.o $(CORE_OFILES)
19 $(CC) $(CFLAGS) $(LDFLAGS) $^ -o idr-test
20 24
21multiorder: multiorder.o $(CORE_OFILES) 25multiorder: multiorder.o $(CORE_OFILES)
22 $(CC) $(CFLAGS) $(LDFLAGS) $^ -o multiorder
23 26
24clean: 27clean:
25 $(RM) $(TARGETS) *.o radix-tree.c idr.c generated/map-shift.h 28 $(RM) $(TARGETS) *.o radix-tree.c idr.c generated/map-shift.h
26 29
27vpath %.c ../../lib 30vpath %.c ../../lib
28 31
29$(OFILES): *.h */*.h generated/map-shift.h \ 32$(OFILES): Makefile *.h */*.h generated/map-shift.h \
30 ../../include/linux/*.h \ 33 ../../include/linux/*.h \
31 ../../include/asm/*.h \ 34 ../../include/asm/*.h \
32 ../../../include/linux/radix-tree.h \ 35 ../../../include/linux/radix-tree.h \
@@ -41,7 +44,7 @@ idr.c: ../../../lib/idr.c
41.PHONY: mapshift 44.PHONY: mapshift
42 45
43mapshift: 46mapshift:
44 @if ! grep -qw $(SHIFT) generated/map-shift.h; then \ 47 @if ! grep -qws $(SHIFT) generated/map-shift.h; then \
45 echo "#define RADIX_TREE_MAP_SHIFT $(SHIFT)" > \ 48 echo "#define RADIX_TREE_MAP_SHIFT $(SHIFT)" > \
46 generated/map-shift.h; \ 49 generated/map-shift.h; \
47 fi 50 fi
diff --git a/tools/testing/radix-tree/benchmark.c b/tools/testing/radix-tree/benchmark.c
index 9b09ddfe462f..99c40f3ed133 100644
--- a/tools/testing/radix-tree/benchmark.c
+++ b/tools/testing/radix-tree/benchmark.c
@@ -17,6 +17,9 @@
17#include <time.h> 17#include <time.h>
18#include "test.h" 18#include "test.h"
19 19
20#define for_each_index(i, base, order) \
21 for (i = base; i < base + (1 << order); i++)
22
20#define NSEC_PER_SEC 1000000000L 23#define NSEC_PER_SEC 1000000000L
21 24
22static long long benchmark_iter(struct radix_tree_root *root, bool tagged) 25static long long benchmark_iter(struct radix_tree_root *root, bool tagged)
@@ -57,27 +60,176 @@ again:
57 return nsec; 60 return nsec;
58} 61}
59 62
63static void benchmark_insert(struct radix_tree_root *root,
64 unsigned long size, unsigned long step, int order)
65{
66 struct timespec start, finish;
67 unsigned long index;
68 long long nsec;
69
70 clock_gettime(CLOCK_MONOTONIC, &start);
71
72 for (index = 0 ; index < size ; index += step)
73 item_insert_order(root, index, order);
74
75 clock_gettime(CLOCK_MONOTONIC, &finish);
76
77 nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC +
78 (finish.tv_nsec - start.tv_nsec);
79
80 printv(2, "Size: %8ld, step: %8ld, order: %d, insertion: %15lld ns\n",
81 size, step, order, nsec);
82}
83
84static void benchmark_tagging(struct radix_tree_root *root,
85 unsigned long size, unsigned long step, int order)
86{
87 struct timespec start, finish;
88 unsigned long index;
89 long long nsec;
90
91 clock_gettime(CLOCK_MONOTONIC, &start);
92
93 for (index = 0 ; index < size ; index += step)
94 radix_tree_tag_set(root, index, 0);
95
96 clock_gettime(CLOCK_MONOTONIC, &finish);
97
98 nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC +
99 (finish.tv_nsec - start.tv_nsec);
100
101 printv(2, "Size: %8ld, step: %8ld, order: %d, tagging: %17lld ns\n",
102 size, step, order, nsec);
103}
104
105static void benchmark_delete(struct radix_tree_root *root,
106 unsigned long size, unsigned long step, int order)
107{
108 struct timespec start, finish;
109 unsigned long index, i;
110 long long nsec;
111
112 clock_gettime(CLOCK_MONOTONIC, &start);
113
114 for (index = 0 ; index < size ; index += step)
115 for_each_index(i, index, order)
116 item_delete(root, i);
117
118 clock_gettime(CLOCK_MONOTONIC, &finish);
119
120 nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC +
121 (finish.tv_nsec - start.tv_nsec);
122
123 printv(2, "Size: %8ld, step: %8ld, order: %d, deletion: %16lld ns\n",
124 size, step, order, nsec);
125}
126
60static void benchmark_size(unsigned long size, unsigned long step, int order) 127static void benchmark_size(unsigned long size, unsigned long step, int order)
61{ 128{
62 RADIX_TREE(tree, GFP_KERNEL); 129 RADIX_TREE(tree, GFP_KERNEL);
63 long long normal, tagged; 130 long long normal, tagged;
64 unsigned long index;
65 131
66 for (index = 0 ; index < size ; index += step) { 132 benchmark_insert(&tree, size, step, order);
67 item_insert_order(&tree, index, order); 133 benchmark_tagging(&tree, size, step, order);
68 radix_tree_tag_set(&tree, index, 0);
69 }
70 134
71 tagged = benchmark_iter(&tree, true); 135 tagged = benchmark_iter(&tree, true);
72 normal = benchmark_iter(&tree, false); 136 normal = benchmark_iter(&tree, false);
73 137
74 printv(2, "Size %ld, step %6ld, order %d tagged %10lld ns, normal %10lld ns\n", 138 printv(2, "Size: %8ld, step: %8ld, order: %d, tagged iteration: %8lld ns\n",
75 size, step, order, tagged, normal); 139 size, step, order, tagged);
140 printv(2, "Size: %8ld, step: %8ld, order: %d, normal iteration: %8lld ns\n",
141 size, step, order, normal);
142
143 benchmark_delete(&tree, size, step, order);
76 144
77 item_kill_tree(&tree); 145 item_kill_tree(&tree);
78 rcu_barrier(); 146 rcu_barrier();
79} 147}
80 148
149static long long __benchmark_split(unsigned long index,
150 int old_order, int new_order)
151{
152 struct timespec start, finish;
153 long long nsec;
154 RADIX_TREE(tree, GFP_ATOMIC);
155
156 item_insert_order(&tree, index, old_order);
157
158 clock_gettime(CLOCK_MONOTONIC, &start);
159 radix_tree_split(&tree, index, new_order);
160 clock_gettime(CLOCK_MONOTONIC, &finish);
161 nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC +
162 (finish.tv_nsec - start.tv_nsec);
163
164 item_kill_tree(&tree);
165
166 return nsec;
167
168}
169
170static void benchmark_split(unsigned long size, unsigned long step)
171{
172 int i, j, idx;
173 long long nsec = 0;
174
175
176 for (idx = 0; idx < size; idx += step) {
177 for (i = 3; i < 11; i++) {
178 for (j = 0; j < i; j++) {
179 nsec += __benchmark_split(idx, i, j);
180 }
181 }
182 }
183
184 printv(2, "Size %8ld, step %8ld, split time %10lld ns\n",
185 size, step, nsec);
186
187}
188
189static long long __benchmark_join(unsigned long index,
190 unsigned order1, unsigned order2)
191{
192 unsigned long loc;
193 struct timespec start, finish;
194 long long nsec;
195 void *item, *item2 = item_create(index + 1, order1);
196 RADIX_TREE(tree, GFP_KERNEL);
197
198 item_insert_order(&tree, index, order2);
199 item = radix_tree_lookup(&tree, index);
200
201 clock_gettime(CLOCK_MONOTONIC, &start);
202 radix_tree_join(&tree, index + 1, order1, item2);
203 clock_gettime(CLOCK_MONOTONIC, &finish);
204 nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC +
205 (finish.tv_nsec - start.tv_nsec);
206
207 loc = find_item(&tree, item);
208 if (loc == -1)
209 free(item);
210
211 item_kill_tree(&tree);
212
213 return nsec;
214}
215
216static void benchmark_join(unsigned long step)
217{
218 int i, j, idx;
219 long long nsec = 0;
220
221 for (idx = 0; idx < 1 << 10; idx += step) {
222 for (i = 1; i < 15; i++) {
223 for (j = 0; j < i; j++) {
224 nsec += __benchmark_join(idx, i, j);
225 }
226 }
227 }
228
229 printv(2, "Size %8d, step %8ld, join time %10lld ns\n",
230 1 << 10, step, nsec);
231}
232
81void benchmark(void) 233void benchmark(void)
82{ 234{
83 unsigned long size[] = {1 << 10, 1 << 20, 0}; 235 unsigned long size[] = {1 << 10, 1 << 20, 0};
@@ -95,4 +247,11 @@ void benchmark(void)
95 for (c = 0; size[c]; c++) 247 for (c = 0; size[c]; c++)
96 for (s = 0; step[s]; s++) 248 for (s = 0; step[s]; s++)
97 benchmark_size(size[c], step[s] << 9, 9); 249 benchmark_size(size[c], step[s] << 9, 9);
250
251 for (c = 0; size[c]; c++)
252 for (s = 0; step[s]; s++)
253 benchmark_split(size[c], step[s]);
254
255 for (s = 0; step[s]; s++)
256 benchmark_join(step[s]);
98} 257}
diff --git a/tools/testing/radix-tree/idr-test.c b/tools/testing/radix-tree/idr-test.c
index a26098c6123d..30cd0b296f1a 100644
--- a/tools/testing/radix-tree/idr-test.c
+++ b/tools/testing/radix-tree/idr-test.c
@@ -153,6 +153,30 @@ void idr_nowait_test(void)
153 idr_destroy(&idr); 153 idr_destroy(&idr);
154} 154}
155 155
156void idr_get_next_test(void)
157{
158 unsigned long i;
159 int nextid;
160 DEFINE_IDR(idr);
161
162 int indices[] = {4, 7, 9, 15, 65, 128, 1000, 99999, 0};
163
164 for(i = 0; indices[i]; i++) {
165 struct item *item = item_create(indices[i], 0);
166 assert(idr_alloc(&idr, item, indices[i], indices[i+1],
167 GFP_KERNEL) == indices[i]);
168 }
169
170 for(i = 0, nextid = 0; indices[i]; i++) {
171 idr_get_next(&idr, &nextid);
172 assert(nextid == indices[i]);
173 nextid++;
174 }
175
176 idr_for_each(&idr, item_idr_free, &idr);
177 idr_destroy(&idr);
178}
179
156void idr_checks(void) 180void idr_checks(void)
157{ 181{
158 unsigned long i; 182 unsigned long i;
@@ -202,6 +226,7 @@ void idr_checks(void)
202 idr_alloc_test(); 226 idr_alloc_test();
203 idr_null_test(); 227 idr_null_test();
204 idr_nowait_test(); 228 idr_nowait_test();
229 idr_get_next_test();
205} 230}
206 231
207/* 232/*
@@ -338,7 +363,7 @@ void ida_check_random(void)
338{ 363{
339 DEFINE_IDA(ida); 364 DEFINE_IDA(ida);
340 DECLARE_BITMAP(bitmap, 2048); 365 DECLARE_BITMAP(bitmap, 2048);
341 int id; 366 int id, err;
342 unsigned int i; 367 unsigned int i;
343 time_t s = time(NULL); 368 time_t s = time(NULL);
344 369
@@ -352,8 +377,11 @@ void ida_check_random(void)
352 ida_remove(&ida, bit); 377 ida_remove(&ida, bit);
353 } else { 378 } else {
354 __set_bit(bit, bitmap); 379 __set_bit(bit, bitmap);
355 ida_pre_get(&ida, GFP_KERNEL); 380 do {
356 assert(!ida_get_new_above(&ida, bit, &id)); 381 ida_pre_get(&ida, GFP_KERNEL);
382 err = ida_get_new_above(&ida, bit, &id);
383 } while (err == -ENOMEM);
384 assert(!err);
357 assert(id == bit); 385 assert(id == bit);
358 } 386 }
359 } 387 }
@@ -362,6 +390,24 @@ void ida_check_random(void)
362 goto repeat; 390 goto repeat;
363} 391}
364 392
393void ida_simple_get_remove_test(void)
394{
395 DEFINE_IDA(ida);
396 unsigned long i;
397
398 for (i = 0; i < 10000; i++) {
399 assert(ida_simple_get(&ida, 0, 20000, GFP_KERNEL) == i);
400 }
401 assert(ida_simple_get(&ida, 5, 30, GFP_KERNEL) < 0);
402
403 for (i = 0; i < 10000; i++) {
404 ida_simple_remove(&ida, i);
405 }
406 assert(ida_is_empty(&ida));
407
408 ida_destroy(&ida);
409}
410
365void ida_checks(void) 411void ida_checks(void)
366{ 412{
367 DEFINE_IDA(ida); 413 DEFINE_IDA(ida);
@@ -428,15 +474,41 @@ void ida_checks(void)
428 ida_check_max(); 474 ida_check_max();
429 ida_check_conv(); 475 ida_check_conv();
430 ida_check_random(); 476 ida_check_random();
477 ida_simple_get_remove_test();
431 478
432 radix_tree_cpu_dead(1); 479 radix_tree_cpu_dead(1);
433} 480}
434 481
482static void *ida_random_fn(void *arg)
483{
484 rcu_register_thread();
485 ida_check_random();
486 rcu_unregister_thread();
487 return NULL;
488}
489
490void ida_thread_tests(void)
491{
492 pthread_t threads[10];
493 int i;
494
495 for (i = 0; i < ARRAY_SIZE(threads); i++)
496 if (pthread_create(&threads[i], NULL, ida_random_fn, NULL)) {
497 perror("creating ida thread");
498 exit(1);
499 }
500
501 while (i--)
502 pthread_join(threads[i], NULL);
503}
504
435int __weak main(void) 505int __weak main(void)
436{ 506{
437 radix_tree_init(); 507 radix_tree_init();
438 idr_checks(); 508 idr_checks();
439 ida_checks(); 509 ida_checks();
510 ida_thread_tests();
511 radix_tree_cpu_dead(1);
440 rcu_barrier(); 512 rcu_barrier();
441 if (nr_allocated) 513 if (nr_allocated)
442 printf("nr_allocated = %d\n", nr_allocated); 514 printf("nr_allocated = %d\n", nr_allocated);
diff --git a/tools/testing/radix-tree/main.c b/tools/testing/radix-tree/main.c
index b829127d5670..bc9a78449572 100644
--- a/tools/testing/radix-tree/main.c
+++ b/tools/testing/radix-tree/main.c
@@ -368,6 +368,7 @@ int main(int argc, char **argv)
368 iteration_test(0, 10 + 90 * long_run); 368 iteration_test(0, 10 + 90 * long_run);
369 iteration_test(7, 10 + 90 * long_run); 369 iteration_test(7, 10 + 90 * long_run);
370 single_thread_tests(long_run); 370 single_thread_tests(long_run);
371 ida_thread_tests();
371 372
372 /* Free any remaining preallocated nodes */ 373 /* Free any remaining preallocated nodes */
373 radix_tree_cpu_dead(0); 374 radix_tree_cpu_dead(0);
diff --git a/tools/testing/radix-tree/tag_check.c b/tools/testing/radix-tree/tag_check.c
index d4ff00989245..36dcf7d6945d 100644
--- a/tools/testing/radix-tree/tag_check.c
+++ b/tools/testing/radix-tree/tag_check.c
@@ -330,6 +330,34 @@ static void single_check(void)
330 item_kill_tree(&tree); 330 item_kill_tree(&tree);
331} 331}
332 332
333void radix_tree_clear_tags_test(void)
334{
335 unsigned long index;
336 struct radix_tree_node *node;
337 struct radix_tree_iter iter;
338 void **slot;
339
340 RADIX_TREE(tree, GFP_KERNEL);
341
342 item_insert(&tree, 0);
343 item_tag_set(&tree, 0, 0);
344 __radix_tree_lookup(&tree, 0, &node, &slot);
345 radix_tree_clear_tags(&tree, node, slot);
346 assert(item_tag_get(&tree, 0, 0) == 0);
347
348 for (index = 0; index < 1000; index++) {
349 item_insert(&tree, index);
350 item_tag_set(&tree, index, 0);
351 }
352
353 radix_tree_for_each_slot(slot, &tree, &iter, 0) {
354 radix_tree_clear_tags(&tree, iter.node, slot);
355 assert(item_tag_get(&tree, iter.index, 0) == 0);
356 }
357
358 item_kill_tree(&tree);
359}
360
333void tag_check(void) 361void tag_check(void)
334{ 362{
335 single_check(); 363 single_check();
@@ -347,4 +375,5 @@ void tag_check(void)
347 thrash_tags(); 375 thrash_tags();
348 rcu_barrier(); 376 rcu_barrier();
349 printv(2, "after thrash_tags: %d allocated\n", nr_allocated); 377 printv(2, "after thrash_tags: %d allocated\n", nr_allocated);
378 radix_tree_clear_tags_test();
350} 379}
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h
index b30e11d9d271..0f8220cc6166 100644
--- a/tools/testing/radix-tree/test.h
+++ b/tools/testing/radix-tree/test.h
@@ -36,6 +36,7 @@ void iteration_test(unsigned order, unsigned duration);
36void benchmark(void); 36void benchmark(void);
37void idr_checks(void); 37void idr_checks(void);
38void ida_checks(void); 38void ida_checks(void);
39void ida_thread_tests(void);
39 40
40struct item * 41struct item *
41item_tag_set(struct radix_tree_root *root, unsigned long index, int tag); 42item_tag_set(struct radix_tree_root *root, unsigned long index, int tag);