3 * Author: Konstantin Khlebnikov <koct9i@gmail.com>
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 #include <linux/radix-tree.h>
15 #include <linux/slab.h>
16 #include <linux/errno.h>
20 #define for_each_index(i, base, order) \
21 for (i = base; i < base + (1 << order); i++)
23 #define NSEC_PER_SEC 1000000000L
25 static long long benchmark_iter(struct radix_tree_root
*root
, bool tagged
)
27 volatile unsigned long sink
= 0;
28 struct radix_tree_iter iter
;
29 struct timespec start
, finish
;
37 clock_gettime(CLOCK_MONOTONIC
, &start
);
38 for (l
= 0; l
< loops
; l
++) {
40 radix_tree_for_each_tagged(slot
, root
, &iter
, 0, 0)
41 sink
^= (unsigned long)slot
;
43 radix_tree_for_each_slot(slot
, root
, &iter
, 0)
44 sink
^= (unsigned long)slot
;
47 clock_gettime(CLOCK_MONOTONIC
, &finish
);
49 nsec
= (finish
.tv_sec
- start
.tv_sec
) * NSEC_PER_SEC
+
50 (finish
.tv_nsec
- start
.tv_nsec
);
53 if (loops
== 1 && nsec
* 5 < NSEC_PER_SEC
) {
54 loops
= NSEC_PER_SEC
/ nsec
/ 4 + 1;
63 static void benchmark_insert(struct radix_tree_root
*root
,
64 unsigned long size
, unsigned long step
, int order
)
66 struct timespec start
, finish
;
70 clock_gettime(CLOCK_MONOTONIC
, &start
);
72 for (index
= 0 ; index
< size
; index
+= step
)
73 item_insert_order(root
, index
, order
);
75 clock_gettime(CLOCK_MONOTONIC
, &finish
);
77 nsec
= (finish
.tv_sec
- start
.tv_sec
) * NSEC_PER_SEC
+
78 (finish
.tv_nsec
- start
.tv_nsec
);
80 printv(2, "Size: %8ld, step: %8ld, order: %d, insertion: %15lld ns\n",
81 size
, step
, order
, nsec
);
84 static void benchmark_tagging(struct radix_tree_root
*root
,
85 unsigned long size
, unsigned long step
, int order
)
87 struct timespec start
, finish
;
91 clock_gettime(CLOCK_MONOTONIC
, &start
);
93 for (index
= 0 ; index
< size
; index
+= step
)
94 radix_tree_tag_set(root
, index
, 0);
96 clock_gettime(CLOCK_MONOTONIC
, &finish
);
98 nsec
= (finish
.tv_sec
- start
.tv_sec
) * NSEC_PER_SEC
+
99 (finish
.tv_nsec
- start
.tv_nsec
);
101 printv(2, "Size: %8ld, step: %8ld, order: %d, tagging: %17lld ns\n",
102 size
, step
, order
, nsec
);
105 static void benchmark_delete(struct radix_tree_root
*root
,
106 unsigned long size
, unsigned long step
, int order
)
108 struct timespec start
, finish
;
109 unsigned long index
, i
;
112 clock_gettime(CLOCK_MONOTONIC
, &start
);
114 for (index
= 0 ; index
< size
; index
+= step
)
115 for_each_index(i
, index
, order
)
116 item_delete(root
, i
);
118 clock_gettime(CLOCK_MONOTONIC
, &finish
);
120 nsec
= (finish
.tv_sec
- start
.tv_sec
) * NSEC_PER_SEC
+
121 (finish
.tv_nsec
- start
.tv_nsec
);
123 printv(2, "Size: %8ld, step: %8ld, order: %d, deletion: %16lld ns\n",
124 size
, step
, order
, nsec
);
127 static void benchmark_size(unsigned long size
, unsigned long step
, int order
)
129 RADIX_TREE(tree
, GFP_KERNEL
);
130 long long normal
, tagged
;
132 benchmark_insert(&tree
, size
, step
, order
);
133 benchmark_tagging(&tree
, size
, step
, order
);
135 tagged
= benchmark_iter(&tree
, true);
136 normal
= benchmark_iter(&tree
, false);
138 printv(2, "Size: %8ld, step: %8ld, order: %d, tagged iteration: %8lld ns\n",
139 size
, step
, order
, tagged
);
140 printv(2, "Size: %8ld, step: %8ld, order: %d, normal iteration: %8lld ns\n",
141 size
, step
, order
, normal
);
143 benchmark_delete(&tree
, size
, step
, order
);
145 item_kill_tree(&tree
);
149 static long long __benchmark_split(unsigned long index
,
150 int old_order
, int new_order
)
152 struct timespec start
, finish
;
154 RADIX_TREE(tree
, GFP_ATOMIC
);
156 item_insert_order(&tree
, index
, old_order
);
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
);
164 item_kill_tree(&tree
);
170 static void benchmark_split(unsigned long size
, unsigned long step
)
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
);
184 printv(2, "Size %8ld, step %8ld, split time %10lld ns\n",
189 static long long __benchmark_join(unsigned long index
,
190 unsigned order1
, unsigned order2
)
193 struct timespec start
, finish
;
195 void *item
, *item2
= item_create(index
+ 1, order1
);
196 RADIX_TREE(tree
, GFP_KERNEL
);
198 item_insert_order(&tree
, index
, order2
);
199 item
= radix_tree_lookup(&tree
, index
);
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
);
207 loc
= find_item(&tree
, item
);
211 item_kill_tree(&tree
);
216 static void benchmark_join(unsigned long step
)
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
);
229 printv(2, "Size %8d, step %8ld, join time %10lld ns\n",
230 1 << 10, step
, nsec
);
235 unsigned long size
[] = {1 << 10, 1 << 20, 0};
236 unsigned long step
[] = {1, 2, 7, 15, 63, 64, 65,
237 128, 256, 512, 12345, 0};
240 printv(1, "starting benchmarks\n");
241 printv(1, "RADIX_TREE_MAP_SHIFT = %d\n", RADIX_TREE_MAP_SHIFT
);
243 for (c
= 0; size
[c
]; c
++)
244 for (s
= 0; step
[s
]; s
++)
245 benchmark_size(size
[c
], step
[s
], 0);
247 for (c
= 0; size
[c
]; c
++)
248 for (s
= 0; step
[s
]; s
++)
249 benchmark_size(size
[c
], step
[s
] << 9, 9);
251 for (c
= 0; size
[c
]; c
++)
252 for (s
= 0; step
[s
]; s
++)
253 benchmark_split(size
[c
], step
[s
]);
255 for (s
= 0; step
[s
]; s
++)
256 benchmark_join(step
[s
]);