diff options
author | Yury Norov <yury.norov@gmail.com> | 2022-09-17 20:07:13 -0700 |
---|---|---|
committer | Yury Norov <yury.norov@gmail.com> | 2022-09-26 12:19:12 -0700 |
commit | 3cea8d475327756066e2a54f0b651bb7284dd448 (patch) | |
tree | a9ae97708cf840672349bb19e0e1eec57fcc5c32 /include/linux/bitops.h | |
parent | 24291caf8447f6fc060c8d00136bdc30ee207f38 (diff) | |
download | linux-stable-3cea8d475327756066e2a54f0b651bb7284dd448.tar.gz linux-stable-3cea8d475327756066e2a54f0b651bb7284dd448.tar.bz2 linux-stable-3cea8d475327756066e2a54f0b651bb7284dd448.zip |
lib: add find_nth{,_and,_andnot}_bit()
Kernel lacks for a function that searches for Nth bit in a bitmap.
Usually people do it like this:
for_each_set_bit(bit, mask, size)
if (n-- == 0)
return bit;
We can do it more efficiently, if we:
1. find a word containing Nth bit, using hweight(); and
2. find the bit, using a helper fns(), that works similarly to
__ffs() and ffz().
fns() is implemented as a simple loop. For x86_64, there's PDEP instruction
to do that: ret = clz(pdep(1 << idx, num)). However, for large bitmaps the
most of improvement comes from using hweight(), so I kept fns() simple.
New find_nth_bit() is ~70 times faster on x86_64/kvm in find_bit benchmark:
find_nth_bit: 7154190 ns, 16411 iterations
for_each_bit: 505493126 ns, 16315 iterations
With all that, a family of 3 new functions is added, and used where
appropriate in the following patches.
Signed-off-by: Yury Norov <yury.norov@gmail.com>
Diffstat (limited to 'include/linux/bitops.h')
-rw-r--r-- | include/linux/bitops.h | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/include/linux/bitops.h b/include/linux/bitops.h index 3b89c64bcfd8..d7dd83fafeba 100644 --- a/include/linux/bitops.h +++ b/include/linux/bitops.h @@ -248,6 +248,25 @@ static inline unsigned long __ffs64(u64 word) } /** + * fns - find N'th set bit in a word + * @word: The word to search + * @n: Bit to find + */ +static inline unsigned long fns(unsigned long word, unsigned int n) +{ + unsigned int bit; + + while (word) { + bit = __ffs(word); + if (n-- == 0) + return bit; + __clear_bit(bit, &word); + } + + return BITS_PER_LONG; +} + +/** * assign_bit - Assign value to a bit in memory * @nr: the bit to set * @addr: the address to start counting from |