This is the last remaining "Test Module" kselftest, the rest having been converted to KUnit.
Relative to v1 this keeps benchmarks out of KUnit in light of Yury's concerns:
On Sat, Feb 8, 2025 at 12:53 PM Yury Norov yury.norov@gmail.com wrote:
[...]
This is my evidence: sometimes people report performance or whatever issues on their systems, suspecting bitmaps guilty. I ask them to run the bitmap or find_bit test to narrow the problem. Sometimes I need to test a hardware I have no access to, and I have to (kindly!) ask
people
to build a small test and run it. I don't want to ask them to rebuild the whole kernel, or even to build something else.
I tested this using:
$ tools/testing/kunit/kunit.py run --arch arm64 --make_options LLVM=1 bitmap
There was a previous attempt[2] to do this in July 2024. Please bear with me as I try to understand and address the objections from that time. I've spoken with Muhammad Usama Anjum, the author of that series, and received their approval to "take over" this work. Here we go...
On 7/26/24 11:45 PM, John Hubbard wrote:
This changes the situation from "works for Linus' tab completion case", to "causes a tab completion problem"! :)
I think a tests/ subdir is how we eventually decided to do this [1], right?
So:
lib/tests/bitmap_kunit.c[1] https://lore.kernel.org/20240724201354.make.730-kees@kernel.org
This is true and unfortunate, but not trivial to fix because new kallsyms tests were placed in lib/tests in commit 84b4a51fce4c ("selftests: add new kallsyms selftests") *after* the KUnit filename best practices were adopted.
I propose that the KUnit maintainers blaze this trail using `string_kunit.c` which currently still lives in lib/ despite the KUnit docs giving it as an example at lib/tests/.
On 7/27/24 12:24 AM, Shuah Khan wrote:
This change will take away the ability to run bitmap tests during boot on a non-kunit kernel.
Nack on this change. I wan to see all tests that are being removed from lib because they have been converted - also it doesn't make sense to convert some tests like this one that add the ability test during boot.
This point was also discussed in another thread[3] in which:
On 7/27/24 12:35 AM, Shuah Khan wrote:
Please make sure you aren't taking away the ability to run these tests during boot.
It doesn't make sense to convert every single test especially when it is intended to be run during boot without dependencies - not as a kunit test but a regression test during boot.
bitmap is one example - pay attention to the config help test - bitmap one clearly states it runs regression testing during boot. Any test that says that isn't a candidate for conversion.
I am going to nack any such conversions.
The crux of the argument seems to be that the config help text is taken to describe the author's intent with the fragment "at boot". I think this may be a case of confirmation bias: I see at least the following KUnit tests with "at boot" in their help text: - CPUMASK_KUNIT_TEST - BITFIELD_KUNIT - CHECKSUM_KUNIT - UTIL_MACROS_KUNIT
It seems to me that the inference being made is that any test that runs "at boot" is intended to be run by both developers and users, but I find no evidence that bitmap in particular would ever provide additional value when run by users.
There's further discussion about KUnit not being "ideal for cases where people would want to check a subsystem on a running kernel", but I find no evidence that bitmap in particular is actually testing the running kernel; it is a unit test of the bitmap functions, which is also stated in the config help text.
David Gow made many of the same points in his final reply[4], which was never replied to.
Link: https://lore.kernel.org/all/20250207-printf-kunit-convert-v2-0-057b23860823@... [0] Link: https://lore.kernel.org/all/20250207-scanf-kunit-convert-v4-0-a23e2afaede8@g... [1] Link: https://lore.kernel.org/all/20240726110658.2281070-1-usama.anjum@collabora.c... [2] Link: https://lore.kernel.org/all/327831fb-47ab-4555-8f0b-19a8dbcaacd7@collabora.c... [3] Link: https://lore.kernel.org/all/CABVgOSmMoPD3JfzVd4VTkzGL2fZCo8LfwzaVSzeFimPrhgL... [4]
Thanks for your attention.
Signed-off-by: Tamir Duberstein tamird@gmail.com --- Changes in v2: - Rebase on v6.19-rc1, dropping the first patch. - Extract benchmarks into new module and deduplicate `test_bitmap_{read,write}_perf`. - Remove tc_err() and use KUnit assertions. - Parameterize `test_bitmap_cut` and `test_bitmap_parse{,list}`. - Drop KUnit boilerplate from BITMAP_KUNIT_TEST help text. - Drop arch changes. - Link to v1: https://lore.kernel.org/r/20250207-bitmap-kunit-convert-v1-0-c520675343b6@gm...
--- Tamir Duberstein (3): test_bitmap: extract benchmark module bitmap: convert self-test to KUnit bitmap: break kunit into test cases
MAINTAINERS | 3 +- lib/Kconfig.debug | 16 +- lib/Makefile | 5 +- lib/bitmap_benchmark.c | 89 +++++ lib/{test_bitmap.c => bitmap_kunit.c} | 630 ++++++++++++++-------------------- tools/testing/selftests/lib/Makefile | 2 +- tools/testing/selftests/lib/bitmap.sh | 3 - tools/testing/selftests/lib/config | 1 - 8 files changed, 360 insertions(+), 389 deletions(-) --- base-commit: 8f0b4cce4481fb22653697cced8d0d04027cb1e8 change-id: 20250207-bitmap-kunit-convert-92d3147b2eee
Best regards, -- Tamir Duberstein tamird@gmail.com
From: Tamir Duberstein tamird@gmail.com
Add CONFIG_BITMAP_BENCHMARK to build benchmarks separately from unit tests. The new module is marked authored by the author of commit 991e5583647d ("lib/test_bitmap: add tests for bitmap_{read,write}()") which added these benchmarks.
Extract duplicated code between `test_bitmap_{read,write}_perf`.
Cc: Alexander Potapenko glider@google.com Signed-off-by: Tamir Duberstein tamird@gmail.com --- MAINTAINERS | 1 + lib/Kconfig.debug | 8 +++++ lib/Makefile | 1 + lib/bitmap_benchmark.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/test_bitmap.c | 50 ---------------------------- 5 files changed, 99 insertions(+), 50 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS index 5b11839cba9d..4ddaef15b408 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4426,6 +4426,7 @@ F: include/uapi/linux/bits.h F: include/vdso/bits.h F: lib/bitmap-str.c F: lib/bitmap.c +F: lib/bitmap_benchmark.c F: lib/cpumask.c F: lib/find_bit.c F: lib/find_bit_benchmark.c diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index ba36939fda79..60434b31a940 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2492,6 +2492,14 @@ config FFS_KUNIT_TEST config TEST_KSTRTOX tristate "Test kstrto*() family of functions at runtime"
+config BITMAP_BENCHMARK + tristate "Benchmark bitmap_*() family of functions" + help + This builds the "bitmap_benchmark_test" module that measure bitmap_*() + family of functions performance. + + If unsure, say N. + config TEST_BITMAP tristate "Test bitmap_*() family of functions at runtime" help diff --git a/lib/Makefile b/lib/Makefile index aaf677cf4527..892cb3152b65 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -61,6 +61,7 @@ obj-y += string_helpers.o obj-y += hexdump.o obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o obj-y += kstrtox.o +obj-$(CONFIG_BITMAP_BENCHMARK) += bitmap_benchmark.o obj-$(CONFIG_FIND_BIT_BENCHMARK) += find_bit_benchmark.o obj-$(CONFIG_FIND_BIT_BENCHMARK_RUST) += find_bit_benchmark_rust.o obj-$(CONFIG_TEST_BPF) += test_bpf.o diff --git a/lib/bitmap_benchmark.c b/lib/bitmap_benchmark.c new file mode 100644 index 000000000000..47f4cea4e831 --- /dev/null +++ b/lib/bitmap_benchmark.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Benchmarks for bitmap API. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/bitmap.h> +#include <linux/init.h> +#include <linux/ktime.h> +#include <linux/module.h> +#include <linux/printk.h> + +/* + * 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) + +typedef void (*bitmap_bench_fn)(unsigned long *bitmap, unsigned long i, unsigned long nbits); + +static void __init bench_bitmap(bitmap_bench_fn bench_fn, const char *name) +{ + DECLARE_BITMAP(bitmap, TEST_BIT_LEN); + unsigned int cnt, nbits, i; + 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; + bench_fn(bitmap, i, nbits); + } + } + } + time = ktime_get() - time; + pr_info("Time spent in %s:\t%llu\n", name, time); +} + +#undef TEST_BIT_LEN + +static inline void bitmap_read_bench(unsigned long *bitmap, unsigned long i, unsigned long nbits) +{ + unsigned long val; + /* + * Prevent the compiler from optimizing away the + * bitmap_read() by using its value. + */ + WRITE_ONCE(val, bitmap_read(bitmap, i, nbits)); +} + +static void __init test_bitmap_read_perf(void) +{ + bench_bitmap(bitmap_read_bench, __func__); +} + +static inline void bitmap_write_bench(unsigned long *bitmap, unsigned long i, unsigned long nbits) +{ + unsigned long val = 0xfeedface; + + bitmap_write(bitmap, val, i, nbits); +} + +static void __init test_bitmap_write_perf(void) +{ + bench_bitmap(bitmap_write_bench, __func__); +} + +static int __init bitmap_benchmark_init(void) +{ + test_bitmap_read_perf(); + test_bitmap_write_perf(); + + return 0; +} +module_init(bitmap_benchmark_init); + +static void __exit bitmap_benchmark_exit(void) +{ + pr_info("Unloaded\n"); +} +module_exit(bitmap_benchmark_exit); + +MODULE_AUTHOR("Alexander Potapenko glider@google.com"); +MODULE_DESCRIPTION("Benchmarks for bitmap API"); +MODULE_LICENSE("GPL"); diff --git a/lib/test_bitmap.c b/lib/test_bitmap.c index c83829ef557f..f728b6485c88 100644 --- a/lib/test_bitmap.c +++ b/lib/test_bitmap.c @@ -1372,54 +1372,6 @@ static void __init test_bitmap_read_write(void) 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_info("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_info("Time spent in %s:\t%llu\n", __func__, time); -} - #undef TEST_BIT_LEN
static void __init selftest(void) @@ -1440,8 +1392,6 @@ static void __init selftest(void) 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();
From: Tamir Duberstein tamird@gmail.com
Convert the bitmap() self-test to a KUnit test.
In the interest of keeping the patch reasonably-sized this doesn't refactor the tests into proper parameterized tests - it's all one big test case.
Reviewed-by: David Gow davidgow@google.com Signed-off-by: Tamir Duberstein tamird@gmail.com --- MAINTAINERS | 2 +- lib/Kconfig.debug | 16 +- lib/Makefile | 4 +- lib/{test_bitmap.c => bitmap_kunit.c} | 314 +++++++++++++--------------------- tools/testing/selftests/lib/Makefile | 2 +- tools/testing/selftests/lib/bitmap.sh | 3 - tools/testing/selftests/lib/config | 1 - 7 files changed, 135 insertions(+), 207 deletions(-)
diff --git a/MAINTAINERS b/MAINTAINERS index 4ddaef15b408..bb5269ff2bcd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4430,7 +4430,7 @@ F: lib/bitmap_benchmark.c F: lib/cpumask.c F: lib/find_bit.c F: lib/find_bit_benchmark.c -F: lib/test_bitmap.c +F: lib/tests/bitmap_kunit.c F: lib/tests/cpumask_kunit.c F: tools/include/linux/bitfield.h F: tools/include/linux/bitmap.h diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 60434b31a940..e7a4991e5395 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2438,6 +2438,15 @@ config ASYNC_RAID6_TEST config TEST_HEXDUMP tristate "Test functions located in the hexdump module at runtime"
+config BITMAP_KUNIT_TEST + tristate "KUnit test bitmap_*() family of functions at runtime" if !KUNIT_ALL_TESTS + depends on KUNIT + default KUNIT_ALL_TESTS + help + Enable this option to test the bitmap functions at runtime. + + If unsure, say N. + config PRINTF_KUNIT_TEST tristate "KUnit test printf() family of functions at runtime" if !KUNIT_ALL_TESTS depends on KUNIT @@ -2500,13 +2509,6 @@ config BITMAP_BENCHMARK
If unsure, say N.
-config TEST_BITMAP - tristate "Test bitmap_*() family of functions at runtime" - help - Enable this option to test the bitmap functions at boot. - - If unsure, say N. - config TEST_UUID tristate "Test functions located in the uuid module at runtime"
diff --git a/lib/Makefile b/lib/Makefile index 892cb3152b65..683084afb793 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -84,10 +84,10 @@ obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o
-obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o +obj-$(CONFIG_BITMAP_KUNIT_TEST) += bitmap_kunit.o ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_KASAN),yy) # FIXME: Clang breaks test_bitmap_const_eval when KASAN and GCOV are enabled -GCOV_PROFILE_test_bitmap.o := n +GCOV_PROFILE_bitmap_kunit.o := n endif
obj-$(CONFIG_TEST_UUID) += test_uuid.o diff --git a/lib/test_bitmap.c b/lib/bitmap_kunit.c similarity index 83% rename from lib/test_bitmap.c rename to lib/bitmap_kunit.c index f728b6485c88..3a71e2039c1f 100644 --- a/lib/test_bitmap.c +++ b/lib/bitmap_kunit.c @@ -3,10 +3,8 @@ * Test cases for bitmap API. */
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - +#include <kunit/test.h> #include <linux/bitmap.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/printk.h> @@ -14,16 +12,17 @@ #include <linux/string.h> #include <linux/uaccess.h>
-#include "../tools/testing/selftests/kselftest_module.h" - #define EXP1_IN_BITS (sizeof(exp1) * 8)
-KSTM_MODULE_GLOBALS(); +static char pbl_buffer[PAGE_SIZE]; +static char print_buf[PAGE_SIZE * 2]; + +static struct kunit *kunittest;
-static char pbl_buffer[PAGE_SIZE] __initdata; -static char print_buf[PAGE_SIZE * 2] __initdata; +#define tc_err(fmt, ...) \ + KUNIT_FAIL(kunittest, fmt, ##__VA_ARGS__)
-static const unsigned long exp1[] __initconst = { +static const unsigned long exp1[] = { BITMAP_FROM_U64(1), BITMAP_FROM_U64(2), BITMAP_FROM_U64(0x0000ffff), @@ -41,130 +40,63 @@ static const unsigned long exp1[] __initconst = { BITMAP_FROM_U64(0x80000000), };
-static const unsigned long exp2[] __initconst = { +static const unsigned long exp2[] = { BITMAP_FROM_U64(0x3333333311111111ULL), BITMAP_FROM_U64(0xffffffff77777777ULL), };
/* Fibonacci sequence */ -static const unsigned long exp2_to_exp3_mask[] __initconst = { +static const unsigned long exp2_to_exp3_mask[] = { BITMAP_FROM_U64(0x008000020020212eULL), }; /* exp3_0_1 = (exp2[0] & ~exp2_to_exp3_mask) | (exp2[1] & exp2_to_exp3_mask) */ -static const unsigned long exp3_0_1[] __initconst = { +static const unsigned long exp3_0_1[] = { BITMAP_FROM_U64(0x33b3333311313137ULL), }; /* exp3_1_0 = (exp2[1] & ~exp2_to_exp3_mask) | (exp2[0] & exp2_to_exp3_mask) */ -static const unsigned long exp3_1_0[] __initconst = { +static const unsigned long exp3_1_0[] = { BITMAP_FROM_U64(0xff7fffff77575751ULL), };
-static bool __init -__check_eq_ulong(const char *srcfile, unsigned int line, - const unsigned long exp_ulong, unsigned long 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, - unsigned int nbits) -{ - if (!bitmap_equal(exp_bmap, bmap, nbits)) { - pr_warn("[%s:%u] bitmaps contents differ: expected "%*pbl", got "%*pbl"\n", - srcfile, line, - nbits, exp_bmap, nbits, bmap); - return false; - } - return true; -} - -static bool __init -__check_eq_pbl(const char *srcfile, unsigned int line, - const char *expected_pbl, - const unsigned long *bitmap, unsigned int nbits) -{ - snprintf(pbl_buffer, sizeof(pbl_buffer), "%*pbl", nbits, bitmap); - if (strcmp(expected_pbl, pbl_buffer)) { - pr_warn("[%s:%u] expected "%s", got "%s"\n", - srcfile, line, - expected_pbl, pbl_buffer); - return false; - } - return true; -} - -static bool __init __check_eq_clump8(const char *srcfile, unsigned int line, - const unsigned int offset, - const unsigned int size, - const unsigned char *const clump_exp, - const unsigned long *const clump) -{ - unsigned long exp; - - if (offset >= size) { - pr_warn("[%s:%u] bit offset for clump out-of-bounds: expected less than %u, got %u\n", - srcfile, line, size, offset); - return false; - } - - exp = clump_exp[offset / 8]; - if (!exp) { - pr_warn("[%s:%u] bit offset for zero clump: expected nonzero clump, got bit offset %u with clump value 0", - srcfile, line, offset); - return false; - } - - if (*clump != exp) { - pr_warn("[%s:%u] expected clump value of 0x%lX, got clump value of 0x%lX", - srcfile, line, exp, *clump); - return false; - } - - return true; -} - -static bool __init -__check_eq_str(const char *srcfile, unsigned int line, - const char *exp_str, const char *str, - unsigned int len) -{ - bool eq; - - eq = strncmp(exp_str, str, len) == 0; - if (!eq) - pr_err("[%s:%u] expected %s, got %s\n", srcfile, line, exp_str, str); - - return eq; -} - -#define __expect_eq(suffix, ...) \ - ({ \ - int result = 0; \ - total_tests++; \ - if (!__check_eq_ ## suffix(__FILE__, __LINE__, \ - ##__VA_ARGS__)) { \ - failed_tests++; \ - result = 1; \ +#define expect_eq_ulong(exp_ulong, x) KUNIT_EXPECT_EQ(kunittest, exp_ulong, x) + +#define expect_eq_bitmap(exp_bmap, bmap, nbits) \ + KUNIT_EXPECT_TRUE_MSG(kunittest, bitmap_equal(exp_bmap, bmap, nbits), \ + "bitmaps contents differ: expected "%*pbl", got "%*pbl"", \ + nbits, exp_bmap, nbits, bmap) + +#define expect_eq_pbl(expected_pbl, bitmap, nbits) do { \ + { \ + snprintf(pbl_buffer, sizeof(pbl_buffer), "%*pbl", nbits, bitmap); \ + KUNIT_EXPECT_STREQ(kunittest, expected_pbl, pbl_buffer); \ + } \ + } while (0) + +#define expect_eq_clump8(offset, size, clump_exp, clump) do { \ + { \ + unsigned long exp; \ + \ + KUNIT_EXPECT_LT_MSG(kunittest, offset, size, \ + "bit offset for clump out-of-bounds"); \ + \ + exp = clump_exp[offset / 8]; \ + KUNIT_EXPECT_NE_MSG(kunittest, exp, 0, \ + "bit offset %u for zero clump", offset); \ + \ + KUNIT_EXPECT_EQ(kunittest, *clump, exp); \ + } \ + } while (0) + +#define expect_eq_str(exp_str, str, len) \ + { \ + if (strncmp(exp_str, str, len) != 0) { \ + tc_err("expected %s, got %s", exp_str, str); \ } \ - result; \ - }) + }
-#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__) -#define expect_eq_clump8(...) __expect_eq(clump8, ##__VA_ARGS__) -#define expect_eq_str(...) __expect_eq(str, ##__VA_ARGS__)
-static void __init test_zero_clear(void) +static void test_zero_clear(void) { DECLARE_BITMAP(bmap, 1024);
@@ -193,7 +125,7 @@ static void __init test_zero_clear(void) expect_eq_pbl("", bmap, 1024); }
-static void __init test_find_nth_bit(void) +static void test_find_nth_bit(void) { unsigned long b, bit, cnt = 0; DECLARE_BITMAP(bmap, 64 * 3); @@ -234,7 +166,7 @@ static void __init test_find_nth_bit(void) } }
-static void __init test_fill_set(void) +static void test_fill_set(void) { DECLARE_BITMAP(bmap, 1024);
@@ -263,7 +195,7 @@ static void __init test_fill_set(void) expect_eq_pbl("0-1023", bmap, 1024); }
-static void __init test_copy(void) +static void test_copy(void) { DECLARE_BITMAP(bmap1, 1024); DECLARE_BITMAP(bmap2, 1024); @@ -302,7 +234,7 @@ static void __init test_copy(void) expect_eq_pbl("0-108,128-1023", bmap2, 1024); }
-static void __init test_bitmap_region(void) +static void test_bitmap_region(void) { int pos, order;
@@ -327,7 +259,7 @@ static void __init test_bitmap_region(void)
#define EXP2_IN_BITS (sizeof(exp2) * 8)
-static void __init test_replace(void) +static void test_replace(void) { unsigned int nbits = 64; unsigned int nlongs = DIV_ROUND_UP(nbits, BITS_PER_LONG); @@ -352,23 +284,23 @@ static void __init test_replace(void) expect_eq_bitmap(bmap, exp3_1_0, nbits); }
-static const unsigned long sg_mask[] __initconst = { +static const unsigned long sg_mask[] = { BITMAP_FROM_U64(0x000000000000035aULL), };
-static const unsigned long sg_src[] __initconst = { +static const unsigned long sg_src[] = { BITMAP_FROM_U64(0x0000000000000667ULL), };
-static const unsigned long sg_gather_exp[] __initconst = { +static const unsigned long sg_gather_exp[] = { BITMAP_FROM_U64(0x0000000000000029ULL), };
-static const unsigned long sg_scatter_exp[] __initconst = { +static const unsigned long sg_scatter_exp[] = { BITMAP_FROM_U64(0x000000000000021aULL), };
-static void __init test_bitmap_sg(void) +static void test_bitmap_sg(void) { unsigned int nbits = 64; DECLARE_BITMAP(bmap_gather, 100); @@ -404,7 +336,7 @@ struct test_bitmap_parselist{ const int flags; };
-static const struct test_bitmap_parselist parselist_tests[] __initconst = { +static const struct test_bitmap_parselist parselist_tests[] = { #define step (sizeof(u64) / sizeof(unsigned long))
{0, "0", &exp1[0], 8, 0}, @@ -489,7 +421,7 @@ static const struct test_bitmap_parselist parselist_tests[] __initconst = {
};
-static void __init test_bitmap_parselist(void) +static void test_bitmap_parselist(void) { int i; int err; @@ -504,30 +436,28 @@ static void __init test_bitmap_parselist(void) time = ktime_get() - time;
if (err != ptest.errno) { - pr_err("parselist: %d: input is %s, errno is %d, expected %d\n", + tc_err("parselist: %d: input is %s, errno is %d, expected %d", i, ptest.in, err, ptest.errno); - failed_tests++; continue; }
if (!err && ptest.expected && !__bitmap_equal(bmap, ptest.expected, ptest.nbits)) { - pr_err("parselist: %d: input is %s, result is 0x%lx, expected 0x%lx\n", + tc_err("parselist: %d: input is %s, result is 0x%lx, expected 0x%lx", i, ptest.in, bmap[0], *ptest.expected); - failed_tests++; continue; }
if (ptest.flags & PARSE_TIME) - pr_info("parselist: %d: input is '%s' OK, Time: %llu\n", + kunit_info(kunittest, "parselist: %d: input is '%s' OK, Time: %llu", i, ptest.in, time);
#undef ptest } }
-static void __init test_bitmap_printlist(void) +static void test_bitmap_printlist(void) { unsigned long *bmap = kmalloc(PAGE_SIZE, GFP_KERNEL); char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); @@ -548,37 +478,35 @@ static void __init test_bitmap_printlist(void) time = ktime_get() - time;
if (ret != slen + 1) { - pr_err("bitmap_print_to_pagebuf: result is %d, expected %d\n", ret, slen); - failed_tests++; + tc_err("bitmap_print_to_pagebuf: result is %d, expected %d", ret, slen); goto out; }
if (strncmp(buf, expected, slen)) { - pr_err("bitmap_print_to_pagebuf: result is %s, expected %s\n", buf, expected); - failed_tests++; + tc_err("bitmap_print_to_pagebuf: result is %s, expected %s", buf, expected); goto out; }
- pr_info("bitmap_print_to_pagebuf: input is '%s', Time: %llu\n", buf, time); + kunit_info(kunittest, "bitmap_print_to_pagebuf: input is '%s', Time: %llu", buf, time); out: kfree(buf); kfree(bmap); }
-static const unsigned long parse_test[] __initconst = { +static const unsigned long parse_test[] = { BITMAP_FROM_U64(0), BITMAP_FROM_U64(1), BITMAP_FROM_U64(0xdeadbeef), BITMAP_FROM_U64(0x100000000ULL), };
-static const unsigned long parse_test2[] __initconst = { +static const unsigned long parse_test2[] = { BITMAP_FROM_U64(0x100000000ULL), BITMAP_FROM_U64(0xdeadbeef), BITMAP_FROM_U64(0x100000000ULL), BITMAP_FROM_U64(0xbaadf00ddeadbeef), BITMAP_FROM_U64(0x100000000ULL), BITMAP_FROM_U64(0x0badf00ddeadbeef), };
-static const struct test_bitmap_parselist parse_tests[] __initconst = { +static const struct test_bitmap_parselist parse_tests[] = { {0, "", &parse_test[0 * step], 32, 0}, {0, " ", &parse_test[0 * step], 32, 0}, {0, "0", &parse_test[0 * step], 32, 0}, @@ -605,7 +533,7 @@ static const struct test_bitmap_parselist parse_tests[] __initconst = { #undef step };
-static void __init test_bitmap_parse(void) +static void test_bitmap_parse(void) { int i; int err; @@ -621,28 +549,26 @@ static void __init test_bitmap_parse(void) time = ktime_get() - time;
if (err != test.errno) { - pr_err("parse: %d: input is %s, errno is %d, expected %d\n", + tc_err("parse: %d: input is %s, errno is %d, expected %d", i, test.in, err, test.errno); - failed_tests++; continue; }
if (!err && test.expected && !__bitmap_equal(bmap, test.expected, test.nbits)) { - pr_err("parse: %d: input is %s, result is 0x%lx, expected 0x%lx\n", + tc_err("parse: %d: input is %s, result is 0x%lx, expected 0x%lx", i, test.in, bmap[0], *test.expected); - failed_tests++; continue; }
if (test.flags & PARSE_TIME) - pr_info("parse: %d: input is '%s' OK, Time: %llu\n", + kunit_info(kunittest, "parse: %d: input is '%s' OK, Time: %llu", i, test.in, time); } }
-static void __init test_bitmap_arr32(void) +static void test_bitmap_arr32(void) { unsigned int nbits, next_bit; u32 arr[EXP1_IN_BITS / 32]; @@ -658,10 +584,8 @@ static void __init test_bitmap_arr32(void) next_bit = find_next_bit(bmap2, round_up(nbits, BITS_PER_LONG), nbits); if (next_bit < round_up(nbits, BITS_PER_LONG)) { - pr_err("bitmap_copy_arr32(nbits == %d:" - " tail is not safely cleared: %d\n", + tc_err("bitmap_copy_arr32(nbits == %d: tail is not safely cleared: %d", nbits, next_bit); - failed_tests++; }
if (nbits < EXP1_IN_BITS - 32) @@ -670,7 +594,7 @@ static void __init test_bitmap_arr32(void) } }
-static void __init test_bitmap_arr64(void) +static void test_bitmap_arr64(void) { unsigned int nbits, next_bit; u64 arr[EXP1_IN_BITS / 64]; @@ -686,17 +610,15 @@ static void __init test_bitmap_arr64(void)
next_bit = find_next_bit(bmap2, round_up(nbits, BITS_PER_LONG), nbits); if (next_bit < round_up(nbits, BITS_PER_LONG)) { - pr_err("bitmap_copy_arr64(nbits == %d:" - " tail is not safely cleared: %d\n", nbits, next_bit); - failed_tests++; + tc_err("bitmap_copy_arr64(nbits == %d: tail is not safely cleared: %d", + nbits, next_bit); }
if ((nbits % 64) && (arr[(nbits - 1) / 64] & ~GENMASK_ULL((nbits - 1) % 64, 0))) { - pr_err("bitmap_to_arr64(nbits == %d): tail is not safely cleared: 0x%016llx (must be 0x%016llx)\n", + tc_err("bitmap_to_arr64(nbits == %d): tail is not safely cleared: 0x%016llx (must be 0x%016llx)", nbits, arr[(nbits - 1) / 64], GENMASK_ULL((nbits - 1) % 64, 0)); - failed_tests++; }
if (nbits < EXP1_IN_BITS - 64) @@ -704,7 +626,7 @@ static void __init test_bitmap_arr64(void) } }
-static void noinline __init test_mem_optimisations(void) +static noinline void test_mem_optimisations(void) { DECLARE_BITMAP(bmap1, 1024); DECLARE_BITMAP(bmap2, 1024); @@ -718,30 +640,25 @@ static void noinline __init test_mem_optimisations(void) bitmap_set(bmap1, start, nbits); __bitmap_set(bmap2, start, nbits); if (!bitmap_equal(bmap1, bmap2, 1024)) { - printk("set not equal %d %d\n", start, nbits); - failed_tests++; + tc_err("set not equal %d %d", start, nbits); } if (!__bitmap_equal(bmap1, bmap2, 1024)) { - printk("set not __equal %d %d\n", start, nbits); - failed_tests++; + tc_err("set not __equal %d %d", start, nbits); }
bitmap_clear(bmap1, start, nbits); __bitmap_clear(bmap2, start, nbits); if (!bitmap_equal(bmap1, bmap2, 1024)) { - printk("clear not equal %d %d\n", start, nbits); - failed_tests++; + tc_err("clear not equal %d %d", start, nbits); } if (!__bitmap_equal(bmap1, bmap2, 1024)) { - printk("clear not __equal %d %d\n", start, - nbits); - failed_tests++; + tc_err("clear not __equal %d %d", start, nbits); } } } }
-static const unsigned char clump_exp[] __initconst = { +static const unsigned char clump_exp[] = { 0x01, /* 1 bit set */ 0x02, /* non-edge 1 bit set */ 0x00, /* zero bits set */ @@ -752,7 +669,7 @@ static const unsigned char clump_exp[] __initconst = { 0x05, /* non-adjacent 2 bits set */ };
-static void __init test_for_each_set_clump8(void) +static void test_for_each_set_clump8(void) { #define CLUMP_EXP_NUMBITS 64 DECLARE_BITMAP(bits, CLUMP_EXP_NUMBITS); @@ -774,7 +691,7 @@ static void __init test_for_each_set_clump8(void) expect_eq_clump8(start, CLUMP_EXP_NUMBITS, clump_exp, &clump); }
-static void __init test_for_each_set_bit_wrap(void) +static void test_for_each_set_bit_wrap(void) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -799,7 +716,7 @@ static void __init test_for_each_set_bit_wrap(void) } }
-static void __init test_for_each_set_bit(void) +static void test_for_each_set_bit(void) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -821,7 +738,7 @@ static void __init test_for_each_set_bit(void) expect_eq_bitmap(orig, copy, 500); }
-static void __init test_for_each_set_bit_from(void) +static void test_for_each_set_bit_from(void) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -851,7 +768,7 @@ static void __init test_for_each_set_bit_from(void) } }
-static void __init test_for_each_clear_bit(void) +static void test_for_each_clear_bit(void) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -873,7 +790,7 @@ static void __init test_for_each_clear_bit(void) expect_eq_bitmap(orig, copy, 500); }
-static void __init test_for_each_clear_bit_from(void) +static void test_for_each_clear_bit_from(void) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -903,7 +820,7 @@ static void __init test_for_each_clear_bit_from(void) } }
-static void __init test_for_each_set_bitrange(void) +static void test_for_each_set_bitrange(void) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -925,7 +842,7 @@ static void __init test_for_each_set_bitrange(void) expect_eq_bitmap(orig, copy, 500); }
-static void __init test_for_each_clear_bitrange(void) +static void test_for_each_clear_bitrange(void) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -947,7 +864,7 @@ static void __init test_for_each_clear_bitrange(void) expect_eq_bitmap(orig, copy, 500); }
-static void __init test_for_each_set_bitrange_from(void) +static void test_for_each_set_bitrange_from(void) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -977,7 +894,7 @@ static void __init test_for_each_set_bitrange_from(void) } }
-static void __init test_for_each_clear_bitrange_from(void) +static void test_for_each_clear_bitrange_from(void) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -1048,7 +965,7 @@ static struct test_bitmap_cut test_cut[] = { }, };
-static void __init test_bitmap_cut(void) +static void test_bitmap_cut(void) { unsigned long b[5], *in = &b[1], *out = &b[0]; /* Partial overlap */ int i; @@ -1071,14 +988,14 @@ struct test_bitmap_print { const char *list; };
-static const unsigned long small_bitmap[] __initconst = { +static const unsigned long small_bitmap[] = { BITMAP_FROM_U64(0x3333333311111111ULL), };
-static const char small_mask[] __initconst = "33333333,11111111\n"; -static const char small_list[] __initconst = "0,4,8,12,16,20,24,28,32-33,36-37,40-41,44-45,48-49,52-53,56-57,60-61\n"; +static const char small_mask[] = "33333333,11111111\n"; +static const char small_list[] = "0,4,8,12,16,20,24,28,32-33,36-37,40-41,44-45,48-49,52-53,56-57,60-61\n";
-static const unsigned long large_bitmap[] __initconst = { +static const unsigned long large_bitmap[] = { BITMAP_FROM_U64(0x3333333311111111ULL), BITMAP_FROM_U64(0x3333333311111111ULL), BITMAP_FROM_U64(0x3333333311111111ULL), BITMAP_FROM_U64(0x3333333311111111ULL), BITMAP_FROM_U64(0x3333333311111111ULL), BITMAP_FROM_U64(0x3333333311111111ULL), @@ -1101,7 +1018,7 @@ static const unsigned long large_bitmap[] __initconst = { BITMAP_FROM_U64(0x3333333311111111ULL), BITMAP_FROM_U64(0x3333333311111111ULL), };
-static const char large_mask[] __initconst = "33333333,11111111,33333333,11111111," +static const char large_mask[] = "33333333,11111111,33333333,11111111," "33333333,11111111,33333333,11111111," "33333333,11111111,33333333,11111111," "33333333,11111111,33333333,11111111," @@ -1122,7 +1039,7 @@ static const char large_mask[] __initconst = "33333333,11111111,33333333,1111111 "33333333,11111111,33333333,11111111," "33333333,11111111,33333333,11111111\n";
-static const char large_list[] __initconst = /* more than 4KB */ +static const char large_list[] = /* more than 4KB */ "0,4,8,12,16,20,24,28,32-33,36-37,40-41,44-45,48-49,52-53,56-57,60-61,64,68,72,76,80,84,88,92,96-97,100-101,104-1" "05,108-109,112-113,116-117,120-121,124-125,128,132,136,140,144,148,152,156,160-161,164-165,168-169,172-173,176-1" "77,180-181,184-185,188-189,192,196,200,204,208,212,216,220,224-225,228-229,232-233,236-237,240-241,244-245,248-2" @@ -1164,12 +1081,12 @@ static const char large_list[] __initconst = /* more than 4KB */ "2489,2492-2493,2496,2500,2504,2508,2512,2516,2520,2524,2528-2529,2532-2533,2536-2537,2540-2541,2544-2545,2548-25" "49,2552-2553,2556-2557\n";
-static const struct test_bitmap_print test_print[] __initconst = { +static const struct test_bitmap_print test_print[] = { { small_bitmap, sizeof(small_bitmap) * BITS_PER_BYTE, small_mask, small_list }, { large_bitmap, sizeof(large_bitmap) * BITS_PER_BYTE, large_mask, large_list }, };
-static void __init test_bitmap_print_buf(void) +static void test_bitmap_print_buf(void) { int i;
@@ -1201,7 +1118,7 @@ static void __init test_bitmap_print_buf(void) * FIXME: Clang breaks compile-time evaluations when KASAN and GCOV are enabled. * To workaround it, GCOV is force-disabled in Makefile for this configuration. */ -static void __init test_bitmap_const_eval(void) +static void test_bitmap_const_eval(void) { DECLARE_BITMAP(bitmap, BITS_PER_LONG); unsigned long initvar = BIT(2); @@ -1269,7 +1186,7 @@ static void __init test_bitmap_const_eval(void) /* * Helper function to test bitmap_write() overwriting the chosen byte pattern. */ -static void __init test_bitmap_write_helper(const char *pattern) +static void test_bitmap_write_helper(const char *pattern) { DECLARE_BITMAP(bitmap, TEST_BIT_LEN); DECLARE_BITMAP(exp_bitmap, TEST_BIT_LEN); @@ -1323,7 +1240,7 @@ static void __init test_bitmap_write_helper(const char *pattern) } }
-static void __init test_bitmap_read_write(void) +static void test_bitmap_read_write(void) { unsigned char *pattern[3] = {"", "all:1/2", "all"}; DECLARE_BITMAP(bitmap, TEST_BIT_LEN); @@ -1374,8 +1291,10 @@ static void __init test_bitmap_read_write(void)
#undef TEST_BIT_LEN
-static void __init selftest(void) +static void bitmap_test(struct kunit *test) { + kunittest = test; + test_zero_clear(); test_fill_set(); test_copy(); @@ -1406,7 +1325,18 @@ static void __init selftest(void) test_for_each_set_bit_wrap(); }
-KSTM_MODULE_LOADERS(test_bitmap); +static struct kunit_case bitmap_test_cases[] = { + KUNIT_CASE(bitmap_test), + {} +}; + +static struct kunit_suite bitmap_test_suite = { + .name = "bitmap", + .test_cases = bitmap_test_cases, +}; + +kunit_test_suite(bitmap_test_suite); + MODULE_AUTHOR("david decotigny david.decotigny@googlers.com"); MODULE_DESCRIPTION("Test cases for bitmap API"); MODULE_LICENSE("GPL"); diff --git a/tools/testing/selftests/lib/Makefile b/tools/testing/selftests/lib/Makefile index f876bf4744e1..e4617f153542 100644 --- a/tools/testing/selftests/lib/Makefile +++ b/tools/testing/selftests/lib/Makefile @@ -4,5 +4,5 @@ # No binaries, but make sure arg-less "make" doesn't trigger "run_tests" all:
-TEST_PROGS := bitmap.sh +TEST_PROGS := include ../lib.mk diff --git a/tools/testing/selftests/lib/bitmap.sh b/tools/testing/selftests/lib/bitmap.sh deleted file mode 100755 index 00a416fbc0ef..000000000000 --- a/tools/testing/selftests/lib/bitmap.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -# SPDX-License-Identifier: GPL-2.0 -$(dirname $0)/../kselftest/module.sh "bitmap" test_bitmap diff --git a/tools/testing/selftests/lib/config b/tools/testing/selftests/lib/config index 377b3699ff31..3792212895e5 100644 --- a/tools/testing/selftests/lib/config +++ b/tools/testing/selftests/lib/config @@ -1,3 +1,2 @@ -CONFIG_TEST_BITMAP=m CONFIG_PRIME_NUMBERS=m CONFIG_TEST_BITOPS=m
From: Tamir Duberstein tamird@gmail.com
Move individual tests into `bitmap_test_cases`.
Retire the tc_err macro. It was using during migration to reduce churn, but now obscures the opporunity for richer assertion.
Parameterize tests where possible to ensure KUnit assertions produce descriptive messages.
Reduce duplication between `test_bitmap_parse{,list}`. Note that `test_bitmap_parse_fn` is defined out-of-line to reduce churn.
Reviewed-by: David Gow davidgow@google.com Reviewed-by: Muhammad Usama Anjum usama.anjum@collabora.com Signed-off-by: Tamir Duberstein tamird@gmail.com --- lib/bitmap_kunit.c | 388 ++++++++++++++++++++++++++--------------------------- 1 file changed, 191 insertions(+), 197 deletions(-)
diff --git a/lib/bitmap_kunit.c b/lib/bitmap_kunit.c index 3a71e2039c1f..88770a1804cb 100644 --- a/lib/bitmap_kunit.c +++ b/lib/bitmap_kunit.c @@ -10,6 +10,7 @@ #include <linux/printk.h> #include <linux/slab.h> #include <linux/string.h> +#include <linux/string_helpers.h> #include <linux/uaccess.h>
#define EXP1_IN_BITS (sizeof(exp1) * 8) @@ -17,11 +18,6 @@ static char pbl_buffer[PAGE_SIZE]; static char print_buf[PAGE_SIZE * 2];
-static struct kunit *kunittest; - -#define tc_err(fmt, ...) \ - KUNIT_FAIL(kunittest, fmt, ##__VA_ARGS__) - static const unsigned long exp1[] = { BITMAP_FROM_U64(1), BITMAP_FROM_U64(2), @@ -87,16 +83,9 @@ static const unsigned long exp3_1_0[] = { } \ } while (0)
-#define expect_eq_str(exp_str, str, len) \ - { \ - if (strncmp(exp_str, str, len) != 0) { \ - tc_err("expected %s, got %s", exp_str, str); \ - } \ - } - #define expect_eq_uint(x, y) expect_eq_ulong((unsigned int)(x), (unsigned int)(y))
-static void test_zero_clear(void) +static void test_zero_clear(struct kunit *kunittest) { DECLARE_BITMAP(bmap, 1024);
@@ -125,7 +114,7 @@ static void test_zero_clear(void) expect_eq_pbl("", bmap, 1024); }
-static void test_find_nth_bit(void) +static void test_find_nth_bit(struct kunit *kunittest) { unsigned long b, bit, cnt = 0; DECLARE_BITMAP(bmap, 64 * 3); @@ -166,7 +155,7 @@ static void test_find_nth_bit(void) } }
-static void test_fill_set(void) +static void test_fill_set(struct kunit *kunittest) { DECLARE_BITMAP(bmap, 1024);
@@ -195,7 +184,7 @@ static void test_fill_set(void) expect_eq_pbl("0-1023", bmap, 1024); }
-static void test_copy(void) +static void test_copy(struct kunit *kunittest) { DECLARE_BITMAP(bmap1, 1024); DECLARE_BITMAP(bmap2, 1024); @@ -234,7 +223,7 @@ static void test_copy(void) expect_eq_pbl("0-108,128-1023", bmap2, 1024); }
-static void test_bitmap_region(void) +static void test_bitmap_region(struct kunit *kunittest) { int pos, order;
@@ -259,7 +248,7 @@ static void test_bitmap_region(void)
#define EXP2_IN_BITS (sizeof(exp2) * 8)
-static void test_replace(void) +static void test_replace(struct kunit *kunittest) { unsigned int nbits = 64; unsigned int nlongs = DIV_ROUND_UP(nbits, BITS_PER_LONG); @@ -300,7 +289,7 @@ static const unsigned long sg_scatter_exp[] = { BITMAP_FROM_U64(0x000000000000021aULL), };
-static void test_bitmap_sg(void) +static void test_bitmap_sg(struct kunit *kunittest) { unsigned int nbits = 64; DECLARE_BITMAP(bmap_gather, 100); @@ -336,6 +325,19 @@ struct test_bitmap_parselist{ const int flags; };
+static void parselist_to_desc(const struct test_bitmap_parselist *param, char *desc) +{ + int n = 0; + + n += snprintf(desc + n, KUNIT_PARAM_DESC_SIZE - n, """); + n += string_escape_str(param->in, desc + n, KUNIT_PARAM_DESC_SIZE - n, ESCAPE_SPACE, NULL); + n += snprintf(desc + n, KUNIT_PARAM_DESC_SIZE - n, """); +} + +typedef int (*bitmap_parse_fn)(const struct test_bitmap_parselist *test, unsigned long *maskp); + +static void test_bitmap_parse_fn(struct kunit *kunittest, bitmap_parse_fn fn); + static const struct test_bitmap_parselist parselist_tests[] = { #define step (sizeof(u64) / sizeof(unsigned long))
@@ -421,76 +423,60 @@ static const struct test_bitmap_parselist parselist_tests[] = {
};
-static void test_bitmap_parselist(void) +KUNIT_ARRAY_PARAM(test_parselist, parselist_tests, parselist_to_desc); + +static int do_bitmap_parselist(const struct test_bitmap_parselist *test, unsigned long *maskp) { - int i; + return bitmap_parselist(test->in, maskp, test->nbits); +} + +static void test_bitmap_parselist(struct kunit *kunittest) +{ + test_bitmap_parse_fn(kunittest, do_bitmap_parselist); +} + +static void test_bitmap_parse_fn(struct kunit *kunittest, bitmap_parse_fn fn) +{ + const struct test_bitmap_parselist *t = kunittest->param_value; int err; ktime_t time; DECLARE_BITMAP(bmap, 2048);
- for (i = 0; i < ARRAY_SIZE(parselist_tests); i++) { -#define ptest parselist_tests[i] - - time = ktime_get(); - err = bitmap_parselist(ptest.in, bmap, ptest.nbits); - time = ktime_get() - time; - - if (err != ptest.errno) { - tc_err("parselist: %d: input is %s, errno is %d, expected %d", - i, ptest.in, err, ptest.errno); - continue; - } - - if (!err && ptest.expected - && !__bitmap_equal(bmap, ptest.expected, ptest.nbits)) { - tc_err("parselist: %d: input is %s, result is 0x%lx, expected 0x%lx", - i, ptest.in, bmap[0], - *ptest.expected); - continue; - } + time = ktime_get(); + err = fn(t, bmap); + time = ktime_get() - time;
- if (ptest.flags & PARSE_TIME) - kunit_info(kunittest, "parselist: %d: input is '%s' OK, Time: %llu", - i, ptest.in, time); + KUNIT_ASSERT_EQ(kunittest, err, t->errno);
-#undef ptest + if (!err && t->expected && !__bitmap_equal(bmap, t->expected, t->nbits)) { + KUNIT_FAIL_AND_ABORT(kunittest, + "result is 0x%lx, expected 0x%lx", bmap[0], *t->expected); } + + if (t->flags & PARSE_TIME) + kunit_info(kunittest, "Time: %llu", time); }
-static void test_bitmap_printlist(void) +static void test_bitmap_printlist(struct kunit *kunittest) { - unsigned long *bmap = kmalloc(PAGE_SIZE, GFP_KERNEL); - char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); + static long bmap[PAGE_SIZE]; + static char buf[PAGE_SIZE]; char expected[256]; int ret, slen; ktime_t time;
- if (!buf || !bmap) - goto out; - memset(bmap, -1, PAGE_SIZE); - slen = snprintf(expected, 256, "0-%ld", PAGE_SIZE * 8 - 1); - if (slen < 0) - goto out; + slen = snprintf(expected, sizeof(expected), "0-%ld\n", PAGE_SIZE * 8 - 1); + KUNIT_ASSERT_GT(kunittest, slen, 0);
time = ktime_get(); ret = bitmap_print_to_pagebuf(true, buf, bmap, PAGE_SIZE * 8); time = ktime_get() - time;
- if (ret != slen + 1) { - tc_err("bitmap_print_to_pagebuf: result is %d, expected %d", ret, slen); - goto out; - } - - if (strncmp(buf, expected, slen)) { - tc_err("bitmap_print_to_pagebuf: result is %s, expected %s", buf, expected); - goto out; - } + KUNIT_ASSERT_EQ(kunittest, ret, slen); + KUNIT_ASSERT_STREQ(kunittest, buf, expected);
- kunit_info(kunittest, "bitmap_print_to_pagebuf: input is '%s', Time: %llu", buf, time); -out: - kfree(buf); - kfree(bmap); + kunit_info(kunittest, "Time: %llu", time); }
static const unsigned long parse_test[] = { @@ -533,42 +519,21 @@ static const struct test_bitmap_parselist parse_tests[] = { #undef step };
-static void test_bitmap_parse(void) -{ - int i; - int err; - ktime_t time; - DECLARE_BITMAP(bmap, 2048); - - for (i = 0; i < ARRAY_SIZE(parse_tests); i++) { - struct test_bitmap_parselist test = parse_tests[i]; - size_t len = test.flags & NO_LEN ? UINT_MAX : strlen(test.in); - - time = ktime_get(); - err = bitmap_parse(test.in, len, bmap, test.nbits); - time = ktime_get() - time; +KUNIT_ARRAY_PARAM(test_parse, parse_tests, parselist_to_desc);
- if (err != test.errno) { - tc_err("parse: %d: input is %s, errno is %d, expected %d", - i, test.in, err, test.errno); - continue; - } +static int do_bitmap_parse(const struct test_bitmap_parselist *test, unsigned long *maskp) +{ + const size_t len = test->flags & NO_LEN ? UINT_MAX : strlen(test->in);
- if (!err && test.expected - && !__bitmap_equal(bmap, test.expected, test.nbits)) { - tc_err("parse: %d: input is %s, result is 0x%lx, expected 0x%lx", - i, test.in, bmap[0], - *test.expected); - continue; - } + return bitmap_parse(test->in, len, maskp, test->nbits); +}
- if (test.flags & PARSE_TIME) - kunit_info(kunittest, "parse: %d: input is '%s' OK, Time: %llu", - i, test.in, time); - } +static void test_bitmap_parse(struct kunit *kunittest) +{ + test_bitmap_parse_fn(kunittest, do_bitmap_parse); }
-static void test_bitmap_arr32(void) +static void test_bitmap_arr32(struct kunit *kunittest) { unsigned int nbits, next_bit; u32 arr[EXP1_IN_BITS / 32]; @@ -584,8 +549,9 @@ static void test_bitmap_arr32(void) next_bit = find_next_bit(bmap2, round_up(nbits, BITS_PER_LONG), nbits); if (next_bit < round_up(nbits, BITS_PER_LONG)) { - tc_err("bitmap_copy_arr32(nbits == %d: tail is not safely cleared: %d", - nbits, next_bit); + KUNIT_FAIL(kunittest, + "bitmap_copy_arr32(nbits == %d: tail is not safely cleared: %d", + nbits, next_bit); }
if (nbits < EXP1_IN_BITS - 32) @@ -594,7 +560,7 @@ static void test_bitmap_arr32(void) } }
-static void test_bitmap_arr64(void) +static void test_bitmap_arr64(struct kunit *kunittest) { unsigned int nbits, next_bit; u64 arr[EXP1_IN_BITS / 64]; @@ -610,15 +576,16 @@ static void test_bitmap_arr64(void)
next_bit = find_next_bit(bmap2, round_up(nbits, BITS_PER_LONG), nbits); if (next_bit < round_up(nbits, BITS_PER_LONG)) { - tc_err("bitmap_copy_arr64(nbits == %d: tail is not safely cleared: %d", - nbits, next_bit); + KUNIT_FAIL(kunittest, + "bitmap_copy_arr64(nbits == %d: tail is not safely cleared: %d", + nbits, next_bit); }
if ((nbits % 64) && (arr[(nbits - 1) / 64] & ~GENMASK_ULL((nbits - 1) % 64, 0))) { - tc_err("bitmap_to_arr64(nbits == %d): tail is not safely cleared: 0x%016llx (must be 0x%016llx)", - nbits, arr[(nbits - 1) / 64], - GENMASK_ULL((nbits - 1) % 64, 0)); + KUNIT_FAIL(kunittest, + "bitmap_to_arr64(nbits == %d): tail is not safely cleared: 0x%016llx (must be 0x%016llx)", + nbits, arr[(nbits - 1) / 64], GENMASK_ULL((nbits - 1) % 64, 0)); }
if (nbits < EXP1_IN_BITS - 64) @@ -626,7 +593,7 @@ static void test_bitmap_arr64(void) } }
-static noinline void test_mem_optimisations(void) +static noinline void test_mem_optimisations(struct kunit *kunittest) { DECLARE_BITMAP(bmap1, 1024); DECLARE_BITMAP(bmap2, 1024); @@ -640,19 +607,19 @@ static noinline void test_mem_optimisations(void) bitmap_set(bmap1, start, nbits); __bitmap_set(bmap2, start, nbits); if (!bitmap_equal(bmap1, bmap2, 1024)) { - tc_err("set not equal %d %d", start, nbits); + KUNIT_FAIL(kunittest, "set not equal %d %d", start, nbits); } if (!__bitmap_equal(bmap1, bmap2, 1024)) { - tc_err("set not __equal %d %d", start, nbits); + KUNIT_FAIL(kunittest, "set not __equal %d %d", start, nbits); }
bitmap_clear(bmap1, start, nbits); __bitmap_clear(bmap2, start, nbits); if (!bitmap_equal(bmap1, bmap2, 1024)) { - tc_err("clear not equal %d %d", start, nbits); + KUNIT_FAIL(kunittest, "clear not equal %d %d", start, nbits); } if (!__bitmap_equal(bmap1, bmap2, 1024)) { - tc_err("clear not __equal %d %d", start, nbits); + KUNIT_FAIL(kunittest, "clear not __equal %d %d", start, nbits); } } } @@ -669,7 +636,7 @@ static const unsigned char clump_exp[] = { 0x05, /* non-adjacent 2 bits set */ };
-static void test_for_each_set_clump8(void) +static void test_for_each_set_clump8(struct kunit *kunittest) { #define CLUMP_EXP_NUMBITS 64 DECLARE_BITMAP(bits, CLUMP_EXP_NUMBITS); @@ -691,7 +658,7 @@ static void test_for_each_set_clump8(void) expect_eq_clump8(start, CLUMP_EXP_NUMBITS, clump_exp, &clump); }
-static void test_for_each_set_bit_wrap(void) +static void test_for_each_set_bit_wrap(struct kunit *kunittest) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -716,7 +683,7 @@ static void test_for_each_set_bit_wrap(void) } }
-static void test_for_each_set_bit(void) +static void test_for_each_set_bit(struct kunit *kunittest) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -738,7 +705,7 @@ static void test_for_each_set_bit(void) expect_eq_bitmap(orig, copy, 500); }
-static void test_for_each_set_bit_from(void) +static void test_for_each_set_bit_from(struct kunit *kunittest) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -768,7 +735,7 @@ static void test_for_each_set_bit_from(void) } }
-static void test_for_each_clear_bit(void) +static void test_for_each_clear_bit(struct kunit *kunittest) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -790,7 +757,7 @@ static void test_for_each_clear_bit(void) expect_eq_bitmap(orig, copy, 500); }
-static void test_for_each_clear_bit_from(void) +static void test_for_each_clear_bit_from(struct kunit *kunittest) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -820,7 +787,7 @@ static void test_for_each_clear_bit_from(void) } }
-static void test_for_each_set_bitrange(void) +static void test_for_each_set_bitrange(struct kunit *kunittest) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -842,7 +809,7 @@ static void test_for_each_set_bitrange(void) expect_eq_bitmap(orig, copy, 500); }
-static void test_for_each_clear_bitrange(void) +static void test_for_each_clear_bitrange(struct kunit *kunittest) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -864,7 +831,7 @@ static void test_for_each_clear_bitrange(void) expect_eq_bitmap(orig, copy, 500); }
-static void test_for_each_set_bitrange_from(void) +static void test_for_each_set_bitrange_from(struct kunit *kunittest) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -894,7 +861,7 @@ static void test_for_each_set_bitrange_from(void) } }
-static void test_for_each_clear_bitrange_from(void) +static void test_for_each_clear_bitrange_from(struct kunit *kunittest) { DECLARE_BITMAP(orig, 500); DECLARE_BITMAP(copy, 500); @@ -965,20 +932,50 @@ static struct test_bitmap_cut test_cut[] = { }, };
-static void test_bitmap_cut(void) +static void cut_to_desc(struct test_bitmap_cut *param, char * const desc) { - unsigned long b[5], *in = &b[1], *out = &b[0]; /* Partial overlap */ + int n = 0; int i;
- for (i = 0; i < ARRAY_SIZE(test_cut); i++) { - struct test_bitmap_cut *t = &test_cut[i]; + #define append(...) (n += snprintf(desc + n, KUNIT_PARAM_DESC_SIZE - n, ##__VA_ARGS__)) + + append("first=%d,cut=%d,nbits=%d", param->first, param->cut, param->nbits); + + #define append_array(name) do { \ + { \ + append("," #name "={"); \ + for (i = 0; i < ARRAY_SIZE(param->name); i++) { \ + if (param->name[i] == 0) { \ + break; \ + } \ + if (i != 0) { \ + append(","); \ + } \ + append("0x%08lxUL", param->name[i]); \ + } \ + append("}"); \ + } \ + } while (0)
- memcpy(in, t->in, sizeof(t->in)); + append_array(in); + append_array(expected);
- bitmap_cut(out, in, t->first, t->cut, t->nbits); + #undef append_array + #undef append +}
- expect_eq_bitmap(t->expected, out, t->nbits); - } +KUNIT_ARRAY_PARAM(test_cut, test_cut, cut_to_desc); + +static void test_bitmap_cut(struct kunit *kunittest) +{ + const struct test_bitmap_cut *t = kunittest->param_value; + unsigned long b[5], *in = &b[1], *out = &b[0]; /* Partial overlap */ + + memcpy(in, t->in, sizeof(t->in)); + + bitmap_cut(out, in, t->first, t->cut, t->nbits); + + expect_eq_bitmap(t->expected, out, t->nbits); }
struct test_bitmap_print { @@ -986,6 +983,7 @@ struct test_bitmap_print { unsigned long nbits; const char *mask; const char *list; + const char *name; };
static const unsigned long small_bitmap[] = { @@ -1082,35 +1080,33 @@ static const char large_list[] = /* more than 4KB */ "49,2552-2553,2556-2557\n";
static const struct test_bitmap_print test_print[] = { - { small_bitmap, sizeof(small_bitmap) * BITS_PER_BYTE, small_mask, small_list }, - { large_bitmap, sizeof(large_bitmap) * BITS_PER_BYTE, large_mask, large_list }, + { small_bitmap, sizeof(small_bitmap) * BITS_PER_BYTE, small_mask, small_list, "small" }, + { large_bitmap, sizeof(large_bitmap) * BITS_PER_BYTE, large_mask, large_list, "large" }, };
-static void test_bitmap_print_buf(void) +KUNIT_ARRAY_PARAM_DESC(test_print, test_print, name); + +static void test_bitmap_print_buf(struct kunit *kunittest) { - int i; + const struct test_bitmap_print *t = kunittest->param_value; + int n;
- for (i = 0; i < ARRAY_SIZE(test_print); i++) { - const struct test_bitmap_print *t = &test_print[i]; - int n; + n = bitmap_print_bitmask_to_buf(print_buf, t->bitmap, t->nbits, + 0, 2 * PAGE_SIZE); + expect_eq_uint(strlen(t->mask) + 1, n); + KUNIT_EXPECT_STREQ(kunittest, t->mask, print_buf);
- n = bitmap_print_bitmask_to_buf(print_buf, t->bitmap, t->nbits, - 0, 2 * PAGE_SIZE); - expect_eq_uint(strlen(t->mask) + 1, n); - expect_eq_str(t->mask, print_buf, n); + n = bitmap_print_list_to_buf(print_buf, t->bitmap, t->nbits, + 0, 2 * PAGE_SIZE); + expect_eq_uint(strlen(t->list) + 1, n); + KUNIT_EXPECT_STREQ(kunittest, t->list, print_buf);
+ /* test by non-zero offset */ + if (strlen(t->list) > PAGE_SIZE) { n = bitmap_print_list_to_buf(print_buf, t->bitmap, t->nbits, - 0, 2 * PAGE_SIZE); - expect_eq_uint(strlen(t->list) + 1, n); - expect_eq_str(t->list, print_buf, n); - - /* test by non-zero offset */ - if (strlen(t->list) > PAGE_SIZE) { - n = bitmap_print_list_to_buf(print_buf, t->bitmap, t->nbits, - PAGE_SIZE, PAGE_SIZE); - expect_eq_uint(strlen(t->list) + 1 - PAGE_SIZE, n); - expect_eq_str(t->list + PAGE_SIZE, print_buf, n); - } + PAGE_SIZE, PAGE_SIZE); + expect_eq_uint(strlen(t->list) + 1 - PAGE_SIZE, n); + KUNIT_EXPECT_STREQ(kunittest, t->list + PAGE_SIZE, print_buf); } }
@@ -1118,7 +1114,7 @@ static void test_bitmap_print_buf(void) * FIXME: Clang breaks compile-time evaluations when KASAN and GCOV are enabled. * To workaround it, GCOV is force-disabled in Makefile for this configuration. */ -static void test_bitmap_const_eval(void) +static void test_bitmap_const_eval(struct kunit *kunittest) { DECLARE_BITMAP(bitmap, BITS_PER_LONG); unsigned long initvar = BIT(2); @@ -1183,11 +1179,19 @@ static void test_bitmap_const_eval(void) */ #define TEST_BIT_LEN (1000)
-/* - * Helper function to test bitmap_write() overwriting the chosen byte pattern. - */ -static void test_bitmap_write_helper(const char *pattern) +static const char * const pattern[] = {"", "all:1/2", "all"}; + +static void pattern_to_desc(const char * const *param, char *desc) { + snprintf(desc, KUNIT_PARAM_DESC_SIZE, ""%s"", *param); +} + +KUNIT_ARRAY_PARAM(pattern, pattern, pattern_to_desc); + +static void test_bitmap_write_pattern(struct kunit *kunittest) +{ + const char * const *p = kunittest->param_value; + const char *pattern = *p; DECLARE_BITMAP(bitmap, TEST_BIT_LEN); DECLARE_BITMAP(exp_bitmap, TEST_BIT_LEN); DECLARE_BITMAP(pat_bitmap, TEST_BIT_LEN); @@ -1240,13 +1244,12 @@ static void test_bitmap_write_helper(const char *pattern) } }
-static void test_bitmap_read_write(void) +static void test_bitmap_read_write(struct kunit *kunittest) { - 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; + int i;
/* * Reading/writing zero bits should not crash the kernel. @@ -1284,49 +1287,40 @@ static void test_bitmap_read_write(void) 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]); }
#undef TEST_BIT_LEN
-static void bitmap_test(struct kunit *test) -{ - kunittest = test; - - test_zero_clear(); - test_fill_set(); - test_copy(); - test_bitmap_region(); - test_replace(); - test_bitmap_sg(); - test_bitmap_arr32(); - test_bitmap_arr64(); - test_bitmap_parse(); - test_bitmap_parselist(); - test_bitmap_printlist(); - test_mem_optimisations(); - test_bitmap_cut(); - test_bitmap_print_buf(); - test_bitmap_const_eval(); - test_bitmap_read_write(); - - test_find_nth_bit(); - test_for_each_set_bit(); - test_for_each_set_bit_from(); - test_for_each_clear_bit(); - test_for_each_clear_bit_from(); - test_for_each_set_bitrange(); - test_for_each_clear_bitrange(); - test_for_each_set_bitrange_from(); - test_for_each_clear_bitrange_from(); - test_for_each_set_clump8(); - test_for_each_set_bit_wrap(); -} - static struct kunit_case bitmap_test_cases[] = { - KUNIT_CASE(bitmap_test), + KUNIT_CASE(test_zero_clear), + KUNIT_CASE(test_fill_set), + KUNIT_CASE(test_copy), + KUNIT_CASE(test_bitmap_region), + KUNIT_CASE(test_replace), + KUNIT_CASE(test_bitmap_sg), + KUNIT_CASE(test_bitmap_arr32), + KUNIT_CASE(test_bitmap_arr64), + KUNIT_CASE_PARAM(test_bitmap_parse, test_parse_gen_params), + KUNIT_CASE_PARAM(test_bitmap_parselist, test_parselist_gen_params), + KUNIT_CASE(test_bitmap_printlist), + KUNIT_CASE(test_mem_optimisations), + KUNIT_CASE_PARAM(test_bitmap_cut, test_cut_gen_params), + KUNIT_CASE_PARAM(test_bitmap_print_buf, test_print_gen_params), + KUNIT_CASE(test_bitmap_const_eval), + KUNIT_CASE(test_bitmap_read_write), + KUNIT_CASE_PARAM(test_bitmap_write_pattern, pattern_gen_params), + + KUNIT_CASE(test_find_nth_bit), + KUNIT_CASE(test_for_each_set_bit), + KUNIT_CASE(test_for_each_set_bit_from), + KUNIT_CASE(test_for_each_clear_bit), + KUNIT_CASE(test_for_each_clear_bit_from), + KUNIT_CASE(test_for_each_set_bitrange), + KUNIT_CASE(test_for_each_clear_bitrange), + KUNIT_CASE(test_for_each_set_bitrange_from), + KUNIT_CASE(test_for_each_clear_bitrange_from), + KUNIT_CASE(test_for_each_set_clump8), + KUNIT_CASE(test_for_each_set_bit_wrap), {} };
linux-kselftest-mirror@lists.linaro.org