1 // SPDX-License-Identifier: GPL-2.0-only
4 * Author: Konstantin Khlebnikov <koct9i@gmail.com>
6 #include <linux/radix-tree.h>
7 #include <linux/slab.h>
8 #include <linux/errno.h>
12 #define NSEC_PER_SEC 1000000000L
14 static long long benchmark_iter(struct radix_tree_root
*root
, bool tagged
)
16 volatile unsigned long sink
= 0;
17 struct radix_tree_iter iter
;
18 struct timespec start
, finish
;
26 clock_gettime(CLOCK_MONOTONIC
, &start
);
27 for (l
= 0; l
< loops
; l
++) {
29 radix_tree_for_each_tagged(slot
, root
, &iter
, 0, 0)
30 sink
^= (unsigned long)slot
;
32 radix_tree_for_each_slot(slot
, root
, &iter
, 0)
33 sink
^= (unsigned long)slot
;
36 clock_gettime(CLOCK_MONOTONIC
, &finish
);
38 nsec
= (finish
.tv_sec
- start
.tv_sec
) * NSEC_PER_SEC
+
39 (finish
.tv_nsec
- start
.tv_nsec
);
42 if (loops
== 1 && nsec
* 5 < NSEC_PER_SEC
) {
43 loops
= NSEC_PER_SEC
/ nsec
/ 4 + 1;
52 static void benchmark_insert(struct radix_tree_root
*root
,
53 unsigned long size
, unsigned long step
)
55 struct timespec start
, finish
;
59 clock_gettime(CLOCK_MONOTONIC
, &start
);
61 for (index
= 0 ; index
< size
; index
+= step
)
62 item_insert(root
, index
);
64 clock_gettime(CLOCK_MONOTONIC
, &finish
);
66 nsec
= (finish
.tv_sec
- start
.tv_sec
) * NSEC_PER_SEC
+
67 (finish
.tv_nsec
- start
.tv_nsec
);
69 printv(2, "Size: %8ld, step: %8ld, insertion: %15lld ns\n",
73 static void benchmark_tagging(struct radix_tree_root
*root
,
74 unsigned long size
, unsigned long step
)
76 struct timespec start
, finish
;
80 clock_gettime(CLOCK_MONOTONIC
, &start
);
82 for (index
= 0 ; index
< size
; index
+= step
)
83 radix_tree_tag_set(root
, index
, 0);
85 clock_gettime(CLOCK_MONOTONIC
, &finish
);
87 nsec
= (finish
.tv_sec
- start
.tv_sec
) * NSEC_PER_SEC
+
88 (finish
.tv_nsec
- start
.tv_nsec
);
90 printv(2, "Size: %8ld, step: %8ld, tagging: %17lld ns\n",
94 static void benchmark_delete(struct radix_tree_root
*root
,
95 unsigned long size
, unsigned long step
)
97 struct timespec start
, finish
;
101 clock_gettime(CLOCK_MONOTONIC
, &start
);
103 for (index
= 0 ; index
< size
; index
+= step
)
104 item_delete(root
, index
);
106 clock_gettime(CLOCK_MONOTONIC
, &finish
);
108 nsec
= (finish
.tv_sec
- start
.tv_sec
) * NSEC_PER_SEC
+
109 (finish
.tv_nsec
- start
.tv_nsec
);
111 printv(2, "Size: %8ld, step: %8ld, deletion: %16lld ns\n",
115 static void benchmark_size(unsigned long size
, unsigned long step
)
117 RADIX_TREE(tree
, GFP_KERNEL
);
118 long long normal
, tagged
;
120 benchmark_insert(&tree
, size
, step
);
121 benchmark_tagging(&tree
, size
, step
);
123 tagged
= benchmark_iter(&tree
, true);
124 normal
= benchmark_iter(&tree
, false);
126 printv(2, "Size: %8ld, step: %8ld, tagged iteration: %8lld ns\n",
128 printv(2, "Size: %8ld, step: %8ld, normal iteration: %8lld ns\n",
131 benchmark_delete(&tree
, size
, step
);
133 item_kill_tree(&tree
);
139 unsigned long size
[] = {1 << 10, 1 << 20, 0};
140 unsigned long step
[] = {1, 2, 7, 15, 63, 64, 65,
141 128, 256, 512, 12345, 0};
144 printv(1, "starting benchmarks\n");
145 printv(1, "RADIX_TREE_MAP_SHIFT = %d\n", RADIX_TREE_MAP_SHIFT
);
147 for (c
= 0; size
[c
]; c
++)
148 for (s
= 0; step
[s
]; s
++)
149 benchmark_size(size
[c
], step
[s
]);