]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
kunit: Adjust kunit_test timeout based on test_{suite,case} speed
authorUjwal Jain <ujwaljain@google.com>
Sat, 14 Jun 2025 08:47:11 +0000 (16:47 +0800)
committerShuah Khan <skhan@linuxfoundation.org>
Wed, 25 Jun 2025 02:47:39 +0000 (20:47 -0600)
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.

Link: https://lore.kernel.org/r/20250614084711.2654593-2-davidgow@google.com
Signed-off-by: Ujwal Jain <ujwaljain@google.com>
Co-developed-by: David Gow <davidgow@google.com>
Signed-off-by: David Gow <davidgow@google.com>
Reviewed-by: Rae Moar <rmoar@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
include/kunit/try-catch.h
lib/kunit/kunit-test.c
lib/kunit/test.c
lib/kunit/try-catch-impl.h
lib/kunit/try-catch.c

index 7c966a1adbd30d7834b78c22a76cacabe2f853ed..d4e1a5b98ed67e4f71ff1bcc71422d5bada54b75 100644 (file)
@@ -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;
 };
 
index f8f567196ca93c112d13e190fe115340b9cf2d31..8c01eabd4eaf286de218fad25b5622f7805446a6 100644 (file)
@@ -44,7 +44,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);
@@ -76,7 +77,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);
@@ -130,7 +132,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);
index 146d1b48a0965e8aaddb6162928f408bbb542645..002121675605d082c040b271fd8fba2e86e70d8c 100644 (file)
@@ -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. */
index 203ba6a5e7409c79d578351d6de395e426f2c4f9..6f401b97cd0b9842e7533f1b828f72f884450f74 100644 (file)
@@ -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 */
index 6bbe0025b0790bd2affacae4bbc36f2739a6f9d7..d84a879f0a789f3625538735644910c84ac80e56 100644 (file)
@@ -34,31 +34,6 @@ static int kunit_generic_run_threadfn_adapter(void *data)
        return 0;
 }
 
-static unsigned long kunit_test_timeout(void)
-{
-       /*
-        * TODO(brendanhiggins@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);