mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/5] lib/find: add find_nth_bit()
@ 2022-09-18  3:07 Yury Norov
  2022-09-18  3:07 ` [PATCH v3 1/6] lib/bitmap: don't call __bitmap_weight() in kernel code Yury Norov
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Yury Norov @ 2022-09-18  3:07 UTC (permalink / raw)
  To: linux-kernel, Alexander Lobakin, Andy Shevchenko, Arnd Bergmann,
	David Gow, Eric Dumazet, Isabella Basso, Kees Cook, Keith Busch,
	Kumar Kartikeya Dwivedi, Marco Elver, Mark Rutland,
	Rasmus Villemoes, Steven Rostedt,
	Toke Høiland-Jørgensen, Valentin Schneider
  Cc: Yury Norov

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;

Which is not so elegant and very slow.

This series adds fast routines for this task, and applies them where
appropriate.

v1: https://lore.kernel.org/lkml/20220706182300.70862-4-yury.norov@gmail.com/T/
v2: https://lore.kernel.org/lkml/CAAH8bW_RYG_Tbpip=BkSFAymDm2y3jJBqTi0PJWA=H-a-L_3tg@mail.gmail.com/T/
v3:
 - add bitmap_weight_and() and use it in cpumask_local_spread();
 - rework find_nth_bit() family: similarly to [1], introduce
   FIND_NTH_BIT(), and optimize the function to return earlier when
   it's known that the rest of bitmap can't meet the requirement.
 - patch "lib/nodemask: inline next_node_in() and node_random()" has
   been merged, so drop it from this series.

On top of:
[1] https://lore.kernel.org/lkml/20220915020730.852234-1-yury.norov@gmail.com/T/

Yury Norov (6):
  lib/bitmap: don't call __bitmap_weight() in kernel code
  lib/bitmap: add bitmap_weight_and()
  lib: add find_nth(,and,andnot)_bit()
  lib/bitmap: add tests for find_nth_bit()
  lib/bitmap: remove bitmap_ord_to_pos
  cpumask: add cpumask_nth_{,and,andnot}

 fs/ntfs3/bitmap.c        |  4 +-
 include/linux/bitmap.h   | 13 +++++-
 include/linux/bitops.h   | 19 +++++++++
 include/linux/cpumask.h  | 55 +++++++++++++++++++++++++
 include/linux/find.h     | 86 ++++++++++++++++++++++++++++++++++++++++
 include/linux/nodemask.h |  3 +-
 lib/bitmap.c             | 68 ++++++++++++-------------------
 lib/cpumask.c            | 28 ++++++-------
 lib/find_bit.c           | 44 ++++++++++++++++++++
 lib/find_bit_benchmark.c | 18 +++++++++
 lib/test_bitmap.c        | 47 +++++++++++++++++++++-
 11 files changed, 320 insertions(+), 65 deletions(-)

-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 1/6] lib/bitmap: don't call __bitmap_weight() in kernel code
  2022-09-18  3:07 [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
@ 2022-09-18  3:07 ` Yury Norov
  2022-09-18  3:07 ` [PATCH v3 2/6] lib/bitmap: add bitmap_weight_and() Yury Norov
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Yury Norov @ 2022-09-18  3:07 UTC (permalink / raw)
  To: linux-kernel, Alexander Lobakin, Andy Shevchenko, Arnd Bergmann,
	David Gow, Eric Dumazet, Isabella Basso, Kees Cook, Keith Busch,
	Kumar Kartikeya Dwivedi, Marco Elver, Mark Rutland,
	Rasmus Villemoes, Steven Rostedt,
	Toke Høiland-Jørgensen, Valentin Schneider
  Cc: Yury Norov

__bitmap_weight() is not to be used directly in the kernel code because
it's a helper for bitmap_weight(). Switch everything to bitmap_weight().

Signed-off-by: Yury Norov <yury.norov@gmail.com>
---
 fs/ntfs3/bitmap.c | 4 ++--
 lib/bitmap.c      | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/ntfs3/bitmap.c b/fs/ntfs3/bitmap.c
index 5d44ceac855b..e92bbd754365 100644
--- a/fs/ntfs3/bitmap.c
+++ b/fs/ntfs3/bitmap.c
@@ -560,7 +560,7 @@ static int wnd_rescan(struct wnd_bitmap *wnd)
 
 		buf = (ulong *)bh->b_data;
 
-		used = __bitmap_weight(buf, wbits);
+		used = bitmap_weight(buf, wbits);
 		if (used < wbits) {
 			frb = wbits - used;
 			wnd->free_bits[iw] = frb;
@@ -1364,7 +1364,7 @@ int wnd_extend(struct wnd_bitmap *wnd, size_t new_bits)
 		buf = (ulong *)bh->b_data;
 
 		__bitmap_clear(buf, b0, blocksize * 8 - b0);
-		frb = wbits - __bitmap_weight(buf, wbits);
+		frb = wbits - bitmap_weight(buf, wbits);
 		wnd->total_zeroes += frb - wnd->free_bits[iw];
 		wnd->free_bits[iw] = frb;
 
diff --git a/lib/bitmap.c b/lib/bitmap.c
index 488e6c3e5acc..d56e275db73e 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -953,7 +953,7 @@ static int bitmap_pos_to_ord(const unsigned long *buf, unsigned int pos, unsigne
 	if (pos >= nbits || !test_bit(pos, buf))
 		return -1;
 
-	return __bitmap_weight(buf, pos);
+	return bitmap_weight(buf, pos);
 }
 
 /**
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 2/6] lib/bitmap: add bitmap_weight_and()
  2022-09-18  3:07 [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
  2022-09-18  3:07 ` [PATCH v3 1/6] lib/bitmap: don't call __bitmap_weight() in kernel code Yury Norov
@ 2022-09-18  3:07 ` Yury Norov
  2022-09-18  3:07 ` [PATCH v3 3/6] lib: add find_nth{,_and,_andnot}_bit() Yury Norov
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Yury Norov @ 2022-09-18  3:07 UTC (permalink / raw)
  To: linux-kernel, Alexander Lobakin, Andy Shevchenko, Arnd Bergmann,
	David Gow, Eric Dumazet, Isabella Basso, Kees Cook, Keith Busch,
	Kumar Kartikeya Dwivedi, Marco Elver, Mark Rutland,
	Rasmus Villemoes, Steven Rostedt,
	Toke Høiland-Jørgensen, Valentin Schneider
  Cc: Yury Norov

The function calculates Hamming weight of (bitmap1 & bitmap2). Now we
have to do like this:
	tmp = bitmap_alloc(nbits);
	bitmap_and(tmp, map1, map2, nbits);
	weight = bitmap_weight(tmp, nbits);
	bitmap_free(tmp);

This requires additional memory, adds pressure on alloc subsystem, and
way less cache-friendly than just:
	weight = bitmap_weight_and(map1, map2, nbits);

The following patches apply it for cpumask functions.

Signed-off-by: Yury Norov <yury.norov@gmail.com>
---
 include/linux/bitmap.h  | 12 ++++++++++++
 include/linux/cpumask.h | 11 +++++++++++
 lib/bitmap.c            | 30 +++++++++++++++++++++---------
 3 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index f65410a49fda..b2aef45af0db 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -51,6 +51,7 @@ struct device;
  *  bitmap_empty(src, nbits)                    Are all bits zero in *src?
  *  bitmap_full(src, nbits)                     Are all bits set in *src?
  *  bitmap_weight(src, nbits)                   Hamming Weight: number set bits
+ *  bitmap_weight_and(src1, src2, nbits)        Hamming Weight of and'ed bitmap
  *  bitmap_set(dst, pos, nbits)                 Set specified bit area
  *  bitmap_clear(dst, pos, nbits)               Clear specified bit area
  *  bitmap_find_next_zero_area(buf, len, pos, n, mask)  Find bit free area
@@ -164,6 +165,8 @@ bool __bitmap_intersects(const unsigned long *bitmap1,
 bool __bitmap_subset(const unsigned long *bitmap1,
 		     const unsigned long *bitmap2, unsigned int nbits);
 unsigned int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits);
+unsigned int __bitmap_weight_and(const unsigned long *bitmap1,
+				 const unsigned long *bitmap2, unsigned int nbits);
 void __bitmap_set(unsigned long *map, unsigned int start, int len);
 void __bitmap_clear(unsigned long *map, unsigned int start, int len);
 
@@ -439,6 +442,15 @@ unsigned int bitmap_weight(const unsigned long *src, unsigned int nbits)
 	return __bitmap_weight(src, nbits);
 }
 
+static __always_inline
+unsigned long bitmap_weight_and(const unsigned long *src1,
+				const unsigned long *src2, unsigned int nbits)
+{
+	if (small_const_nbits(nbits))
+		return hweight_long(*src1 & *src2 & BITMAP_LAST_WORD_MASK(nbits));
+	return __bitmap_weight_and(src1, src2, nbits);
+}
+
 static __always_inline void bitmap_set(unsigned long *map, unsigned int start,
 		unsigned int nbits)
 {
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index e8ad12b5b9d2..31bf08c786e3 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -586,6 +586,17 @@ static inline unsigned int cpumask_weight(const struct cpumask *srcp)
 	return bitmap_weight(cpumask_bits(srcp), nr_cpumask_bits);
 }
 
+/**
+ * cpumask_weight_and - Count of bits in (*srcp1 & *srcp2)
+ * @srcp1: the cpumask to count bits (< nr_cpu_ids) in.
+ * @srcp2: the cpumask to count bits (< nr_cpu_ids) in.
+ */
+static inline unsigned int cpumask_weight_and(const struct cpumask *srcp1,
+						const struct cpumask *srcp2)
+{
+	return bitmap_weight_and(cpumask_bits(srcp1), cpumask_bits(srcp2), nr_cpumask_bits);
+}
+
 /**
  * cpumask_shift_right - *dstp = *srcp >> n
  * @dstp: the cpumask result
diff --git a/lib/bitmap.c b/lib/bitmap.c
index d56e275db73e..3fc2e338ec30 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -333,20 +333,32 @@ bool __bitmap_subset(const unsigned long *bitmap1,
 }
 EXPORT_SYMBOL(__bitmap_subset);
 
+#define BITMAP_WEIGHT(FETCH, bits)	\
+({										\
+	unsigned int __bits = (bits), idx, w = 0;				\
+										\
+	for (idx = 0; idx < __bits / BITS_PER_LONG; idx++)			\
+		w += hweight_long(FETCH);					\
+										\
+	if (__bits % BITS_PER_LONG)						\
+		w += hweight_long((FETCH) & BITMAP_LAST_WORD_MASK(__bits));	\
+										\
+	w;									\
+})
+
 unsigned int __bitmap_weight(const unsigned long *bitmap, unsigned int bits)
 {
-	unsigned int k, lim = bits/BITS_PER_LONG, w = 0;
-
-	for (k = 0; k < lim; k++)
-		w += hweight_long(bitmap[k]);
-
-	if (bits % BITS_PER_LONG)
-		w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits));
-
-	return w;
+	return BITMAP_WEIGHT(bitmap[idx], bits);
 }
 EXPORT_SYMBOL(__bitmap_weight);
 
+unsigned int __bitmap_weight_and(const unsigned long *bitmap1,
+				const unsigned long *bitmap2, unsigned int bits)
+{
+	return BITMAP_WEIGHT(bitmap1[idx] & bitmap2[idx], bits);
+}
+EXPORT_SYMBOL(__bitmap_weight_and);
+
 void __bitmap_set(unsigned long *map, unsigned int start, int len)
 {
 	unsigned long *p = map + BIT_WORD(start);
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 3/6] lib: add find_nth{,_and,_andnot}_bit()
  2022-09-18  3:07 [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
  2022-09-18  3:07 ` [PATCH v3 1/6] lib/bitmap: don't call __bitmap_weight() in kernel code Yury Norov
  2022-09-18  3:07 ` [PATCH v3 2/6] lib/bitmap: add bitmap_weight_and() Yury Norov
@ 2022-09-18  3:07 ` Yury Norov
  2022-09-18  3:07 ` [PATCH v3 4/6] lib/bitmap: add tests for find_nth_bit() Yury Norov
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Yury Norov @ 2022-09-18  3:07 UTC (permalink / raw)
  To: linux-kernel, Alexander Lobakin, Andy Shevchenko, Arnd Bergmann,
	David Gow, Eric Dumazet, Isabella Basso, Kees Cook, Keith Busch,
	Kumar Kartikeya Dwivedi, Marco Elver, Mark Rutland,
	Rasmus Villemoes, Steven Rostedt,
	Toke Høiland-Jørgensen, Valentin Schneider
  Cc: Yury Norov

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>
---
Comparing to v2, it adds a path that allows quit earlier if the
condition can't be met:
	for (idx = 0; (idx + 1) * BITS_PER_LONG <= sz; idx++) {	
 +		if (idx * BITS_PER_LONG + nr >= sz)
 +			goto out;
 	...

 include/linux/bitops.h | 19 ++++++++++
 include/linux/find.h   | 86 ++++++++++++++++++++++++++++++++++++++++++
 lib/find_bit.c         | 44 +++++++++++++++++++++
 3 files changed, 149 insertions(+)

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
@@ -247,6 +247,25 @@ static inline unsigned long __ffs64(u64 word)
 	return __ffs((unsigned long)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
diff --git a/include/linux/find.h b/include/linux/find.h
index dead6f53a97b..b100944daba0 100644
--- a/include/linux/find.h
+++ b/include/linux/find.h
@@ -15,6 +15,11 @@ unsigned long _find_next_and_bit(const unsigned long *addr1, const unsigned long
 unsigned long _find_next_zero_bit(const unsigned long *addr, unsigned long nbits,
 					 unsigned long start);
 extern unsigned long _find_first_bit(const unsigned long *addr, unsigned long size);
+unsigned long __find_nth_bit(const unsigned long *addr, unsigned long size, unsigned long n);
+unsigned long __find_nth_and_bit(const unsigned long *addr1, const unsigned long *addr2,
+				unsigned long size, unsigned long n);
+unsigned long __find_nth_andnot_bit(const unsigned long *addr1, const unsigned long *addr2,
+					unsigned long size, unsigned long n);
 extern unsigned long _find_first_and_bit(const unsigned long *addr1,
 					 const unsigned long *addr2, unsigned long size);
 extern unsigned long _find_first_zero_bit(const unsigned long *addr, unsigned long size);
@@ -136,6 +141,87 @@ unsigned long find_first_bit(const unsigned long *addr, unsigned long size)
 }
 #endif
 
+/**
+ * find_nth_bit - find N'th set bit in a memory region
+ * @addr: The address to start the search at
+ * @size: The maximum number of bits to search
+ * @n: The number of set bit, which position is needed, counting from 0
+ *
+ * The following is semantically equivalent:
+ *	 idx = find_nth_bit(addr, size, 0);
+ *	 idx = find_first_bit(addr, size);
+ *
+ * Returns the bit number of the N'th set bit.
+ * If no such, returns @size.
+ */
+static inline
+unsigned long find_nth_bit(const unsigned long *addr, unsigned long size, unsigned long n)
+{
+	if (n >= size)
+		return size;
+
+	if (small_const_nbits(size)) {
+		unsigned long val =  *addr & GENMASK(size - 1, 0);
+
+		return val ? fns(val, n) : size;
+	}
+
+	return __find_nth_bit(addr, size, n);
+}
+
+/**
+ * find_nth_and_bit - find N'th set bit in 2 memory regions
+ * @addr1: The 1st address to start the search at
+ * @addr2: The 2nd address to start the search at
+ * @size: The maximum number of bits to search
+ * @n: The number of set bit, which position is needed, counting from 0
+ *
+ * Returns the bit number of the N'th set bit.
+ * If no such, returns @size.
+ */
+static inline
+unsigned long find_nth_and_bit(const unsigned long *addr1, const unsigned long *addr2,
+				unsigned long size, unsigned long n)
+{
+	if (n >= size)
+		return size;
+
+	if (small_const_nbits(size)) {
+		unsigned long val =  *addr1 & *addr2 & GENMASK(size - 1, 0);
+
+		return val ? fns(val, n) : size;
+	}
+
+	return __find_nth_and_bit(addr1, addr2, size, n);
+}
+
+/**
+ * find_nth_andnot_bit - find N'th set bit in 2 memory regions,
+ *			 flipping bits in 2nd region
+ * @addr1: The 1st address to start the search at
+ * @addr2: The 2nd address to start the search at
+ * @size: The maximum number of bits to search
+ * @n: The number of set bit, which position is needed, counting from 0
+ *
+ * Returns the bit number of the N'th set bit.
+ * If no such, returns @size.
+ */
+static inline
+unsigned long find_nth_andnot_bit(const unsigned long *addr1, const unsigned long *addr2,
+				unsigned long size, unsigned long n)
+{
+	if (n >= size)
+		return size;
+
+	if (small_const_nbits(size)) {
+		unsigned long val =  *addr1 & (~*addr2) & GENMASK(size - 1, 0);
+
+		return val ? fns(val, n) : size;
+	}
+
+	return __find_nth_andnot_bit(addr1, addr2, size, n);
+}
+
 #ifndef find_first_and_bit
 /**
  * find_first_and_bit - find the first set bit in both memory regions
diff --git a/lib/find_bit.c b/lib/find_bit.c
index 8707b4ef3e5e..ae2a59b59bfe 100644
--- a/lib/find_bit.c
+++ b/lib/find_bit.c
@@ -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)
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 4/6] lib/bitmap: add tests for find_nth_bit()
  2022-09-18  3:07 [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
                   ` (2 preceding siblings ...)
  2022-09-18  3:07 ` [PATCH v3 3/6] lib: add find_nth{,_and,_andnot}_bit() Yury Norov
@ 2022-09-18  3:07 ` Yury Norov
  2022-09-18  3:07 ` [PATCH v3 5/6] lib/bitmap: remove bitmap_ord_to_pos Yury Norov
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Yury Norov @ 2022-09-18  3:07 UTC (permalink / raw)
  To: linux-kernel, Alexander Lobakin, Andy Shevchenko, Arnd Bergmann,
	David Gow, Eric Dumazet, Isabella Basso, Kees Cook, Keith Busch,
	Kumar Kartikeya Dwivedi, Marco Elver, Mark Rutland,
	Rasmus Villemoes, Steven Rostedt,
	Toke Høiland-Jørgensen, Valentin Schneider
  Cc: Yury Norov

Add functional and performance tests for find_nth_bit().

Signed-off-by: Yury Norov <yury.norov@gmail.com>
---
 lib/find_bit_benchmark.c | 18 +++++++++++++++
 lib/test_bitmap.c        | 47 ++++++++++++++++++++++++++++++++++++++--
 2 files changed, 63 insertions(+), 2 deletions(-)

diff --git a/lib/find_bit_benchmark.c b/lib/find_bit_benchmark.c
index db904b57d4b8..10754586403b 100644
--- a/lib/find_bit_benchmark.c
+++ b/lib/find_bit_benchmark.c
@@ -115,6 +115,22 @@ static int __init test_find_last_bit(const void *bitmap, unsigned long len)
 	return 0;
 }
 
+static int __init test_find_nth_bit(const unsigned long *bitmap, unsigned long len)
+{
+	unsigned long l, n, w = bitmap_weight(bitmap, len);
+	ktime_t time;
+
+	time = ktime_get();
+	for (n = 0; n < w; n++) {
+		l = find_nth_bit(bitmap, len, n);
+		WARN_ON(l >= len);
+	}
+	time = ktime_get() - time;
+	pr_err("find_nth_bit:       %18llu ns, %6ld iterations\n", time, w);
+
+	return 0;
+}
+
 static int __init test_find_next_and_bit(const void *bitmap,
 		const void *bitmap2, unsigned long len)
 {
@@ -142,6 +158,7 @@ static int __init find_bit_test(void)
 	test_find_next_bit(bitmap, BITMAP_LEN);
 	test_find_next_zero_bit(bitmap, BITMAP_LEN);
 	test_find_last_bit(bitmap, BITMAP_LEN);
+	test_find_nth_bit(bitmap, BITMAP_LEN / 10);
 
 	/*
 	 * test_find_first_bit() may take some time, so
@@ -164,6 +181,7 @@ static int __init find_bit_test(void)
 	test_find_next_bit(bitmap, BITMAP_LEN);
 	test_find_next_zero_bit(bitmap, BITMAP_LEN);
 	test_find_last_bit(bitmap, BITMAP_LEN);
+	test_find_nth_bit(bitmap, BITMAP_LEN);
 	test_find_first_bit(bitmap, BITMAP_LEN);
 	test_find_first_and_bit(bitmap, bitmap2, BITMAP_LEN);
 	test_find_next_and_bit(bitmap, bitmap2, BITMAP_LEN);
diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c
index 98754ff9fe68..da52dc759c95 100644
--- a/lib/test_bitmap.c
+++ b/lib/test_bitmap.c
@@ -16,6 +16,8 @@
 
 #include "../tools/testing/selftests/kselftest_module.h"
 
+#define EXP1_IN_BITS	(sizeof(exp1) * 8)
+
 KSTM_MODULE_GLOBALS();
 
 static char pbl_buffer[PAGE_SIZE] __initdata;
@@ -219,6 +221,47 @@ static void __init test_zero_clear(void)
 	expect_eq_pbl("", bmap, 1024);
 }
 
+static void __init test_find_nth_bit(void)
+{
+	unsigned long b, bit, cnt = 0;
+	DECLARE_BITMAP(bmap, 64 * 3);
+
+	bitmap_zero(bmap, 64 * 3);
+	__set_bit(10, bmap);
+	__set_bit(20, bmap);
+	__set_bit(30, bmap);
+	__set_bit(40, bmap);
+	__set_bit(50, bmap);
+	__set_bit(60, bmap);
+	__set_bit(80, bmap);
+	__set_bit(123, bmap);
+
+	expect_eq_uint(10,  find_nth_bit(bmap, 64 * 3, 0));
+	expect_eq_uint(20,  find_nth_bit(bmap, 64 * 3, 1));
+	expect_eq_uint(30,  find_nth_bit(bmap, 64 * 3, 2));
+	expect_eq_uint(40,  find_nth_bit(bmap, 64 * 3, 3));
+	expect_eq_uint(50,  find_nth_bit(bmap, 64 * 3, 4));
+	expect_eq_uint(60,  find_nth_bit(bmap, 64 * 3, 5));
+	expect_eq_uint(80,  find_nth_bit(bmap, 64 * 3, 6));
+	expect_eq_uint(123, find_nth_bit(bmap, 64 * 3, 7));
+	expect_eq_uint(64 * 3, find_nth_bit(bmap, 64 * 3, 8));
+
+	expect_eq_uint(10,  find_nth_bit(bmap, 64 * 3 - 1, 0));
+	expect_eq_uint(20,  find_nth_bit(bmap, 64 * 3 - 1, 1));
+	expect_eq_uint(30,  find_nth_bit(bmap, 64 * 3 - 1, 2));
+	expect_eq_uint(40,  find_nth_bit(bmap, 64 * 3 - 1, 3));
+	expect_eq_uint(50,  find_nth_bit(bmap, 64 * 3 - 1, 4));
+	expect_eq_uint(60,  find_nth_bit(bmap, 64 * 3 - 1, 5));
+	expect_eq_uint(80,  find_nth_bit(bmap, 64 * 3 - 1, 6));
+	expect_eq_uint(123, find_nth_bit(bmap, 64 * 3 - 1, 7));
+	expect_eq_uint(64 * 3 - 1, find_nth_bit(bmap, 64 * 3 - 1, 8));
+
+	for_each_set_bit(bit, exp1, EXP1_IN_BITS) {
+		b = find_nth_bit(exp1, EXP1_IN_BITS, cnt++);
+		expect_eq_uint(b, bit);
+	}
+}
+
 static void __init test_fill_set(void)
 {
 	DECLARE_BITMAP(bmap, 1024);
@@ -557,8 +600,6 @@ static void __init test_bitmap_parse(void)
 	}
 }
 
-#define EXP1_IN_BITS	(sizeof(exp1) * 8)
-
 static void __init test_bitmap_arr32(void)
 {
 	unsigned int nbits, next_bit;
@@ -952,6 +993,8 @@ static void __init selftest(void)
 	test_bitmap_cut();
 	test_bitmap_print_buf();
 	test_bitmap_const_eval();
+
+	test_find_nth_bit();
 }
 
 KSTM_MODULE_LOADERS(test_bitmap);
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 5/6] lib/bitmap: remove bitmap_ord_to_pos
  2022-09-18  3:07 [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
                   ` (3 preceding siblings ...)
  2022-09-18  3:07 ` [PATCH v3 4/6] lib/bitmap: add tests for find_nth_bit() Yury Norov
@ 2022-09-18  3:07 ` Yury Norov
  2022-09-18  3:07 ` [PATCH v3 6/6] cpumask: add cpumask_nth_{,and,andnot} Yury Norov
  2022-09-23 16:18 ` [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
  6 siblings, 0 replies; 9+ messages in thread
From: Yury Norov @ 2022-09-18  3:07 UTC (permalink / raw)
  To: linux-kernel, Alexander Lobakin, Andy Shevchenko, Arnd Bergmann,
	David Gow, Eric Dumazet, Isabella Basso, Kees Cook, Keith Busch,
	Kumar Kartikeya Dwivedi, Marco Elver, Mark Rutland,
	Rasmus Villemoes, Steven Rostedt,
	Toke Høiland-Jørgensen, Valentin Schneider
  Cc: Yury Norov

Now that we have find_nth_bit(), we can drop bitmap_ord_to_pos().

Signed-off-by: Yury Norov <yury.norov@gmail.com>
---
 include/linux/bitmap.h   |  1 -
 include/linux/nodemask.h |  3 +--
 lib/bitmap.c             | 36 +++---------------------------------
 3 files changed, 4 insertions(+), 36 deletions(-)

diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index b2aef45af0db..7d6d73b78147 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -225,7 +225,6 @@ void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int n
 #else
 #define bitmap_copy_le bitmap_copy
 #endif
-unsigned int bitmap_ord_to_pos(const unsigned long *bitmap, unsigned int ord, unsigned int nbits);
 int bitmap_print_to_pagebuf(bool list, char *buf,
 				   const unsigned long *maskp, int nmaskbits);
 
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
index 4b71a96190a8..0c45fb066caa 100644
--- a/include/linux/nodemask.h
+++ b/include/linux/nodemask.h
@@ -508,8 +508,7 @@ static inline int node_random(const nodemask_t *maskp)
 
 	w = nodes_weight(*maskp);
 	if (w)
-		bit = bitmap_ord_to_pos(maskp->bits,
-			get_random_int() % w, MAX_NUMNODES);
+		bit = find_nth_bit(maskp->bits, MAX_NUMNODES, get_random_int() % w);
 	return bit;
 #else
 	return 0;
diff --git a/lib/bitmap.c b/lib/bitmap.c
index 3fc2e338ec30..1c81413c51f8 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -968,36 +968,6 @@ static int bitmap_pos_to_ord(const unsigned long *buf, unsigned int pos, unsigne
 	return bitmap_weight(buf, pos);
 }
 
-/**
- * bitmap_ord_to_pos - find position of n-th set bit in bitmap
- *	@buf: pointer to bitmap
- *	@ord: ordinal bit position (n-th set bit, n >= 0)
- *	@nbits: number of valid bit positions in @buf
- *
- * Map the ordinal offset of bit @ord in @buf to its position in @buf.
- * Value of @ord should be in range 0 <= @ord < weight(buf). If @ord
- * >= weight(buf), returns @nbits.
- *
- * If for example, just bits 4 through 7 are set in @buf, then @ord
- * values 0 through 3 will get mapped to 4 through 7, respectively,
- * and all other @ord values returns @nbits.  When @ord value 3
- * gets mapped to (returns) @pos value 7 in this example, that means
- * that the 3rd set bit (starting with 0th) is at position 7 in @buf.
- *
- * The bit positions 0 through @nbits-1 are valid positions in @buf.
- */
-unsigned int bitmap_ord_to_pos(const unsigned long *buf, unsigned int ord, unsigned int nbits)
-{
-	unsigned int pos;
-
-	for (pos = find_first_bit(buf, nbits);
-	     pos < nbits && ord;
-	     pos = find_next_bit(buf, nbits, pos + 1))
-		ord--;
-
-	return pos;
-}
-
 /**
  * bitmap_remap - Apply map defined by a pair of bitmaps to another bitmap
  *	@dst: remapped result
@@ -1047,7 +1017,7 @@ void bitmap_remap(unsigned long *dst, const unsigned long *src,
 		if (n < 0 || w == 0)
 			set_bit(oldbit, dst);	/* identity map */
 		else
-			set_bit(bitmap_ord_to_pos(new, n % w, nbits), dst);
+			set_bit(find_nth_bit(new, nbits, n % w), dst);
 	}
 }
 EXPORT_SYMBOL(bitmap_remap);
@@ -1086,7 +1056,7 @@ int bitmap_bitremap(int oldbit, const unsigned long *old,
 	if (n < 0 || w == 0)
 		return oldbit;
 	else
-		return bitmap_ord_to_pos(new, n % w, bits);
+		return find_nth_bit(new, bits, n % w);
 }
 EXPORT_SYMBOL(bitmap_bitremap);
 
@@ -1210,7 +1180,7 @@ void bitmap_onto(unsigned long *dst, const unsigned long *orig,
 	 * The following code is a more efficient, but less
 	 * obvious, equivalent to the loop:
 	 *	for (m = 0; m < bitmap_weight(relmap, bits); m++) {
-	 *		n = bitmap_ord_to_pos(orig, m, bits);
+	 *		n = find_nth_bit(orig, bits, m);
 	 *		if (test_bit(m, orig))
 	 *			set_bit(n, dst);
 	 *	}
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH v3 6/6] cpumask: add cpumask_nth_{,and,andnot}
  2022-09-18  3:07 [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
                   ` (4 preceding siblings ...)
  2022-09-18  3:07 ` [PATCH v3 5/6] lib/bitmap: remove bitmap_ord_to_pos Yury Norov
@ 2022-09-18  3:07 ` Yury Norov
  2022-09-23 16:18 ` [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
  6 siblings, 0 replies; 9+ messages in thread
From: Yury Norov @ 2022-09-18  3:07 UTC (permalink / raw)
  To: linux-kernel, Alexander Lobakin, Andy Shevchenko, Arnd Bergmann,
	David Gow, Eric Dumazet, Isabella Basso, Kees Cook, Keith Busch,
	Kumar Kartikeya Dwivedi, Marco Elver, Mark Rutland,
	Rasmus Villemoes, Steven Rostedt,
	Toke Høiland-Jørgensen, Valentin Schneider
  Cc: Yury Norov

Add cpumask_nth_{,and,andnot} as wrappers around corresponding
find functions, and use it in cpumask_local_spread().

Signed-off-by: Yury Norov <yury.norov@gmail.com>
---
 include/linux/cpumask.h | 44 +++++++++++++++++++++++++++++++++++++++++
 lib/cpumask.c           | 28 ++++++++++++--------------
 2 files changed, 57 insertions(+), 15 deletions(-)

diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index 31bf08c786e3..621b59820561 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -337,6 +337,50 @@ unsigned int cpumask_any_but(const struct cpumask *mask, unsigned int cpu)
 	return i;
 }
 
+/**
+ * cpumask_nth - get the first cpu in a cpumask
+ * @srcp: the cpumask pointer
+ * @cpu: the N'th cpu to find, starting from 0
+ *
+ * Returns >= nr_cpu_ids if such cpu doesn't exist.
+ */
+static inline unsigned int cpumask_nth(unsigned int cpu, const struct cpumask *srcp)
+{
+	return find_nth_bit(cpumask_bits(srcp), nr_cpumask_bits, cpumask_check(cpu));
+}
+
+/**
+ * cpumask_nth_and - get the first cpu in 2 cpumasks
+ * @srcp1: the cpumask pointer
+ * @srcp2: the cpumask pointer
+ * @cpu: the N'th cpu to find, starting from 0
+ *
+ * Returns >= nr_cpu_ids if such cpu doesn't exist.
+ */
+static inline
+unsigned int cpumask_nth_and(unsigned int cpu, const struct cpumask *srcp1,
+							const struct cpumask *srcp2)
+{
+	return find_nth_and_bit(cpumask_bits(srcp1), cpumask_bits(srcp2),
+				nr_cpumask_bits, cpumask_check(cpu));
+}
+
+/**
+ * cpumask_nth_andnot - get the first cpu set in 1st cpumask, and clear in 2nd.
+ * @srcp1: the cpumask pointer
+ * @srcp2: the cpumask pointer
+ * @cpu: the N'th cpu to find, starting from 0
+ *
+ * Returns >= nr_cpu_ids if such cpu doesn't exist.
+ */
+static inline
+unsigned int cpumask_nth_andnot(unsigned int cpu, const struct cpumask *srcp1,
+							const struct cpumask *srcp2)
+{
+	return find_nth_andnot_bit(cpumask_bits(srcp1), cpumask_bits(srcp2),
+				nr_cpumask_bits, cpumask_check(cpu));
+}
+
 #define CPU_BITS_NONE						\
 {								\
 	[0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL			\
diff --git a/lib/cpumask.c b/lib/cpumask.c
index f0ae119be8c4..2c4a63b6f03f 100644
--- a/lib/cpumask.c
+++ b/lib/cpumask.c
@@ -128,23 +128,21 @@ unsigned int cpumask_local_spread(unsigned int i, int node)
 	i %= num_online_cpus();
 
 	if (node == NUMA_NO_NODE) {
-		for_each_cpu(cpu, cpu_online_mask)
-			if (i-- == 0)
-				return cpu;
+		cpu = cpumask_nth(i, cpu_online_mask);
+		if (cpu < nr_cpu_ids)
+			return cpu;
 	} else {
 		/* NUMA first. */
-		for_each_cpu_and(cpu, cpumask_of_node(node), cpu_online_mask)
-			if (i-- == 0)
-				return cpu;
-
-		for_each_cpu(cpu, cpu_online_mask) {
-			/* Skip NUMA nodes, done above. */
-			if (cpumask_test_cpu(cpu, cpumask_of_node(node)))
-				continue;
-
-			if (i-- == 0)
-				return cpu;
-		}
+		cpu = cpumask_nth_and(i, cpu_online_mask, cpumask_of_node(node));
+		if (cpu < nr_cpu_ids)
+			return cpu;
+
+		i -= cpumask_weight_and(cpu_online_mask, cpumask_of_node(node));
+
+		/* Skip NUMA nodes, done above. */
+		cpu = cpumask_nth_andnot(i, cpu_online_mask, cpumask_of_node(node));
+		if (cpu < nr_cpu_ids)
+			return cpu;
 	}
 	BUG();
 }
-- 
2.34.1


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 0/5] lib/find: add find_nth_bit()
  2022-09-18  3:07 [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
                   ` (5 preceding siblings ...)
  2022-09-18  3:07 ` [PATCH v3 6/6] cpumask: add cpumask_nth_{,and,andnot} Yury Norov
@ 2022-09-23 16:18 ` Yury Norov
  2022-09-26 19:17   ` Yury Norov
  6 siblings, 1 reply; 9+ messages in thread
From: Yury Norov @ 2022-09-23 16:18 UTC (permalink / raw)
  To: linux-kernel, Alexander Lobakin, Andy Shevchenko, Arnd Bergmann,
	David Gow, Eric Dumazet, Isabella Basso, Kees Cook, Keith Busch,
	Kumar Kartikeya Dwivedi, Marco Elver, Mark Rutland,
	Rasmus Villemoes, Steven Rostedt,
	Toke Høiland-Jørgensen, Valentin Schneider

Ping?

On Sat, Sep 17, 2022 at 08:07:10PM -0700, Yury Norov wrote:
> 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;
> 
> Which is not so elegant and very slow.
> 
> This series adds fast routines for this task, and applies them where
> appropriate.
> 
> v1: https://lore.kernel.org/lkml/20220706182300.70862-4-yury.norov@gmail.com/T/
> v2: https://lore.kernel.org/lkml/CAAH8bW_RYG_Tbpip=BkSFAymDm2y3jJBqTi0PJWA=H-a-L_3tg@mail.gmail.com/T/
> v3:
>  - add bitmap_weight_and() and use it in cpumask_local_spread();
>  - rework find_nth_bit() family: similarly to [1], introduce
>    FIND_NTH_BIT(), and optimize the function to return earlier when
>    it's known that the rest of bitmap can't meet the requirement.
>  - patch "lib/nodemask: inline next_node_in() and node_random()" has
>    been merged, so drop it from this series.
> 
> On top of:
> [1] https://lore.kernel.org/lkml/20220915020730.852234-1-yury.norov@gmail.com/T/
> 
> Yury Norov (6):
>   lib/bitmap: don't call __bitmap_weight() in kernel code
>   lib/bitmap: add bitmap_weight_and()
>   lib: add find_nth(,and,andnot)_bit()
>   lib/bitmap: add tests for find_nth_bit()
>   lib/bitmap: remove bitmap_ord_to_pos
>   cpumask: add cpumask_nth_{,and,andnot}
> 
>  fs/ntfs3/bitmap.c        |  4 +-
>  include/linux/bitmap.h   | 13 +++++-
>  include/linux/bitops.h   | 19 +++++++++
>  include/linux/cpumask.h  | 55 +++++++++++++++++++++++++
>  include/linux/find.h     | 86 ++++++++++++++++++++++++++++++++++++++++
>  include/linux/nodemask.h |  3 +-
>  lib/bitmap.c             | 68 ++++++++++++-------------------
>  lib/cpumask.c            | 28 ++++++-------
>  lib/find_bit.c           | 44 ++++++++++++++++++++
>  lib/find_bit_benchmark.c | 18 +++++++++
>  lib/test_bitmap.c        | 47 +++++++++++++++++++++-
>  11 files changed, 320 insertions(+), 65 deletions(-)
> 
> -- 
> 2.34.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH v3 0/5] lib/find: add find_nth_bit()
  2022-09-23 16:18 ` [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
@ 2022-09-26 19:17   ` Yury Norov
  0 siblings, 0 replies; 9+ messages in thread
From: Yury Norov @ 2022-09-26 19:17 UTC (permalink / raw)
  To: linux-kernel, Alexander Lobakin, Andy Shevchenko, Arnd Bergmann,
	David Gow, Eric Dumazet, Isabella Basso, Kees Cook, Keith Busch,
	Kumar Kartikeya Dwivedi, Marco Elver, Mark Rutland,
	Rasmus Villemoes, Steven Rostedt,
	Toke Høiland-Jørgensen, Valentin Schneider

OK, take in bitmap-for-next.

On Fri, Sep 23, 2022 at 09:18:44AM -0700, Yury Norov wrote:
> Ping?
> 
> On Sat, Sep 17, 2022 at 08:07:10PM -0700, Yury Norov wrote:
> > 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;
> > 
> > Which is not so elegant and very slow.
> > 
> > This series adds fast routines for this task, and applies them where
> > appropriate.
> > 
> > v1: https://lore.kernel.org/lkml/20220706182300.70862-4-yury.norov@gmail.com/T/
> > v2: https://lore.kernel.org/lkml/CAAH8bW_RYG_Tbpip=BkSFAymDm2y3jJBqTi0PJWA=H-a-L_3tg@mail.gmail.com/T/
> > v3:
> >  - add bitmap_weight_and() and use it in cpumask_local_spread();
> >  - rework find_nth_bit() family: similarly to [1], introduce
> >    FIND_NTH_BIT(), and optimize the function to return earlier when
> >    it's known that the rest of bitmap can't meet the requirement.
> >  - patch "lib/nodemask: inline next_node_in() and node_random()" has
> >    been merged, so drop it from this series.
> > 
> > On top of:
> > [1] https://lore.kernel.org/lkml/20220915020730.852234-1-yury.norov@gmail.com/T/
> > 
> > Yury Norov (6):
> >   lib/bitmap: don't call __bitmap_weight() in kernel code
> >   lib/bitmap: add bitmap_weight_and()
> >   lib: add find_nth(,and,andnot)_bit()
> >   lib/bitmap: add tests for find_nth_bit()
> >   lib/bitmap: remove bitmap_ord_to_pos
> >   cpumask: add cpumask_nth_{,and,andnot}
> > 
> >  fs/ntfs3/bitmap.c        |  4 +-
> >  include/linux/bitmap.h   | 13 +++++-
> >  include/linux/bitops.h   | 19 +++++++++
> >  include/linux/cpumask.h  | 55 +++++++++++++++++++++++++
> >  include/linux/find.h     | 86 ++++++++++++++++++++++++++++++++++++++++
> >  include/linux/nodemask.h |  3 +-
> >  lib/bitmap.c             | 68 ++++++++++++-------------------
> >  lib/cpumask.c            | 28 ++++++-------
> >  lib/find_bit.c           | 44 ++++++++++++++++++++
> >  lib/find_bit_benchmark.c | 18 +++++++++
> >  lib/test_bitmap.c        | 47 +++++++++++++++++++++-
> >  11 files changed, 320 insertions(+), 65 deletions(-)
> > 
> > -- 
> > 2.34.1

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2022-09-26 19:17 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-09-18  3:07 [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
2022-09-18  3:07 ` [PATCH v3 1/6] lib/bitmap: don't call __bitmap_weight() in kernel code Yury Norov
2022-09-18  3:07 ` [PATCH v3 2/6] lib/bitmap: add bitmap_weight_and() Yury Norov
2022-09-18  3:07 ` [PATCH v3 3/6] lib: add find_nth{,_and,_andnot}_bit() Yury Norov
2022-09-18  3:07 ` [PATCH v3 4/6] lib/bitmap: add tests for find_nth_bit() Yury Norov
2022-09-18  3:07 ` [PATCH v3 5/6] lib/bitmap: remove bitmap_ord_to_pos Yury Norov
2022-09-18  3:07 ` [PATCH v3 6/6] cpumask: add cpumask_nth_{,and,andnot} Yury Norov
2022-09-23 16:18 ` [PATCH v3 0/5] lib/find: add find_nth_bit() Yury Norov
2022-09-26 19:17   ` Yury Norov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®