lib/test_bitmap: add tests for bitmap_{read,write}()
Add basic tests ensuring that values can be added at arbitrary positions of the bitmap, including those spanning into the adjacent unsigned longs. Two new performance tests, test_bitmap_read_perf() and test_bitmap_write_perf(), can be used to assess future performance improvements of bitmap_read() and bitmap_write(): [ 0.431119][ T1] test_bitmap: Time spent in test_bitmap_read_perf: 615253 [ 0.433197][ T1] test_bitmap: Time spent in test_bitmap_write_perf: 916313 (numbers from a Intel(R) Xeon(R) Gold 6154 CPU @ 3.00GHz machine running QEMU). Signed-off-by: Alexander Potapenko <glider@google.com> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Acked-by: Yury Norov <yury.norov@gmail.com> Signed-off-by: Yury Norov <yury.norov@gmail.com> Signed-off-by: Alexander Lobakin <aleksander.lobakin@intel.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
63c15822b8
commit
991e558364
@ -60,18 +60,17 @@ static const unsigned long exp3_1_0[] __initconst = {
|
||||
};
|
||||
|
||||
static bool __init
|
||||
__check_eq_uint(const char *srcfile, unsigned int line,
|
||||
const unsigned int exp_uint, unsigned int x)
|
||||
__check_eq_ulong(const char *srcfile, unsigned int line,
|
||||
const unsigned long exp_ulong, unsigned long x)
|
||||
{
|
||||
if (exp_uint != x) {
|
||||
pr_err("[%s:%u] expected %u, got %u\n",
|
||||
srcfile, line, exp_uint, x);
|
||||
if (exp_ulong != x) {
|
||||
pr_err("[%s:%u] expected %lu, got %lu\n",
|
||||
srcfile, line, exp_ulong, x);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool __init
|
||||
__check_eq_bitmap(const char *srcfile, unsigned int line,
|
||||
const unsigned long *exp_bmap, const unsigned long *bmap,
|
||||
@ -185,7 +184,8 @@ __check_eq_str(const char *srcfile, unsigned int line,
|
||||
result; \
|
||||
})
|
||||
|
||||
#define expect_eq_uint(...) __expect_eq(uint, ##__VA_ARGS__)
|
||||
#define expect_eq_ulong(...) __expect_eq(ulong, ##__VA_ARGS__)
|
||||
#define expect_eq_uint(x, y) expect_eq_ulong((unsigned int)(x), (unsigned int)(y))
|
||||
#define expect_eq_bitmap(...) __expect_eq(bitmap, ##__VA_ARGS__)
|
||||
#define expect_eq_pbl(...) __expect_eq(pbl, ##__VA_ARGS__)
|
||||
#define expect_eq_u32_array(...) __expect_eq(u32_array, ##__VA_ARGS__)
|
||||
@ -1286,6 +1286,168 @@ static void __init test_bitmap_const_eval(void)
|
||||
BUILD_BUG_ON(~var != ~BIT(25));
|
||||
}
|
||||
|
||||
/*
|
||||
* Test bitmap should be big enough to include the cases when start is not in
|
||||
* the first word, and start+nbits lands in the following word.
|
||||
*/
|
||||
#define TEST_BIT_LEN (1000)
|
||||
|
||||
/*
|
||||
* Helper function to test bitmap_write() overwriting the chosen byte pattern.
|
||||
*/
|
||||
static void __init test_bitmap_write_helper(const char *pattern)
|
||||
{
|
||||
DECLARE_BITMAP(bitmap, TEST_BIT_LEN);
|
||||
DECLARE_BITMAP(exp_bitmap, TEST_BIT_LEN);
|
||||
DECLARE_BITMAP(pat_bitmap, TEST_BIT_LEN);
|
||||
unsigned long w, r, bit;
|
||||
int i, n, nbits;
|
||||
|
||||
/*
|
||||
* Only parse the pattern once and store the result in the intermediate
|
||||
* bitmap.
|
||||
*/
|
||||
bitmap_parselist(pattern, pat_bitmap, TEST_BIT_LEN);
|
||||
|
||||
/*
|
||||
* Check that writing a single bit does not accidentally touch the
|
||||
* adjacent bits.
|
||||
*/
|
||||
for (i = 0; i < TEST_BIT_LEN; i++) {
|
||||
bitmap_copy(bitmap, pat_bitmap, TEST_BIT_LEN);
|
||||
bitmap_copy(exp_bitmap, pat_bitmap, TEST_BIT_LEN);
|
||||
for (bit = 0; bit <= 1; bit++) {
|
||||
bitmap_write(bitmap, bit, i, 1);
|
||||
__assign_bit(i, exp_bitmap, bit);
|
||||
expect_eq_bitmap(exp_bitmap, bitmap,
|
||||
TEST_BIT_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ensure writing 0 bits does not change anything. */
|
||||
bitmap_copy(bitmap, pat_bitmap, TEST_BIT_LEN);
|
||||
bitmap_copy(exp_bitmap, pat_bitmap, TEST_BIT_LEN);
|
||||
for (i = 0; i < TEST_BIT_LEN; i++) {
|
||||
bitmap_write(bitmap, ~0UL, i, 0);
|
||||
expect_eq_bitmap(exp_bitmap, bitmap, TEST_BIT_LEN);
|
||||
}
|
||||
|
||||
for (nbits = BITS_PER_LONG; nbits >= 1; nbits--) {
|
||||
w = IS_ENABLED(CONFIG_64BIT) ? 0xdeadbeefdeadbeefUL
|
||||
: 0xdeadbeefUL;
|
||||
w >>= (BITS_PER_LONG - nbits);
|
||||
for (i = 0; i <= TEST_BIT_LEN - nbits; i++) {
|
||||
bitmap_copy(bitmap, pat_bitmap, TEST_BIT_LEN);
|
||||
bitmap_copy(exp_bitmap, pat_bitmap, TEST_BIT_LEN);
|
||||
for (n = 0; n < nbits; n++)
|
||||
__assign_bit(i + n, exp_bitmap, w & BIT(n));
|
||||
bitmap_write(bitmap, w, i, nbits);
|
||||
expect_eq_bitmap(exp_bitmap, bitmap, TEST_BIT_LEN);
|
||||
r = bitmap_read(bitmap, i, nbits);
|
||||
expect_eq_ulong(r, w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __init test_bitmap_read_write(void)
|
||||
{
|
||||
unsigned char *pattern[3] = {"", "all:1/2", "all"};
|
||||
DECLARE_BITMAP(bitmap, TEST_BIT_LEN);
|
||||
unsigned long zero_bits = 0, bits_per_long = BITS_PER_LONG;
|
||||
unsigned long val;
|
||||
int i, pi;
|
||||
|
||||
/*
|
||||
* Reading/writing zero bits should not crash the kernel.
|
||||
* READ_ONCE() prevents constant folding.
|
||||
*/
|
||||
bitmap_write(NULL, 0, 0, READ_ONCE(zero_bits));
|
||||
/* Return value of bitmap_read() is undefined here. */
|
||||
bitmap_read(NULL, 0, READ_ONCE(zero_bits));
|
||||
|
||||
/*
|
||||
* Reading/writing more than BITS_PER_LONG bits should not crash the
|
||||
* kernel. READ_ONCE() prevents constant folding.
|
||||
*/
|
||||
bitmap_write(NULL, 0, 0, READ_ONCE(bits_per_long) + 1);
|
||||
/* Return value of bitmap_read() is undefined here. */
|
||||
bitmap_read(NULL, 0, READ_ONCE(bits_per_long) + 1);
|
||||
|
||||
/*
|
||||
* Ensure that bitmap_read() reads the same value that was previously
|
||||
* written, and two consequent values are correctly merged.
|
||||
* The resulting bit pattern is asymmetric to rule out possible issues
|
||||
* with bit numeration order.
|
||||
*/
|
||||
for (i = 0; i < TEST_BIT_LEN - 7; i++) {
|
||||
bitmap_zero(bitmap, TEST_BIT_LEN);
|
||||
|
||||
bitmap_write(bitmap, 0b10101UL, i, 5);
|
||||
val = bitmap_read(bitmap, i, 5);
|
||||
expect_eq_ulong(0b10101UL, val);
|
||||
|
||||
bitmap_write(bitmap, 0b101UL, i + 5, 3);
|
||||
val = bitmap_read(bitmap, i + 5, 3);
|
||||
expect_eq_ulong(0b101UL, val);
|
||||
|
||||
val = bitmap_read(bitmap, i, 8);
|
||||
expect_eq_ulong(0b10110101UL, val);
|
||||
}
|
||||
|
||||
for (pi = 0; pi < ARRAY_SIZE(pattern); pi++)
|
||||
test_bitmap_write_helper(pattern[pi]);
|
||||
}
|
||||
|
||||
static void __init test_bitmap_read_perf(void)
|
||||
{
|
||||
DECLARE_BITMAP(bitmap, TEST_BIT_LEN);
|
||||
unsigned int cnt, nbits, i;
|
||||
unsigned long val;
|
||||
ktime_t time;
|
||||
|
||||
bitmap_fill(bitmap, TEST_BIT_LEN);
|
||||
time = ktime_get();
|
||||
for (cnt = 0; cnt < 5; cnt++) {
|
||||
for (nbits = 1; nbits <= BITS_PER_LONG; nbits++) {
|
||||
for (i = 0; i < TEST_BIT_LEN; i++) {
|
||||
if (i + nbits > TEST_BIT_LEN)
|
||||
break;
|
||||
/*
|
||||
* Prevent the compiler from optimizing away the
|
||||
* bitmap_read() by using its value.
|
||||
*/
|
||||
WRITE_ONCE(val, bitmap_read(bitmap, i, nbits));
|
||||
}
|
||||
}
|
||||
}
|
||||
time = ktime_get() - time;
|
||||
pr_err("Time spent in %s:\t%llu\n", __func__, time);
|
||||
}
|
||||
|
||||
static void __init test_bitmap_write_perf(void)
|
||||
{
|
||||
DECLARE_BITMAP(bitmap, TEST_BIT_LEN);
|
||||
unsigned int cnt, nbits, i;
|
||||
unsigned long val = 0xfeedface;
|
||||
ktime_t time;
|
||||
|
||||
bitmap_zero(bitmap, TEST_BIT_LEN);
|
||||
time = ktime_get();
|
||||
for (cnt = 0; cnt < 5; cnt++) {
|
||||
for (nbits = 1; nbits <= BITS_PER_LONG; nbits++) {
|
||||
for (i = 0; i < TEST_BIT_LEN; i++) {
|
||||
if (i + nbits > TEST_BIT_LEN)
|
||||
break;
|
||||
bitmap_write(bitmap, val, i, nbits);
|
||||
}
|
||||
}
|
||||
}
|
||||
time = ktime_get() - time;
|
||||
pr_err("Time spent in %s:\t%llu\n", __func__, time);
|
||||
}
|
||||
|
||||
#undef TEST_BIT_LEN
|
||||
|
||||
static void __init selftest(void)
|
||||
{
|
||||
test_zero_clear();
|
||||
@ -1303,6 +1465,9 @@ static void __init selftest(void)
|
||||
test_bitmap_cut();
|
||||
test_bitmap_print_buf();
|
||||
test_bitmap_const_eval();
|
||||
test_bitmap_read_write();
|
||||
test_bitmap_read_perf();
|
||||
test_bitmap_write_perf();
|
||||
|
||||
test_find_nth_bit();
|
||||
test_for_each_set_bit();
|
||||
|
Loading…
Reference in New Issue
Block a user