Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lib/interval_tree: add test case for span iteration

Verify interval_tree_span_iter_xxx() helpers works as expected.

Link: https://lkml.kernel.org/r/20250310074938.26756-6-richard.weiyang@gmail.com
Signed-off-by: Wei Yang <richard.weiyang@gmail.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Michel Lespinasse <michel@lespinasse.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Wei Yang and committed by
Andrew Morton
ccaf3efc 82114e45

+123 -2
+117
lib/interval_tree_test.c
··· 6 6 #include <linux/slab.h> 7 7 #include <asm/timex.h> 8 8 #include <linux/bitmap.h> 9 + #include <linux/maple_tree.h> 9 10 10 11 #define __param(type, name, init, msg) \ 11 12 static type name = init; \ ··· 194 193 return 0; 195 194 } 196 195 196 + #ifdef CONFIG_INTERVAL_TREE_SPAN_ITER 197 + /* 198 + * Helper function to get span of current position from maple tree point of 199 + * view. 200 + */ 201 + static void mas_cur_span(struct ma_state *mas, struct interval_tree_span_iter *state) 202 + { 203 + unsigned long cur_start; 204 + unsigned long cur_last; 205 + int is_hole; 206 + 207 + if (mas->status == ma_overflow) 208 + return; 209 + 210 + /* walk to current position */ 211 + state->is_hole = mas_walk(mas) ? 0 : 1; 212 + 213 + cur_start = mas->index < state->first_index ? 214 + state->first_index : mas->index; 215 + 216 + /* whether we have followers */ 217 + do { 218 + 219 + cur_last = mas->last > state->last_index ? 220 + state->last_index : mas->last; 221 + 222 + is_hole = mas_next_range(mas, state->last_index) ? 0 : 1; 223 + 224 + } while (mas->status != ma_overflow && is_hole == state->is_hole); 225 + 226 + if (state->is_hole) { 227 + state->start_hole = cur_start; 228 + state->last_hole = cur_last; 229 + } else { 230 + state->start_used = cur_start; 231 + state->last_used = cur_last; 232 + } 233 + 234 + /* advance position for next round */ 235 + if (mas->status != ma_overflow) 236 + mas_set(mas, cur_last + 1); 237 + } 238 + 239 + static int span_iteration_check(void) 240 + { 241 + int i, j, k; 242 + unsigned long start, last; 243 + struct interval_tree_span_iter span, mas_span; 244 + 245 + DEFINE_MTREE(tree); 246 + 247 + MA_STATE(mas, &tree, 0, 0); 248 + 249 + printk(KERN_ALERT "interval tree span iteration\n"); 250 + 251 + for (i = 0; i < search_loops; i++) { 252 + /* Initialize interval tree for each round */ 253 + init(); 254 + for (j = 0; j < nnodes; j++) 255 + interval_tree_insert(nodes + j, &root); 256 + 257 + /* Put all the range into maple tree */ 258 + mt_init_flags(&tree, MT_FLAGS_ALLOC_RANGE); 259 + mt_set_in_rcu(&tree); 260 + 261 + for (j = 0; j < nnodes; j++) 262 + WARN_ON_ONCE(mtree_store_range(&tree, nodes[j].start, 263 + nodes[j].last, nodes + j, GFP_KERNEL)); 264 + 265 + /* Let's try nsearches different ranges */ 266 + for (k = 0; k < nsearches; k++) { 267 + /* Try whole range once */ 268 + if (!k) { 269 + start = 0UL; 270 + last = ULONG_MAX; 271 + } else { 272 + last = (prandom_u32_state(&rnd) >> 4) % max_endpoint; 273 + start = (prandom_u32_state(&rnd) >> 4) % last; 274 + } 275 + 276 + mas_span.first_index = start; 277 + mas_span.last_index = last; 278 + mas_span.is_hole = -1; 279 + mas_set(&mas, start); 280 + 281 + interval_tree_for_each_span(&span, &root, start, last) { 282 + mas_cur_span(&mas, &mas_span); 283 + 284 + WARN_ON_ONCE(span.is_hole != mas_span.is_hole); 285 + 286 + if (span.is_hole) { 287 + WARN_ON_ONCE(span.start_hole != mas_span.start_hole); 288 + WARN_ON_ONCE(span.last_hole != mas_span.last_hole); 289 + } else { 290 + WARN_ON_ONCE(span.start_used != mas_span.start_used); 291 + WARN_ON_ONCE(span.last_used != mas_span.last_used); 292 + } 293 + } 294 + 295 + } 296 + 297 + WARN_ON_ONCE(mas.status != ma_overflow); 298 + 299 + /* Cleanup maple tree for each round */ 300 + mtree_destroy(&tree); 301 + /* Cleanup interval tree for each round */ 302 + for (j = 0; j < nnodes; j++) 303 + interval_tree_remove(nodes + j, &root); 304 + } 305 + return 0; 306 + } 307 + #else 308 + static inline int span_iteration_check(void) {return 0; } 309 + #endif 310 + 197 311 static int interval_tree_test_init(void) 198 312 { 199 313 nodes = kmalloc_array(nnodes, sizeof(struct interval_tree_node), ··· 327 211 basic_check(); 328 212 search_check(); 329 213 intersection_range_check(); 214 + span_iteration_check(); 330 215 331 216 kfree(queries); 332 217 kfree(nodes);
+4 -2
tools/testing/rbtree/Makefile
··· 3 3 .PHONY: clean 4 4 5 5 TARGETS = rbtree_test interval_tree_test 6 - OFILES = $(LIBS) rbtree-shim.o interval_tree-shim.o 6 + OFILES = $(SHARED_OFILES) rbtree-shim.o interval_tree-shim.o maple-shim.o 7 7 DEPS = ../../../include/linux/rbtree.h \ 8 8 ../../../include/linux/rbtree_types.h \ 9 9 ../../../include/linux/rbtree_augmented.h \ ··· 25 25 rbtree-shim.o: $(DEPS) 26 26 rbtree_test.o: ../../../lib/rbtree_test.c 27 27 interval_tree-shim.o: $(DEPS) 28 + interval_tree-shim.o: CFLAGS += -DCONFIG_INTERVAL_TREE_SPAN_ITER 28 29 interval_tree_test.o: ../../../lib/interval_tree_test.c 30 + interval_tree_test.o: CFLAGS += -DCONFIG_INTERVAL_TREE_SPAN_ITER 29 31 30 32 clean: 31 - $(RM) $(TARGETS) *.o generated/* 33 + $(RM) $(TARGETS) *.o radix-tree.c idr.c generated/*
+2
tools/testing/rbtree/interval_tree_test.c
··· 6 6 #include <linux/math64.h> 7 7 #include <linux/kern_levels.h> 8 8 #include "shared.h" 9 + #include "maple-shared.h" 9 10 10 11 #include "../../../lib/interval_tree_test.c" 11 12 ··· 52 51 usage(); 53 52 } 54 53 54 + maple_tree_init(); 55 55 interval_tree_tests(); 56 56 return 0; 57 57 }