Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

kunit: Adjust kunit_test timeout based on test_{suite,case} speed

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>

authored by

Ujwal Jain and committed by
Shuah Khan
63d0a912 e42ad393

+56 -33
+1
include/kunit/try-catch.h
··· 47 47 int try_result; 48 48 kunit_try_catch_func_t try; 49 49 kunit_try_catch_func_t catch; 50 + unsigned long timeout; 50 51 void *context; 51 52 }; 52 53
+6 -3
lib/kunit/kunit-test.c
··· 44 44 kunit_try_catch_init(try_catch, 45 45 test, 46 46 kunit_test_successful_try, 47 - kunit_test_no_catch); 47 + kunit_test_no_catch, 48 + 300 * msecs_to_jiffies(MSEC_PER_SEC)); 48 49 kunit_try_catch_run(try_catch, test); 49 50 50 51 KUNIT_EXPECT_TRUE(test, ctx->function_called); ··· 77 76 kunit_try_catch_init(try_catch, 78 77 test, 79 78 kunit_test_unsuccessful_try, 80 - kunit_test_catch); 79 + kunit_test_catch, 80 + 300 * msecs_to_jiffies(MSEC_PER_SEC)); 81 81 kunit_try_catch_run(try_catch, test); 82 82 83 83 KUNIT_EXPECT_TRUE(test, ctx->function_called); ··· 132 130 kunit_try_catch_init(try_catch, 133 131 test, 134 132 kunit_test_null_dereference, 135 - kunit_test_catch); 133 + kunit_test_catch, 134 + 300 * msecs_to_jiffies(MSEC_PER_SEC)); 136 135 kunit_try_catch_run(try_catch, test); 137 136 138 137 KUNIT_EXPECT_EQ(test, try_catch->try_result, -EINTR);
+44 -2
lib/kunit/test.c
··· 373 373 duration.tv_sec, duration.tv_nsec); 374 374 } 375 375 376 + /* Returns timeout multiplier based on speed. 377 + * DEFAULT: 1 378 + * KUNIT_SPEED_SLOW: 3 379 + * KUNIT_SPEED_VERY_SLOW: 12 380 + */ 381 + static int kunit_timeout_mult(enum kunit_speed speed) 382 + { 383 + switch (speed) { 384 + case KUNIT_SPEED_SLOW: 385 + return 3; 386 + case KUNIT_SPEED_VERY_SLOW: 387 + return 12; 388 + default: 389 + return 1; 390 + } 391 + } 392 + 393 + static unsigned long kunit_test_timeout(struct kunit_suite *suite, struct kunit_case *test_case) 394 + { 395 + int mult = 1; 396 + /* 397 + * TODO: Make the default (base) timeout configurable, so that users with 398 + * particularly slow or fast machines can successfully run tests, while 399 + * still taking advantage of the relative speed. 400 + */ 401 + unsigned long default_timeout = 300; 402 + 403 + /* 404 + * The default test timeout is 300 seconds and will be adjusted by mult 405 + * based on the test speed. The test speed will be overridden by the 406 + * innermost test component. 407 + */ 408 + if (suite->attr.speed != KUNIT_SPEED_UNSET) 409 + mult = kunit_timeout_mult(suite->attr.speed); 410 + if (test_case->attr.speed != KUNIT_SPEED_UNSET) 411 + mult = kunit_timeout_mult(test_case->attr.speed); 412 + return mult * default_timeout * msecs_to_jiffies(MSEC_PER_SEC); 413 + } 414 + 415 + 376 416 /* 377 417 * Initializes and runs test case. Does not clean up or do post validations. 378 418 */ ··· 567 527 kunit_try_catch_init(try_catch, 568 528 test, 569 529 kunit_try_run_case, 570 - kunit_catch_run_case); 530 + kunit_catch_run_case, 531 + kunit_test_timeout(suite, test_case)); 571 532 context.test = test; 572 533 context.suite = suite; 573 534 context.test_case = test_case; ··· 578 537 kunit_try_catch_init(try_catch, 579 538 test, 580 539 kunit_try_run_case_cleanup, 581 - kunit_catch_run_case_cleanup); 540 + kunit_catch_run_case_cleanup, 541 + kunit_test_timeout(suite, test_case)); 582 542 kunit_try_catch_run(try_catch, &context); 583 543 584 544 /* Propagate the parameter result to the test case. */
+3 -1
lib/kunit/try-catch-impl.h
··· 17 17 static inline void kunit_try_catch_init(struct kunit_try_catch *try_catch, 18 18 struct kunit *test, 19 19 kunit_try_catch_func_t try, 20 - kunit_try_catch_func_t catch) 20 + kunit_try_catch_func_t catch, 21 + unsigned long timeout) 21 22 { 22 23 try_catch->test = test; 23 24 try_catch->try = try; 24 25 try_catch->catch = catch; 26 + try_catch->timeout = timeout; 25 27 } 26 28 27 29 #endif /* _KUNIT_TRY_CATCH_IMPL_H */
+2 -27
lib/kunit/try-catch.c
··· 34 34 return 0; 35 35 } 36 36 37 - static unsigned long kunit_test_timeout(void) 38 - { 39 - /* 40 - * TODO(brendanhiggins@google.com): We should probably have some type of 41 - * variable timeout here. The only question is what that timeout value 42 - * should be. 43 - * 44 - * The intention has always been, at some point, to be able to label 45 - * tests with some type of size bucket (unit/small, integration/medium, 46 - * large/system/end-to-end, etc), where each size bucket would get a 47 - * default timeout value kind of like what Bazel does: 48 - * https://docs.bazel.build/versions/master/be/common-definitions.html#test.size 49 - * There is still some debate to be had on exactly how we do this. (For 50 - * one, we probably want to have some sort of test runner level 51 - * timeout.) 52 - * 53 - * For more background on this topic, see: 54 - * https://mike-bland.com/2011/11/01/small-medium-large.html 55 - * 56 - * If tests timeout due to exceeding sysctl_hung_task_timeout_secs, 57 - * the task will be killed and an oops generated. 58 - */ 59 - return 300 * msecs_to_jiffies(MSEC_PER_SEC); /* 5 min */ 60 - } 61 - 62 37 void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context) 63 38 { 64 39 struct kunit *test = try_catch->test; ··· 60 85 task_done = task_struct->vfork_done; 61 86 wake_up_process(task_struct); 62 87 63 - time_remaining = wait_for_completion_timeout(task_done, 64 - kunit_test_timeout()); 88 + time_remaining = wait_for_completion_timeout( 89 + task_done, try_catch->timeout); 65 90 if (time_remaining == 0) { 66 91 try_catch->try_result = -ETIMEDOUT; 67 92 kthread_stop(task_struct);