On Sat, Jun 14, 2025 at 4:47 AM David Gow davidgow@google.com wrote:
From: Ujwal Jain ujwaljain@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
 
Hello!
This change is looking great to me. No major concerns with the code and the tests are all passing.
Just a few thoughts: I am wondering where the multipliers of 3 and 12 came from? Are there specific tests that need those timeout amounts? And then given this changes the behavior of tests marked as slow and very_slow, we should update the documentation. And if possible, we should also add tests to check this feature.
Otherwise, this looks good to me!
Thanks! -Rae
Reviewed-by: Rae Moar rmoar@google.com
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 ujwaljain@google.com Co-developed-by: David Gow davidgow@google.com Signed-off-by: David Gow davidgow@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(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);-- 2.50.0.rc1.591.g9c95f17f64-goog