Skip to content

Commit

Permalink
Introduce a concept of max runtime
Browse files Browse the repository at this point in the history
This commit introduces a concept of max test runtime. In other words
test runtime is capped at a certain value in order to make testruns more
deterministic. Test is free to to finish before the runtime is used up,
for example when maximal number of iterations was reached, but test must
stop once the runtime has been used up.

Testcases that run for more than a second or two must check for
remaining runtime by regular calls to tst_remaining_runtime() and should
exit when zero is returned.

The test max runtime must be set either by the .max_iteration_runtime in
the tst_test structure or in the test setup by a call to
tst_set_runtime().

The test timeout is then computed as a sum of DEFAULT_TIMEOUT (currently
set to 30 seconds) and the test runtime. The DEFAULT_TIMEOUT is nothing
more than a safety margin for teardown of the test.

This commit also maps the -I parameter to the test max runtime if
available and introduces LTP_RUNTIME_MUL enviroment variable so that we
have an easy controll over the runtime cap.

Lastly but not least the function related to the timeout are turned into
no-op by this commit and removed after all test are converted to the
runtime API.

Acked-by: Petr Vorel <pvorel@suse.cz>
Reviewed-by: Li Wang <liwang@redhat.com>
Reviewed-by: Richard Palethorpe <rpalethorpe@suse.com>
Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
  • Loading branch information
metan-ucw committed May 24, 2022
1 parent 6dd6876 commit 0f72d51
Show file tree
Hide file tree
Showing 13 changed files with 264 additions and 117 deletions.
42 changes: 32 additions & 10 deletions doc/c-test-api.txt
Expand Up @@ -93,14 +93,35 @@ in range of [0, '.tcnt' - 1].

IMPORTANT: Only one of '.test' and '.test_all' can be set at a time.

Each test has a default timeout set to 300s. The default timeout can be
overridden by setting '.timeout' in the test structure or by calling
'tst_set_timeout()' in the test 'setup()'. There are a few testcases whose run
time may vary arbitrarily, for these timeout can be disabled by setting it to
-1.
Each test has a limit on how long it can run and the limit composes of two
parts max_runtime and timeout. The max_runtime is a limit for how long can the
'.test_all' or a set of '.test' functions take and the timeout is static part
that should cover the duration of test setup and cleanup plus some safety.

Test can find out how much time (in seconds) is remaining to timeout,
by calling 'tst_timeout_remaining()'.
Any test that runs for more than a second or two has to make sure to:

- set the runtime either by setting the '.max_runtime' in tst_test or by
calling 'tst_set_runtime()' in the test setup

- monitor remaning runtime by regular calls to 'tst_remaining_runtime()' and
exit when runtime has been used up

Test is free to exit before max_runtime has been used up for example when
minimal number of iteration was finished.

The limit is applied to a single call of the '.test_all' function that means
that for example when '.test_variants' or '.all_filesystems' is set the whole
test will be limited by 'variants * (max_runtime + timeout)' seconds and the
test runtime will be likely close to 'variants * max_runtime' seconds.

[source,c]
-------------------------------------------------------------------------------
/*
* Returns number of seconds or zero in case that runtime has been used up.
*/

int tst_remaining_runtime(void);
-------------------------------------------------------------------------------

LAPI headers
++++++++++++
Expand Down Expand Up @@ -377,12 +398,13 @@ WARNING: This function is not thread safe.

[source,c]
-------------------------------------------------------------------------------
void tst_set_timeout(unsigned int timeout);
void tst_set_max_runtime(int max_runtime);
-------------------------------------------------------------------------------

Allows for setting timeout per test iteration dynamically in the test setup(),
Allows for setting max_runtime per test iteration dynamically in the test setup(),
the timeout is specified in seconds. There are a few testcases whose runtime
can vary arbitrarily, these can disable timeouts by setting it to -1.
can vary arbitrarily, these can disable timeouts by setting it to
TST_UNLIMITED_RUNTIME.

[source,c]
-------------------------------------------------------------------------------
Expand Down
30 changes: 29 additions & 1 deletion doc/user-guide.txt
Expand Up @@ -22,9 +22,13 @@ For running LTP network tests see `testcases/network/README.md`.
| 'LTP_SINGLE_FS_TYPE' | Testing only - specifies filesystem instead all
supported (for tests with '.all_filesystems').
| 'LTP_DEV_FS_TYPE' | Filesystem used for testing (default: 'ext2').
| 'LTP_TIMEOUT_MUL' | Multiply timeout, must be number >= 1 (> 1 is useful for
| 'LTP_TIMEOUT_MUL' | Multiplies timeout, must be number >= 0.1 (> 1 is useful for
slow machines to avoid unexpected timeout).
Variable is also used in shell tests, but ceiled to int.
| 'LTP_RUNTIME_MUL' | Multiplies maximal test iteration runtime. Tests
that run for more than a second or two are capped on
runtime. You can scale the default runtime both up
and down with this multiplier.
| 'LTP_VIRT_OVERRIDE' | Overrides virtual machine detection in the test
library. Setting it to empty string tell the library
that system is not a virtual machine. Other possible
Expand All @@ -36,3 +40,27 @@ For running LTP network tests see `testcases/network/README.md`.
and others, which imply it, shell: 'TST_NEEDS_TMPDIR=1').
| 'TST_NO_CLEANUP' | Disable running test cleanup (defined in 'TST_CLEANUP').
|==============================================================================


2. Test execution time and timeout
----------------------------------

The limit on how long a test can run does compose of two parts max_runtime and
timeout. The limit does apply to a single test variant, that means for example
that tests that run for all available filesystems will apply this limit for a
single filesytem only.

The max_runtime is a cap on how long the run() function can take, for most
testcases this part is set to zero. For tests that do run for more than a
second or two the max_runtime has to be defined and the run() function has to
check actively how much runtime is left.

Test runtime can be scaled up and down with 'LTP_RUNTIME_MUL' environment
variable or set on a commandline by the '-I' parameter. Hoewever be vary that
setting the runtime too low will cause long running tests to exit prematurely
possibly before the have a chance actually test anyting.

The timeout part is a limit for the test setup and cleanup and also safety
margin for the runtime accounting. It's currently set to 30 seconds but may
change later. If your target machine is too slow it can be scaled up with the
'LTP_TIMEOUT_MUL' environment variable.
27 changes: 27 additions & 0 deletions include/tst_test.h
Expand Up @@ -134,6 +134,8 @@ extern unsigned int tst_variant;

#define TST_NO_HUGEPAGES ((unsigned long)-1)

#define TST_UNLIMITED_RUNTIME (-1)

struct tst_test {
/* number of tests available in test() function */
unsigned int tcnt;
Expand Down Expand Up @@ -236,6 +238,18 @@ struct tst_test {

/* override default timeout per test run, disabled == -1 */
int timeout;
/*
* Maximal test runtime in seconds.
*
* Any test that runs for more than a second or two should set this and
* also use tst_remaining_runtime() to exit when runtime was used up.
* Tests may finish sooner, for example if requested number of
* iterations was reached before the runtime runs out.
*
* If test runtime cannot be know in advance it should be set to
* TST_UNLIMITED_RUNTIME.
*/
int max_runtime;

void (*setup)(void);
void (*cleanup)(void);
Expand Down Expand Up @@ -323,6 +337,19 @@ unsigned int tst_timeout_remaining(void);
unsigned int tst_multiply_timeout(unsigned int timeout);
void tst_set_timeout(int timeout);

/*
* Returns remaining test runtime. Test that runs for more than a few seconds
* should check if they should exit by calling this function regularly.
*
* The function returns remaining runtime in seconds. If runtime was used up
* zero is returned.
*/
unsigned int tst_remaining_runtime(void);

/*
* Sets maximal test runtime in seconds.
*/
void tst_set_max_runtime(int max_runtime);

/*
* Returns path to the test temporary directory in a newly allocated buffer.
Expand Down
5 changes: 2 additions & 3 deletions lib/newlib_tests/.gitignore
Expand Up @@ -7,9 +7,7 @@ test06
test07
test08
test09
test10
test11
test12
test13
test14
test15
Expand All @@ -22,7 +20,6 @@ tst_safe_fileops
tst_res_hexd
tst_strstatus
tst_print_result
test18
test19
test20
test22
Expand Down Expand Up @@ -56,3 +53,5 @@ tst_needs_cmds05
tst_needs_cmds06
tst_needs_cmds07
tst_needs_cmds08
test_runtime01
test_runtime02
2 changes: 1 addition & 1 deletion lib/newlib_tests/runtest.sh
@@ -1,7 +1,7 @@
#!/bin/sh
# Copyright (c) 2021 Petr Vorel <pvorel@suse.cz>

LTP_C_API_TESTS="${LTP_C_API_TESTS:-test05 test07 test09 test12 test15 test18
LTP_C_API_TESTS="${LTP_C_API_TESTS:-test05 test07 test09 test15 test_runtime01
tst_needs_cmds01 tst_needs_cmds02 tst_needs_cmds03 tst_needs_cmds06
tst_needs_cmds07 tst_bool_expr test_exec test_timer tst_res_hexd tst_strstatus
tst_fuzzy_sync03 test_zero_hugepage.sh test_kconfig.sh
Expand Down
22 changes: 0 additions & 22 deletions lib/newlib_tests/test10.c

This file was deleted.

21 changes: 0 additions & 21 deletions lib/newlib_tests/test12.c

This file was deleted.

1 change: 0 additions & 1 deletion lib/newlib_tests/test13.c
Expand Up @@ -20,7 +20,6 @@ static void do_test(void)
}

static struct tst_test test = {
.timeout = 1,
.forks_child = 1,
.test_all = do_test,
};
22 changes: 0 additions & 22 deletions lib/newlib_tests/test18.c

This file was deleted.

1 change: 0 additions & 1 deletion lib/newlib_tests/test_children_cleanup.c
Expand Up @@ -39,5 +39,4 @@ static void run(void)
static struct tst_test test = {
.test_all = run,
.forks_child = 1,
.timeout = 10,
};
30 changes: 30 additions & 0 deletions lib/newlib_tests/test_runtime01.c
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2018, Linux Test Project
*
* Runs for 4 seconds for each test iteration.
*/
#include <stdlib.h>
#include <unistd.h>
#include "tst_test.h"

static void run(void)
{
int runtime;

tst_res(TINFO, "Running variant %i", tst_variant);

do {
runtime = tst_remaining_runtime();
tst_res(TINFO, "Remaining runtime %d", runtime);
sleep(1);
} while (runtime);

tst_res(TPASS, "Finished loop!");
}

static struct tst_test test = {
.test_all = run,
.max_runtime = 4,
.test_variants = 2,
};
28 changes: 28 additions & 0 deletions lib/newlib_tests/test_runtime02.c
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2021, Linux Test Project
*/
/*
* This test is set up so that the timeout is not long enough to guarantee
* enough runtime for two iterations, i.e. the timeout without offset and after
* scaling is too small and the tests ends up with TBROK.
*
* The default timeout in the test library is set to 30 seconds. The test
* runtime is set to 5 so the test should timeout after 35 seconds.
*/

#include <stdlib.h>
#include <unistd.h>
#include "tst_test.h"

static void run(void)
{
tst_res(TINFO, "Sleeping for 40 seconds");
sleep(40);
tst_res(TFAIL, "Still alive");
}

static struct tst_test test = {
.test_all = run,
.max_runtime = 5,
};

0 comments on commit 0f72d51

Please sign in to comment.