lib/bitmap: add bitmap_weight_and()
authorYury Norov <yury.norov@gmail.com>
Sun, 18 Sep 2022 03:07:12 +0000 (20:07 -0700)
committerYury Norov <yury.norov@gmail.com>
Mon, 26 Sep 2022 19:19:12 +0000 (12:19 -0700)
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
include/linux/cpumask.h
lib/bitmap.c

index f65410a..b2aef45 100644 (file)
@@ -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)
 {
index 1b442fb..9a71af8 100644 (file)
@@ -587,6 +587,17 @@ static inline unsigned int cpumask_weight(const struct cpumask *srcp)
 }
 
 /**
+ * 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
  * @srcp: the input to shift
index d56e275..3fc2e33 100644 (file)
@@ -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);