162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/module.h> 362306a36Sopenharmony_ci#include <linux/moduleparam.h> 462306a36Sopenharmony_ci#include <linux/interval_tree.h> 562306a36Sopenharmony_ci#include <linux/random.h> 662306a36Sopenharmony_ci#include <linux/slab.h> 762306a36Sopenharmony_ci#include <asm/timex.h> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#define __param(type, name, init, msg) \ 1062306a36Sopenharmony_ci static type name = init; \ 1162306a36Sopenharmony_ci module_param(name, type, 0444); \ 1262306a36Sopenharmony_ci MODULE_PARM_DESC(name, msg); 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci__param(int, nnodes, 100, "Number of nodes in the interval tree"); 1562306a36Sopenharmony_ci__param(int, perf_loops, 1000, "Number of iterations modifying the tree"); 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci__param(int, nsearches, 100, "Number of searches to the interval tree"); 1862306a36Sopenharmony_ci__param(int, search_loops, 1000, "Number of iterations searching the tree"); 1962306a36Sopenharmony_ci__param(bool, search_all, false, "Searches will iterate all nodes in the tree"); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci__param(uint, max_endpoint, ~0, "Largest value for the interval's endpoint"); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistatic struct rb_root_cached root = RB_ROOT_CACHED; 2462306a36Sopenharmony_cistatic struct interval_tree_node *nodes = NULL; 2562306a36Sopenharmony_cistatic u32 *queries = NULL; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic struct rnd_state rnd; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic inline unsigned long 3062306a36Sopenharmony_cisearch(struct rb_root_cached *root, unsigned long start, unsigned long last) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci struct interval_tree_node *node; 3362306a36Sopenharmony_ci unsigned long results = 0; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci for (node = interval_tree_iter_first(root, start, last); node; 3662306a36Sopenharmony_ci node = interval_tree_iter_next(node, start, last)) 3762306a36Sopenharmony_ci results++; 3862306a36Sopenharmony_ci return results; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic void init(void) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci int i; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci for (i = 0; i < nnodes; i++) { 4662306a36Sopenharmony_ci u32 b = (prandom_u32_state(&rnd) >> 4) % max_endpoint; 4762306a36Sopenharmony_ci u32 a = (prandom_u32_state(&rnd) >> 4) % b; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci nodes[i].start = a; 5062306a36Sopenharmony_ci nodes[i].last = b; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci /* 5462306a36Sopenharmony_ci * Limit the search scope to what the user defined. 5562306a36Sopenharmony_ci * Otherwise we are merely measuring empty walks, 5662306a36Sopenharmony_ci * which is pointless. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_ci for (i = 0; i < nsearches; i++) 5962306a36Sopenharmony_ci queries[i] = (prandom_u32_state(&rnd) >> 4) % max_endpoint; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic int interval_tree_test_init(void) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci int i, j; 6562306a36Sopenharmony_ci unsigned long results; 6662306a36Sopenharmony_ci cycles_t time1, time2, time; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci nodes = kmalloc_array(nnodes, sizeof(struct interval_tree_node), 6962306a36Sopenharmony_ci GFP_KERNEL); 7062306a36Sopenharmony_ci if (!nodes) 7162306a36Sopenharmony_ci return -ENOMEM; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci queries = kmalloc_array(nsearches, sizeof(int), GFP_KERNEL); 7462306a36Sopenharmony_ci if (!queries) { 7562306a36Sopenharmony_ci kfree(nodes); 7662306a36Sopenharmony_ci return -ENOMEM; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci printk(KERN_ALERT "interval tree insert/remove"); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci prandom_seed_state(&rnd, 3141592653589793238ULL); 8262306a36Sopenharmony_ci init(); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci time1 = get_cycles(); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci for (i = 0; i < perf_loops; i++) { 8762306a36Sopenharmony_ci for (j = 0; j < nnodes; j++) 8862306a36Sopenharmony_ci interval_tree_insert(nodes + j, &root); 8962306a36Sopenharmony_ci for (j = 0; j < nnodes; j++) 9062306a36Sopenharmony_ci interval_tree_remove(nodes + j, &root); 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci time2 = get_cycles(); 9462306a36Sopenharmony_ci time = time2 - time1; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci time = div_u64(time, perf_loops); 9762306a36Sopenharmony_ci printk(" -> %llu cycles\n", (unsigned long long)time); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci printk(KERN_ALERT "interval tree search"); 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci for (j = 0; j < nnodes; j++) 10262306a36Sopenharmony_ci interval_tree_insert(nodes + j, &root); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci time1 = get_cycles(); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci results = 0; 10762306a36Sopenharmony_ci for (i = 0; i < search_loops; i++) 10862306a36Sopenharmony_ci for (j = 0; j < nsearches; j++) { 10962306a36Sopenharmony_ci unsigned long start = search_all ? 0 : queries[j]; 11062306a36Sopenharmony_ci unsigned long last = search_all ? max_endpoint : queries[j]; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci results += search(&root, start, last); 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci time2 = get_cycles(); 11662306a36Sopenharmony_ci time = time2 - time1; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci time = div_u64(time, search_loops); 11962306a36Sopenharmony_ci results = div_u64(results, search_loops); 12062306a36Sopenharmony_ci printk(" -> %llu cycles (%lu results)\n", 12162306a36Sopenharmony_ci (unsigned long long)time, results); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci kfree(queries); 12462306a36Sopenharmony_ci kfree(nodes); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return -EAGAIN; /* Fail will directly unload the module */ 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic void interval_tree_test_exit(void) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci printk(KERN_ALERT "test exit\n"); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cimodule_init(interval_tree_test_init) 13562306a36Sopenharmony_cimodule_exit(interval_tree_test_exit) 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 13862306a36Sopenharmony_ciMODULE_AUTHOR("Michel Lespinasse"); 13962306a36Sopenharmony_ciMODULE_DESCRIPTION("Interval Tree test"); 140