linux-kselftest.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/5] test_hash.c: refactor into KUnit
@ 2021-09-26 22:33 Isabella Basso
  2021-09-26 22:33 ` [PATCH v2 1/5] hash.h: remove unused define directive Isabella Basso
                   ` (5 more replies)
  0 siblings, 6 replies; 20+ messages in thread
From: Isabella Basso @ 2021-09-26 22:33 UTC (permalink / raw)
  To: geert
  Cc: ferreiraenzoa, augusto.duraes33, brendanhiggins, dlatypov,
	davidgow, linux-kselftest, linux-kernel, kunit-dev,
	~lkcamp/patches, rodrigosiqueiramelo, Isabella Basso

We refactored the lib/test_hash.c file into KUnit as part of the student
group LKCAMP [1] introductory hackathon for kernel development.

This test was pointed to our group by Daniel Latypov [2], so its full
conversion into a pure KUnit test was our goal in this patch series, but
we ran into many problems relating to it not being split as unit tests,
which complicated matters a bit, as the reasoning behind the original
tests is quite cryptic for those unfamiliar with hash implementations.

Some interesting developments we'd like to highlight are:

- In patch 1/5 we noticed that there was an unused define directive that
  could be removed.
- In patch 4/5 we noticed how stringhash and hash tests are all under
  the lib/test_hash.c file, which might cause some confusion, and we
  also broke those kernel config entries up.

Overall KUnit developments have been made in the other patches in this
series:

In patches 2/5, 3/5 and 5/5 we refactored the lib/test_hash.c
file so as to make it more compatible with the KUnit style, whilst
preserving the original idea of the maintainer who designed it (i.e.
George Spelvin), which might be undesirable for unit tests, but we
assume it is enough for a first patch.

This is our first patch series so we hope our contributions are
interesting and also hope to get some useful criticism from the
community. :)

Changes since V1:
- Fixed compilation on parisc and m68k.
- Fixed whitespace mistakes.
- Renamed a few functions.
- Refactored globals into struct for test function params, thus removing
  a patch. 
- Reworded some commit messages.

[1] - https://lkcamp.dev/
[2] - https://lore.kernel.org/linux-kselftest/CAGS_qxojszgM19u=3HLwFgKX5bm5KhywvsSunuBAt5RtR+GyxQ@mail.gmail.com/

Isabella Basso (5):
  hash.h: remove unused define directive
  test_hash.c: split test_int_hash into arch-specific functions
  test_hash.c: split test_hash_init
  lib/Kconfig.debug: properly split hash test kernel entries
  test_hash.c: refactor into kunit

 include/linux/hash.h       |   5 +-
 lib/Kconfig.debug          |  28 ++++-
 lib/Makefile               |   3 +-
 lib/test_hash.c            | 247 +++++++++++++++++--------------------
 tools/include/linux/hash.h |   5 +-
 5 files changed, 139 insertions(+), 149 deletions(-)

-- 
2.33.0


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

* [PATCH v2 1/5] hash.h: remove unused define directive
  2021-09-26 22:33 [PATCH v2 0/5] test_hash.c: refactor into KUnit Isabella Basso
@ 2021-09-26 22:33 ` Isabella Basso
  2021-10-02  7:19   ` David Gow
  2021-09-26 22:33 ` [PATCH v2 2/5] test_hash.c: split test_int_hash into arch-specific functions Isabella Basso
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 20+ messages in thread
From: Isabella Basso @ 2021-09-26 22:33 UTC (permalink / raw)
  To: geert
  Cc: ferreiraenzoa, augusto.duraes33, brendanhiggins, dlatypov,
	davidgow, linux-kselftest, linux-kernel, kunit-dev,
	~lkcamp/patches, rodrigosiqueiramelo, Isabella Basso

Currently, there exist hash_32() and __hash_32() functions, which were
introduced in a patch [1] targeting architecture specific optimizations.
These functions can be overridden on a per-architecture basis to achieve
such optimizations. They must set their corresponding define directive
(HAVE_ARCH_HASH_32 and HAVE_ARCH__HASH_32, respectively) so that header
files can deal with these overrides properly.

As the supported 32-bit architectures that have their own hash function
implementation (i.e. m68k, Microblaze, H8/300, pa-risc) have only been
making use of the (more general) __hash_32() function (which only lacks
a right shift operation when compared to the hash_32() function),
remove the define directive corresponding to the arch-specific hash_32()
implementation.

[1] https://lore.kernel.org/lkml/20160525073311.5600.qmail@ns.sciencehorizons.net/

Changes since v1:
- As suggested by David Gow:
  1. Reword commit message.

Tested-by: David Gow <davidgow@google.com>
Co-developed-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
Signed-off-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
Co-developed-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
Signed-off-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
---
 include/linux/hash.h       |  5 +----
 lib/test_hash.c            | 24 +-----------------------
 tools/include/linux/hash.h |  5 +----
 3 files changed, 3 insertions(+), 31 deletions(-)

diff --git a/include/linux/hash.h b/include/linux/hash.h
index ad6fa21d977b..38edaa08f862 100644
--- a/include/linux/hash.h
+++ b/include/linux/hash.h
@@ -62,10 +62,7 @@ static inline u32 __hash_32_generic(u32 val)
 	return val * GOLDEN_RATIO_32;
 }
 
-#ifndef HAVE_ARCH_HASH_32
-#define hash_32 hash_32_generic
-#endif
-static inline u32 hash_32_generic(u32 val, unsigned int bits)
+static inline u32 hash_32(u32 val, unsigned int bits)
 {
 	/* High bits are more random, so use them. */
 	return __hash_32(val) >> (32 - bits);
diff --git a/lib/test_hash.c b/lib/test_hash.c
index 0ee40b4a56dd..d4b0cfdb0377 100644
--- a/lib/test_hash.c
+++ b/lib/test_hash.c
@@ -94,22 +94,7 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
 			pr_err("hash_32(%#x, %d) = %#x > %#x", h0, k, h1, m);
 			return false;
 		}
-#ifdef HAVE_ARCH_HASH_32
-		h2 = hash_32_generic(h0, k);
-#if HAVE_ARCH_HASH_32 == 1
-		if (h1 != h2) {
-			pr_err("hash_32(%#x, %d) = %#x != hash_32_generic() "
-				" = %#x", h0, k, h1, h2);
-			return false;
-		}
-#else
-		if (h2 > m) {
-			pr_err("hash_32_generic(%#x, %d) = %#x > %#x",
-				h0, k, h1, m);
-			return false;
-		}
-#endif
-#endif
+
 		/* Test hash_64 */
 		hash_or[1][k] |= h1 = hash_64(h64, k);
 		if (h1 > m) {
@@ -227,13 +212,6 @@ test_hash_init(void)
 #else
 	pr_info("__hash_32() has no arch implementation to test.");
 #endif
-#ifdef HAVE_ARCH_HASH_32
-#if HAVE_ARCH_HASH_32 != 1
-	pr_info("hash_32() is arch-specific; not compared to generic.");
-#endif
-#else
-	pr_info("hash_32() has no arch implementation to test.");
-#endif
 #ifdef HAVE_ARCH_HASH_64
 #if HAVE_ARCH_HASH_64 != 1
 	pr_info("hash_64() is arch-specific; not compared to generic.");
diff --git a/tools/include/linux/hash.h b/tools/include/linux/hash.h
index ad6fa21d977b..38edaa08f862 100644
--- a/tools/include/linux/hash.h
+++ b/tools/include/linux/hash.h
@@ -62,10 +62,7 @@ static inline u32 __hash_32_generic(u32 val)
 	return val * GOLDEN_RATIO_32;
 }
 
-#ifndef HAVE_ARCH_HASH_32
-#define hash_32 hash_32_generic
-#endif
-static inline u32 hash_32_generic(u32 val, unsigned int bits)
+static inline u32 hash_32(u32 val, unsigned int bits)
 {
 	/* High bits are more random, so use them. */
 	return __hash_32(val) >> (32 - bits);
-- 
2.33.0


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

* [PATCH v2 2/5] test_hash.c: split test_int_hash into arch-specific functions
  2021-09-26 22:33 [PATCH v2 0/5] test_hash.c: refactor into KUnit Isabella Basso
  2021-09-26 22:33 ` [PATCH v2 1/5] hash.h: remove unused define directive Isabella Basso
@ 2021-09-26 22:33 ` Isabella Basso
  2021-10-02  7:20   ` David Gow
  2021-09-26 22:33 ` [PATCH v2 3/5] test_hash.c: split test_hash_init Isabella Basso
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 20+ messages in thread
From: Isabella Basso @ 2021-09-26 22:33 UTC (permalink / raw)
  To: geert
  Cc: ferreiraenzoa, augusto.duraes33, brendanhiggins, dlatypov,
	davidgow, linux-kselftest, linux-kernel, kunit-dev,
	~lkcamp/patches, rodrigosiqueiramelo, Isabella Basso

Split the test_int_hash function to keep its mainloop separate from
arch-specific chunks, which are only compiled as needed. This aims at
improving readability.

Tested-by: David Gow <davidgow@google.com>
Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
---
 lib/test_hash.c | 86 ++++++++++++++++++++++++++++++++-----------------
 1 file changed, 57 insertions(+), 29 deletions(-)

diff --git a/lib/test_hash.c b/lib/test_hash.c
index d4b0cfdb0377..08fe63776c4f 100644
--- a/lib/test_hash.c
+++ b/lib/test_hash.c
@@ -56,6 +56,53 @@ fill_buf(char *buf, size_t len, u32 seed)
 	}
 }
 
+/* Holds most testing variables for the int test */
+struct test_hash_params {
+	unsigned long long *h64;
+	u32 h0;
+	u32 h1;
+	u32 h2;
+	u32 (*hash_or)[33];
+};
+
+#ifdef HAVE_ARCH__HASH_32
+static bool __init
+test_int__hash_32(struct test_hash_params *params)
+{
+	params->hash_or[1][0] |= params->h2 = __hash_32_generic(params->h0);
+#if HAVE_ARCH__HASH_32 == 1
+	if (params->h1 != params->h2) {
+		pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
+		       params->h0, params->h1, params->h2);
+		return false;
+	}
+#endif
+	return true;
+}
+#endif
+
+#ifdef HAVE_ARCH_HASH_64
+static bool __init
+test_int_hash_64(struct test_hash_params *params, u32 const *m, int *k)
+{
+	params->h2 = hash_64_generic(*params->h64, *k);
+#if HAVE_ARCH_HASH_64 == 1
+	if (params->h1 != params->h2) {
+		pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() = %#x",
+		       *params->h64, *k, params->h1, params->h2);
+		return false;
+	}
+#else
+	if (params->h2 > *m) {
+		pr_err("hash_64_generic(%#llx, %d) = %#x > %#x",
+		       *params->h64, *k, params->h1, *m);
+		return false;
+	}
+#endif
+	return true;
+}
+#endif
+
 /*
  * Test the various integer hash functions.  h64 (or its low-order bits)
  * is the integer to hash.  hash_or accumulates the OR of the hash values,
@@ -69,19 +116,13 @@ static bool __init
 test_int_hash(unsigned long long h64, u32 hash_or[2][33])
 {
 	int k;
-	u32 h0 = (u32)h64, h1, h2;
+	struct test_hash_params params = { &h64, (u32)h64, 0, 0, hash_or };
 
 	/* Test __hash32 */
-	hash_or[0][0] |= h1 = __hash_32(h0);
+	hash_or[0][0] |= params.h1 = __hash_32(params.h0);
 #ifdef HAVE_ARCH__HASH_32
-	hash_or[1][0] |= h2 = __hash_32_generic(h0);
-#if HAVE_ARCH__HASH_32 == 1
-	if (h1 != h2) {
-		pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
-			h0, h1, h2);
+	if (!test_int__hash_32(&params))
 		return false;
-	}
-#endif
 #endif
 
 	/* Test k = 1..32 bits */
@@ -89,37 +130,24 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
 		u32 const m = ((u32)2 << (k-1)) - 1;	/* Low k bits set */
 
 		/* Test hash_32 */
-		hash_or[0][k] |= h1 = hash_32(h0, k);
-		if (h1 > m) {
-			pr_err("hash_32(%#x, %d) = %#x > %#x", h0, k, h1, m);
+		hash_or[0][k] |= params.h1 = hash_32(params.h0, k);
+		if (params.h1 > m) {
+			pr_err("hash_32(%#x, %d) = %#x > %#x", params.h0, k, params.h1, m);
 			return false;
 		}
 
 		/* Test hash_64 */
-		hash_or[1][k] |= h1 = hash_64(h64, k);
-		if (h1 > m) {
-			pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, h1, m);
+		hash_or[1][k] |= params.h1 = hash_64(h64, k);
+		if (params.h1 > m) {
+			pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, params.h1, m);
 			return false;
 		}
 #ifdef HAVE_ARCH_HASH_64
-		h2 = hash_64_generic(h64, k);
-#if HAVE_ARCH_HASH_64 == 1
-		if (h1 != h2) {
-			pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() "
-				"= %#x", h64, k, h1, h2);
+		if (!test_int_hash_64(&params, &m, &k))
 			return false;
-		}
-#else
-		if (h2 > m) {
-			pr_err("hash_64_generic(%#llx, %d) = %#x > %#x",
-				h64, k, h1, m);
-			return false;
-		}
-#endif
 #endif
 	}
 
-	(void)h2;	/* Suppress unused variable warning */
 	return true;
 }
 
-- 
2.33.0


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

* [PATCH v2 3/5] test_hash.c: split test_hash_init
  2021-09-26 22:33 [PATCH v2 0/5] test_hash.c: refactor into KUnit Isabella Basso
  2021-09-26 22:33 ` [PATCH v2 1/5] hash.h: remove unused define directive Isabella Basso
  2021-09-26 22:33 ` [PATCH v2 2/5] test_hash.c: split test_int_hash into arch-specific functions Isabella Basso
@ 2021-09-26 22:33 ` Isabella Basso
  2021-09-27  8:17   ` Marco Elver
  2021-10-02  7:20   ` David Gow
  2021-09-26 22:33 ` [PATCH v2 4/5] lib/Kconfig.debug: properly split hash test kernel entries Isabella Basso
                   ` (2 subsequent siblings)
  5 siblings, 2 replies; 20+ messages in thread
From: Isabella Basso @ 2021-09-26 22:33 UTC (permalink / raw)
  To: geert
  Cc: ferreiraenzoa, augusto.duraes33, brendanhiggins, dlatypov,
	davidgow, linux-kselftest, linux-kernel, kunit-dev,
	~lkcamp/patches, rodrigosiqueiramelo, Isabella Basso

Split up test_hash_init so that it calls each test more explicitly
insofar it is possible without rewriting the entire file. This aims at
improving readability.

Split tests performed on string_or as they don't interfere with those
performed in hash_or. Also separate pr_info calls about skipped tests as
they're not part of the tests themselves, but only warn about
(un)defined arch-specific hash functions.

Changes since v1:
- As suggested by David Gow:
  1. Rename arch-specific test functions.
  2. Remove spare whitespace changes.
- As suggested by Marco Elver:
  1. Add struct for carrying test variables.

Tested-by: David Gow <davidgow@google.com>
Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
---
 lib/test_hash.c | 66 ++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 54 insertions(+), 12 deletions(-)

diff --git a/lib/test_hash.c b/lib/test_hash.c
index 08fe63776c4f..db9dd18b4e8b 100644
--- a/lib/test_hash.c
+++ b/lib/test_hash.c
@@ -153,11 +153,39 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
 
 #define SIZE 256	/* Run time is cubic in SIZE */
 
-static int __init
-test_hash_init(void)
+static int __init test_string_or(void)
 {
 	char buf[SIZE+1];
-	u32 string_or = 0, hash_or[2][33] = { { 0, } };
+	u32 string_or = 0;
+	int i, j;
+
+	fill_buf(buf, SIZE, 1);
+
+	/* Test every possible non-empty substring in the buffer. */
+	for (j = SIZE; j > 0; --j) {
+		buf[j] = '\0';
+
+		for (i = 0; i <= j; i++) {
+			u32 h0 = full_name_hash(buf+i, buf+i, j-i);
+
+			string_or |= h0;
+		} /* i */
+	} /* j */
+
+	/* The OR of all the hash values should cover all the bits */
+	if (~string_or) {
+		pr_err("OR of all string hash results = %#x != %#x",
+		       string_or, -1u);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int __init test_hash_or(void)
+{
+	char buf[SIZE+1];
+	u32 hash_or[2][33] = { { 0, } };
 	unsigned tests = 0;
 	unsigned long long h64 = 0;
 	int i, j;
@@ -187,7 +215,6 @@ test_hash_init(void)
 				return -EINVAL;
 			}
 
-			string_or |= h0;
 			h64 = h64 << 32 | h0;	/* For use with hash_64 */
 			if (!test_int_hash(h64, hash_or))
 				return -EINVAL;
@@ -195,12 +222,6 @@ test_hash_init(void)
 		} /* i */
 	} /* j */
 
-	/* The OR of all the hash values should cover all the bits */
-	if (~string_or) {
-		pr_err("OR of all string hash results = %#x != %#x",
-			string_or, -1u);
-		return -EINVAL;
-	}
 	if (~hash_or[0][0]) {
 		pr_err("OR of all __hash_32 results = %#x != %#x",
 			hash_or[0][0], -1u);
@@ -232,6 +253,13 @@ test_hash_init(void)
 		}
 	}
 
+	pr_notice("%u tests passed.", tests);
+
+	return 0;
+}
+
+static void __init notice_skipped_tests(void)
+{
 	/* Issue notices about skipped tests. */
 #ifdef HAVE_ARCH__HASH_32
 #if HAVE_ARCH__HASH_32 != 1
@@ -247,10 +275,24 @@ test_hash_init(void)
 #else
 	pr_info("hash_64() has no arch implementation to test.");
 #endif
+}
 
-	pr_notice("%u tests passed.", tests);
+static int __init
+test_hash_init(void)
+{
+	int ret;
 
-	return 0;
+	ret = test_string_or();
+	if (ret < 0)
+		return ret;
+
+	ret = test_hash_or();
+	if (ret < 0)
+		return ret;
+
+	notice_skipped_tests();
+
+	return ret;
 }
 
 static void __exit test_hash_exit(void)
-- 
2.33.0


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

* [PATCH v2 4/5] lib/Kconfig.debug: properly split hash test kernel entries
  2021-09-26 22:33 [PATCH v2 0/5] test_hash.c: refactor into KUnit Isabella Basso
                   ` (2 preceding siblings ...)
  2021-09-26 22:33 ` [PATCH v2 3/5] test_hash.c: split test_hash_init Isabella Basso
@ 2021-09-26 22:33 ` Isabella Basso
  2021-10-02  7:22   ` David Gow
  2021-09-26 22:33 ` [PATCH v2 5/5] test_hash.c: refactor into kunit Isabella Basso
  2021-10-02  7:29 ` [PATCH v2 0/5] test_hash.c: refactor into KUnit David Gow
  5 siblings, 1 reply; 20+ messages in thread
From: Isabella Basso @ 2021-09-26 22:33 UTC (permalink / raw)
  To: geert
  Cc: ferreiraenzoa, augusto.duraes33, brendanhiggins, dlatypov,
	davidgow, linux-kselftest, linux-kernel, kunit-dev,
	~lkcamp/patches, rodrigosiqueiramelo, Isabella Basso

Split TEST_HASH so that each entry only has one file.

Note that there's no stringhash test file, but actually
<linux/stringhash.h> tests are performed in lib/test_hash.c.

Tested-by: David Gow <davidgow@google.com>
Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
---
 lib/Kconfig.debug | 14 +++++++++++---
 lib/Makefile      |  3 ++-
 2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 2a9b6dcdac4f..eb6c4daf5fcb 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2207,9 +2207,17 @@ config TEST_RHASHTABLE
 config TEST_HASH
 	tristate "Perform selftest on hash functions"
 	help
-	  Enable this option to test the kernel's integer (<linux/hash.h>),
-	  string (<linux/stringhash.h>), and siphash (<linux/siphash.h>)
-	  hash functions on boot (or module load).
+	  Enable this option to test the kernel's integer (<linux/hash.h>), and
+	  string (<linux/stringhash.h>) hash functions on boot (or module load).
+
+	  This is intended to help people writing architecture-specific
+	  optimized versions.  If unsure, say N.
+
+config TEST_SIPHASH
+	tristate "Perform selftest on siphash functions"
+	help
+	  Enable this option to test the kernel's siphash (<linux/siphash.h>) hash
+	  functions on boot (or module load).
 
 	  This is intended to help people writing architecture-specific
 	  optimized versions.  If unsure, say N.
diff --git a/lib/Makefile b/lib/Makefile
index 5efd1b435a37..c2e81d0eb31c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -61,7 +61,8 @@ obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
 obj-$(CONFIG_TEST_BITOPS) += test_bitops.o
 CFLAGS_test_bitops.o += -Werror
 obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
-obj-$(CONFIG_TEST_HASH) += test_hash.o test_siphash.o
+obj-$(CONFIG_TEST_SIPHASH) += test_siphash.o
+obj-$(CONFIG_TEST_HASH) += test_hash.o
 obj-$(CONFIG_TEST_IDA) += test_ida.o
 obj-$(CONFIG_KASAN_KUNIT_TEST) += test_kasan.o
 CFLAGS_test_kasan.o += -fno-builtin
-- 
2.33.0


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

* [PATCH v2 5/5] test_hash.c: refactor into kunit
  2021-09-26 22:33 [PATCH v2 0/5] test_hash.c: refactor into KUnit Isabella Basso
                   ` (3 preceding siblings ...)
  2021-09-26 22:33 ` [PATCH v2 4/5] lib/Kconfig.debug: properly split hash test kernel entries Isabella Basso
@ 2021-09-26 22:33 ` Isabella Basso
  2021-10-02  7:22   ` David Gow
  2021-10-02  7:29 ` [PATCH v2 0/5] test_hash.c: refactor into KUnit David Gow
  5 siblings, 1 reply; 20+ messages in thread
From: Isabella Basso @ 2021-09-26 22:33 UTC (permalink / raw)
  To: geert
  Cc: ferreiraenzoa, augusto.duraes33, brendanhiggins, dlatypov,
	davidgow, linux-kselftest, linux-kernel, kunit-dev,
	~lkcamp/patches, rodrigosiqueiramelo, Isabella Basso,
	kernel test robot

Use KUnit framework to make tests more easily integrable with CIs. Even
though these tests are not yet properly written as unit tests this
change should help in debugging.

Also remove kernel messages (i.e. through pr_info) as KUnit handles all
debugging output and let it handle module init and exit details.

Changes since v1:
- As suggested by David Gow:
  1. Keep module support.
  2. Reword commit message.
- As reported by the kernel test bot:
  1. Fix compilation for m68k and parisc architectures.

Reported-by: kernel test robot <lkp@intel.com>
Tested-by: David Gow <davidgow@google.com>
Co-developed-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
Signed-off-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
Co-developed-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
Signed-off-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
---
 lib/Kconfig.debug |  28 ++++---
 lib/Makefile      |   2 +-
 lib/test_hash.c   | 187 ++++++++++++++--------------------------------
 3 files changed, 78 insertions(+), 139 deletions(-)

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index eb6c4daf5fcb..04eec87c2964 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2204,15 +2204,6 @@ config TEST_RHASHTABLE
 
 	  If unsure, say N.
 
-config TEST_HASH
-	tristate "Perform selftest on hash functions"
-	help
-	  Enable this option to test the kernel's integer (<linux/hash.h>), and
-	  string (<linux/stringhash.h>) hash functions on boot (or module load).
-
-	  This is intended to help people writing architecture-specific
-	  optimized versions.  If unsure, say N.
-
 config TEST_SIPHASH
 	tristate "Perform selftest on siphash functions"
 	help
@@ -2361,6 +2352,25 @@ config BITFIELD_KUNIT
 
 	  If unsure, say N.
 
+config HASH_KUNIT_TEST
+	tristate "KUnit Test for integer hash functions" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	default KUNIT_ALL_TESTS
+	help
+	  Enable this option to test the kernel's string (<linux/stringhash.h>), and
+	  integer (<linux/hash.h>) hash functions on boot.
+
+	  KUnit tests run during boot and output the results to the debug log
+	  in TAP format (https://testanything.org/). Only useful for kernel devs
+	  running the KUnit test harness, and not intended for inclusion into a
+	  production build.
+
+	  For more information on KUnit and unit tests in general please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  This is intended to help people writing architecture-specific
+	  optimized versions. If unsure, say N.
+
 config RESOURCE_KUNIT_TEST
 	tristate "KUnit test for resource API"
 	depends on KUNIT
diff --git a/lib/Makefile b/lib/Makefile
index c2e81d0eb31c..0bc336d9d036 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -62,7 +62,7 @@ obj-$(CONFIG_TEST_BITOPS) += test_bitops.o
 CFLAGS_test_bitops.o += -Werror
 obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
 obj-$(CONFIG_TEST_SIPHASH) += test_siphash.o
-obj-$(CONFIG_TEST_HASH) += test_hash.o
+obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o
 obj-$(CONFIG_TEST_IDA) += test_ida.o
 obj-$(CONFIG_KASAN_KUNIT_TEST) += test_kasan.o
 CFLAGS_test_kasan.o += -fno-builtin
diff --git a/lib/test_hash.c b/lib/test_hash.c
index db9dd18b4e8b..9cb8b1d2ab06 100644
--- a/lib/test_hash.c
+++ b/lib/test_hash.c
@@ -14,14 +14,12 @@
  * and hash_64().
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt "\n"
-
 #include <linux/compiler.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/hash.h>
 #include <linux/stringhash.h>
-#include <linux/printk.h>
+#include <kunit/test.h>
 
 /* 32-bit XORSHIFT generator.  Seed must not be zero. */
 static u32 __init __attribute_const__
@@ -66,40 +64,32 @@ struct test_hash_params {
 };
 
 #ifdef HAVE_ARCH__HASH_32
-static bool __init
-test_int__hash_32(struct test_hash_params *params)
+static void __init
+test_int__hash_32(struct kunit *test, struct test_hash_params *params)
 {
 	params->hash_or[1][0] |= params->h2 = __hash_32_generic(params->h0);
 #if HAVE_ARCH__HASH_32 == 1
-	if (params->h1 != params->h2) {
-		pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
-		       params->h0, params->h1, params->h2);
-		return false;
-	}
+	KUNIT_EXPECT_EQ_MSG(test, params->h1, params->h2,
+			    "__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
+			    params->h0, params->h1, params->h2);
 #endif
-	return true;
 }
 #endif
 
 #ifdef HAVE_ARCH_HASH_64
-static bool __init
-test_int_hash_64(struct test_hash_params *params, u32 const *m, int *k)
+static void __init
+test_int_hash_64(struct kunit *test, struct test_hash_params *params, u32 const *m, int *k)
 {
 	params->h2 = hash_64_generic(*params->h64, *k);
 #if HAVE_ARCH_HASH_64 == 1
-	if (params->h1 != params->h2) {
-		pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() = %#x",
-		       *params->h64, *k, params->h1, params->h2);
-		return false;
-	}
+	KUNIT_EXPECT_EQ_MSG(test, params->h1, params->h2,
+			    "hash_64(%#llx, %d) = %#x != hash_64_generic() = %#x",
+			    *params->h64, *k, params->h1, params->h2);
 #else
-	if (params->h2 > *m) {
-		pr_err("hash_64_generic(%#llx, %d) = %#x > %#x",
-		       *params->h64, *k, params->h1, *m);
-		return false;
-	}
+	KUNIT_EXPECT_LE_MSG(test, params->h1, params->h2,
+			    "hash_64_generic(%#llx, %d) = %#x > %#x",
+			    *params->h64, *k, params->h1, *m);
 #endif
-	return true;
 }
 #endif
 
@@ -112,8 +102,8 @@ test_int_hash_64(struct test_hash_params *params, u32 const *m, int *k)
  * inline, the code being tested is actually in the module, and you can
  * recompile and re-test the module without rebooting.
  */
-static bool __init
-test_int_hash(unsigned long long h64, u32 hash_or[2][33])
+static void __init
+test_int_hash(struct kunit *test, unsigned long long h64, u32 hash_or[2][33])
 {
 	int k;
 	struct test_hash_params params = { &h64, (u32)h64, 0, 0, hash_or };
@@ -121,8 +111,7 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
 	/* Test __hash32 */
 	hash_or[0][0] |= params.h1 = __hash_32(params.h0);
 #ifdef HAVE_ARCH__HASH_32
-	if (!test_int__hash_32(&params))
-		return false;
+	test_int__hash_32(test, &params);
 #endif
 
 	/* Test k = 1..32 bits */
@@ -131,29 +120,24 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
 
 		/* Test hash_32 */
 		hash_or[0][k] |= params.h1 = hash_32(params.h0, k);
-		if (params.h1 > m) {
-			pr_err("hash_32(%#x, %d) = %#x > %#x", params.h0, k, params.h1, m);
-			return false;
-		}
+		KUNIT_EXPECT_LE_MSG(test, params.h1, m,
+				    "hash_32(%#x, %d) = %#x > %#x",
+				    params.h0, k, params.h1, m);
 
 		/* Test hash_64 */
 		hash_or[1][k] |= params.h1 = hash_64(h64, k);
-		if (params.h1 > m) {
-			pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, params.h1, m);
-			return false;
-		}
+		KUNIT_EXPECT_LE_MSG(test, params.h1, m,
+				    "hash_64(%#llx, %d) = %#x > %#x",
+				    h64, k, params.h1, m);
 #ifdef HAVE_ARCH_HASH_64
-		if (!test_int_hash_64(&params, &m, &k))
-			return false;
+		test_int_hash_64(test, &params, &m, &k);
 #endif
 	}
-
-	return true;
 }
 
 #define SIZE 256	/* Run time is cubic in SIZE */
 
-static int __init test_string_or(void)
+static void __init test_string_or(struct kunit *test)
 {
 	char buf[SIZE+1];
 	u32 string_or = 0;
@@ -173,20 +157,15 @@ static int __init test_string_or(void)
 	} /* j */
 
 	/* The OR of all the hash values should cover all the bits */
-	if (~string_or) {
-		pr_err("OR of all string hash results = %#x != %#x",
-		       string_or, -1u);
-		return -EINVAL;
-	}
-
-	return 0;
+	KUNIT_EXPECT_FALSE_MSG(test, ~string_or,
+			       "OR of all string hash results = %#x != %#x",
+			       string_or, -1u);
 }
 
-static int __init test_hash_or(void)
+static void __init test_hash_or(struct kunit *test)
 {
 	char buf[SIZE+1];
 	u32 hash_or[2][33] = { { 0, } };
-	unsigned tests = 0;
 	unsigned long long h64 = 0;
 	int i, j;
 
@@ -201,39 +180,27 @@ static int __init test_hash_or(void)
 			u32 h0 = full_name_hash(buf+i, buf+i, j-i);
 
 			/* Check that hashlen_string gets the length right */
-			if (hashlen_len(hashlen) != j-i) {
-				pr_err("hashlen_string(%d..%d) returned length"
-					" %u, expected %d",
-					i, j, hashlen_len(hashlen), j-i);
-				return -EINVAL;
-			}
+			KUNIT_EXPECT_EQ_MSG(test, hashlen_len(hashlen), j-i,
+					    "hashlen_string(%d..%d) returned length %u, expected %d",
+					    i, j, hashlen_len(hashlen), j-i);
 			/* Check that the hashes match */
-			if (hashlen_hash(hashlen) != h0) {
-				pr_err("hashlen_string(%d..%d) = %08x != "
-					"full_name_hash() = %08x",
-					i, j, hashlen_hash(hashlen), h0);
-				return -EINVAL;
-			}
+			KUNIT_EXPECT_EQ_MSG(test, hashlen_hash(hashlen), h0,
+					    "hashlen_string(%d..%d) = %08x != full_name_hash() = %08x",
+					    i, j, hashlen_hash(hashlen), h0);
 
 			h64 = h64 << 32 | h0;	/* For use with hash_64 */
-			if (!test_int_hash(h64, hash_or))
-				return -EINVAL;
-			tests++;
+			test_int_hash(test, h64, hash_or);
 		} /* i */
 	} /* j */
 
-	if (~hash_or[0][0]) {
-		pr_err("OR of all __hash_32 results = %#x != %#x",
-			hash_or[0][0], -1u);
-		return -EINVAL;
-	}
+	KUNIT_EXPECT_FALSE_MSG(test, ~hash_or[0][0],
+			       "OR of all __hash_32 results = %#x != %#x",
+			       hash_or[0][0], -1u);
 #ifdef HAVE_ARCH__HASH_32
 #if HAVE_ARCH__HASH_32 != 1	/* Test is pointless if results match */
-	if (~hash_or[1][0]) {
-		pr_err("OR of all __hash_32_generic results = %#x != %#x",
-			hash_or[1][0], -1u);
-		return -EINVAL;
-	}
+	KUNIT_EXPECT_FALSE_MSG(test, ~hash_or[1][0],
+			       "OR of all __hash_32_generic results = %#x != %#x",
+			       hash_or[1][0], -1u);
 #endif
 #endif
 
@@ -241,65 +208,27 @@ static int __init test_hash_or(void)
 	for (i = 1; i <= 32; i++) {
 		u32 const m = ((u32)2 << (i-1)) - 1;	/* Low i bits set */
 
-		if (hash_or[0][i] != m) {
-			pr_err("OR of all hash_32(%d) results = %#x "
-				"(%#x expected)", i, hash_or[0][i], m);
-			return -EINVAL;
-		}
-		if (hash_or[1][i] != m) {
-			pr_err("OR of all hash_64(%d) results = %#x "
-				"(%#x expected)", i, hash_or[1][i], m);
-			return -EINVAL;
-		}
+		KUNIT_EXPECT_EQ_MSG(test, hash_or[0][i], m,
+				    "OR of all hash_32(%d) results = %#x (%#x expected)",
+				    i, hash_or[0][i], m);
+		KUNIT_EXPECT_EQ_MSG(test, hash_or[1][i], m,
+				    "OR of all hash_64(%d) results = %#x (%#x expected)",
+				    i, hash_or[1][i], m);
 	}
-
-	pr_notice("%u tests passed.", tests);
-
-	return 0;
-}
-
-static void __init notice_skipped_tests(void)
-{
-	/* Issue notices about skipped tests. */
-#ifdef HAVE_ARCH__HASH_32
-#if HAVE_ARCH__HASH_32 != 1
-	pr_info("__hash_32() is arch-specific; not compared to generic.");
-#endif
-#else
-	pr_info("__hash_32() has no arch implementation to test.");
-#endif
-#ifdef HAVE_ARCH_HASH_64
-#if HAVE_ARCH_HASH_64 != 1
-	pr_info("hash_64() is arch-specific; not compared to generic.");
-#endif
-#else
-	pr_info("hash_64() has no arch implementation to test.");
-#endif
 }
 
-static int __init
-test_hash_init(void)
-{
-	int ret;
-
-	ret = test_string_or();
-	if (ret < 0)
-		return ret;
-
-	ret = test_hash_or();
-	if (ret < 0)
-		return ret;
-
-	notice_skipped_tests();
+static struct kunit_case hash_test_cases[] __refdata = {
+	KUNIT_CASE(test_string_or),
+	KUNIT_CASE(test_hash_or),
+	{}
+};
 
-	return ret;
-}
+static struct kunit_suite hash_test_suite = {
+	.name = "hash",
+	.test_cases = hash_test_cases,
+};
 
-static void __exit test_hash_exit(void)
-{
-}
 
-module_init(test_hash_init);	/* Does everything */
-module_exit(test_hash_exit);	/* Does nothing */
+kunit_test_suite(hash_test_suite);
 
 MODULE_LICENSE("GPL");
-- 
2.33.0


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

* Re: [PATCH v2 3/5] test_hash.c: split test_hash_init
  2021-09-26 22:33 ` [PATCH v2 3/5] test_hash.c: split test_hash_init Isabella Basso
@ 2021-09-27  8:17   ` Marco Elver
  2021-09-27 12:02     ` Isabella B do Amaral
  2021-10-02  7:20   ` David Gow
  1 sibling, 1 reply; 20+ messages in thread
From: Marco Elver @ 2021-09-27  8:17 UTC (permalink / raw)
  To: Isabella Basso
  Cc: geert, ferreiraenzoa, augusto.duraes33, brendanhiggins, dlatypov,
	davidgow, linux-kselftest, linux-kernel, kunit-dev,
	~lkcamp/patches, rodrigosiqueiramelo

On Mon, 27 Sept 2021 at 00:33, 'Isabella Basso' via KUnit Development
<kunit-dev@googlegroups.com> wrote:
>
> Split up test_hash_init so that it calls each test more explicitly
> insofar it is possible without rewriting the entire file. This aims at
> improving readability.
>
> Split tests performed on string_or as they don't interfere with those
> performed in hash_or. Also separate pr_info calls about skipped tests as
> they're not part of the tests themselves, but only warn about
> (un)defined arch-specific hash functions.
>
> Changes since v1:
> - As suggested by David Gow:
>   1. Rename arch-specific test functions.
>   2. Remove spare whitespace changes.
> - As suggested by Marco Elver:
>   1. Add struct for carrying test variables.

Did the patches get mixed up? The struct doesn't appear to be introduced here.

> Tested-by: David Gow <davidgow@google.com>
> Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
> ---
>  lib/test_hash.c | 66 ++++++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 54 insertions(+), 12 deletions(-)
>
> diff --git a/lib/test_hash.c b/lib/test_hash.c
> index 08fe63776c4f..db9dd18b4e8b 100644
> --- a/lib/test_hash.c
> +++ b/lib/test_hash.c
> @@ -153,11 +153,39 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
>
>  #define SIZE 256       /* Run time is cubic in SIZE */
>
> -static int __init
> -test_hash_init(void)
> +static int __init test_string_or(void)
>  {
>         char buf[SIZE+1];
> -       u32 string_or = 0, hash_or[2][33] = { { 0, } };
> +       u32 string_or = 0;
> +       int i, j;
> +
> +       fill_buf(buf, SIZE, 1);
> +
> +       /* Test every possible non-empty substring in the buffer. */
> +       for (j = SIZE; j > 0; --j) {
> +               buf[j] = '\0';
> +
> +               for (i = 0; i <= j; i++) {
> +                       u32 h0 = full_name_hash(buf+i, buf+i, j-i);
> +
> +                       string_or |= h0;
> +               } /* i */
> +       } /* j */
> +
> +       /* The OR of all the hash values should cover all the bits */
> +       if (~string_or) {
> +               pr_err("OR of all string hash results = %#x != %#x",
> +                      string_or, -1u);
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static int __init test_hash_or(void)
> +{
> +       char buf[SIZE+1];
> +       u32 hash_or[2][33] = { { 0, } };
>         unsigned tests = 0;
>         unsigned long long h64 = 0;
>         int i, j;
> @@ -187,7 +215,6 @@ test_hash_init(void)
>                                 return -EINVAL;
>                         }
>
> -                       string_or |= h0;
>                         h64 = h64 << 32 | h0;   /* For use with hash_64 */
>                         if (!test_int_hash(h64, hash_or))
>                                 return -EINVAL;
> @@ -195,12 +222,6 @@ test_hash_init(void)
>                 } /* i */
>         } /* j */
>
> -       /* The OR of all the hash values should cover all the bits */
> -       if (~string_or) {
> -               pr_err("OR of all string hash results = %#x != %#x",
> -                       string_or, -1u);
> -               return -EINVAL;
> -       }
>         if (~hash_or[0][0]) {
>                 pr_err("OR of all __hash_32 results = %#x != %#x",
>                         hash_or[0][0], -1u);
> @@ -232,6 +253,13 @@ test_hash_init(void)
>                 }
>         }
>
> +       pr_notice("%u tests passed.", tests);
> +
> +       return 0;
> +}
> +
> +static void __init notice_skipped_tests(void)
> +{
>         /* Issue notices about skipped tests. */
>  #ifdef HAVE_ARCH__HASH_32
>  #if HAVE_ARCH__HASH_32 != 1
> @@ -247,10 +275,24 @@ test_hash_init(void)
>  #else
>         pr_info("hash_64() has no arch implementation to test.");
>  #endif
> +}
>
> -       pr_notice("%u tests passed.", tests);
> +static int __init
> +test_hash_init(void)
> +{
> +       int ret;
>
> -       return 0;
> +       ret = test_string_or();
> +       if (ret < 0)
> +               return ret;
> +
> +       ret = test_hash_or();
> +       if (ret < 0)
> +               return ret;
> +
> +       notice_skipped_tests();
> +
> +       return ret;
>  }
>
>  static void __exit test_hash_exit(void)
> --
> 2.33.0
>
> --
> You received this message because you are subscribed to the Google Groups "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to kunit-dev+unsubscribe@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/kunit-dev/20210926223322.848641-4-isabellabdoamaral%40usp.br.

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

* Re: [PATCH v2 3/5] test_hash.c: split test_hash_init
  2021-09-27  8:17   ` Marco Elver
@ 2021-09-27 12:02     ` Isabella B do Amaral
  2021-09-27 12:27       ` Marco Elver
  0 siblings, 1 reply; 20+ messages in thread
From: Isabella B do Amaral @ 2021-09-27 12:02 UTC (permalink / raw)
  To: Marco Elver
  Cc: Geert Uytterhoeven, Enzo Ferreira, Augusto Durães Camargo,
	Brendan Higgins, Daniel Latypov, David Gow,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, Rodrigo Siqueira

Hi, Marco,

On Mon, Sep 27, 2021 at 5:17 AM Marco Elver <elver@google.com> wrote:
>
> On Mon, 27 Sept 2021 at 00:33, 'Isabella Basso' via KUnit Development
> <kunit-dev@googlegroups.com> wrote:
> >
> > Split up test_hash_init so that it calls each test more explicitly
> > insofar it is possible without rewriting the entire file. This aims at
> > improving readability.
> >
> > Split tests performed on string_or as they don't interfere with those
> > performed in hash_or. Also separate pr_info calls about skipped tests as
> > they're not part of the tests themselves, but only warn about
> > (un)defined arch-specific hash functions.
> >
> > Changes since v1:
> > - As suggested by David Gow:
> >   1. Rename arch-specific test functions.
> >   2. Remove spare whitespace changes.
> > - As suggested by Marco Elver:
> >   1. Add struct for carrying test variables.
>
> Did the patches get mixed up? The struct doesn't appear to be introduced here.

Yeah, thanks for the heads up! I must have mixed the messages when rebasing.
Sorry about that. The struct was actually introduced in patch 2/5. Do
you want to
have a look at it or should I send the v3 with the correct message before that?

Cheers,
Isabella Basso

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

* Re: [PATCH v2 3/5] test_hash.c: split test_hash_init
  2021-09-27 12:02     ` Isabella B do Amaral
@ 2021-09-27 12:27       ` Marco Elver
  0 siblings, 0 replies; 20+ messages in thread
From: Marco Elver @ 2021-09-27 12:27 UTC (permalink / raw)
  To: Isabella B do Amaral
  Cc: Geert Uytterhoeven, Enzo Ferreira, Augusto Durães Camargo,
	Brendan Higgins, Daniel Latypov, David Gow,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, Rodrigo Siqueira

On Mon, 27 Sept 2021 at 14:03, Isabella B do Amaral
<isabellabdoamaral@usp.br> wrote:
>
> Hi, Marco,
>
> On Mon, Sep 27, 2021 at 5:17 AM Marco Elver <elver@google.com> wrote:
> >
> > On Mon, 27 Sept 2021 at 00:33, 'Isabella Basso' via KUnit Development
> > <kunit-dev@googlegroups.com> wrote:
> > >
> > > Split up test_hash_init so that it calls each test more explicitly
> > > insofar it is possible without rewriting the entire file. This aims at
> > > improving readability.
> > >
> > > Split tests performed on string_or as they don't interfere with those
> > > performed in hash_or. Also separate pr_info calls about skipped tests as
> > > they're not part of the tests themselves, but only warn about
> > > (un)defined arch-specific hash functions.
> > >
> > > Changes since v1:
> > > - As suggested by David Gow:
> > >   1. Rename arch-specific test functions.
> > >   2. Remove spare whitespace changes.
> > > - As suggested by Marco Elver:
> > >   1. Add struct for carrying test variables.
> >
> > Did the patches get mixed up? The struct doesn't appear to be introduced here.
>
> Yeah, thanks for the heads up! I must have mixed the messages when rebasing.
> Sorry about that. The struct was actually introduced in patch 2/5. Do
> you want to
> have a look at it or should I send the v3 with the correct message before that?

For review it's fine as-is, given it's a trivial change, but the final
series should have it in the right place.

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

* Re: [PATCH v2 1/5] hash.h: remove unused define directive
  2021-09-26 22:33 ` [PATCH v2 1/5] hash.h: remove unused define directive Isabella Basso
@ 2021-10-02  7:19   ` David Gow
  2021-10-28 15:46     ` Isabella B do Amaral
  0 siblings, 1 reply; 20+ messages in thread
From: David Gow @ 2021-10-02  7:19 UTC (permalink / raw)
  To: Isabella Basso
  Cc: Geert Uytterhoeven, ferreiraenzoa, augusto.duraes33,
	Brendan Higgins, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, rodrigosiqueiramelo

On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
>
> Currently, there exist hash_32() and __hash_32() functions, which were
> introduced in a patch [1] targeting architecture specific optimizations.
> These functions can be overridden on a per-architecture basis to achieve
> such optimizations. They must set their corresponding define directive
> (HAVE_ARCH_HASH_32 and HAVE_ARCH__HASH_32, respectively) so that header
> files can deal with these overrides properly.
>
> As the supported 32-bit architectures that have their own hash function
> implementation (i.e. m68k, Microblaze, H8/300, pa-risc) have only been
> making use of the (more general) __hash_32() function (which only lacks
> a right shift operation when compared to the hash_32() function),
> remove the define directive corresponding to the arch-specific hash_32()
> implementation.
>
> [1] https://lore.kernel.org/lkml/20160525073311.5600.qmail@ns.sciencehorizons.net/
>
> Changes since v1:
> - As suggested by David Gow:
>   1. Reword commit message.

Maybe move this changelog to below the "---", so it doesn't show up in
the final commit message?

>
> Tested-by: David Gow <davidgow@google.com>
> Co-developed-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
> Signed-off-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
> Co-developed-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
> Signed-off-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
> Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
> ---

This looks sensible enough to me. Since no-one seems to be speaking up
in architecture-specific hash_32()'s defence, let's get rid of it.

Reviewed-by: David Gow <davidgow@google.com>

Cheers,
-- David


>  include/linux/hash.h       |  5 +----
>  lib/test_hash.c            | 24 +-----------------------
>  tools/include/linux/hash.h |  5 +----
>  3 files changed, 3 insertions(+), 31 deletions(-)
>
> diff --git a/include/linux/hash.h b/include/linux/hash.h
> index ad6fa21d977b..38edaa08f862 100644
> --- a/include/linux/hash.h
> +++ b/include/linux/hash.h
> @@ -62,10 +62,7 @@ static inline u32 __hash_32_generic(u32 val)
>         return val * GOLDEN_RATIO_32;
>  }
>
> -#ifndef HAVE_ARCH_HASH_32
> -#define hash_32 hash_32_generic
> -#endif
> -static inline u32 hash_32_generic(u32 val, unsigned int bits)
> +static inline u32 hash_32(u32 val, unsigned int bits)
>  {
>         /* High bits are more random, so use them. */
>         return __hash_32(val) >> (32 - bits);
> diff --git a/lib/test_hash.c b/lib/test_hash.c
> index 0ee40b4a56dd..d4b0cfdb0377 100644
> --- a/lib/test_hash.c
> +++ b/lib/test_hash.c
> @@ -94,22 +94,7 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
>                         pr_err("hash_32(%#x, %d) = %#x > %#x", h0, k, h1, m);
>                         return false;
>                 }
> -#ifdef HAVE_ARCH_HASH_32
> -               h2 = hash_32_generic(h0, k);
> -#if HAVE_ARCH_HASH_32 == 1
> -               if (h1 != h2) {
> -                       pr_err("hash_32(%#x, %d) = %#x != hash_32_generic() "
> -                               " = %#x", h0, k, h1, h2);
> -                       return false;
> -               }
> -#else
> -               if (h2 > m) {
> -                       pr_err("hash_32_generic(%#x, %d) = %#x > %#x",
> -                               h0, k, h1, m);
> -                       return false;
> -               }
> -#endif
> -#endif
> +
>                 /* Test hash_64 */
>                 hash_or[1][k] |= h1 = hash_64(h64, k);
>                 if (h1 > m) {
> @@ -227,13 +212,6 @@ test_hash_init(void)
>  #else
>         pr_info("__hash_32() has no arch implementation to test.");
>  #endif
> -#ifdef HAVE_ARCH_HASH_32
> -#if HAVE_ARCH_HASH_32 != 1
> -       pr_info("hash_32() is arch-specific; not compared to generic.");
> -#endif
> -#else
> -       pr_info("hash_32() has no arch implementation to test.");
> -#endif
>  #ifdef HAVE_ARCH_HASH_64
>  #if HAVE_ARCH_HASH_64 != 1
>         pr_info("hash_64() is arch-specific; not compared to generic.");
> diff --git a/tools/include/linux/hash.h b/tools/include/linux/hash.h
> index ad6fa21d977b..38edaa08f862 100644
> --- a/tools/include/linux/hash.h
> +++ b/tools/include/linux/hash.h
> @@ -62,10 +62,7 @@ static inline u32 __hash_32_generic(u32 val)
>         return val * GOLDEN_RATIO_32;
>  }
>
> -#ifndef HAVE_ARCH_HASH_32
> -#define hash_32 hash_32_generic
> -#endif
> -static inline u32 hash_32_generic(u32 val, unsigned int bits)
> +static inline u32 hash_32(u32 val, unsigned int bits)
>  {
>         /* High bits are more random, so use them. */
>         return __hash_32(val) >> (32 - bits);
> --
> 2.33.0
>

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

* Re: [PATCH v2 2/5] test_hash.c: split test_int_hash into arch-specific functions
  2021-09-26 22:33 ` [PATCH v2 2/5] test_hash.c: split test_int_hash into arch-specific functions Isabella Basso
@ 2021-10-02  7:20   ` David Gow
  2021-10-28 15:48     ` Isabella B do Amaral
  0 siblings, 1 reply; 20+ messages in thread
From: David Gow @ 2021-10-02  7:20 UTC (permalink / raw)
  To: Isabella Basso
  Cc: Geert Uytterhoeven, ferreiraenzoa, augusto.duraes33,
	Brendan Higgins, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, rodrigosiqueiramelo

On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
>
> Split the test_int_hash function to keep its mainloop separate from
> arch-specific chunks, which are only compiled as needed. This aims at
> improving readability.
>
> Tested-by: David Gow <davidgow@google.com>
> Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
> ---

This looks good to me. It's possibly worth fixing up the changelog
mixup between this and patch 3 if you send out a v3.

A minor suggestion re: commenting below, otherwise this is:

Reviewed-by: David Gow <davidgow@google.com>

-- David

>  lib/test_hash.c | 86 ++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 57 insertions(+), 29 deletions(-)
>
> diff --git a/lib/test_hash.c b/lib/test_hash.c
> index d4b0cfdb0377..08fe63776c4f 100644
> --- a/lib/test_hash.c
> +++ b/lib/test_hash.c
> @@ -56,6 +56,53 @@ fill_buf(char *buf, size_t len, u32 seed)
>         }
>  }
>
> +/* Holds most testing variables for the int test */

It might be worth commenting what these variables actually are here,
as it's pretty confusing on a quick read through.

Maybe something like:

> +struct test_hash_params {
> +       unsigned long long *h64;

/* Pointer to integer to be hashed. */

> +       u32 h0;

/* Low 32-bits of integer to be hashed. */

> +       u32 h1;

/* Arch-specific hash result. */

> +       u32 h2;

/* Generic hash result. */

> +       u32 (*hash_or)[33];

/* ORed hashes of given size (in bits) */


> +};
> +
> +#ifdef HAVE_ARCH__HASH_32
> +static bool __init
> +test_int__hash_32(struct test_hash_params *params)
> +{
> +       params->hash_or[1][0] |= params->h2 = __hash_32_generic(params->h0);
> +#if HAVE_ARCH__HASH_32 == 1
> +       if (params->h1 != params->h2) {
> +               pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
> +                      params->h0, params->h1, params->h2);
> +               return false;
> +       }
> +#endif
> +       return true;
> +}
> +#endif
> +
> +#ifdef HAVE_ARCH_HASH_64
> +static bool __init
> +test_int_hash_64(struct test_hash_params *params, u32 const *m, int *k)
> +{
> +       params->h2 = hash_64_generic(*params->h64, *k);
> +#if HAVE_ARCH_HASH_64 == 1
> +       if (params->h1 != params->h2) {
> +               pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() = %#x",
> +                      *params->h64, *k, params->h1, params->h2);
> +               return false;
> +       }
> +#else
> +       if (params->h2 > *m) {
> +               pr_err("hash_64_generic(%#llx, %d) = %#x > %#x",
> +                      *params->h64, *k, params->h1, *m);
> +               return false;
> +       }
> +#endif
> +       return true;
> +}
> +#endif
> +
>  /*
>   * Test the various integer hash functions.  h64 (or its low-order bits)
>   * is the integer to hash.  hash_or accumulates the OR of the hash values,
> @@ -69,19 +116,13 @@ static bool __init
>  test_int_hash(unsigned long long h64, u32 hash_or[2][33])
>  {
>         int k;
> -       u32 h0 = (u32)h64, h1, h2;
> +       struct test_hash_params params = { &h64, (u32)h64, 0, 0, hash_or };
>
>         /* Test __hash32 */
> -       hash_or[0][0] |= h1 = __hash_32(h0);
> +       hash_or[0][0] |= params.h1 = __hash_32(params.h0);
>  #ifdef HAVE_ARCH__HASH_32
> -       hash_or[1][0] |= h2 = __hash_32_generic(h0);
> -#if HAVE_ARCH__HASH_32 == 1
> -       if (h1 != h2) {
> -               pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
> -                       h0, h1, h2);
> +       if (!test_int__hash_32(&params))
>                 return false;
> -       }
> -#endif
>  #endif
>
>         /* Test k = 1..32 bits */
> @@ -89,37 +130,24 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
>                 u32 const m = ((u32)2 << (k-1)) - 1;    /* Low k bits set */
>
>                 /* Test hash_32 */
> -               hash_or[0][k] |= h1 = hash_32(h0, k);
> -               if (h1 > m) {
> -                       pr_err("hash_32(%#x, %d) = %#x > %#x", h0, k, h1, m);
> +               hash_or[0][k] |= params.h1 = hash_32(params.h0, k);
> +               if (params.h1 > m) {
> +                       pr_err("hash_32(%#x, %d) = %#x > %#x", params.h0, k, params.h1, m);
>                         return false;
>                 }
>
>                 /* Test hash_64 */
> -               hash_or[1][k] |= h1 = hash_64(h64, k);
> -               if (h1 > m) {
> -                       pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, h1, m);
> +               hash_or[1][k] |= params.h1 = hash_64(h64, k);
> +               if (params.h1 > m) {
> +                       pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, params.h1, m);
>                         return false;
>                 }
>  #ifdef HAVE_ARCH_HASH_64
> -               h2 = hash_64_generic(h64, k);
> -#if HAVE_ARCH_HASH_64 == 1
> -               if (h1 != h2) {
> -                       pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() "
> -                               "= %#x", h64, k, h1, h2);
> +               if (!test_int_hash_64(&params, &m, &k))
>                         return false;
> -               }
> -#else
> -               if (h2 > m) {
> -                       pr_err("hash_64_generic(%#llx, %d) = %#x > %#x",
> -                               h64, k, h1, m);
> -                       return false;
> -               }
> -#endif
>  #endif
>         }
>
> -       (void)h2;       /* Suppress unused variable warning */
>         return true;
>  }
>
> --
> 2.33.0
>

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

* Re: [PATCH v2 3/5] test_hash.c: split test_hash_init
  2021-09-26 22:33 ` [PATCH v2 3/5] test_hash.c: split test_hash_init Isabella Basso
  2021-09-27  8:17   ` Marco Elver
@ 2021-10-02  7:20   ` David Gow
  1 sibling, 0 replies; 20+ messages in thread
From: David Gow @ 2021-10-02  7:20 UTC (permalink / raw)
  To: Isabella Basso
  Cc: Geert Uytterhoeven, ferreiraenzoa, augusto.duraes33,
	Brendan Higgins, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, rodrigosiqueiramelo

On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
>
> Split up test_hash_init so that it calls each test more explicitly
> insofar it is possible without rewriting the entire file. This aims at
> improving readability.
>
> Split tests performed on string_or as they don't interfere with those
> performed in hash_or. Also separate pr_info calls about skipped tests as
> they're not part of the tests themselves, but only warn about
> (un)defined arch-specific hash functions.
>
> Changes since v1:
> - As suggested by David Gow:
>   1. Rename arch-specific test functions.
>   2. Remove spare whitespace changes.
> - As suggested by Marco Elver:
>   1. Add struct for carrying test variables.

Nit: Move the changelog to after the "---" (and the correct patch).

>
> Tested-by: David Gow <davidgow@google.com>
> Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
> ---

This seems good to me, though I admit this is the part I'm probably
least knowledgeable about. I'm pretty sure there has to be a more
straightforward way to test some of these hash functions, but it's
probably better to keep this as-is rather than doing anything too
drastic in the middle of the port to KUnit.

The biggest downside here is that we now double the number of calls to
fill_buffer() and full_name_hash(), so the test is likely to be a bit
slower. It still runs fast enough (at least with the default SIZE of
256) that it's not noticeable to me, though, so I don't think it's a
problem.

Apart from Marco's comment about the changelog in the commit message
is fixed, this is:

Reviewed-by: David Gow <davidgow@google.com>

Cheers,
-- David


>  lib/test_hash.c | 66 ++++++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 54 insertions(+), 12 deletions(-)
>
> diff --git a/lib/test_hash.c b/lib/test_hash.c
> index 08fe63776c4f..db9dd18b4e8b 100644
> --- a/lib/test_hash.c
> +++ b/lib/test_hash.c
> @@ -153,11 +153,39 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
>
>  #define SIZE 256       /* Run time is cubic in SIZE */
>
> -static int __init
> -test_hash_init(void)
> +static int __init test_string_or(void)
>  {
>         char buf[SIZE+1];
> -       u32 string_or = 0, hash_or[2][33] = { { 0, } };
> +       u32 string_or = 0;
> +       int i, j;
> +
> +       fill_buf(buf, SIZE, 1);
> +
> +       /* Test every possible non-empty substring in the buffer. */
> +       for (j = SIZE; j > 0; --j) {
> +               buf[j] = '\0';
> +
> +               for (i = 0; i <= j; i++) {
> +                       u32 h0 = full_name_hash(buf+i, buf+i, j-i);
> +
> +                       string_or |= h0;
> +               } /* i */
> +       } /* j */
> +
> +       /* The OR of all the hash values should cover all the bits */
> +       if (~string_or) {
> +               pr_err("OR of all string hash results = %#x != %#x",
> +                      string_or, -1u);
> +               return -EINVAL;
> +       }
> +
> +       return 0;
> +}
> +
> +static int __init test_hash_or(void)
> +{
> +       char buf[SIZE+1];
> +       u32 hash_or[2][33] = { { 0, } };
>         unsigned tests = 0;
>         unsigned long long h64 = 0;
>         int i, j;
> @@ -187,7 +215,6 @@ test_hash_init(void)
>                                 return -EINVAL;
>                         }
>
> -                       string_or |= h0;
>                         h64 = h64 << 32 | h0;   /* For use with hash_64 */
>                         if (!test_int_hash(h64, hash_or))
>                                 return -EINVAL;
> @@ -195,12 +222,6 @@ test_hash_init(void)
>                 } /* i */
>         } /* j */
>
> -       /* The OR of all the hash values should cover all the bits */
> -       if (~string_or) {
> -               pr_err("OR of all string hash results = %#x != %#x",
> -                       string_or, -1u);
> -               return -EINVAL;
> -       }
>         if (~hash_or[0][0]) {
>                 pr_err("OR of all __hash_32 results = %#x != %#x",
>                         hash_or[0][0], -1u);
> @@ -232,6 +253,13 @@ test_hash_init(void)
>                 }
>         }
>
> +       pr_notice("%u tests passed.", tests);
> +
> +       return 0;
> +}
> +
> +static void __init notice_skipped_tests(void)
> +{
>         /* Issue notices about skipped tests. */
>  #ifdef HAVE_ARCH__HASH_32
>  #if HAVE_ARCH__HASH_32 != 1
> @@ -247,10 +275,24 @@ test_hash_init(void)
>  #else
>         pr_info("hash_64() has no arch implementation to test.");
>  #endif
> +}
>
> -       pr_notice("%u tests passed.", tests);
> +static int __init
> +test_hash_init(void)
> +{
> +       int ret;
>
> -       return 0;
> +       ret = test_string_or();
> +       if (ret < 0)
> +               return ret;
> +
> +       ret = test_hash_or();
> +       if (ret < 0)
> +               return ret;
> +
> +       notice_skipped_tests();
> +
> +       return ret;
>  }
>
>  static void __exit test_hash_exit(void)
> --
> 2.33.0
>

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

* Re: [PATCH v2 4/5] lib/Kconfig.debug: properly split hash test kernel entries
  2021-09-26 22:33 ` [PATCH v2 4/5] lib/Kconfig.debug: properly split hash test kernel entries Isabella Basso
@ 2021-10-02  7:22   ` David Gow
  0 siblings, 0 replies; 20+ messages in thread
From: David Gow @ 2021-10-02  7:22 UTC (permalink / raw)
  To: Isabella Basso
  Cc: Geert Uytterhoeven, ferreiraenzoa, augusto.duraes33,
	Brendan Higgins, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, rodrigosiqueiramelo

On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
>
> Split TEST_HASH so that each entry only has one file.
>
> Note that there's no stringhash test file, but actually
> <linux/stringhash.h> tests are performed in lib/test_hash.c.
>
> Tested-by: David Gow <davidgow@google.com>
> Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
> ---

Looks good to me.

Reviewed-by: David Gow <davidgow@google.com>

Cheers,
-- David

>  lib/Kconfig.debug | 14 +++++++++++---
>  lib/Makefile      |  3 ++-
>  2 files changed, 13 insertions(+), 4 deletions(-)
>
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index 2a9b6dcdac4f..eb6c4daf5fcb 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2207,9 +2207,17 @@ config TEST_RHASHTABLE
>  config TEST_HASH
>         tristate "Perform selftest on hash functions"
>         help
> -         Enable this option to test the kernel's integer (<linux/hash.h>),
> -         string (<linux/stringhash.h>), and siphash (<linux/siphash.h>)
> -         hash functions on boot (or module load).
> +         Enable this option to test the kernel's integer (<linux/hash.h>), and
> +         string (<linux/stringhash.h>) hash functions on boot (or module load).
> +
> +         This is intended to help people writing architecture-specific
> +         optimized versions.  If unsure, say N.
> +
> +config TEST_SIPHASH
> +       tristate "Perform selftest on siphash functions"
> +       help
> +         Enable this option to test the kernel's siphash (<linux/siphash.h>) hash
> +         functions on boot (or module load).
>
>           This is intended to help people writing architecture-specific
>           optimized versions.  If unsure, say N.
> diff --git a/lib/Makefile b/lib/Makefile
> index 5efd1b435a37..c2e81d0eb31c 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -61,7 +61,8 @@ obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
>  obj-$(CONFIG_TEST_BITOPS) += test_bitops.o
>  CFLAGS_test_bitops.o += -Werror
>  obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
> -obj-$(CONFIG_TEST_HASH) += test_hash.o test_siphash.o
> +obj-$(CONFIG_TEST_SIPHASH) += test_siphash.o
> +obj-$(CONFIG_TEST_HASH) += test_hash.o
>  obj-$(CONFIG_TEST_IDA) += test_ida.o
>  obj-$(CONFIG_KASAN_KUNIT_TEST) += test_kasan.o
>  CFLAGS_test_kasan.o += -fno-builtin
> --
> 2.33.0
>

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

* Re: [PATCH v2 5/5] test_hash.c: refactor into kunit
  2021-09-26 22:33 ` [PATCH v2 5/5] test_hash.c: refactor into kunit Isabella Basso
@ 2021-10-02  7:22   ` David Gow
  2021-10-28 21:09     ` Isabella B do Amaral
  0 siblings, 1 reply; 20+ messages in thread
From: David Gow @ 2021-10-02  7:22 UTC (permalink / raw)
  To: Isabella Basso
  Cc: Geert Uytterhoeven, ferreiraenzoa, augusto.duraes33,
	Brendan Higgins, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, rodrigosiqueiramelo,
	kernel test robot

On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
>
> Use KUnit framework to make tests more easily integrable with CIs. Even
> though these tests are not yet properly written as unit tests this
> change should help in debugging.
>
> Also remove kernel messages (i.e. through pr_info) as KUnit handles all
> debugging output and let it handle module init and exit details.
>
> Changes since v1:
> - As suggested by David Gow:
>   1. Keep module support.
>   2. Reword commit message.
> - As reported by the kernel test bot:
>   1. Fix compilation for m68k and parisc architectures.
>

It might be worth moving the changelog under the "---" here, so that
it's not a part of the final commit message.

> Reported-by: kernel test robot <lkp@intel.com>
> Tested-by: David Gow <davidgow@google.com>
> Co-developed-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
> Signed-off-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
> Co-developed-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
> Signed-off-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
> Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
> ---

I went through this in a little more detail, and I'm happy with it.
It'd still be nice if someone with more knowledge of the hashing code
looked over it, but since George's email bounced, I'm happy to give
this my reviewed-by.

There are a few minor comments below (and above, I guess), which would
be worth doing as part of a v3.

Reviewed-by: David Gow <davidgow@google.com>

Thanks,
-- David

>  lib/Kconfig.debug |  28 ++++---
>  lib/Makefile      |   2 +-
>  lib/test_hash.c   | 187 ++++++++++++++--------------------------------
>  3 files changed, 78 insertions(+), 139 deletions(-)
>
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index eb6c4daf5fcb..04eec87c2964 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2204,15 +2204,6 @@ config TEST_RHASHTABLE
>
>           If unsure, say N.
>
> -config TEST_HASH
> -       tristate "Perform selftest on hash functions"
> -       help
> -         Enable this option to test the kernel's integer (<linux/hash.h>), and
> -         string (<linux/stringhash.h>) hash functions on boot (or module load).
> -
> -         This is intended to help people writing architecture-specific
> -         optimized versions.  If unsure, say N.
> -
>  config TEST_SIPHASH
>         tristate "Perform selftest on siphash functions"
>         help
> @@ -2361,6 +2352,25 @@ config BITFIELD_KUNIT
>
>           If unsure, say N.
>
> +config HASH_KUNIT_TEST
> +       tristate "KUnit Test for integer hash functions" if !KUNIT_ALL_TESTS
> +       depends on KUNIT
> +       default KUNIT_ALL_TESTS
> +       help
> +         Enable this option to test the kernel's string (<linux/stringhash.h>), and
> +         integer (<linux/hash.h>) hash functions on boot.
> +
> +         KUnit tests run during boot and output the results to the debug log
> +         in TAP format (https://testanything.org/). Only useful for kernel devs
> +         running the KUnit test harness, and not intended for inclusion into a
> +         production build.
> +
> +         For more information on KUnit and unit tests in general please refer
> +         to the KUnit documentation in Documentation/dev-tools/kunit/.
> +
> +         This is intended to help people writing architecture-specific
> +         optimized versions. If unsure, say N.
> +
>  config RESOURCE_KUNIT_TEST
>         tristate "KUnit test for resource API"
>         depends on KUNIT
> diff --git a/lib/Makefile b/lib/Makefile
> index c2e81d0eb31c..0bc336d9d036 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -62,7 +62,7 @@ obj-$(CONFIG_TEST_BITOPS) += test_bitops.o
>  CFLAGS_test_bitops.o += -Werror
>  obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
>  obj-$(CONFIG_TEST_SIPHASH) += test_siphash.o
> -obj-$(CONFIG_TEST_HASH) += test_hash.o
> +obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o
>  obj-$(CONFIG_TEST_IDA) += test_ida.o
>  obj-$(CONFIG_KASAN_KUNIT_TEST) += test_kasan.o
>  CFLAGS_test_kasan.o += -fno-builtin
> diff --git a/lib/test_hash.c b/lib/test_hash.c
> index db9dd18b4e8b..9cb8b1d2ab06 100644
> --- a/lib/test_hash.c
> +++ b/lib/test_hash.c
> @@ -14,14 +14,12 @@
>   * and hash_64().
>   */
>
> -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt "\n"
> -
>  #include <linux/compiler.h>
>  #include <linux/types.h>
>  #include <linux/module.h>
>  #include <linux/hash.h>
>  #include <linux/stringhash.h>
> -#include <linux/printk.h>
> +#include <kunit/test.h>
>
>  /* 32-bit XORSHIFT generator.  Seed must not be zero. */
>  static u32 __init __attribute_const__
> @@ -66,40 +64,32 @@ struct test_hash_params {
>  };
>
>  #ifdef HAVE_ARCH__HASH_32
> -static bool __init
> -test_int__hash_32(struct test_hash_params *params)
> +static void __init

Let's get rid of the __init bits here: it's possible KUnit tests will
execute after kernel and/or module initialisation.

> +test_int__hash_32(struct kunit *test, struct test_hash_params *params)
>  {
>         params->hash_or[1][0] |= params->h2 = __hash_32_generic(params->h0);
>  #if HAVE_ARCH__HASH_32 == 1
> -       if (params->h1 != params->h2) {
> -               pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
> -                      params->h0, params->h1, params->h2);
> -               return false;
> -       }
> +       KUNIT_EXPECT_EQ_MSG(test, params->h1, params->h2,
> +                           "__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
> +                           params->h0, params->h1, params->h2);
>  #endif
> -       return true;
>  }
>  #endif
>
>  #ifdef HAVE_ARCH_HASH_64
> -static bool __init
> -test_int_hash_64(struct test_hash_params *params, u32 const *m, int *k)
> +static void __init

Ditto for all other functions in this file: remove the __init.

> +test_int_hash_64(struct kunit *test, struct test_hash_params *params, u32 const *m, int *k)
>  {
>         params->h2 = hash_64_generic(*params->h64, *k);
>  #if HAVE_ARCH_HASH_64 == 1
> -       if (params->h1 != params->h2) {
> -               pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() = %#x",
> -                      *params->h64, *k, params->h1, params->h2);
> -               return false;
> -       }
> +       KUNIT_EXPECT_EQ_MSG(test, params->h1, params->h2,
> +                           "hash_64(%#llx, %d) = %#x != hash_64_generic() = %#x",
> +                           *params->h64, *k, params->h1, params->h2);
>  #else
> -       if (params->h2 > *m) {
> -               pr_err("hash_64_generic(%#llx, %d) = %#x > %#x",
> -                      *params->h64, *k, params->h1, *m);
> -               return false;
> -       }
> +       KUNIT_EXPECT_LE_MSG(test, params->h1, params->h2,
> +                           "hash_64_generic(%#llx, %d) = %#x > %#x",
> +                           *params->h64, *k, params->h1, *m);
>  #endif
> -       return true;
>  }
>  #endif
>
> @@ -112,8 +102,8 @@ test_int_hash_64(struct test_hash_params *params, u32 const *m, int *k)
>   * inline, the code being tested is actually in the module, and you can
>   * recompile and re-test the module without rebooting.
>   */
> -static bool __init
> -test_int_hash(unsigned long long h64, u32 hash_or[2][33])
> +static void __init
> +test_int_hash(struct kunit *test, unsigned long long h64, u32 hash_or[2][33])
>  {
>         int k;
>         struct test_hash_params params = { &h64, (u32)h64, 0, 0, hash_or };
> @@ -121,8 +111,7 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
>         /* Test __hash32 */
>         hash_or[0][0] |= params.h1 = __hash_32(params.h0);
>  #ifdef HAVE_ARCH__HASH_32
> -       if (!test_int__hash_32(&params))
> -               return false;
> +       test_int__hash_32(test, &params);
>  #endif
>
>         /* Test k = 1..32 bits */
> @@ -131,29 +120,24 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
>
>                 /* Test hash_32 */
>                 hash_or[0][k] |= params.h1 = hash_32(params.h0, k);
> -               if (params.h1 > m) {
> -                       pr_err("hash_32(%#x, %d) = %#x > %#x", params.h0, k, params.h1, m);
> -                       return false;
> -               }
> +               KUNIT_EXPECT_LE_MSG(test, params.h1, m,
> +                                   "hash_32(%#x, %d) = %#x > %#x",
> +                                   params.h0, k, params.h1, m);
>
>                 /* Test hash_64 */
>                 hash_or[1][k] |= params.h1 = hash_64(h64, k);
> -               if (params.h1 > m) {
> -                       pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, params.h1, m);
> -                       return false;
> -               }
> +               KUNIT_EXPECT_LE_MSG(test, params.h1, m,
> +                                   "hash_64(%#llx, %d) = %#x > %#x",
> +                                   h64, k, params.h1, m);
>  #ifdef HAVE_ARCH_HASH_64
> -               if (!test_int_hash_64(&params, &m, &k))
> -                       return false;
> +               test_int_hash_64(test, &params, &m, &k);
>  #endif
>         }
> -
> -       return true;
>  }
>
>  #define SIZE 256       /* Run time is cubic in SIZE */
>
> -static int __init test_string_or(void)
> +static void __init test_string_or(struct kunit *test)
>  {
>         char buf[SIZE+1];
>         u32 string_or = 0;
> @@ -173,20 +157,15 @@ static int __init test_string_or(void)
>         } /* j */
>
>         /* The OR of all the hash values should cover all the bits */
> -       if (~string_or) {
> -               pr_err("OR of all string hash results = %#x != %#x",
> -                      string_or, -1u);
> -               return -EINVAL;
> -       }
> -
> -       return 0;
> +       KUNIT_EXPECT_FALSE_MSG(test, ~string_or,
> +                              "OR of all string hash results = %#x != %#x",
> +                              string_or, -1u);

It might be worth using KUNIT_EXPECT_EQ_MSG() instead of
EXPECT_FALSE(), as the real goal of this is to check if all bits are
set.

This'd look something like:
KUNIT_EXPECT_EQ_MSG(test, string_or, -1u, "OR of all string hash
results = %#x != %#x", string_or, -1u);

If instead we checked if string_or == -1u, I think it'd be clearer and
match the message better. (In fact, I think you could get away with
removing the message and using the non-_MSG variants if you really
wanted, though the extra text describing it as the OR of all string
results is better.)

>  }
>
> -static int __init test_hash_or(void)
> +static void __init test_hash_or(struct kunit *test)
>  {
>         char buf[SIZE+1];
>         u32 hash_or[2][33] = { { 0, } };
> -       unsigned tests = 0;
>         unsigned long long h64 = 0;
>         int i, j;
>
> @@ -201,39 +180,27 @@ static int __init test_hash_or(void)
>                         u32 h0 = full_name_hash(buf+i, buf+i, j-i);
>
>                         /* Check that hashlen_string gets the length right */
> -                       if (hashlen_len(hashlen) != j-i) {
> -                               pr_err("hashlen_string(%d..%d) returned length"
> -                                       " %u, expected %d",
> -                                       i, j, hashlen_len(hashlen), j-i);
> -                               return -EINVAL;
> -                       }
> +                       KUNIT_EXPECT_EQ_MSG(test, hashlen_len(hashlen), j-i,
> +                                           "hashlen_string(%d..%d) returned length %u, expected %d",
> +                                           i, j, hashlen_len(hashlen), j-i);
>                         /* Check that the hashes match */
> -                       if (hashlen_hash(hashlen) != h0) {
> -                               pr_err("hashlen_string(%d..%d) = %08x != "
> -                                       "full_name_hash() = %08x",
> -                                       i, j, hashlen_hash(hashlen), h0);
> -                               return -EINVAL;
> -                       }
> +                       KUNIT_EXPECT_EQ_MSG(test, hashlen_hash(hashlen), h0,
> +                                           "hashlen_string(%d..%d) = %08x != full_name_hash() = %08x",
> +                                           i, j, hashlen_hash(hashlen), h0);
>
>                         h64 = h64 << 32 | h0;   /* For use with hash_64 */
> -                       if (!test_int_hash(h64, hash_or))
> -                               return -EINVAL;
> -                       tests++;
> +                       test_int_hash(test, h64, hash_or);
>                 } /* i */
>         } /* j */
>
> -       if (~hash_or[0][0]) {
> -               pr_err("OR of all __hash_32 results = %#x != %#x",
> -                       hash_or[0][0], -1u);
> -               return -EINVAL;
> -       }
> +       KUNIT_EXPECT_FALSE_MSG(test, ~hash_or[0][0],

As above, maybe KUNIT_EXPECT_EQ_MSG() instead. (And ditto for all
similar checks against ~hash_or[...])?


> +                              "OR of all __hash_32 results = %#x != %#x",
> +                              hash_or[0][0], -1u);
>  #ifdef HAVE_ARCH__HASH_32
>  #if HAVE_ARCH__HASH_32 != 1    /* Test is pointless if results match */
> -       if (~hash_or[1][0]) {
> -               pr_err("OR of all __hash_32_generic results = %#x != %#x",
> -                       hash_or[1][0], -1u);
> -               return -EINVAL;
> -       }
> +       KUNIT_EXPECT_FALSE_MSG(test, ~hash_or[1][0],
> +                              "OR of all __hash_32_generic results = %#x != %#x",
> +                              hash_or[1][0], -1u);
>  #endif
>  #endif
>
> @@ -241,65 +208,27 @@ static int __init test_hash_or(void)
>         for (i = 1; i <= 32; i++) {
>                 u32 const m = ((u32)2 << (i-1)) - 1;    /* Low i bits set */
>
> -               if (hash_or[0][i] != m) {
> -                       pr_err("OR of all hash_32(%d) results = %#x "
> -                               "(%#x expected)", i, hash_or[0][i], m);
> -                       return -EINVAL;
> -               }
> -               if (hash_or[1][i] != m) {
> -                       pr_err("OR of all hash_64(%d) results = %#x "
> -                               "(%#x expected)", i, hash_or[1][i], m);
> -                       return -EINVAL;
> -               }
> +               KUNIT_EXPECT_EQ_MSG(test, hash_or[0][i], m,
> +                                   "OR of all hash_32(%d) results = %#x (%#x expected)",
> +                                   i, hash_or[0][i], m);
> +               KUNIT_EXPECT_EQ_MSG(test, hash_or[1][i], m,
> +                                   "OR of all hash_64(%d) results = %#x (%#x expected)",
> +                                   i, hash_or[1][i], m);
>         }
> -
> -       pr_notice("%u tests passed.", tests);
> -
> -       return 0;
> -}
> -
> -static void __init notice_skipped_tests(void)
> -{
> -       /* Issue notices about skipped tests. */
> -#ifdef HAVE_ARCH__HASH_32
> -#if HAVE_ARCH__HASH_32 != 1
> -       pr_info("__hash_32() is arch-specific; not compared to generic.");
> -#endif
> -#else
> -       pr_info("__hash_32() has no arch implementation to test.");
> -#endif
> -#ifdef HAVE_ARCH_HASH_64
> -#if HAVE_ARCH_HASH_64 != 1
> -       pr_info("hash_64() is arch-specific; not compared to generic.");
> -#endif
> -#else
> -       pr_info("hash_64() has no arch implementation to test.");
> -#endif
>  }
>
> -static int __init
> -test_hash_init(void)
> -{
> -       int ret;
> -
> -       ret = test_string_or();
> -       if (ret < 0)
> -               return ret;
> -
> -       ret = test_hash_or();
> -       if (ret < 0)
> -               return ret;
> -
> -       notice_skipped_tests();
> +static struct kunit_case hash_test_cases[] __refdata = {
> +       KUNIT_CASE(test_string_or),
> +       KUNIT_CASE(test_hash_or),
> +       {}
> +};
>
> -       return ret;
> -}
> +static struct kunit_suite hash_test_suite = {
> +       .name = "hash",
> +       .test_cases = hash_test_cases,
> +};
>
> -static void __exit test_hash_exit(void)
> -{
> -}
>
> -module_init(test_hash_init);   /* Does everything */
> -module_exit(test_hash_exit);   /* Does nothing */
> +kunit_test_suite(hash_test_suite);
>
>  MODULE_LICENSE("GPL");
> --
> 2.33.0
>

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

* Re: [PATCH v2 0/5] test_hash.c: refactor into KUnit
  2021-09-26 22:33 [PATCH v2 0/5] test_hash.c: refactor into KUnit Isabella Basso
                   ` (4 preceding siblings ...)
  2021-09-26 22:33 ` [PATCH v2 5/5] test_hash.c: refactor into kunit Isabella Basso
@ 2021-10-02  7:29 ` David Gow
  2021-10-05 21:19   ` Brendan Higgins
  5 siblings, 1 reply; 20+ messages in thread
From: David Gow @ 2021-10-02  7:29 UTC (permalink / raw)
  To: Isabella Basso
  Cc: Geert Uytterhoeven, ferreiraenzoa, augusto.duraes33,
	Brendan Higgins, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, rodrigosiqueiramelo

On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
>
> We refactored the lib/test_hash.c file into KUnit as part of the student
> group LKCAMP [1] introductory hackathon for kernel development.
>
> This test was pointed to our group by Daniel Latypov [2], so its full
> conversion into a pure KUnit test was our goal in this patch series, but
> we ran into many problems relating to it not being split as unit tests,
> which complicated matters a bit, as the reasoning behind the original
> tests is quite cryptic for those unfamiliar with hash implementations.
>
> Some interesting developments we'd like to highlight are:
>
> - In patch 1/5 we noticed that there was an unused define directive that
>   could be removed.
> - In patch 4/5 we noticed how stringhash and hash tests are all under
>   the lib/test_hash.c file, which might cause some confusion, and we
>   also broke those kernel config entries up.
>
> Overall KUnit developments have been made in the other patches in this
> series:
>
> In patches 2/5, 3/5 and 5/5 we refactored the lib/test_hash.c
> file so as to make it more compatible with the KUnit style, whilst
> preserving the original idea of the maintainer who designed it (i.e.
> George Spelvin), which might be undesirable for unit tests, but we
> assume it is enough for a first patch.
>
> This is our first patch series so we hope our contributions are
> interesting and also hope to get some useful criticism from the
> community. :)
>
> Changes since V1:
> - Fixed compilation on parisc and m68k.
> - Fixed whitespace mistakes.
> - Renamed a few functions.
> - Refactored globals into struct for test function params, thus removing
>   a patch.
> - Reworded some commit messages.
>
> [1] - https://lkcamp.dev/
> [2] - https://lore.kernel.org/linux-kselftest/CAGS_qxojszgM19u=3HLwFgKX5bm5KhywvsSunuBAt5RtR+GyxQ@mail.gmail.com/
>

Thanks: I've gone through this new revision, and it still works fine,
and my prior comments have been addressed. The commit messages in
particular are much clearer, thank you! I've reviewed the various
patches and left a few comments here and there, but there's nothing
too drastic.

I'm pretty happy with this from the KUnit side, but it would be ideal
if someone with more knowledge of the hash functions looked over it.
Unfortunately, George's email is bouncing, and no-one else has made
any particularly major changes to this.

My only remaining comment on the tests themselves is that it'd be nice
to have them split up further into more, smaller tests. Given that
it's a port of an existing test, though, I understand the desire not
to change things too drastically.

We also need to work out how this is going to go upstream: does it go
through the kunit branch (via Shuah's kselftest repo), or directly to
Linus (who's handled most of the other recent-ish changes here.
Brendan, any thoughts?

Cheers,
-- David



> Isabella Basso (5):
>   hash.h: remove unused define directive
>   test_hash.c: split test_int_hash into arch-specific functions
>   test_hash.c: split test_hash_init
>   lib/Kconfig.debug: properly split hash test kernel entries
>   test_hash.c: refactor into kunit
>
>  include/linux/hash.h       |   5 +-
>  lib/Kconfig.debug          |  28 ++++-
>  lib/Makefile               |   3 +-
>  lib/test_hash.c            | 247 +++++++++++++++++--------------------
>  tools/include/linux/hash.h |   5 +-
>  5 files changed, 139 insertions(+), 149 deletions(-)
>
> --
> 2.33.0
>

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

* Re: [PATCH v2 0/5] test_hash.c: refactor into KUnit
  2021-10-02  7:29 ` [PATCH v2 0/5] test_hash.c: refactor into KUnit David Gow
@ 2021-10-05 21:19   ` Brendan Higgins
  2021-10-28 16:48     ` Isabella B do Amaral
  0 siblings, 1 reply; 20+ messages in thread
From: Brendan Higgins @ 2021-10-05 21:19 UTC (permalink / raw)
  To: David Gow, Shuah Khan
  Cc: Isabella Basso, Geert Uytterhoeven, ferreiraenzoa,
	augusto.duraes33, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, rodrigosiqueiramelo

+Shuah Khan

On Sat, Oct 2, 2021 at 12:30 AM David Gow <davidgow@google.com> wrote:
>
> On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
> >
> > We refactored the lib/test_hash.c file into KUnit as part of the student
> > group LKCAMP [1] introductory hackathon for kernel development.
> >
> > This test was pointed to our group by Daniel Latypov [2], so its full
> > conversion into a pure KUnit test was our goal in this patch series, but
> > we ran into many problems relating to it not being split as unit tests,
> > which complicated matters a bit, as the reasoning behind the original
> > tests is quite cryptic for those unfamiliar with hash implementations.
> >
> > Some interesting developments we'd like to highlight are:
> >
> > - In patch 1/5 we noticed that there was an unused define directive that
> >   could be removed.
> > - In patch 4/5 we noticed how stringhash and hash tests are all under
> >   the lib/test_hash.c file, which might cause some confusion, and we
> >   also broke those kernel config entries up.
> >
> > Overall KUnit developments have been made in the other patches in this
> > series:
> >
> > In patches 2/5, 3/5 and 5/5 we refactored the lib/test_hash.c
> > file so as to make it more compatible with the KUnit style, whilst
> > preserving the original idea of the maintainer who designed it (i.e.
> > George Spelvin), which might be undesirable for unit tests, but we
> > assume it is enough for a first patch.
> >
> > This is our first patch series so we hope our contributions are
> > interesting and also hope to get some useful criticism from the
> > community. :)
> >
> > Changes since V1:
> > - Fixed compilation on parisc and m68k.
> > - Fixed whitespace mistakes.
> > - Renamed a few functions.
> > - Refactored globals into struct for test function params, thus removing
> >   a patch.
> > - Reworded some commit messages.
> >
> > [1] - https://lkcamp.dev/
> > [2] - https://lore.kernel.org/linux-kselftest/CAGS_qxojszgM19u=3HLwFgKX5bm5KhywvsSunuBAt5RtR+GyxQ@mail.gmail.com/
> >
>
> Thanks: I've gone through this new revision, and it still works fine,
> and my prior comments have been addressed. The commit messages in
> particular are much clearer, thank you! I've reviewed the various
> patches and left a few comments here and there, but there's nothing
> too drastic.
>
> I'm pretty happy with this from the KUnit side, but it would be ideal
> if someone with more knowledge of the hash functions looked over it.
> Unfortunately, George's email is bouncing, and no-one else has made
> any particularly major changes to this.
>
> My only remaining comment on the tests themselves is that it'd be nice
> to have them split up further into more, smaller tests. Given that
> it's a port of an existing test, though, I understand the desire not
> to change things too drastically.
>
> We also need to work out how this is going to go upstream: does it go
> through the kunit branch (via Shuah's kselftest repo), or directly to
> Linus (who's handled most of the other recent-ish changes here.
> Brendan, any thoughts?

I think Shuah should take them in 5.16.

Shuah, let me know if you are OK taking these in 5.16 and I will
update the patch tracker.

> Cheers,
> -- David
>
>
>
> > Isabella Basso (5):
> >   hash.h: remove unused define directive
> >   test_hash.c: split test_int_hash into arch-specific functions
> >   test_hash.c: split test_hash_init
> >   lib/Kconfig.debug: properly split hash test kernel entries
> >   test_hash.c: refactor into kunit
> >
> >  include/linux/hash.h       |   5 +-
> >  lib/Kconfig.debug          |  28 ++++-
> >  lib/Makefile               |   3 +-
> >  lib/test_hash.c            | 247 +++++++++++++++++--------------------
> >  tools/include/linux/hash.h |   5 +-
> >  5 files changed, 139 insertions(+), 149 deletions(-)
> >
> > --
> > 2.33.0
> >

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

* Re: [PATCH v2 1/5] hash.h: remove unused define directive
  2021-10-02  7:19   ` David Gow
@ 2021-10-28 15:46     ` Isabella B do Amaral
  0 siblings, 0 replies; 20+ messages in thread
From: Isabella B do Amaral @ 2021-10-28 15:46 UTC (permalink / raw)
  To: David Gow
  Cc: Geert Uytterhoeven, Enzo Ferreira, Augusto Durães Camargo,
	Brendan Higgins, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, Rodrigo Siqueira

Hi, David,

On Sat, Oct 2, 2021 at 4:20 AM David Gow <davidgow@google.com> wrote:
>
> On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
> >
> > Currently, there exist hash_32() and __hash_32() functions, which were
> > introduced in a patch [1] targeting architecture specific optimizations.
> > These functions can be overridden on a per-architecture basis to achieve
> > such optimizations. They must set their corresponding define directive
> > (HAVE_ARCH_HASH_32 and HAVE_ARCH__HASH_32, respectively) so that header
> > files can deal with these overrides properly.
> >
> > As the supported 32-bit architectures that have their own hash function
> > implementation (i.e. m68k, Microblaze, H8/300, pa-risc) have only been
> > making use of the (more general) __hash_32() function (which only lacks
> > a right shift operation when compared to the hash_32() function),
> > remove the define directive corresponding to the arch-specific hash_32()
> > implementation.
> >
> > [1] https://lore.kernel.org/lkml/20160525073311.5600.qmail@ns.sciencehorizons.net/
> >
> > Changes since v1:
> > - As suggested by David Gow:
> >   1. Reword commit message.
>
> Maybe move this changelog to below the "---", so it doesn't show up in
> the final commit message?

Oh, okay! Thanks for pointing that out :) I didn't quite know how I
should put these.

>
> >
> > Tested-by: David Gow <davidgow@google.com>
> > Co-developed-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
> > Signed-off-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
> > Co-developed-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
> > Signed-off-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
> > Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
> > ---
>
> This looks sensible enough to me. Since no-one seems to be speaking up
> in architecture-specific hash_32()'s defence, let's get rid of it.
>
> Reviewed-by: David Gow <davidgow@google.com>
>

Alright! Thanks for the review.

Cheers,
--
Isabella B.

>
> >  include/linux/hash.h       |  5 +----
> >  lib/test_hash.c            | 24 +-----------------------
> >  tools/include/linux/hash.h |  5 +----
> >  3 files changed, 3 insertions(+), 31 deletions(-)
> >
> > diff --git a/include/linux/hash.h b/include/linux/hash.h
> > index ad6fa21d977b..38edaa08f862 100644
> > --- a/include/linux/hash.h
> > +++ b/include/linux/hash.h
> > @@ -62,10 +62,7 @@ static inline u32 __hash_32_generic(u32 val)
> >         return val * GOLDEN_RATIO_32;
> >  }
> >
> > -#ifndef HAVE_ARCH_HASH_32
> > -#define hash_32 hash_32_generic
> > -#endif
> > -static inline u32 hash_32_generic(u32 val, unsigned int bits)
> > +static inline u32 hash_32(u32 val, unsigned int bits)
> >  {
> >         /* High bits are more random, so use them. */
> >         return __hash_32(val) >> (32 - bits);
> > diff --git a/lib/test_hash.c b/lib/test_hash.c
> > index 0ee40b4a56dd..d4b0cfdb0377 100644
> > --- a/lib/test_hash.c
> > +++ b/lib/test_hash.c
> > @@ -94,22 +94,7 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
> >                         pr_err("hash_32(%#x, %d) = %#x > %#x", h0, k, h1, m);
> >                         return false;
> >                 }
> > -#ifdef HAVE_ARCH_HASH_32
> > -               h2 = hash_32_generic(h0, k);
> > -#if HAVE_ARCH_HASH_32 == 1
> > -               if (h1 != h2) {
> > -                       pr_err("hash_32(%#x, %d) = %#x != hash_32_generic() "
> > -                               " = %#x", h0, k, h1, h2);
> > -                       return false;
> > -               }
> > -#else
> > -               if (h2 > m) {
> > -                       pr_err("hash_32_generic(%#x, %d) = %#x > %#x",
> > -                               h0, k, h1, m);
> > -                       return false;
> > -               }
> > -#endif
> > -#endif
> > +
> >                 /* Test hash_64 */
> >                 hash_or[1][k] |= h1 = hash_64(h64, k);
> >                 if (h1 > m) {
> > @@ -227,13 +212,6 @@ test_hash_init(void)
> >  #else
> >         pr_info("__hash_32() has no arch implementation to test.");
> >  #endif
> > -#ifdef HAVE_ARCH_HASH_32
> > -#if HAVE_ARCH_HASH_32 != 1
> > -       pr_info("hash_32() is arch-specific; not compared to generic.");
> > -#endif
> > -#else
> > -       pr_info("hash_32() has no arch implementation to test.");
> > -#endif
> >  #ifdef HAVE_ARCH_HASH_64
> >  #if HAVE_ARCH_HASH_64 != 1
> >         pr_info("hash_64() is arch-specific; not compared to generic.");
> > diff --git a/tools/include/linux/hash.h b/tools/include/linux/hash.h
> > index ad6fa21d977b..38edaa08f862 100644
> > --- a/tools/include/linux/hash.h
> > +++ b/tools/include/linux/hash.h
> > @@ -62,10 +62,7 @@ static inline u32 __hash_32_generic(u32 val)
> >         return val * GOLDEN_RATIO_32;
> >  }
> >
> > -#ifndef HAVE_ARCH_HASH_32
> > -#define hash_32 hash_32_generic
> > -#endif
> > -static inline u32 hash_32_generic(u32 val, unsigned int bits)
> > +static inline u32 hash_32(u32 val, unsigned int bits)
> >  {
> >         /* High bits are more random, so use them. */
> >         return __hash_32(val) >> (32 - bits);
> > --
> > 2.33.0
> >

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

* Re: [PATCH v2 2/5] test_hash.c: split test_int_hash into arch-specific functions
  2021-10-02  7:20   ` David Gow
@ 2021-10-28 15:48     ` Isabella B do Amaral
  0 siblings, 0 replies; 20+ messages in thread
From: Isabella B do Amaral @ 2021-10-28 15:48 UTC (permalink / raw)
  To: David Gow
  Cc: Geert Uytterhoeven, Enzo Ferreira, Augusto Durães Camargo,
	Brendan Higgins, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, Rodrigo Siqueira

On Sat, Oct 2, 2021 at 4:20 AM David Gow <davidgow@google.com> wrote:
>
> On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
> >
> > Split the test_int_hash function to keep its mainloop separate from
> > arch-specific chunks, which are only compiled as needed. This aims at
> > improving readability.
> >
> > Tested-by: David Gow <davidgow@google.com>
> > Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
> > ---
>
> This looks good to me. It's possibly worth fixing up the changelog
> mixup between this and patch 3 if you send out a v3.
>
> A minor suggestion re: commenting below, otherwise this is:
>
> Reviewed-by: David Gow <davidgow@google.com>
>
> -- David
>
> >  lib/test_hash.c | 86 ++++++++++++++++++++++++++++++++-----------------
> >  1 file changed, 57 insertions(+), 29 deletions(-)
> >
> > diff --git a/lib/test_hash.c b/lib/test_hash.c
> > index d4b0cfdb0377..08fe63776c4f 100644
> > --- a/lib/test_hash.c
> > +++ b/lib/test_hash.c
> > @@ -56,6 +56,53 @@ fill_buf(char *buf, size_t len, u32 seed)
> >         }
> >  }
> >
> > +/* Holds most testing variables for the int test */
>
> It might be worth commenting what these variables actually are here,
> as it's pretty confusing on a quick read through.
>
> Maybe something like:
>
> > +struct test_hash_params {
> > +       unsigned long long *h64;
>
> /* Pointer to integer to be hashed. */
>
> > +       u32 h0;
>
> /* Low 32-bits of integer to be hashed. */
>
> > +       u32 h1;
>
> /* Arch-specific hash result. */
>
> > +       u32 h2;
>
> /* Generic hash result. */
>
> > +       u32 (*hash_or)[33];
>
> /* ORed hashes of given size (in bits) */
>

Those comments look pretty sensible to me! I think I'll stick with them :)

Thanks,
--
Isabella Basso

>
> > +};
> > +
> > +#ifdef HAVE_ARCH__HASH_32
> > +static bool __init
> > +test_int__hash_32(struct test_hash_params *params)
> > +{
> > +       params->hash_or[1][0] |= params->h2 = __hash_32_generic(params->h0);
> > +#if HAVE_ARCH__HASH_32 == 1
> > +       if (params->h1 != params->h2) {
> > +               pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
> > +                      params->h0, params->h1, params->h2);
> > +               return false;
> > +       }
> > +#endif
> > +       return true;
> > +}
> > +#endif
> > +
> > +#ifdef HAVE_ARCH_HASH_64
> > +static bool __init
> > +test_int_hash_64(struct test_hash_params *params, u32 const *m, int *k)
> > +{
> > +       params->h2 = hash_64_generic(*params->h64, *k);
> > +#if HAVE_ARCH_HASH_64 == 1
> > +       if (params->h1 != params->h2) {
> > +               pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() = %#x",
> > +                      *params->h64, *k, params->h1, params->h2);
> > +               return false;
> > +       }
> > +#else
> > +       if (params->h2 > *m) {
> > +               pr_err("hash_64_generic(%#llx, %d) = %#x > %#x",
> > +                      *params->h64, *k, params->h1, *m);
> > +               return false;
> > +       }
> > +#endif
> > +       return true;
> > +}
> > +#endif
> > +
> >  /*
> >   * Test the various integer hash functions.  h64 (or its low-order bits)
> >   * is the integer to hash.  hash_or accumulates the OR of the hash values,
> > @@ -69,19 +116,13 @@ static bool __init
> >  test_int_hash(unsigned long long h64, u32 hash_or[2][33])
> >  {
> >         int k;
> > -       u32 h0 = (u32)h64, h1, h2;
> > +       struct test_hash_params params = { &h64, (u32)h64, 0, 0, hash_or };
> >
> >         /* Test __hash32 */
> > -       hash_or[0][0] |= h1 = __hash_32(h0);
> > +       hash_or[0][0] |= params.h1 = __hash_32(params.h0);
> >  #ifdef HAVE_ARCH__HASH_32
> > -       hash_or[1][0] |= h2 = __hash_32_generic(h0);
> > -#if HAVE_ARCH__HASH_32 == 1
> > -       if (h1 != h2) {
> > -               pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
> > -                       h0, h1, h2);
> > +       if (!test_int__hash_32(&params))
> >                 return false;
> > -       }
> > -#endif
> >  #endif
> >
> >         /* Test k = 1..32 bits */
> > @@ -89,37 +130,24 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
> >                 u32 const m = ((u32)2 << (k-1)) - 1;    /* Low k bits set */
> >
> >                 /* Test hash_32 */
> > -               hash_or[0][k] |= h1 = hash_32(h0, k);
> > -               if (h1 > m) {
> > -                       pr_err("hash_32(%#x, %d) = %#x > %#x", h0, k, h1, m);
> > +               hash_or[0][k] |= params.h1 = hash_32(params.h0, k);
> > +               if (params.h1 > m) {
> > +                       pr_err("hash_32(%#x, %d) = %#x > %#x", params.h0, k, params.h1, m);
> >                         return false;
> >                 }
> >
> >                 /* Test hash_64 */
> > -               hash_or[1][k] |= h1 = hash_64(h64, k);
> > -               if (h1 > m) {
> > -                       pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, h1, m);
> > +               hash_or[1][k] |= params.h1 = hash_64(h64, k);
> > +               if (params.h1 > m) {
> > +                       pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, params.h1, m);
> >                         return false;
> >                 }
> >  #ifdef HAVE_ARCH_HASH_64
> > -               h2 = hash_64_generic(h64, k);
> > -#if HAVE_ARCH_HASH_64 == 1
> > -               if (h1 != h2) {
> > -                       pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() "
> > -                               "= %#x", h64, k, h1, h2);
> > +               if (!test_int_hash_64(&params, &m, &k))
> >                         return false;
> > -               }
> > -#else
> > -               if (h2 > m) {
> > -                       pr_err("hash_64_generic(%#llx, %d) = %#x > %#x",
> > -                               h64, k, h1, m);
> > -                       return false;
> > -               }
> > -#endif
> >  #endif
> >         }
> >
> > -       (void)h2;       /* Suppress unused variable warning */
> >         return true;
> >  }
> >
> > --
> > 2.33.0
> >

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

* Re: [PATCH v2 0/5] test_hash.c: refactor into KUnit
  2021-10-05 21:19   ` Brendan Higgins
@ 2021-10-28 16:48     ` Isabella B do Amaral
  0 siblings, 0 replies; 20+ messages in thread
From: Isabella B do Amaral @ 2021-10-28 16:48 UTC (permalink / raw)
  To: Brendan Higgins
  Cc: David Gow, Shuah Khan, Geert Uytterhoeven, Enzo Ferreira,
	Augusto Durães Camargo, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, Rodrigo Siqueira

Hi all,

On Tue, Oct 5, 2021 at 6:19 PM Brendan Higgins
<brendanhiggins@google.com> wrote:
>
> +Shuah Khan
>
> On Sat, Oct 2, 2021 at 12:30 AM David Gow <davidgow@google.com> wrote:
> >
> > On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
> > >
> > > We refactored the lib/test_hash.c file into KUnit as part of the student
> > > group LKCAMP [1] introductory hackathon for kernel development.
> > >
> > > This test was pointed to our group by Daniel Latypov [2], so its full
> > > conversion into a pure KUnit test was our goal in this patch series, but
> > > we ran into many problems relating to it not being split as unit tests,
> > > which complicated matters a bit, as the reasoning behind the original
> > > tests is quite cryptic for those unfamiliar with hash implementations.
> > >
> > > Some interesting developments we'd like to highlight are:
> > >
> > > - In patch 1/5 we noticed that there was an unused define directive that
> > >   could be removed.
> > > - In patch 4/5 we noticed how stringhash and hash tests are all under
> > >   the lib/test_hash.c file, which might cause some confusion, and we
> > >   also broke those kernel config entries up.
> > >
> > > Overall KUnit developments have been made in the other patches in this
> > > series:
> > >
> > > In patches 2/5, 3/5 and 5/5 we refactored the lib/test_hash.c
> > > file so as to make it more compatible with the KUnit style, whilst
> > > preserving the original idea of the maintainer who designed it (i.e.
> > > George Spelvin), which might be undesirable for unit tests, but we
> > > assume it is enough for a first patch.
> > >
> > > This is our first patch series so we hope our contributions are
> > > interesting and also hope to get some useful criticism from the
> > > community. :)
> > >
> > > Changes since V1:
> > > - Fixed compilation on parisc and m68k.
> > > - Fixed whitespace mistakes.
> > > - Renamed a few functions.
> > > - Refactored globals into struct for test function params, thus removing
> > >   a patch.
> > > - Reworded some commit messages.
> > >
> > > [1] - https://lkcamp.dev/
> > > [2] - https://lore.kernel.org/linux-kselftest/CAGS_qxojszgM19u=3HLwFgKX5bm5KhywvsSunuBAt5RtR+GyxQ@mail.gmail.com/
> > >
> >
> > Thanks: I've gone through this new revision, and it still works fine,
> > and my prior comments have been addressed. The commit messages in
> > particular are much clearer, thank you! I've reviewed the various
> > patches and left a few comments here and there, but there's nothing
> > too drastic.
> >
> > I'm pretty happy with this from the KUnit side, but it would be ideal
> > if someone with more knowledge of the hash functions looked over it.
> > Unfortunately, George's email is bouncing, and no-one else has made
> > any particularly major changes to this.

I'm glad to hear this :) I'd also like to point out that "George Spelvin" is a
rather unusual figure [3] so we shouldn't be expecting much back from
him, anyway. Maybe I should've looked that up before trying to tackle this
patch, as I've no idea who might be able to properly review the hash part of
it.

> >
> > My only remaining comment on the tests themselves is that it'd be nice
> > to have them split up further into more, smaller tests. Given that
> > it's a port of an existing test, though, I understand the desire not
> > to change things too drastically.

Thanks for your comprehension!

> >
> > We also need to work out how this is going to go upstream: does it go
> > through the kunit branch (via Shuah's kselftest repo), or directly to
> > Linus (who's handled most of the other recent-ish changes here.
> > Brendan, any thoughts?
>
> I think Shuah should take them in 5.16.
>
> Shuah, let me know if you are OK taking these in 5.16 and I will
> update the patch tracker.
>

Thanks a lot for your interest in this patch :)

We were a little worried about who might be able to get it upstream, so we
appreciate that you also thought of this!

> > Cheers,
> > -- David
> >
> >
> >
> > > Isabella Basso (5):
> > >   hash.h: remove unused define directive
> > >   test_hash.c: split test_int_hash into arch-specific functions
> > >   test_hash.c: split test_hash_init
> > >   lib/Kconfig.debug: properly split hash test kernel entries
> > >   test_hash.c: refactor into kunit
> > >
> > >  include/linux/hash.h       |   5 +-
> > >  lib/Kconfig.debug          |  28 ++++-
> > >  lib/Makefile               |   3 +-
> > >  lib/test_hash.c            | 247 +++++++++++++++++--------------------
> > >  tools/include/linux/hash.h |   5 +-
> > >  5 files changed, 139 insertions(+), 149 deletions(-)
> > >
> > > --
> > > 2.33.0
> > >

I'm sorry for the delay in my response, but I think I can send a V3 soon,
probably until next week.

[3] - https://lwn.net/Articles/688216/

Cheers,
--
Isabella Basso

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

* Re: [PATCH v2 5/5] test_hash.c: refactor into kunit
  2021-10-02  7:22   ` David Gow
@ 2021-10-28 21:09     ` Isabella B do Amaral
  0 siblings, 0 replies; 20+ messages in thread
From: Isabella B do Amaral @ 2021-10-28 21:09 UTC (permalink / raw)
  To: David Gow
  Cc: Geert Uytterhoeven, Enzo Ferreira, Augusto Durães Camargo,
	Brendan Higgins, Daniel Latypov,
	open list:KERNEL SELFTEST FRAMEWORK, Linux Kernel Mailing List,
	KUnit Development, ~lkcamp/patches, Rodrigo Siqueira,
	kernel test robot

Hi, David,

On Sat, Oct 2, 2021 at 4:22 AM David Gow <davidgow@google.com> wrote:
>
> On Mon, Sep 27, 2021 at 6:33 AM Isabella Basso <isabellabdoamaral@usp.br> wrote:
> >
> > Use KUnit framework to make tests more easily integrable with CIs. Even
> > though these tests are not yet properly written as unit tests this
> > change should help in debugging.
> >
> > Also remove kernel messages (i.e. through pr_info) as KUnit handles all
> > debugging output and let it handle module init and exit details.
> >
> > Changes since v1:
> > - As suggested by David Gow:
> >   1. Keep module support.
> >   2. Reword commit message.
> > - As reported by the kernel test bot:
> >   1. Fix compilation for m68k and parisc architectures.
> >
>
> It might be worth moving the changelog under the "---" here, so that
> it's not a part of the final commit message.
>
> > Reported-by: kernel test robot <lkp@intel.com>
> > Tested-by: David Gow <davidgow@google.com>
> > Co-developed-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
> > Signed-off-by: Augusto Durães Camargo <augusto.duraes33@gmail.com>
> > Co-developed-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
> > Signed-off-by: Enzo Ferreira <ferreiraenzoa@gmail.com>
> > Signed-off-by: Isabella Basso <isabellabdoamaral@usp.br>
> > ---
>
> I went through this in a little more detail, and I'm happy with it.
> It'd still be nice if someone with more knowledge of the hashing code
> looked over it, but since George's email bounced, I'm happy to give
> this my reviewed-by.
>
> There are a few minor comments below (and above, I guess), which would
> be worth doing as part of a v3.
>
> Reviewed-by: David Gow <davidgow@google.com>
>
> Thanks,
> -- David
>
> >  lib/Kconfig.debug |  28 ++++---
> >  lib/Makefile      |   2 +-
> >  lib/test_hash.c   | 187 ++++++++++++++--------------------------------
> >  3 files changed, 78 insertions(+), 139 deletions(-)
> >
> > diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> > index eb6c4daf5fcb..04eec87c2964 100644
> > --- a/lib/Kconfig.debug
> > +++ b/lib/Kconfig.debug
> > @@ -2204,15 +2204,6 @@ config TEST_RHASHTABLE
> >
> >           If unsure, say N.
> >
> > -config TEST_HASH
> > -       tristate "Perform selftest on hash functions"
> > -       help
> > -         Enable this option to test the kernel's integer (<linux/hash.h>), and
> > -         string (<linux/stringhash.h>) hash functions on boot (or module load).
> > -
> > -         This is intended to help people writing architecture-specific
> > -         optimized versions.  If unsure, say N.
> > -
> >  config TEST_SIPHASH
> >         tristate "Perform selftest on siphash functions"
> >         help
> > @@ -2361,6 +2352,25 @@ config BITFIELD_KUNIT
> >
> >           If unsure, say N.
> >
> > +config HASH_KUNIT_TEST
> > +       tristate "KUnit Test for integer hash functions" if !KUNIT_ALL_TESTS
> > +       depends on KUNIT
> > +       default KUNIT_ALL_TESTS
> > +       help
> > +         Enable this option to test the kernel's string (<linux/stringhash.h>), and
> > +         integer (<linux/hash.h>) hash functions on boot.
> > +
> > +         KUnit tests run during boot and output the results to the debug log
> > +         in TAP format (https://testanything.org/). Only useful for kernel devs
> > +         running the KUnit test harness, and not intended for inclusion into a
> > +         production build.
> > +
> > +         For more information on KUnit and unit tests in general please refer
> > +         to the KUnit documentation in Documentation/dev-tools/kunit/.
> > +
> > +         This is intended to help people writing architecture-specific
> > +         optimized versions. If unsure, say N.
> > +
> >  config RESOURCE_KUNIT_TEST
> >         tristate "KUnit test for resource API"
> >         depends on KUNIT
> > diff --git a/lib/Makefile b/lib/Makefile
> > index c2e81d0eb31c..0bc336d9d036 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -62,7 +62,7 @@ obj-$(CONFIG_TEST_BITOPS) += test_bitops.o
> >  CFLAGS_test_bitops.o += -Werror
> >  obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
> >  obj-$(CONFIG_TEST_SIPHASH) += test_siphash.o
> > -obj-$(CONFIG_TEST_HASH) += test_hash.o
> > +obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o
> >  obj-$(CONFIG_TEST_IDA) += test_ida.o
> >  obj-$(CONFIG_KASAN_KUNIT_TEST) += test_kasan.o
> >  CFLAGS_test_kasan.o += -fno-builtin
> > diff --git a/lib/test_hash.c b/lib/test_hash.c
> > index db9dd18b4e8b..9cb8b1d2ab06 100644
> > --- a/lib/test_hash.c
> > +++ b/lib/test_hash.c
> > @@ -14,14 +14,12 @@
> >   * and hash_64().
> >   */
> >
> > -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt "\n"
> > -
> >  #include <linux/compiler.h>
> >  #include <linux/types.h>
> >  #include <linux/module.h>
> >  #include <linux/hash.h>
> >  #include <linux/stringhash.h>
> > -#include <linux/printk.h>
> > +#include <kunit/test.h>
> >
> >  /* 32-bit XORSHIFT generator.  Seed must not be zero. */
> >  static u32 __init __attribute_const__
> > @@ -66,40 +64,32 @@ struct test_hash_params {
> >  };
> >
> >  #ifdef HAVE_ARCH__HASH_32
> > -static bool __init
> > -test_int__hash_32(struct test_hash_params *params)
> > +static void __init
>
> Let's get rid of the __init bits here: it's possible KUnit tests will
> execute after kernel and/or module initialisation.

That makes sense! I thought those were necessary for some reason, my bad.

>
> > +test_int__hash_32(struct kunit *test, struct test_hash_params *params)
> >  {
> >         params->hash_or[1][0] |= params->h2 = __hash_32_generic(params->h0);
> >  #if HAVE_ARCH__HASH_32 == 1
> > -       if (params->h1 != params->h2) {
> > -               pr_err("__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
> > -                      params->h0, params->h1, params->h2);
> > -               return false;
> > -       }
> > +       KUNIT_EXPECT_EQ_MSG(test, params->h1, params->h2,
> > +                           "__hash_32(%#x) = %#x != __hash_32_generic() = %#x",
> > +                           params->h0, params->h1, params->h2);
> >  #endif
> > -       return true;
> >  }
> >  #endif
> >
> >  #ifdef HAVE_ARCH_HASH_64
> > -static bool __init
> > -test_int_hash_64(struct test_hash_params *params, u32 const *m, int *k)
> > +static void __init
>
> Ditto for all other functions in this file: remove the __init.
>
> > +test_int_hash_64(struct kunit *test, struct test_hash_params *params, u32 const *m, int *k)
> >  {
> >         params->h2 = hash_64_generic(*params->h64, *k);
> >  #if HAVE_ARCH_HASH_64 == 1
> > -       if (params->h1 != params->h2) {
> > -               pr_err("hash_64(%#llx, %d) = %#x != hash_64_generic() = %#x",
> > -                      *params->h64, *k, params->h1, params->h2);
> > -               return false;
> > -       }
> > +       KUNIT_EXPECT_EQ_MSG(test, params->h1, params->h2,
> > +                           "hash_64(%#llx, %d) = %#x != hash_64_generic() = %#x",
> > +                           *params->h64, *k, params->h1, params->h2);
> >  #else
> > -       if (params->h2 > *m) {
> > -               pr_err("hash_64_generic(%#llx, %d) = %#x > %#x",
> > -                      *params->h64, *k, params->h1, *m);
> > -               return false;
> > -       }
> > +       KUNIT_EXPECT_LE_MSG(test, params->h1, params->h2,
> > +                           "hash_64_generic(%#llx, %d) = %#x > %#x",
> > +                           *params->h64, *k, params->h1, *m);
> >  #endif
> > -       return true;
> >  }
> >  #endif
> >
> > @@ -112,8 +102,8 @@ test_int_hash_64(struct test_hash_params *params, u32 const *m, int *k)
> >   * inline, the code being tested is actually in the module, and you can
> >   * recompile and re-test the module without rebooting.
> >   */
> > -static bool __init
> > -test_int_hash(unsigned long long h64, u32 hash_or[2][33])
> > +static void __init
> > +test_int_hash(struct kunit *test, unsigned long long h64, u32 hash_or[2][33])
> >  {
> >         int k;
> >         struct test_hash_params params = { &h64, (u32)h64, 0, 0, hash_or };
> > @@ -121,8 +111,7 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
> >         /* Test __hash32 */
> >         hash_or[0][0] |= params.h1 = __hash_32(params.h0);
> >  #ifdef HAVE_ARCH__HASH_32
> > -       if (!test_int__hash_32(&params))
> > -               return false;
> > +       test_int__hash_32(test, &params);
> >  #endif
> >
> >         /* Test k = 1..32 bits */
> > @@ -131,29 +120,24 @@ test_int_hash(unsigned long long h64, u32 hash_or[2][33])
> >
> >                 /* Test hash_32 */
> >                 hash_or[0][k] |= params.h1 = hash_32(params.h0, k);
> > -               if (params.h1 > m) {
> > -                       pr_err("hash_32(%#x, %d) = %#x > %#x", params.h0, k, params.h1, m);
> > -                       return false;
> > -               }
> > +               KUNIT_EXPECT_LE_MSG(test, params.h1, m,
> > +                                   "hash_32(%#x, %d) = %#x > %#x",
> > +                                   params.h0, k, params.h1, m);
> >
> >                 /* Test hash_64 */
> >                 hash_or[1][k] |= params.h1 = hash_64(h64, k);
> > -               if (params.h1 > m) {
> > -                       pr_err("hash_64(%#llx, %d) = %#x > %#x", h64, k, params.h1, m);
> > -                       return false;
> > -               }
> > +               KUNIT_EXPECT_LE_MSG(test, params.h1, m,
> > +                                   "hash_64(%#llx, %d) = %#x > %#x",
> > +                                   h64, k, params.h1, m);
> >  #ifdef HAVE_ARCH_HASH_64
> > -               if (!test_int_hash_64(&params, &m, &k))
> > -                       return false;
> > +               test_int_hash_64(test, &params, &m, &k);
> >  #endif
> >         }
> > -
> > -       return true;
> >  }
> >
> >  #define SIZE 256       /* Run time is cubic in SIZE */
> >
> > -static int __init test_string_or(void)
> > +static void __init test_string_or(struct kunit *test)
> >  {
> >         char buf[SIZE+1];
> >         u32 string_or = 0;
> > @@ -173,20 +157,15 @@ static int __init test_string_or(void)
> >         } /* j */
> >
> >         /* The OR of all the hash values should cover all the bits */
> > -       if (~string_or) {
> > -               pr_err("OR of all string hash results = %#x != %#x",
> > -                      string_or, -1u);
> > -               return -EINVAL;
> > -       }
> > -
> > -       return 0;
> > +       KUNIT_EXPECT_FALSE_MSG(test, ~string_or,
> > +                              "OR of all string hash results = %#x != %#x",
> > +                              string_or, -1u);
>
> It might be worth using KUNIT_EXPECT_EQ_MSG() instead of
> EXPECT_FALSE(), as the real goal of this is to check if all bits are
> set.
>
> This'd look something like:
> KUNIT_EXPECT_EQ_MSG(test, string_or, -1u, "OR of all string hash
> results = %#x != %#x", string_or, -1u);

That makes a lot of sense to me. Thanks for the suggestion :)

>
> If instead we checked if string_or == -1u, I think it'd be clearer and
> match the message better. (In fact, I think you could get away with
> removing the message and using the non-_MSG variants if you really
> wanted, though the extra text describing it as the OR of all string
> results is better.)

I like the text as well, as these tests are not really well separated I think
it makes sense keeping them.

>
> >  }
> >
> > -static int __init test_hash_or(void)
> > +static void __init test_hash_or(struct kunit *test)
> >  {
> >         char buf[SIZE+1];
> >         u32 hash_or[2][33] = { { 0, } };
> > -       unsigned tests = 0;
> >         unsigned long long h64 = 0;
> >         int i, j;
> >
> > @@ -201,39 +180,27 @@ static int __init test_hash_or(void)
> >                         u32 h0 = full_name_hash(buf+i, buf+i, j-i);
> >
> >                         /* Check that hashlen_string gets the length right */
> > -                       if (hashlen_len(hashlen) != j-i) {
> > -                               pr_err("hashlen_string(%d..%d) returned length"
> > -                                       " %u, expected %d",
> > -                                       i, j, hashlen_len(hashlen), j-i);
> > -                               return -EINVAL;
> > -                       }
> > +                       KUNIT_EXPECT_EQ_MSG(test, hashlen_len(hashlen), j-i,
> > +                                           "hashlen_string(%d..%d) returned length %u, expected %d",
> > +                                           i, j, hashlen_len(hashlen), j-i);
> >                         /* Check that the hashes match */
> > -                       if (hashlen_hash(hashlen) != h0) {
> > -                               pr_err("hashlen_string(%d..%d) = %08x != "
> > -                                       "full_name_hash() = %08x",
> > -                                       i, j, hashlen_hash(hashlen), h0);
> > -                               return -EINVAL;
> > -                       }
> > +                       KUNIT_EXPECT_EQ_MSG(test, hashlen_hash(hashlen), h0,
> > +                                           "hashlen_string(%d..%d) = %08x != full_name_hash() = %08x",
> > +                                           i, j, hashlen_hash(hashlen), h0);
> >
> >                         h64 = h64 << 32 | h0;   /* For use with hash_64 */
> > -                       if (!test_int_hash(h64, hash_or))
> > -                               return -EINVAL;
> > -                       tests++;
> > +                       test_int_hash(test, h64, hash_or);
> >                 } /* i */
> >         } /* j */
> >
> > -       if (~hash_or[0][0]) {
> > -               pr_err("OR of all __hash_32 results = %#x != %#x",
> > -                       hash_or[0][0], -1u);
> > -               return -EINVAL;
> > -       }
> > +       KUNIT_EXPECT_FALSE_MSG(test, ~hash_or[0][0],
>
> As above, maybe KUNIT_EXPECT_EQ_MSG() instead. (And ditto for all
> similar checks against ~hash_or[...])?
>
>
> > +                              "OR of all __hash_32 results = %#x != %#x",
> > +                              hash_or[0][0], -1u);
> >  #ifdef HAVE_ARCH__HASH_32
> >  #if HAVE_ARCH__HASH_32 != 1    /* Test is pointless if results match */
> > -       if (~hash_or[1][0]) {
> > -               pr_err("OR of all __hash_32_generic results = %#x != %#x",
> > -                       hash_or[1][0], -1u);
> > -               return -EINVAL;
> > -       }
> > +       KUNIT_EXPECT_FALSE_MSG(test, ~hash_or[1][0],
> > +                              "OR of all __hash_32_generic results = %#x != %#x",
> > +                              hash_or[1][0], -1u);
> >  #endif
> >  #endif
> >
> > @@ -241,65 +208,27 @@ static int __init test_hash_or(void)
> >         for (i = 1; i <= 32; i++) {
> >                 u32 const m = ((u32)2 << (i-1)) - 1;    /* Low i bits set */
> >
> > -               if (hash_or[0][i] != m) {
> > -                       pr_err("OR of all hash_32(%d) results = %#x "
> > -                               "(%#x expected)", i, hash_or[0][i], m);
> > -                       return -EINVAL;
> > -               }
> > -               if (hash_or[1][i] != m) {
> > -                       pr_err("OR of all hash_64(%d) results = %#x "
> > -                               "(%#x expected)", i, hash_or[1][i], m);
> > -                       return -EINVAL;
> > -               }
> > +               KUNIT_EXPECT_EQ_MSG(test, hash_or[0][i], m,
> > +                                   "OR of all hash_32(%d) results = %#x (%#x expected)",
> > +                                   i, hash_or[0][i], m);
> > +               KUNIT_EXPECT_EQ_MSG(test, hash_or[1][i], m,
> > +                                   "OR of all hash_64(%d) results = %#x (%#x expected)",
> > +                                   i, hash_or[1][i], m);
> >         }
> > -
> > -       pr_notice("%u tests passed.", tests);
> > -
> > -       return 0;
> > -}
> > -
> > -static void __init notice_skipped_tests(void)
> > -{
> > -       /* Issue notices about skipped tests. */
> > -#ifdef HAVE_ARCH__HASH_32
> > -#if HAVE_ARCH__HASH_32 != 1
> > -       pr_info("__hash_32() is arch-specific; not compared to generic.");
> > -#endif
> > -#else
> > -       pr_info("__hash_32() has no arch implementation to test.");
> > -#endif
> > -#ifdef HAVE_ARCH_HASH_64
> > -#if HAVE_ARCH_HASH_64 != 1
> > -       pr_info("hash_64() is arch-specific; not compared to generic.");
> > -#endif
> > -#else
> > -       pr_info("hash_64() has no arch implementation to test.");
> > -#endif
> >  }
> >
> > -static int __init
> > -test_hash_init(void)
> > -{
> > -       int ret;
> > -
> > -       ret = test_string_or();
> > -       if (ret < 0)
> > -               return ret;
> > -
> > -       ret = test_hash_or();
> > -       if (ret < 0)
> > -               return ret;
> > -
> > -       notice_skipped_tests();
> > +static struct kunit_case hash_test_cases[] __refdata = {
> > +       KUNIT_CASE(test_string_or),
> > +       KUNIT_CASE(test_hash_or),
> > +       {}
> > +};
> >
> > -       return ret;
> > -}
> > +static struct kunit_suite hash_test_suite = {
> > +       .name = "hash",
> > +       .test_cases = hash_test_cases,
> > +};
> >
> > -static void __exit test_hash_exit(void)
> > -{
> > -}
> >
> > -module_init(test_hash_init);   /* Does everything */
> > -module_exit(test_hash_exit);   /* Does nothing */
> > +kunit_test_suite(hash_test_suite);
> >
> >  MODULE_LICENSE("GPL");
> > --
> > 2.33.0
> >

Again, thanks for your review!

Cheers,
--
Isabella Basso

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

end of thread, other threads:[~2021-10-28 21:10 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-26 22:33 [PATCH v2 0/5] test_hash.c: refactor into KUnit Isabella Basso
2021-09-26 22:33 ` [PATCH v2 1/5] hash.h: remove unused define directive Isabella Basso
2021-10-02  7:19   ` David Gow
2021-10-28 15:46     ` Isabella B do Amaral
2021-09-26 22:33 ` [PATCH v2 2/5] test_hash.c: split test_int_hash into arch-specific functions Isabella Basso
2021-10-02  7:20   ` David Gow
2021-10-28 15:48     ` Isabella B do Amaral
2021-09-26 22:33 ` [PATCH v2 3/5] test_hash.c: split test_hash_init Isabella Basso
2021-09-27  8:17   ` Marco Elver
2021-09-27 12:02     ` Isabella B do Amaral
2021-09-27 12:27       ` Marco Elver
2021-10-02  7:20   ` David Gow
2021-09-26 22:33 ` [PATCH v2 4/5] lib/Kconfig.debug: properly split hash test kernel entries Isabella Basso
2021-10-02  7:22   ` David Gow
2021-09-26 22:33 ` [PATCH v2 5/5] test_hash.c: refactor into kunit Isabella Basso
2021-10-02  7:22   ` David Gow
2021-10-28 21:09     ` Isabella B do Amaral
2021-10-02  7:29 ` [PATCH v2 0/5] test_hash.c: refactor into KUnit David Gow
2021-10-05 21:19   ` Brendan Higgins
2021-10-28 16:48     ` Isabella B do Amaral

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).