Linux-kselftest Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH] [RFC] kunit: move binary assertion out of line
@ 2020-01-10 13:43 Arnd Bergmann
  2020-01-14  2:12 ` Brendan Higgins
  0 siblings, 1 reply; 4+ messages in thread
From: Arnd Bergmann @ 2020-01-10 13:43 UTC (permalink / raw)
  To: Brendan Higgins
  Cc: Arnd Bergmann, Kees Cook, Ard Biesheuvel, Stephen Boyd,
	Dmitry Torokhov, Rafael J. Wysocki, linux-kselftest, kunit-dev,
	Shuah Khan, Greg Kroah-Hartman, Logan Gunthorpe, linux-kernel

In combination with the structleak gcc plugin, kunit can lead to excessive
stack usage when each assertion adds another structure to the stack from
of the calling function:

base/test/property-entry-test.c:99:1: error: the frame size of 3032 bytes is larger than 2048 bytes [-Werror=frame-larger-than=]

As most assertions are binary, change those over to a direct function
call that does not have this problem.  This can probably be improved
further, I just went for a straightforward conversion, but a function
call with 12 fixed arguments plus varargs it not great either.

Cc: Kees Cook <keescook@chromium.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Brendan Higgins <brendanhiggins@google.com>
Cc: Stephen Boyd <sboyd@kernel.org>
Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
Cc: "Rafael J. Wysocki" <rjw@rjwysocki.net>
Cc: linux-kselftest@vger.kernel.org
Cc: kunit-dev@googlegroups.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
I think improving the compiler or the plugin to not force the
allocation of these structs would be better, as it avoids the
whack-a-mole game of fixing up each time it hits us, but this
may not be possible using the current plugin infrastructure.
---
 include/kunit/test.h | 155 ++++++++++++-------------------------------
 lib/kunit/assert.c   |   8 +--
 lib/kunit/test.c     |  42 ++++++++++++
 3 files changed, 90 insertions(+), 115 deletions(-)

diff --git a/include/kunit/test.h b/include/kunit/test.h
index dba48304b3bd..76eadd4a8b77 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -391,6 +391,16 @@ void kunit_do_assertion(struct kunit *test,
 			bool pass,
 			const char *fmt, ...);
 
+void kunit_do_binary_assertion(struct kunit *test, bool pass,
+			       enum kunit_assert_type type,
+			       int line, const char *file,
+			       const char *operation,
+			       const char *left_text, long long left_value,
+			       const char *right_text, long long right_value,
+			       void (*format)(const struct kunit_assert *assert,
+					       struct string_stream *stream),
+			       const char *fmt, ...);
+
 #define KUNIT_ASSERTION(test, pass, assert_class, INITIALIZER, fmt, ...) do {  \
 	struct assert_class __assertion = INITIALIZER;			       \
 	kunit_do_assertion(test,					       \
@@ -491,19 +501,32 @@ do {									       \
 	typeof(left) __left = (left);					       \
 	typeof(right) __right = (right);				       \
 	((void)__typecheck(__left, __right));				       \
-									       \
-	KUNIT_ASSERTION(test,						       \
-			__left op __right,				       \
-			assert_class,					       \
-			ASSERT_CLASS_INIT(test,				       \
-					  assert_type,			       \
-					  #op,				       \
-					  #left,			       \
-					  __left,			       \
-					  #right,			       \
-					  __right),			       \
-			fmt,						       \
-			##__VA_ARGS__);					       \
+	kunit_do_binary_assertion(test, left op right, assert_type, 	       \
+				  __LINE__, __FILE__,  #op, #left, __left,     \
+				  #right, __right,			       \
+				  kunit_binary_assert_format,		       \
+				  fmt, ##__VA_ARGS__);			       \
+} while (0)
+
+#define KUNIT_BASE_POINTER_ASSERTION(test,				       \
+				     assert_class,			       \
+				     ASSERT_CLASS_INIT,			       \
+				     assert_type,			       \
+				     left,				       \
+				     op,				       \
+				     right,				       \
+				     fmt,				       \
+				     ...)				       \
+do {									       \
+	typeof(left) __left = (left);					       \
+	typeof(right) __right = (right);				       \
+	((void)__typecheck(__left, __right));				       \
+	kunit_do_binary_assertion(test, left op right, assert_type, 	       \
+				  __LINE__, __FILE__,  #op,		       \
+				  #left, (uintptr_t)__left,     	       \
+				  #right, (uintptr_t)__right,		       \
+				  kunit_binary_ptr_assert_format,	       \
+				  fmt, ##__VA_ARGS__);			       \
 } while (0)
 
 #define KUNIT_BASE_EQ_MSG_ASSERTION(test,				       \
@@ -625,12 +648,11 @@ do {									       \
 					  right,			       \
 					  fmt,				       \
 					  ...)				       \
-	KUNIT_BASE_EQ_MSG_ASSERTION(test,				       \
-				    kunit_binary_ptr_assert,		       \
-				    KUNIT_INIT_BINARY_PTR_ASSERT_STRUCT,       \
+	KUNIT_BASE_POINTER_ASSERTION(test,				       \
+				    assert_class,			       \
+				    ASSERT_CLASS_INIT,			       \
 				    assert_type,			       \
-				    left,				       \
-				    right,				       \
+				    left, ==, right,			       \
 				    fmt,				       \
 				    ##__VA_ARGS__)
 
@@ -664,12 +686,11 @@ do {									       \
 					  right,			       \
 					  fmt,				       \
 					  ...)				       \
-	KUNIT_BASE_NE_MSG_ASSERTION(test,				       \
-				    kunit_binary_ptr_assert,		       \
-				    KUNIT_INIT_BINARY_PTR_ASSERT_STRUCT,       \
+	KUNIT_BASE_POINTER_ASSERTION(test,				       \
+				    assert_class,			       \
+				    ASSERT_CLASS_INIT,			       \
 				    assert_type,			       \
-				    left,				       \
-				    right,				       \
+				    left, !=, right,			       \
 				    fmt,				       \
 				    ##__VA_ARGS__)
 
@@ -697,28 +718,6 @@ do {									       \
 				      right,				       \
 				      NULL)
 
-#define KUNIT_BINARY_PTR_LT_MSG_ASSERTION(test,				       \
-					  assert_type,			       \
-					  left,				       \
-					  right,			       \
-					  fmt,				       \
-					  ...)				       \
-	KUNIT_BASE_LT_MSG_ASSERTION(test,				       \
-				    kunit_binary_ptr_assert,		       \
-				    KUNIT_INIT_BINARY_PTR_ASSERT_STRUCT,       \
-				    assert_type,			       \
-				    left,				       \
-				    right,				       \
-				    fmt,				       \
-				    ##__VA_ARGS__)
-
-#define KUNIT_BINARY_PTR_LT_ASSERTION(test, assert_type, left, right)	       \
-	KUNIT_BINARY_PTR_LT_MSG_ASSERTION(test,				       \
-					  assert_type,			       \
-					  left,				       \
-					  right,			       \
-					  NULL)
-
 #define KUNIT_BINARY_LE_MSG_ASSERTION(test, assert_type, left, right, fmt, ...)\
 	KUNIT_BASE_LE_MSG_ASSERTION(test,				       \
 				    kunit_binary_assert,		       \
@@ -736,28 +735,6 @@ do {									       \
 				      right,				       \
 				      NULL)
 
-#define KUNIT_BINARY_PTR_LE_MSG_ASSERTION(test,				       \
-					  assert_type,			       \
-					  left,				       \
-					  right,			       \
-					  fmt,				       \
-					  ...)				       \
-	KUNIT_BASE_LE_MSG_ASSERTION(test,				       \
-				    kunit_binary_ptr_assert,		       \
-				    KUNIT_INIT_BINARY_PTR_ASSERT_STRUCT,       \
-				    assert_type,			       \
-				    left,				       \
-				    right,				       \
-				    fmt,				       \
-				    ##__VA_ARGS__)
-
-#define KUNIT_BINARY_PTR_LE_ASSERTION(test, assert_type, left, right)	       \
-	KUNIT_BINARY_PTR_LE_MSG_ASSERTION(test,				       \
-					  assert_type,			       \
-					  left,				       \
-					  right,			       \
-					  NULL)
-
 #define KUNIT_BINARY_GT_MSG_ASSERTION(test, assert_type, left, right, fmt, ...)\
 	KUNIT_BASE_GT_MSG_ASSERTION(test,				       \
 				    kunit_binary_assert,		       \
@@ -775,28 +752,6 @@ do {									       \
 				      right,				       \
 				      NULL)
 
-#define KUNIT_BINARY_PTR_GT_MSG_ASSERTION(test,				       \
-					  assert_type,			       \
-					  left,				       \
-					  right,			       \
-					  fmt,				       \
-					  ...)				       \
-	KUNIT_BASE_GT_MSG_ASSERTION(test,				       \
-				    kunit_binary_ptr_assert,		       \
-				    KUNIT_INIT_BINARY_PTR_ASSERT_STRUCT,       \
-				    assert_type,			       \
-				    left,				       \
-				    right,				       \
-				    fmt,				       \
-				    ##__VA_ARGS__)
-
-#define KUNIT_BINARY_PTR_GT_ASSERTION(test, assert_type, left, right)	       \
-	KUNIT_BINARY_PTR_GT_MSG_ASSERTION(test,				       \
-					  assert_type,			       \
-					  left,				       \
-					  right,			       \
-					  NULL)
-
 #define KUNIT_BINARY_GE_MSG_ASSERTION(test, assert_type, left, right, fmt, ...)\
 	KUNIT_BASE_GE_MSG_ASSERTION(test,				       \
 				    kunit_binary_assert,		       \
@@ -814,28 +769,6 @@ do {									       \
 				      right,				       \
 				      NULL)
 
-#define KUNIT_BINARY_PTR_GE_MSG_ASSERTION(test,				       \
-					  assert_type,			       \
-					  left,				       \
-					  right,			       \
-					  fmt,				       \
-					  ...)				       \
-	KUNIT_BASE_GE_MSG_ASSERTION(test,				       \
-				    kunit_binary_ptr_assert,		       \
-				    KUNIT_INIT_BINARY_PTR_ASSERT_STRUCT,       \
-				    assert_type,			       \
-				    left,				       \
-				    right,				       \
-				    fmt,				       \
-				    ##__VA_ARGS__)
-
-#define KUNIT_BINARY_PTR_GE_ASSERTION(test, assert_type, left, right)	       \
-	KUNIT_BINARY_PTR_GE_MSG_ASSERTION(test,				       \
-					  assert_type,			       \
-					  left,				       \
-					  right,			       \
-					  NULL)
-
 #define KUNIT_BINARY_STR_ASSERTION(test,				       \
 				   assert_type,				       \
 				   left,				       \
diff --git a/lib/kunit/assert.c b/lib/kunit/assert.c
index 86013d4cf891..abb6c70de925 100644
--- a/lib/kunit/assert.c
+++ b/lib/kunit/assert.c
@@ -101,8 +101,8 @@ void kunit_binary_assert_format(const struct kunit_assert *assert,
 void kunit_binary_ptr_assert_format(const struct kunit_assert *assert,
 				    struct string_stream *stream)
 {
-	struct kunit_binary_ptr_assert *binary_assert = container_of(
-			assert, struct kunit_binary_ptr_assert, assert);
+	struct kunit_binary_assert *binary_assert = container_of(
+			assert, struct kunit_binary_assert, assert);
 
 	kunit_base_assert_format(assert, stream);
 	string_stream_add(stream,
@@ -112,10 +112,10 @@ void kunit_binary_ptr_assert_format(const struct kunit_assert *assert,
 			 binary_assert->right_text);
 	string_stream_add(stream, "\t\t%s == %pK\n",
 			 binary_assert->left_text,
-			 binary_assert->left_value);
+			 (void *)(uintptr_t)binary_assert->left_value);
 	string_stream_add(stream, "\t\t%s == %pK",
 			 binary_assert->right_text,
-			 binary_assert->right_value);
+			 (void *)(uintptr_t)binary_assert->right_value);
 	kunit_assert_print_msg(assert, stream);
 }
 
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index c83c0fa59cbd..937f3fbe5ecc 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -172,6 +172,48 @@ void kunit_do_assertion(struct kunit *test,
 		kunit_abort(test);
 }
 
+void kunit_do_binary_assertion(struct kunit *test, bool pass,
+				enum kunit_assert_type type,
+				int line, const char *file,
+				const char *operation,
+				const char *left_text, long long left_value,
+				const char *right_text, long long right_value,
+				void (*format)(const struct kunit_assert *assert,
+						struct string_stream *stream),
+				const char *fmt, ...)
+{
+	va_list args;
+	struct kunit_binary_assert assert = {
+		.assert = {
+			.test = test,
+			.type = type,
+			.file = file,
+			.line = line,
+			.message.fmt = fmt,
+			.format = format,
+		},
+		.operation = operation,
+		.left_text = left_text,
+		.left_value = left_value,
+		.right_text = right_text,
+		.right_value = right_value,
+	};
+
+	if (pass)
+		return;
+
+	va_start(args, fmt);
+
+	assert.assert.message.va = &args;
+
+	kunit_fail(test, &assert.assert);
+
+	va_end(args);
+
+	if (type == KUNIT_ASSERTION)
+		kunit_abort(test);
+}
+
 void kunit_init_test(struct kunit *test, const char *name)
 {
 	spin_lock_init(&test->lock);
-- 
2.20.0


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

* Re: [PATCH] [RFC] kunit: move binary assertion out of line
  2020-01-10 13:43 [PATCH] [RFC] kunit: move binary assertion out of line Arnd Bergmann
@ 2020-01-14  2:12 ` Brendan Higgins
  2020-01-14  2:13   ` Brendan Higgins
  2020-01-14  8:42   ` Arnd Bergmann
  0 siblings, 2 replies; 4+ messages in thread
From: Brendan Higgins @ 2020-01-14  2:12 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Kees Cook, Ard Biesheuvel, Stephen Boyd, Dmitry Torokhov,
	Rafael J. Wysocki, open list:KERNEL SELFTEST FRAMEWORK,
	KUnit Development, Shuah Khan, Greg Kroah-Hartman,
	Logan Gunthorpe, Linux Kernel Mailing List

On Fri, Jan 10, 2020 at 5:43 AM Arnd Bergmann <arnd@arndb.de> wrote:
>
> In combination with the structleak gcc plugin, kunit can lead to excessive
> stack usage when each assertion adds another structure to the stack from
> of the calling function:
>
> base/test/property-entry-test.c:99:1: error: the frame size of 3032 bytes is larger than 2048 bytes [-Werror=frame-larger-than=]
>
> As most assertions are binary, change those over to a direct function
> call that does not have this problem.  This can probably be improved
> further, I just went for a straightforward conversion, but a function
> call with 12 fixed arguments plus varargs it not great either.

Yeah, I am not exactly excited by maintaining such a set of functions.

I don't think anyone wants to go with the heap allocation route.

Along the lines of the union/single copy idea[1]. What if we just put
a union of all the assertion types in the kunit struct? One is already
allocated for every test case and we only need one assertion object
for each test case at a time, so I imagine that sould work.

I will start messing around with the idea. Still, it sounds like we
are down to either reducing the number of instances of this struct
that get created per test case, or we need to remove it entirely (as
you have done here).

Cheers

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

* Re: [PATCH] [RFC] kunit: move binary assertion out of line
  2020-01-14  2:12 ` Brendan Higgins
@ 2020-01-14  2:13   ` Brendan Higgins
  2020-01-14  8:42   ` Arnd Bergmann
  1 sibling, 0 replies; 4+ messages in thread
From: Brendan Higgins @ 2020-01-14  2:13 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: Kees Cook, Ard Biesheuvel, Stephen Boyd, Dmitry Torokhov,
	Rafael J. Wysocki, open list:KERNEL SELFTEST FRAMEWORK,
	KUnit Development, Shuah Khan, Greg Kroah-Hartman,
	Logan Gunthorpe, Linux Kernel Mailing List

On Mon, Jan 13, 2020 at 6:12 PM Brendan Higgins
<brendanhiggins@google.com> wrote:
>
> On Fri, Jan 10, 2020 at 5:43 AM Arnd Bergmann <arnd@arndb.de> wrote:
> >
> > In combination with the structleak gcc plugin, kunit can lead to excessive
> > stack usage when each assertion adds another structure to the stack from
> > of the calling function:
> >
> > base/test/property-entry-test.c:99:1: error: the frame size of 3032 bytes is larger than 2048 bytes [-Werror=frame-larger-than=]
> >
> > As most assertions are binary, change those over to a direct function
> > call that does not have this problem.  This can probably be improved
> > further, I just went for a straightforward conversion, but a function
> > call with 12 fixed arguments plus varargs it not great either.
>
> Yeah, I am not exactly excited by maintaining such a set of functions.
>
> I don't think anyone wants to go with the heap allocation route.
>
> Along the lines of the union/single copy idea[1]. What if we just put
> a union of all the assertion types in the kunit struct? One is already
> allocated for every test case and we only need one assertion object
> for each test case at a time, so I imagine that sould work.
>
> I will start messing around with the idea. Still, it sounds like we
> are down to either reducing the number of instances of this struct
> that get created per test case, or we need to remove it entirely (as
> you have done here).
>
> Cheers

Woops forgot to link the original discussion.

[1] https://lkml.org/lkml/2020/1/13/1166

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

* Re: [PATCH] [RFC] kunit: move binary assertion out of line
  2020-01-14  2:12 ` Brendan Higgins
  2020-01-14  2:13   ` Brendan Higgins
@ 2020-01-14  8:42   ` Arnd Bergmann
  1 sibling, 0 replies; 4+ messages in thread
From: Arnd Bergmann @ 2020-01-14  8:42 UTC (permalink / raw)
  To: Brendan Higgins
  Cc: Kees Cook, Ard Biesheuvel, Stephen Boyd, Dmitry Torokhov,
	Rafael J. Wysocki, open list:KERNEL SELFTEST FRAMEWORK,
	KUnit Development, Shuah Khan, Greg Kroah-Hartman,
	Logan Gunthorpe, Linux Kernel Mailing List

On Tue, Jan 14, 2020 at 3:13 AM Brendan Higgins
<brendanhiggins@google.com> wrote:
>
> On Fri, Jan 10, 2020 at 5:43 AM Arnd Bergmann <arnd@arndb.de> wrote:
> >
> > In combination with the structleak gcc plugin, kunit can lead to excessive
> > stack usage when each assertion adds another structure to the stack from
> > of the calling function:
> >
> > base/test/property-entry-test.c:99:1: error: the frame size of 3032 bytes is larger than 2048 bytes [-Werror=frame-larger-than=]
> >
> > As most assertions are binary, change those over to a direct function
> > call that does not have this problem.  This can probably be improved
> > further, I just went for a straightforward conversion, but a function
> > call with 12 fixed arguments plus varargs it not great either.
>
> Yeah, I am not exactly excited by maintaining such a set of functions.

Ok.

> I don't think anyone wants to go with the heap allocation route.
>
> Along the lines of the union/single copy idea[1]. What if we just put
> a union of all the assertion types in the kunit struct? One is already
> allocated for every test case and we only need one assertion object
> for each test case at a time, so I imagine that sould work.

Ah right, that should work fine, and may also lead to better object
code if the compiler can avoid repeated assignments of the same
values, e.g. ".file = __FILE__".

          Arnd

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

end of thread, back to index

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-10 13:43 [PATCH] [RFC] kunit: move binary assertion out of line Arnd Bergmann
2020-01-14  2:12 ` Brendan Higgins
2020-01-14  2:13   ` Brendan Higgins
2020-01-14  8:42   ` Arnd Bergmann

Linux-kselftest Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-kselftest/0 linux-kselftest/git/0.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-kselftest linux-kselftest/ https://lore.kernel.org/linux-kselftest \
		linux-kselftest@vger.kernel.org
	public-inbox-index linux-kselftest

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.linux-kselftest


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git