xref: /openbmc/linux/lib/find_bit_benchmark.c (revision 8032bf12)
15b497af4SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2dceeb3e7SYury Norov /*
3dceeb3e7SYury Norov  * Test for find_*_bit functions.
4dceeb3e7SYury Norov  *
5dceeb3e7SYury Norov  * Copyright (c) 2017 Cavium.
6dceeb3e7SYury Norov  */
7dceeb3e7SYury Norov 
8dceeb3e7SYury Norov /*
9dceeb3e7SYury Norov  * find_bit functions are widely used in kernel, so the successful boot
10dceeb3e7SYury Norov  * is good enough test for correctness.
11dceeb3e7SYury Norov  *
12dceeb3e7SYury Norov  * This test is focused on performance of traversing bitmaps. Two typical
13dceeb3e7SYury Norov  * scenarios are reproduced:
14dceeb3e7SYury Norov  * - randomly filled bitmap with approximately equal number of set and
15dceeb3e7SYury Norov  *   cleared bits;
16dceeb3e7SYury Norov  * - sparse bitmap with few set bits at random positions.
17dceeb3e7SYury Norov  */
18dceeb3e7SYury Norov 
19dceeb3e7SYury Norov #include <linux/bitops.h>
20dceeb3e7SYury Norov #include <linux/kernel.h>
21dceeb3e7SYury Norov #include <linux/list.h>
22dceeb3e7SYury Norov #include <linux/module.h>
23dceeb3e7SYury Norov #include <linux/printk.h>
24dceeb3e7SYury Norov #include <linux/random.h>
25dceeb3e7SYury Norov 
26dceeb3e7SYury Norov #define BITMAP_LEN	(4096UL * 8 * 10)
27dceeb3e7SYury Norov #define SPARSE		500
28dceeb3e7SYury Norov 
29dceeb3e7SYury Norov static DECLARE_BITMAP(bitmap, BITMAP_LEN) __initdata;
300ade34c3SClement Courbet static DECLARE_BITMAP(bitmap2, BITMAP_LEN) __initdata;
31dceeb3e7SYury Norov 
32dceeb3e7SYury Norov /*
33dceeb3e7SYury Norov  * This is Schlemiel the Painter's algorithm. It should be called after
34dceeb3e7SYury Norov  * all other tests for the same bitmap because it sets all bits of bitmap to 1.
35dceeb3e7SYury Norov  */
test_find_first_bit(void * bitmap,unsigned long len)36dceeb3e7SYury Norov static int __init test_find_first_bit(void *bitmap, unsigned long len)
37dceeb3e7SYury Norov {
38dceeb3e7SYury Norov 	unsigned long i, cnt;
3915ff67bfSYury Norov 	ktime_t time;
40dceeb3e7SYury Norov 
4115ff67bfSYury Norov 	time = ktime_get();
42dceeb3e7SYury Norov 	for (cnt = i = 0; i < len; cnt++) {
43dceeb3e7SYury Norov 		i = find_first_bit(bitmap, len);
44dceeb3e7SYury Norov 		__clear_bit(i, bitmap);
45dceeb3e7SYury Norov 	}
4615ff67bfSYury Norov 	time = ktime_get() - time;
4715ff67bfSYury Norov 	pr_err("find_first_bit:     %18llu ns, %6ld iterations\n", time, cnt);
48dceeb3e7SYury Norov 
49dceeb3e7SYury Norov 	return 0;
50dceeb3e7SYury Norov }
51dceeb3e7SYury Norov 
test_find_first_and_bit(void * bitmap,const void * bitmap2,unsigned long len)52f68edc92SYury Norov static int __init test_find_first_and_bit(void *bitmap, const void *bitmap2, unsigned long len)
53f68edc92SYury Norov {
54f68edc92SYury Norov 	static DECLARE_BITMAP(cp, BITMAP_LEN) __initdata;
55f68edc92SYury Norov 	unsigned long i, cnt;
56f68edc92SYury Norov 	ktime_t time;
57f68edc92SYury Norov 
58f68edc92SYury Norov 	bitmap_copy(cp, bitmap, BITMAP_LEN);
59f68edc92SYury Norov 
60f68edc92SYury Norov 	time = ktime_get();
61f68edc92SYury Norov 	for (cnt = i = 0; i < len; cnt++) {
62f68edc92SYury Norov 		i = find_first_and_bit(cp, bitmap2, len);
63f68edc92SYury Norov 		__clear_bit(i, cp);
64f68edc92SYury Norov 	}
65f68edc92SYury Norov 	time = ktime_get() - time;
66f68edc92SYury Norov 	pr_err("find_first_and_bit: %18llu ns, %6ld iterations\n", time, cnt);
67f68edc92SYury Norov 
68f68edc92SYury Norov 	return 0;
69f68edc92SYury Norov }
70f68edc92SYury Norov 
test_find_next_bit(const void * bitmap,unsigned long len)71dceeb3e7SYury Norov static int __init test_find_next_bit(const void *bitmap, unsigned long len)
72dceeb3e7SYury Norov {
73dceeb3e7SYury Norov 	unsigned long i, cnt;
7415ff67bfSYury Norov 	ktime_t time;
75dceeb3e7SYury Norov 
7615ff67bfSYury Norov 	time = ktime_get();
77dceeb3e7SYury Norov 	for (cnt = i = 0; i < BITMAP_LEN; cnt++)
78dceeb3e7SYury Norov 		i = find_next_bit(bitmap, BITMAP_LEN, i) + 1;
7915ff67bfSYury Norov 	time = ktime_get() - time;
8015ff67bfSYury Norov 	pr_err("find_next_bit:      %18llu ns, %6ld iterations\n", time, cnt);
81dceeb3e7SYury Norov 
82dceeb3e7SYury Norov 	return 0;
83dceeb3e7SYury Norov }
84dceeb3e7SYury Norov 
test_find_next_zero_bit(const void * bitmap,unsigned long len)85dceeb3e7SYury Norov static int __init test_find_next_zero_bit(const void *bitmap, unsigned long len)
86dceeb3e7SYury Norov {
87dceeb3e7SYury Norov 	unsigned long i, cnt;
8815ff67bfSYury Norov 	ktime_t time;
89dceeb3e7SYury Norov 
9015ff67bfSYury Norov 	time = ktime_get();
91dceeb3e7SYury Norov 	for (cnt = i = 0; i < BITMAP_LEN; cnt++)
92dceeb3e7SYury Norov 		i = find_next_zero_bit(bitmap, len, i) + 1;
9315ff67bfSYury Norov 	time = ktime_get() - time;
9415ff67bfSYury Norov 	pr_err("find_next_zero_bit: %18llu ns, %6ld iterations\n", time, cnt);
95dceeb3e7SYury Norov 
96dceeb3e7SYury Norov 	return 0;
97dceeb3e7SYury Norov }
98dceeb3e7SYury Norov 
test_find_last_bit(const void * bitmap,unsigned long len)99dceeb3e7SYury Norov static int __init test_find_last_bit(const void *bitmap, unsigned long len)
100dceeb3e7SYury Norov {
101dceeb3e7SYury Norov 	unsigned long l, cnt = 0;
10215ff67bfSYury Norov 	ktime_t time;
103dceeb3e7SYury Norov 
10415ff67bfSYury Norov 	time = ktime_get();
105dceeb3e7SYury Norov 	do {
106dceeb3e7SYury Norov 		cnt++;
107dceeb3e7SYury Norov 		l = find_last_bit(bitmap, len);
108dceeb3e7SYury Norov 		if (l >= len)
109dceeb3e7SYury Norov 			break;
110dceeb3e7SYury Norov 		len = l;
111dceeb3e7SYury Norov 	} while (len);
11215ff67bfSYury Norov 	time = ktime_get() - time;
11315ff67bfSYury Norov 	pr_err("find_last_bit:      %18llu ns, %6ld iterations\n", time, cnt);
114dceeb3e7SYury Norov 
115dceeb3e7SYury Norov 	return 0;
116dceeb3e7SYury Norov }
117dceeb3e7SYury Norov 
test_find_nth_bit(const unsigned long * bitmap,unsigned long len)118e3783c80SYury Norov static int __init test_find_nth_bit(const unsigned long *bitmap, unsigned long len)
119e3783c80SYury Norov {
120e3783c80SYury Norov 	unsigned long l, n, w = bitmap_weight(bitmap, len);
121e3783c80SYury Norov 	ktime_t time;
122e3783c80SYury Norov 
123e3783c80SYury Norov 	time = ktime_get();
124e3783c80SYury Norov 	for (n = 0; n < w; n++) {
125e3783c80SYury Norov 		l = find_nth_bit(bitmap, len, n);
126e3783c80SYury Norov 		WARN_ON(l >= len);
127e3783c80SYury Norov 	}
128e3783c80SYury Norov 	time = ktime_get() - time;
129e3783c80SYury Norov 	pr_err("find_nth_bit:       %18llu ns, %6ld iterations\n", time, w);
130e3783c80SYury Norov 
131e3783c80SYury Norov 	return 0;
132e3783c80SYury Norov }
133e3783c80SYury Norov 
test_find_next_and_bit(const void * bitmap,const void * bitmap2,unsigned long len)1340ade34c3SClement Courbet static int __init test_find_next_and_bit(const void *bitmap,
1350ade34c3SClement Courbet 		const void *bitmap2, unsigned long len)
1360ade34c3SClement Courbet {
1370ade34c3SClement Courbet 	unsigned long i, cnt;
138439e00b7SYury Norov 	ktime_t time;
1390ade34c3SClement Courbet 
140439e00b7SYury Norov 	time = ktime_get();
1410ade34c3SClement Courbet 	for (cnt = i = 0; i < BITMAP_LEN; cnt++)
1420ade34c3SClement Courbet 		i = find_next_and_bit(bitmap, bitmap2, BITMAP_LEN, i + 1);
143439e00b7SYury Norov 	time = ktime_get() - time;
144439e00b7SYury Norov 	pr_err("find_next_and_bit:  %18llu ns, %6ld iterations\n", time, cnt);
1450ade34c3SClement Courbet 
1460ade34c3SClement Courbet 	return 0;
1470ade34c3SClement Courbet }
1480ade34c3SClement Courbet 
find_bit_test(void)149dceeb3e7SYury Norov static int __init find_bit_test(void)
150dceeb3e7SYury Norov {
151dceeb3e7SYury Norov 	unsigned long nbits = BITMAP_LEN / SPARSE;
152dceeb3e7SYury Norov 
153dceeb3e7SYury Norov 	pr_err("\nStart testing find_bit() with random-filled bitmap\n");
154dceeb3e7SYury Norov 
155dceeb3e7SYury Norov 	get_random_bytes(bitmap, sizeof(bitmap));
1560ade34c3SClement Courbet 	get_random_bytes(bitmap2, sizeof(bitmap2));
157dceeb3e7SYury Norov 
158dceeb3e7SYury Norov 	test_find_next_bit(bitmap, BITMAP_LEN);
159dceeb3e7SYury Norov 	test_find_next_zero_bit(bitmap, BITMAP_LEN);
160dceeb3e7SYury Norov 	test_find_last_bit(bitmap, BITMAP_LEN);
161e3783c80SYury Norov 	test_find_nth_bit(bitmap, BITMAP_LEN / 10);
1624ba281d5SYury Norov 
1634ba281d5SYury Norov 	/*
1644ba281d5SYury Norov 	 * test_find_first_bit() may take some time, so
1654ba281d5SYury Norov 	 * traverse only part of bitmap to avoid soft lockup.
1664ba281d5SYury Norov 	 */
1674ba281d5SYury Norov 	test_find_first_bit(bitmap, BITMAP_LEN / 10);
168f68edc92SYury Norov 	test_find_first_and_bit(bitmap, bitmap2, BITMAP_LEN / 2);
1690ade34c3SClement Courbet 	test_find_next_and_bit(bitmap, bitmap2, BITMAP_LEN);
170dceeb3e7SYury Norov 
171dceeb3e7SYury Norov 	pr_err("\nStart testing find_bit() with sparse bitmap\n");
172dceeb3e7SYury Norov 
173dceeb3e7SYury Norov 	bitmap_zero(bitmap, BITMAP_LEN);
1740ade34c3SClement Courbet 	bitmap_zero(bitmap2, BITMAP_LEN);
175dceeb3e7SYury Norov 
1760ade34c3SClement Courbet 	while (nbits--) {
177*8032bf12SJason A. Donenfeld 		__set_bit(get_random_u32_below(BITMAP_LEN), bitmap);
178*8032bf12SJason A. Donenfeld 		__set_bit(get_random_u32_below(BITMAP_LEN), bitmap2);
1790ade34c3SClement Courbet 	}
180dceeb3e7SYury Norov 
181dceeb3e7SYury Norov 	test_find_next_bit(bitmap, BITMAP_LEN);
182dceeb3e7SYury Norov 	test_find_next_zero_bit(bitmap, BITMAP_LEN);
183dceeb3e7SYury Norov 	test_find_last_bit(bitmap, BITMAP_LEN);
184e3783c80SYury Norov 	test_find_nth_bit(bitmap, BITMAP_LEN);
185dceeb3e7SYury Norov 	test_find_first_bit(bitmap, BITMAP_LEN);
186f68edc92SYury Norov 	test_find_first_and_bit(bitmap, bitmap2, BITMAP_LEN);
1870ade34c3SClement Courbet 	test_find_next_and_bit(bitmap, bitmap2, BITMAP_LEN);
188dceeb3e7SYury Norov 
18915ff67bfSYury Norov 	/*
19015ff67bfSYury Norov 	 * Everything is OK. Return error just to let user run benchmark
19115ff67bfSYury Norov 	 * again without annoying rmmod.
19215ff67bfSYury Norov 	 */
19315ff67bfSYury Norov 	return -EINVAL;
194dceeb3e7SYury Norov }
195dceeb3e7SYury Norov module_init(find_bit_test);
196dceeb3e7SYury Norov 
197dceeb3e7SYury Norov MODULE_LICENSE("GPL");
198