18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci#include <linux/module.h> 38c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 48c2ecf20Sopenharmony_ci#include <linux/interval_tree.h> 58c2ecf20Sopenharmony_ci#include <linux/random.h> 68c2ecf20Sopenharmony_ci#include <linux/slab.h> 78c2ecf20Sopenharmony_ci#include <asm/timex.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#define __param(type, name, init, msg) \ 108c2ecf20Sopenharmony_ci static type name = init; \ 118c2ecf20Sopenharmony_ci module_param(name, type, 0444); \ 128c2ecf20Sopenharmony_ci MODULE_PARM_DESC(name, msg); 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci__param(int, nnodes, 100, "Number of nodes in the interval tree"); 158c2ecf20Sopenharmony_ci__param(int, perf_loops, 1000, "Number of iterations modifying the tree"); 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci__param(int, nsearches, 100, "Number of searches to the interval tree"); 188c2ecf20Sopenharmony_ci__param(int, search_loops, 1000, "Number of iterations searching the tree"); 198c2ecf20Sopenharmony_ci__param(bool, search_all, false, "Searches will iterate all nodes in the tree"); 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci__param(uint, max_endpoint, ~0, "Largest value for the interval's endpoint"); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistatic struct rb_root_cached root = RB_ROOT_CACHED; 248c2ecf20Sopenharmony_cistatic struct interval_tree_node *nodes = NULL; 258c2ecf20Sopenharmony_cistatic u32 *queries = NULL; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic struct rnd_state rnd; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic inline unsigned long 308c2ecf20Sopenharmony_cisearch(struct rb_root_cached *root, unsigned long start, unsigned long last) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct interval_tree_node *node; 338c2ecf20Sopenharmony_ci unsigned long results = 0; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci for (node = interval_tree_iter_first(root, start, last); node; 368c2ecf20Sopenharmony_ci node = interval_tree_iter_next(node, start, last)) 378c2ecf20Sopenharmony_ci results++; 388c2ecf20Sopenharmony_ci return results; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void init(void) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci int i; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci for (i = 0; i < nnodes; i++) { 468c2ecf20Sopenharmony_ci u32 b = (prandom_u32_state(&rnd) >> 4) % max_endpoint; 478c2ecf20Sopenharmony_ci u32 a = (prandom_u32_state(&rnd) >> 4) % b; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci nodes[i].start = a; 508c2ecf20Sopenharmony_ci nodes[i].last = b; 518c2ecf20Sopenharmony_ci } 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci /* 548c2ecf20Sopenharmony_ci * Limit the search scope to what the user defined. 558c2ecf20Sopenharmony_ci * Otherwise we are merely measuring empty walks, 568c2ecf20Sopenharmony_ci * which is pointless. 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ci for (i = 0; i < nsearches; i++) 598c2ecf20Sopenharmony_ci queries[i] = (prandom_u32_state(&rnd) >> 4) % max_endpoint; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int interval_tree_test_init(void) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci int i, j; 658c2ecf20Sopenharmony_ci unsigned long results; 668c2ecf20Sopenharmony_ci cycles_t time1, time2, time; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci nodes = kmalloc_array(nnodes, sizeof(struct interval_tree_node), 698c2ecf20Sopenharmony_ci GFP_KERNEL); 708c2ecf20Sopenharmony_ci if (!nodes) 718c2ecf20Sopenharmony_ci return -ENOMEM; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci queries = kmalloc_array(nsearches, sizeof(int), GFP_KERNEL); 748c2ecf20Sopenharmony_ci if (!queries) { 758c2ecf20Sopenharmony_ci kfree(nodes); 768c2ecf20Sopenharmony_ci return -ENOMEM; 778c2ecf20Sopenharmony_ci } 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci printk(KERN_ALERT "interval tree insert/remove"); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci prandom_seed_state(&rnd, 3141592653589793238ULL); 828c2ecf20Sopenharmony_ci init(); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci time1 = get_cycles(); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci for (i = 0; i < perf_loops; i++) { 878c2ecf20Sopenharmony_ci for (j = 0; j < nnodes; j++) 888c2ecf20Sopenharmony_ci interval_tree_insert(nodes + j, &root); 898c2ecf20Sopenharmony_ci for (j = 0; j < nnodes; j++) 908c2ecf20Sopenharmony_ci interval_tree_remove(nodes + j, &root); 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci time2 = get_cycles(); 948c2ecf20Sopenharmony_ci time = time2 - time1; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci time = div_u64(time, perf_loops); 978c2ecf20Sopenharmony_ci printk(" -> %llu cycles\n", (unsigned long long)time); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci printk(KERN_ALERT "interval tree search"); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci for (j = 0; j < nnodes; j++) 1028c2ecf20Sopenharmony_ci interval_tree_insert(nodes + j, &root); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci time1 = get_cycles(); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci results = 0; 1078c2ecf20Sopenharmony_ci for (i = 0; i < search_loops; i++) 1088c2ecf20Sopenharmony_ci for (j = 0; j < nsearches; j++) { 1098c2ecf20Sopenharmony_ci unsigned long start = search_all ? 0 : queries[j]; 1108c2ecf20Sopenharmony_ci unsigned long last = search_all ? max_endpoint : queries[j]; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci results += search(&root, start, last); 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci time2 = get_cycles(); 1168c2ecf20Sopenharmony_ci time = time2 - time1; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci time = div_u64(time, search_loops); 1198c2ecf20Sopenharmony_ci results = div_u64(results, search_loops); 1208c2ecf20Sopenharmony_ci printk(" -> %llu cycles (%lu results)\n", 1218c2ecf20Sopenharmony_ci (unsigned long long)time, results); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci kfree(queries); 1248c2ecf20Sopenharmony_ci kfree(nodes); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci return -EAGAIN; /* Fail will directly unload the module */ 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void interval_tree_test_exit(void) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci printk(KERN_ALERT "test exit\n"); 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cimodule_init(interval_tree_test_init) 1358c2ecf20Sopenharmony_cimodule_exit(interval_tree_test_exit) 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1388c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michel Lespinasse"); 1398c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Interval Tree test"); 140