mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 12:43:29 +02:00
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>
This commit is contained in:
@@ -68,6 +68,30 @@ out: \
|
||||
sz; \
|
||||
})
|
||||
|
||||
#define FIND_NTH_BIT(FETCH, size, num) \
|
||||
({ \
|
||||
unsigned long sz = (size), nr = (num), idx, w, tmp; \
|
||||
\
|
||||
for (idx = 0; (idx + 1) * BITS_PER_LONG <= sz; idx++) { \
|
||||
if (idx * BITS_PER_LONG + nr >= sz) \
|
||||
goto out; \
|
||||
\
|
||||
tmp = (FETCH); \
|
||||
w = hweight_long(tmp); \
|
||||
if (w > nr) \
|
||||
goto found; \
|
||||
\
|
||||
nr -= w; \
|
||||
} \
|
||||
\
|
||||
if (sz % BITS_PER_LONG) \
|
||||
tmp = (FETCH) & BITMAP_LAST_WORD_MASK(sz); \
|
||||
found: \
|
||||
sz = min(idx * BITS_PER_LONG + fns(tmp, nr), sz); \
|
||||
out: \
|
||||
sz; \
|
||||
})
|
||||
|
||||
#ifndef find_first_bit
|
||||
/*
|
||||
* Find the first set bit in a memory region.
|
||||
@@ -111,6 +135,26 @@ unsigned long _find_next_bit(const unsigned long *addr, unsigned long nbits, uns
|
||||
EXPORT_SYMBOL(_find_next_bit);
|
||||
#endif
|
||||
|
||||
unsigned long __find_nth_bit(const unsigned long *addr, unsigned long size, unsigned long n)
|
||||
{
|
||||
return FIND_NTH_BIT(addr[idx], size, n);
|
||||
}
|
||||
EXPORT_SYMBOL(__find_nth_bit);
|
||||
|
||||
unsigned long __find_nth_and_bit(const unsigned long *addr1, const unsigned long *addr2,
|
||||
unsigned long size, unsigned long n)
|
||||
{
|
||||
return FIND_NTH_BIT(addr1[idx] & addr2[idx], size, n);
|
||||
}
|
||||
EXPORT_SYMBOL(__find_nth_and_bit);
|
||||
|
||||
unsigned long __find_nth_andnot_bit(const unsigned long *addr1, const unsigned long *addr2,
|
||||
unsigned long size, unsigned long n)
|
||||
{
|
||||
return FIND_NTH_BIT(addr1[idx] & ~addr2[idx], size, n);
|
||||
}
|
||||
EXPORT_SYMBOL(__find_nth_andnot_bit);
|
||||
|
||||
#ifndef find_next_and_bit
|
||||
unsigned long _find_next_and_bit(const unsigned long *addr1, const unsigned long *addr2,
|
||||
unsigned long nbits, unsigned long start)
|
||||
|
Reference in New Issue
Block a user