[igt-dev] [PATCH i-g-t 2/2] runner: Introduce per-test timeouts

Petri Latvala petri.latvala at intel.com
Mon Feb 17 14:50:42 UTC 2020


A new config option, --per-test-timeout, sets a time a single test
cannot exceed without getting itself killed. The time resets when
starting a subtest or a dynamic subtest, so an execution with
--per-test-timeout=20 can indeed go over 20 seconds a long as it
launches a dynamic subtest within that time.

As a bonus, verbose log level from runner now also prints dynamic
subtest begin/result.

Signed-off-by: Petri Latvala <petri.latvala at intel.com>
---
 runner/executor.c     | 34 +++++++++++++++++++++++++++++++---
 runner/runner_tests.c |  6 ++++++
 runner/settings.c     | 11 +++++++++++
 runner/settings.h     |  1 +
 4 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/runner/executor.c b/runner/executor.c
index 33610c9e..72e45b65 100644
--- a/runner/executor.c
+++ b/runner/executor.c
@@ -676,6 +676,7 @@ static const char *need_to_timeout(struct settings *settings,
 				   int killed,
 				   unsigned long taints,
 				   double time_since_activity,
+				   double time_since_subtest,
 				   double time_since_kill)
 {
 	if (killed) {
@@ -712,10 +713,16 @@ static const char *need_to_timeout(struct settings *settings,
 	    is_tainted(taints))
 		return "Killing the test because the kernel is tainted.\n";
 
+	if (settings->per_test_timeout != 0 &&
+	    time_since_subtest > settings->per_test_timeout) {
+		show_kernel_task_state();
+		return "Per-test timeout exceeded. Killing the current test with SIGQUIT.\n";
+	}
+
 	if (settings->inactivity_timeout != 0 &&
 	    time_since_activity > settings->inactivity_timeout) {
 		show_kernel_task_state();
-		return "Timeout. Killing the current test with SIGQUIT.\n";
+		return "Inactivity timeout exceeded. Killing the current test with SIGQUIT.\n";
 	}
 
 	return NULL;
@@ -759,12 +766,12 @@ static int monitor_output(pid_t child,
 	const int interval_length = 1;
 	int wd_timeout;
 	int killed = 0; /* 0 if not killed, signal number otherwise */
-	struct timespec time_beg, time_now, time_last_activity, time_killed;
+	struct timespec time_beg, time_now, time_last_activity, time_last_subtest, time_killed;
 	unsigned long taints = 0;
 	bool aborting = false;
 
 	igt_gettime(&time_beg);
-	time_last_activity = time_killed = time_beg;
+	time_last_activity = time_last_subtest = time_killed = time_beg;
 
 	if (errfd > nfds)
 		nfds = errfd;
@@ -823,6 +830,7 @@ static int monitor_output(pid_t child,
 
 		timeout_reason = need_to_timeout(settings, killed, tainted(&taints),
 						 igt_time_elapsed(&time_last_activity, &time_now),
+						 igt_time_elapsed(&time_last_subtest, &time_now),
 						 igt_time_elapsed(&time_killed, &time_now));
 
 		if (timeout_reason) {
@@ -893,6 +901,8 @@ static int monitor_output(pid_t child,
 					       linelen - strlen(STARTING_SUBTEST));
 					current_subtest[linelen - strlen(STARTING_SUBTEST)] = '\0';
 
+					time_last_subtest = time_now;
+
 					if (settings->log_level >= LOG_LEVEL_VERBOSE) {
 						fwrite(outbuf, 1, linelen, stdout);
 					}
@@ -921,6 +931,24 @@ static int monitor_output(pid_t child,
 						}
 					}
 				}
+				if (linelen > strlen(STARTING_DYNAMIC_SUBTEST) &&
+				    !memcmp(outbuf, STARTING_DYNAMIC_SUBTEST, strlen(STARTING_DYNAMIC_SUBTEST))) {
+					time_last_subtest = time_now;
+
+					if (settings->log_level >= LOG_LEVEL_VERBOSE) {
+						fwrite(outbuf, 1, linelen, stdout);
+					}
+				}
+				if (linelen > strlen(DYNAMIC_SUBTEST_RESULT) &&
+				    !memcmp(outbuf, DYNAMIC_SUBTEST_RESULT, strlen(DYNAMIC_SUBTEST_RESULT))) {
+					char *delim = memchr(outbuf, ':', linelen);
+
+					if (delim != NULL) {
+						if (settings->log_level >= LOG_LEVEL_VERBOSE) {
+							fwrite(outbuf, 1, linelen, stdout);
+						}
+					}
+				}
 
 				memmove(outbuf, newline + 1, outbufsize - linelen);
 				outbufsize -= linelen;
diff --git a/runner/runner_tests.c b/runner/runner_tests.c
index ed30b3f9..2f4e0abb 100644
--- a/runner/runner_tests.c
+++ b/runner/runner_tests.c
@@ -173,6 +173,7 @@ static void assert_settings_equal(struct settings *one, struct settings *two)
 	igt_assert_eq(one->overwrite, two->overwrite);
 	igt_assert_eq(one->multiple_mode, two->multiple_mode);
 	igt_assert_eq(one->inactivity_timeout, two->inactivity_timeout);
+	igt_assert_eq(one->per_test_timeout, two->per_test_timeout);
 	igt_assert_eq(one->use_watchdog, two->use_watchdog);
 	igt_assert_eqstr(one->test_root, two->test_root);
 	igt_assert_eqstr(one->results_path, two->results_path);
@@ -261,6 +262,7 @@ igt_main
 		igt_assert(!settings->overwrite);
 		igt_assert(!settings->multiple_mode);
 		igt_assert_eq(settings->inactivity_timeout, 0);
+		igt_assert_eq(settings->per_test_timeout, 0);
 		igt_assert_eq(settings->overall_timeout, 0);
 		igt_assert(!settings->use_watchdog);
 		igt_assert(strstr(settings->test_root, "test-root-dir") != NULL);
@@ -378,6 +380,7 @@ igt_main
 		igt_assert(!settings->overwrite);
 		igt_assert(!settings->multiple_mode);
 		igt_assert_eq(settings->inactivity_timeout, 0);
+		igt_assert_eq(settings->per_test_timeout, 0);
 		igt_assert_eq(settings->overall_timeout, 0);
 		igt_assert(!settings->use_watchdog);
 		igt_assert(strstr(settings->test_root, testdatadir) != NULL);
@@ -408,6 +411,7 @@ igt_main
 				       "--overwrite",
 				       "--multiple-mode",
 				       "--inactivity-timeout", "27",
+				       "--per-test-timeout", "72",
 				       "--overall-timeout", "360",
 				       "--use-watchdog",
 				       "--piglit-style-dmesg",
@@ -438,6 +442,7 @@ igt_main
 		igt_assert(settings->overwrite);
 		igt_assert(settings->multiple_mode);
 		igt_assert_eq(settings->inactivity_timeout, 27);
+		igt_assert_eq(settings->per_test_timeout, 72);
 		igt_assert_eq(settings->overall_timeout, 360);
 		igt_assert(settings->use_watchdog);
 		igt_assert(strstr(settings->test_root, "test-root-dir") != NULL);
@@ -827,6 +832,7 @@ igt_main
 					       "--overwrite",
 					       "--multiple-mode",
 					       "--inactivity-timeout", "27",
+					       "--per-test-timeout", "72",
 					       "--overall-timeout", "360",
 					       "--use-watchdog",
 					       "--piglit-style-dmesg",
diff --git a/runner/settings.c b/runner/settings.c
index d601cd11..32840307 100644
--- a/runner/settings.c
+++ b/runner/settings.c
@@ -20,6 +20,7 @@ enum {
 	OPT_PIGLIT_DMESG,
 	OPT_DMESG_WARN_LEVEL,
 	OPT_OVERALL_TIMEOUT,
+	OPT_PER_TEST_TIMEOUT,
 	OPT_HELP = 'h',
 	OPT_NAME = 'n',
 	OPT_DRY_RUN = 'd',
@@ -163,6 +164,10 @@ static const char *usage_str =
 	"  --inactivity-timeout <seconds>\n"
 	"                        Kill the running test after <seconds> of inactivity in\n"
 	"                        the test's stdout, stderr, or dmesg\n"
+	"  --per-test-timeout <seconds>\n"
+	"                        Kill the running test after <seconds>. This timeout is per\n"
+	"                        subtest, or dynamic subtest. In other words, every subtest,\n"
+	"                        even when running in multiple-mode, must finish in <seconds>.\n"
 	"  --overall-timeout <seconds>\n"
 	"                        Don't execute more tests after <seconds> has elapsed\n"
 	"  --use-watchdog        Use hardware watchdog for lethal enforcement of the\n"
@@ -325,6 +330,7 @@ bool parse_options(int argc, char **argv,
 		{"ignore-missing", no_argument, NULL, OPT_IGNORE_MISSING},
 		{"multiple-mode", no_argument, NULL, OPT_MULTIPLE},
 		{"inactivity-timeout", required_argument, NULL, OPT_TIMEOUT},
+		{"per-test-timeout", required_argument, NULL, OPT_PER_TEST_TIMEOUT},
 		{"overall-timeout", required_argument, NULL, OPT_OVERALL_TIMEOUT},
 		{"use-watchdog", no_argument, NULL, OPT_WATCHDOG},
 		{"piglit-style-dmesg", no_argument, NULL, OPT_PIGLIT_DMESG},
@@ -388,6 +394,9 @@ bool parse_options(int argc, char **argv,
 		case OPT_TIMEOUT:
 			settings->inactivity_timeout = atoi(optarg);
 			break;
+		case OPT_PER_TEST_TIMEOUT:
+			settings->per_test_timeout = atoi(optarg);
+			break;
 		case OPT_OVERALL_TIMEOUT:
 			settings->overall_timeout = atoi(optarg);
 			break;
@@ -617,6 +626,7 @@ bool serialize_settings(struct settings *settings)
 	SERIALIZE_LINE(f, settings, overwrite, "%d");
 	SERIALIZE_LINE(f, settings, multiple_mode, "%d");
 	SERIALIZE_LINE(f, settings, inactivity_timeout, "%d");
+	SERIALIZE_LINE(f, settings, per_test_timeout, "%d");
 	SERIALIZE_LINE(f, settings, overall_timeout, "%d");
 	SERIALIZE_LINE(f, settings, use_watchdog, "%d");
 	SERIALIZE_LINE(f, settings, piglit_style_dmesg, "%d");
@@ -662,6 +672,7 @@ bool read_settings_from_file(struct settings *settings, FILE *f)
 		PARSE_LINE(settings, name, val, overwrite, numval);
 		PARSE_LINE(settings, name, val, multiple_mode, numval);
 		PARSE_LINE(settings, name, val, inactivity_timeout, numval);
+		PARSE_LINE(settings, name, val, per_test_timeout, numval);
 		PARSE_LINE(settings, name, val, overall_timeout, numval);
 		PARSE_LINE(settings, name, val, use_watchdog, numval);
 		PARSE_LINE(settings, name, val, piglit_style_dmesg, numval);
diff --git a/runner/settings.h b/runner/settings.h
index 13409f04..5203ec6e 100644
--- a/runner/settings.h
+++ b/runner/settings.h
@@ -38,6 +38,7 @@ struct settings {
 	bool overwrite;
 	bool multiple_mode;
 	int inactivity_timeout;
+	int per_test_timeout;
 	int overall_timeout;
 	bool use_watchdog;
 	char *test_root;
-- 
2.20.1



More information about the igt-dev mailing list