| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * benchmark.c: |
|---|
| 3 | 4 | * Author: Konstantin Khlebnikov <koct9i@gmail.com> |
|---|
| 4 | | - * |
|---|
| 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. |
|---|
| 8 | | - * |
|---|
| 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 |
|---|
| 12 | | - * more details. |
|---|
| 13 | 5 | */ |
|---|
| 14 | 6 | #include <linux/radix-tree.h> |
|---|
| 15 | 7 | #include <linux/slab.h> |
|---|
| 16 | 8 | #include <linux/errno.h> |
|---|
| 17 | 9 | #include <time.h> |
|---|
| 18 | 10 | #include "test.h" |
|---|
| 19 | | - |
|---|
| 20 | | -#define for_each_index(i, base, order) \ |
|---|
| 21 | | - for (i = base; i < base + (1 << order); i++) |
|---|
| 22 | 11 | |
|---|
| 23 | 12 | #define NSEC_PER_SEC 1000000000L |
|---|
| 24 | 13 | |
|---|
| .. | .. |
|---|
| 61 | 50 | } |
|---|
| 62 | 51 | |
|---|
| 63 | 52 | static void benchmark_insert(struct radix_tree_root *root, |
|---|
| 64 | | - unsigned long size, unsigned long step, int order) |
|---|
| 53 | + unsigned long size, unsigned long step) |
|---|
| 65 | 54 | { |
|---|
| 66 | 55 | struct timespec start, finish; |
|---|
| 67 | 56 | unsigned long index; |
|---|
| .. | .. |
|---|
| 70 | 59 | clock_gettime(CLOCK_MONOTONIC, &start); |
|---|
| 71 | 60 | |
|---|
| 72 | 61 | for (index = 0 ; index < size ; index += step) |
|---|
| 73 | | - item_insert_order(root, index, order); |
|---|
| 62 | + item_insert(root, index); |
|---|
| 74 | 63 | |
|---|
| 75 | 64 | clock_gettime(CLOCK_MONOTONIC, &finish); |
|---|
| 76 | 65 | |
|---|
| 77 | 66 | nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC + |
|---|
| 78 | 67 | (finish.tv_nsec - start.tv_nsec); |
|---|
| 79 | 68 | |
|---|
| 80 | | - printv(2, "Size: %8ld, step: %8ld, order: %d, insertion: %15lld ns\n", |
|---|
| 81 | | - size, step, order, nsec); |
|---|
| 69 | + printv(2, "Size: %8ld, step: %8ld, insertion: %15lld ns\n", |
|---|
| 70 | + size, step, nsec); |
|---|
| 82 | 71 | } |
|---|
| 83 | 72 | |
|---|
| 84 | 73 | static void benchmark_tagging(struct radix_tree_root *root, |
|---|
| 85 | | - unsigned long size, unsigned long step, int order) |
|---|
| 74 | + unsigned long size, unsigned long step) |
|---|
| 86 | 75 | { |
|---|
| 87 | 76 | struct timespec start, finish; |
|---|
| 88 | 77 | unsigned long index; |
|---|
| .. | .. |
|---|
| 98 | 87 | nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC + |
|---|
| 99 | 88 | (finish.tv_nsec - start.tv_nsec); |
|---|
| 100 | 89 | |
|---|
| 101 | | - printv(2, "Size: %8ld, step: %8ld, order: %d, tagging: %17lld ns\n", |
|---|
| 102 | | - size, step, order, nsec); |
|---|
| 90 | + printv(2, "Size: %8ld, step: %8ld, tagging: %17lld ns\n", |
|---|
| 91 | + size, step, nsec); |
|---|
| 103 | 92 | } |
|---|
| 104 | 93 | |
|---|
| 105 | 94 | static void benchmark_delete(struct radix_tree_root *root, |
|---|
| 106 | | - unsigned long size, unsigned long step, int order) |
|---|
| 95 | + unsigned long size, unsigned long step) |
|---|
| 107 | 96 | { |
|---|
| 108 | 97 | struct timespec start, finish; |
|---|
| 109 | | - unsigned long index, i; |
|---|
| 98 | + unsigned long index; |
|---|
| 110 | 99 | long long nsec; |
|---|
| 111 | 100 | |
|---|
| 112 | 101 | clock_gettime(CLOCK_MONOTONIC, &start); |
|---|
| 113 | 102 | |
|---|
| 114 | 103 | for (index = 0 ; index < size ; index += step) |
|---|
| 115 | | - for_each_index(i, index, order) |
|---|
| 116 | | - item_delete(root, i); |
|---|
| 104 | + item_delete(root, index); |
|---|
| 117 | 105 | |
|---|
| 118 | 106 | clock_gettime(CLOCK_MONOTONIC, &finish); |
|---|
| 119 | 107 | |
|---|
| 120 | 108 | nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC + |
|---|
| 121 | 109 | (finish.tv_nsec - start.tv_nsec); |
|---|
| 122 | 110 | |
|---|
| 123 | | - printv(2, "Size: %8ld, step: %8ld, order: %d, deletion: %16lld ns\n", |
|---|
| 124 | | - size, step, order, nsec); |
|---|
| 111 | + printv(2, "Size: %8ld, step: %8ld, deletion: %16lld ns\n", |
|---|
| 112 | + size, step, nsec); |
|---|
| 125 | 113 | } |
|---|
| 126 | 114 | |
|---|
| 127 | | -static void benchmark_size(unsigned long size, unsigned long step, int order) |
|---|
| 115 | +static void benchmark_size(unsigned long size, unsigned long step) |
|---|
| 128 | 116 | { |
|---|
| 129 | 117 | RADIX_TREE(tree, GFP_KERNEL); |
|---|
| 130 | 118 | long long normal, tagged; |
|---|
| 131 | 119 | |
|---|
| 132 | | - benchmark_insert(&tree, size, step, order); |
|---|
| 133 | | - benchmark_tagging(&tree, size, step, order); |
|---|
| 120 | + benchmark_insert(&tree, size, step); |
|---|
| 121 | + benchmark_tagging(&tree, size, step); |
|---|
| 134 | 122 | |
|---|
| 135 | 123 | tagged = benchmark_iter(&tree, true); |
|---|
| 136 | 124 | normal = benchmark_iter(&tree, false); |
|---|
| 137 | 125 | |
|---|
| 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); |
|---|
| 126 | + printv(2, "Size: %8ld, step: %8ld, tagged iteration: %8lld ns\n", |
|---|
| 127 | + size, step, tagged); |
|---|
| 128 | + printv(2, "Size: %8ld, step: %8ld, normal iteration: %8lld ns\n", |
|---|
| 129 | + size, step, normal); |
|---|
| 142 | 130 | |
|---|
| 143 | | - benchmark_delete(&tree, size, step, order); |
|---|
| 131 | + benchmark_delete(&tree, size, step); |
|---|
| 144 | 132 | |
|---|
| 145 | 133 | item_kill_tree(&tree); |
|---|
| 146 | 134 | rcu_barrier(); |
|---|
| 147 | | -} |
|---|
| 148 | | - |
|---|
| 149 | | -static 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 | | - |
|---|
| 170 | | -static 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 | | - |
|---|
| 189 | | -static 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 | | - |
|---|
| 216 | | -static 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 | 135 | } |
|---|
| 232 | 136 | |
|---|
| 233 | 137 | void benchmark(void) |
|---|
| .. | .. |
|---|
| 242 | 146 | |
|---|
| 243 | 147 | for (c = 0; size[c]; c++) |
|---|
| 244 | 148 | for (s = 0; step[s]; s++) |
|---|
| 245 | | - benchmark_size(size[c], step[s], 0); |
|---|
| 246 | | - |
|---|
| 247 | | - for (c = 0; size[c]; c++) |
|---|
| 248 | | - for (s = 0; step[s]; s++) |
|---|
| 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]); |
|---|
| 149 | + benchmark_size(size[c], step[s]); |
|---|
| 257 | 150 | } |
|---|