]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bitmap: generalize node_random()
authorYury Norov [NVIDIA] <yury.norov@gmail.com>
Thu, 19 Jun 2025 18:26:23 +0000 (14:26 -0400)
committerYury Norov <yury.norov@gmail.com>
Tue, 8 Jul 2025 23:11:57 +0000 (19:11 -0400)
Generalize node_random() and make it available to general bitmaps and
cpumasks users.

Notice, find_first_bit() is generally faster than find_nth_bit(), and we
employ it when there's a single set bit in the bitmap.

See commit 3e061d924fe9c7b4 ("lib/nodemask: optimize node_random for
nodemask with single NUMA node").

CC: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: "Yury Norov [NVIDIA]" <yury.norov@gmail.com>
include/linux/find.h
include/linux/nodemask.h
lib/find_bit.c

index 5a2c267ea7f96465b7136ba9ed58c582ed435595..98c61838002c0861e9a7e0b24bece396a29fb4bb 100644 (file)
@@ -44,6 +44,8 @@ unsigned long _find_next_bit_le(const unsigned long *addr, unsigned
                                long size, unsigned long offset);
 #endif
 
+unsigned long find_random_bit(const unsigned long *addr, unsigned long size);
+
 #ifndef find_next_bit
 /**
  * find_next_bit - find the next set bit in a memory region
index f08ae71585faab7014eed78111ee49caaa7e74ea..7ad1f5c7407ea981ce69aea9fa42d9e1830ee5e9 100644 (file)
@@ -492,21 +492,9 @@ static __always_inline int num_node_state(enum node_states state)
 static __always_inline int node_random(const nodemask_t *maskp)
 {
 #if defined(CONFIG_NUMA) && (MAX_NUMNODES > 1)
-       int w, bit;
-
-       w = nodes_weight(*maskp);
-       switch (w) {
-       case 0:
-               bit = NUMA_NO_NODE;
-               break;
-       case 1:
-               bit = first_node(*maskp);
-               break;
-       default:
-               bit = find_nth_bit(maskp->bits, MAX_NUMNODES, get_random_u32_below(w));
-               break;
-       }
-       return bit;
+       int node = find_random_bit(maskp->bits, MAX_NUMNODES);
+
+       return node < MAX_NUMNODES ? node : NUMA_NO_NODE;
 #else
        return 0;
 #endif
index 06b6342aa3ae0ac2b8a549b2df3accce206d4b1d..d4b5a29e3e7283ae415671d22a0f71720929f20a 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/math.h>
 #include <linux/minmax.h>
 #include <linux/swab.h>
+#include <linux/random.h>
 
 /*
  * Common helper for find_bit() function family
@@ -291,3 +292,26 @@ EXPORT_SYMBOL(_find_next_bit_le);
 #endif
 
 #endif /* __BIG_ENDIAN */
+
+/**
+ * find_random_bit - find a set bit at random position
+ * @addr: The address to base the search on
+ * @size: The bitmap size in bits
+ *
+ * Returns: a position of a random set bit; >= @size otherwise
+ */
+unsigned long find_random_bit(const unsigned long *addr, unsigned long size)
+{
+       int w = bitmap_weight(addr, size);
+
+       switch (w) {
+       case 0:
+               return size;
+       case 1:
+               /* Performance trick for single-bit bitmaps */
+               return find_first_bit(addr, size);
+       default:
+               return find_nth_bit(addr, size, get_random_u32_below(w));
+       }
+}
+EXPORT_SYMBOL(find_random_bit);