From: Ujwal Jain <ujwalj...@google.com>

Currently, the in-kernel kunit test case timeout is 300 seconds. (There
is a separate timeout mechanism for the whole test execution in
kunit.py, but that's unrelated.) However, tests marked 'slow' or 'very
slow' may timeout, particularly on slower machines.

Implement a multiplier to the test-case timeout, so that slower tests
have longer to complete:
- DEFAULT -> 1x default timeout
- KUNIT_SPEED_SLOW -> 3x default timeout
- KUNIT_SPEED_VERY_SLOW -> 12x default timeout

A further change is planned to allow user configuration of the
default/base timeout to allow people with faster or slower machines to
adjust these to their use-cases.

Signed-off-by: Ujwal Jain <ujwalj...@google.com>
Co-developed-by: David Gow <david...@google.com>
Signed-off-by: David Gow <david...@google.com>
---
 include/kunit/try-catch.h  |  1 +
 lib/kunit/kunit-test.c     |  9 +++++---
 lib/kunit/test.c           | 46 ++++++++++++++++++++++++++++++++++++--
 lib/kunit/try-catch-impl.h |  4 +++-
 lib/kunit/try-catch.c      | 29 ++----------------------
 5 files changed, 56 insertions(+), 33 deletions(-)

diff --git a/include/kunit/try-catch.h b/include/kunit/try-catch.h
index 7c966a1adbd3..d4e1a5b98ed6 100644
--- a/include/kunit/try-catch.h
+++ b/include/kunit/try-catch.h
@@ -47,6 +47,7 @@ struct kunit_try_catch {
        int try_result;
        kunit_try_catch_func_t try;
        kunit_try_catch_func_t catch;
+       unsigned long timeout;
        void *context;
 };
 
diff --git a/lib/kunit/kunit-test.c b/lib/kunit/kunit-test.c
index d9c781c859fd..387cdf7782f6 100644
--- a/lib/kunit/kunit-test.c
+++ b/lib/kunit/kunit-test.c
@@ -43,7 +43,8 @@ static void 
kunit_test_try_catch_successful_try_no_catch(struct kunit *test)
        kunit_try_catch_init(try_catch,
                             test,
                             kunit_test_successful_try,
-                            kunit_test_no_catch);
+                            kunit_test_no_catch,
+                            300 * msecs_to_jiffies(MSEC_PER_SEC));
        kunit_try_catch_run(try_catch, test);
 
        KUNIT_EXPECT_TRUE(test, ctx->function_called);
@@ -75,7 +76,8 @@ static void 
kunit_test_try_catch_unsuccessful_try_does_catch(struct kunit *test)
        kunit_try_catch_init(try_catch,
                             test,
                             kunit_test_unsuccessful_try,
-                            kunit_test_catch);
+                            kunit_test_catch,
+                            300 * msecs_to_jiffies(MSEC_PER_SEC));
        kunit_try_catch_run(try_catch, test);
 
        KUNIT_EXPECT_TRUE(test, ctx->function_called);
@@ -129,7 +131,8 @@ static void kunit_test_fault_null_dereference(struct kunit 
*test)
        kunit_try_catch_init(try_catch,
                             test,
                             kunit_test_null_dereference,
-                            kunit_test_catch);
+                            kunit_test_catch,
+                            300 * msecs_to_jiffies(MSEC_PER_SEC));
        kunit_try_catch_run(try_catch, test);
 
        KUNIT_EXPECT_EQ(test, try_catch->try_result, -EINTR);
diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 146d1b48a096..002121675605 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -373,6 +373,46 @@ static void kunit_run_case_check_speed(struct kunit *test,
                   duration.tv_sec, duration.tv_nsec);
 }
 
+/* Returns timeout multiplier based on speed.
+ * DEFAULT:                1
+ * KUNIT_SPEED_SLOW:        3
+ * KUNIT_SPEED_VERY_SLOW:   12
+ */
+static int kunit_timeout_mult(enum kunit_speed speed)
+{
+       switch (speed) {
+       case KUNIT_SPEED_SLOW:
+               return 3;
+       case KUNIT_SPEED_VERY_SLOW:
+               return 12;
+       default:
+               return 1;
+       }
+}
+
+static unsigned long kunit_test_timeout(struct kunit_suite *suite, struct 
kunit_case *test_case)
+{
+       int mult = 1;
+       /*
+        * TODO: Make the default (base) timeout configurable, so that users 
with
+        * particularly slow or fast machines can successfully run tests, while
+        * still taking advantage of the relative speed.
+        */
+       unsigned long default_timeout = 300;
+
+       /*
+        * The default test timeout is 300 seconds and will be adjusted by mult
+        * based on the test speed. The test speed will be overridden by the
+        * innermost test component.
+        */
+       if (suite->attr.speed != KUNIT_SPEED_UNSET)
+               mult = kunit_timeout_mult(suite->attr.speed);
+       if (test_case->attr.speed != KUNIT_SPEED_UNSET)
+               mult = kunit_timeout_mult(test_case->attr.speed);
+       return mult * default_timeout * msecs_to_jiffies(MSEC_PER_SEC);
+}
+
+
 /*
  * Initializes and runs test case. Does not clean up or do post validations.
  */
@@ -527,7 +567,8 @@ static void kunit_run_case_catch_errors(struct kunit_suite 
*suite,
        kunit_try_catch_init(try_catch,
                             test,
                             kunit_try_run_case,
-                            kunit_catch_run_case);
+                            kunit_catch_run_case,
+                            kunit_test_timeout(suite, test_case));
        context.test = test;
        context.suite = suite;
        context.test_case = test_case;
@@ -537,7 +578,8 @@ static void kunit_run_case_catch_errors(struct kunit_suite 
*suite,
        kunit_try_catch_init(try_catch,
                             test,
                             kunit_try_run_case_cleanup,
-                            kunit_catch_run_case_cleanup);
+                            kunit_catch_run_case_cleanup,
+                            kunit_test_timeout(suite, test_case));
        kunit_try_catch_run(try_catch, &context);
 
        /* Propagate the parameter result to the test case. */
diff --git a/lib/kunit/try-catch-impl.h b/lib/kunit/try-catch-impl.h
index 203ba6a5e740..6f401b97cd0b 100644
--- a/lib/kunit/try-catch-impl.h
+++ b/lib/kunit/try-catch-impl.h
@@ -17,11 +17,13 @@ struct kunit;
 static inline void kunit_try_catch_init(struct kunit_try_catch *try_catch,
                                        struct kunit *test,
                                        kunit_try_catch_func_t try,
-                                       kunit_try_catch_func_t catch)
+                                       kunit_try_catch_func_t catch,
+                                       unsigned long timeout)
 {
        try_catch->test = test;
        try_catch->try = try;
        try_catch->catch = catch;
+       try_catch->timeout = timeout;
 }
 
 #endif /* _KUNIT_TRY_CATCH_IMPL_H */
diff --git a/lib/kunit/try-catch.c b/lib/kunit/try-catch.c
index 6bbe0025b079..d84a879f0a78 100644
--- a/lib/kunit/try-catch.c
+++ b/lib/kunit/try-catch.c
@@ -34,31 +34,6 @@ static int kunit_generic_run_threadfn_adapter(void *data)
        return 0;
 }
 
-static unsigned long kunit_test_timeout(void)
-{
-       /*
-        * TODO(brendanhigg...@google.com): We should probably have some type of
-        * variable timeout here. The only question is what that timeout value
-        * should be.
-        *
-        * The intention has always been, at some point, to be able to label
-        * tests with some type of size bucket (unit/small, integration/medium,
-        * large/system/end-to-end, etc), where each size bucket would get a
-        * default timeout value kind of like what Bazel does:
-        * 
https://docs.bazel.build/versions/master/be/common-definitions.html#test.size
-        * There is still some debate to be had on exactly how we do this. (For
-        * one, we probably want to have some sort of test runner level
-        * timeout.)
-        *
-        * For more background on this topic, see:
-        * https://mike-bland.com/2011/11/01/small-medium-large.html
-        *
-        * If tests timeout due to exceeding sysctl_hung_task_timeout_secs,
-        * the task will be killed and an oops generated.
-        */
-       return 300 * msecs_to_jiffies(MSEC_PER_SEC); /* 5 min */
-}
-
 void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context)
 {
        struct kunit *test = try_catch->test;
@@ -85,8 +60,8 @@ void kunit_try_catch_run(struct kunit_try_catch *try_catch, 
void *context)
        task_done = task_struct->vfork_done;
        wake_up_process(task_struct);
 
-       time_remaining = wait_for_completion_timeout(task_done,
-                                                    kunit_test_timeout());
+       time_remaining = wait_for_completion_timeout(
+               task_done, try_catch->timeout);
        if (time_remaining == 0) {
                try_catch->try_result = -ETIMEDOUT;
                kthread_stop(task_struct);
-- 
2.50.0.rc1.591.g9c95f17f64-goog


Reply via email to