[igt-dev] [PATCH i-g-t 1/2] runner: Add --overall-timeout

Petri Latvala petri.latvala at intel.com
Wed Oct 10 10:41:00 UTC 2018


With --overall-timeout $foo, the runner will stop executing new tests
when $foo seconds have already been used.

A resumed run will start over with no time used, using the same
timeout. This allows for executing a long list of tests piecemeal, in
about $foo length executions.

Signed-off-by: Petri Latvala <petri.latvala at intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=106127
Cc: Arkadiusz Hiler <arkadiusz.hiler at intel.com>
Cc: Tomi Sarvela <tomi.p.sarvela at intel.com>
Cc: Martin Peres <martin.peres at linux.intel.com>
---
 runner/executor.c     | 113 ++++++++++++++++++++++++++++++++++--------
 runner/executor.h     |   6 +++
 runner/runner_tests.c |   5 ++
 runner/settings.c     |   9 ++++
 runner/settings.h     |   1 +
 5 files changed, 114 insertions(+), 20 deletions(-)

diff --git a/runner/executor.c b/runner/executor.c
index 8b87a421..fc79f772 100644
--- a/runner/executor.c
+++ b/runner/executor.c
@@ -335,6 +335,7 @@ static bool kill_child(int sig, pid_t child)
 static int monitor_output(pid_t child,
 			   int outfd, int errfd, int kmsgfd, int sigfd,
 			   int *outputs,
+			   double *time_spent,
 			   struct settings *settings)
 {
 	fd_set set;
@@ -619,6 +620,9 @@ static int monitor_output(pid_t child,
 				if (settings->sync) {
 					fdatasync(outputs[_F_JOURNAL]);
 				}
+
+				if (time_spent)
+					*time_spent = time;
 			}
 
 			close(sigfd);
@@ -698,17 +702,30 @@ static int digits(size_t num)
 	return ret;
 }
 
+static void print_time_left(struct execute_state *state,
+			    struct settings *settings)
+{
+	int width;
+
+	if (settings->overall_timeout <= 0)
+		return;
+
+	width = digits(settings->overall_timeout);
+	printf("(%*.0fs left) ", width, state->time_left);
+}
+
 /*
  * Returns:
  *  =0 - Success
  *  <0 - Failure executing
  *  >0 - Timeout happened, need to recreate from journal
  */
-static int execute_entry(size_t idx,
-			  size_t total,
-			  struct settings *settings,
-			  struct job_list_entry *entry,
-			  int testdirfd, int resdirfd)
+static int execute_next_entry(struct execute_state *state,
+			      size_t total,
+			      double *time_spent,
+			      struct settings *settings,
+			      struct job_list_entry *entry,
+			      int testdirfd, int resdirfd)
 {
 	int dirfd;
 	int outputs[_F_LAST];
@@ -720,6 +737,7 @@ static int execute_entry(size_t idx,
 	char name[32];
 	pid_t child;
 	int result;
+	size_t idx = state->next;
 
 	snprintf(name, sizeof(name), "%zd", idx);
 	mkdirat(resdirfd, name, 0777);
@@ -780,7 +798,12 @@ static int execute_entry(size_t idx,
 
 	if (settings->log_level >= LOG_LEVEL_NORMAL) {
 		int width = digits(total);
-		printf("[%0*zd/%0*zd] %s", width, idx + 1, width, total, entry->binary);
+		printf("[%0*zd/%0*zd] ", width, idx + 1, width, total);
+
+		print_time_left(state, settings);
+
+		printf("%s", entry->binary);
+
 		if (entry->subtest_count > 0) {
 			size_t i;
 			const char *delim = "";
@@ -792,6 +815,7 @@ static int execute_entry(size_t idx,
 			}
 			printf(")");
 		}
+
 		printf("\n");
 	}
 
@@ -810,7 +834,7 @@ static int execute_entry(size_t idx,
 		close(errpipe[1]);
 
 		result = monitor_output(child, outfd, errfd, kmsgfd, sigfd,
-					outputs, settings);
+					outputs, time_spent, settings);
 	} else {
 		int outfd = outpipe[1];
 		int errfd = errpipe[1];
@@ -913,6 +937,15 @@ static double timeofday_double()
 	return 0.0;
 }
 
+static void init_time_left(struct execute_state *state,
+			   struct settings *settings)
+{
+	if (settings->overall_timeout <= 0)
+		state->time_left = -1;
+	else
+		state->time_left = settings->overall_timeout;
+}
+
 bool initialize_execute_state_from_resume(int dirfd,
 					  struct execute_state *state,
 					  struct settings *settings,
@@ -931,6 +964,8 @@ bool initialize_execute_state_from_resume(int dirfd,
 		return false;
 	}
 
+	init_time_left(state, settings);
+
 	for (i = list->size; i >= 0; i--) {
 		char name[32];
 
@@ -986,15 +1021,37 @@ bool initialize_execute_state(struct execute_state *state,
 	    !clear_old_results(settings->results_path))
 		return false;
 
+	init_time_left(state, settings);
+
 	return true;
 }
 
+static void reduce_time_left(struct settings *settings,
+			     struct execute_state *state,
+			     double time_spent)
+{
+	if (state->time_left < 0)
+		return;
+
+	if (time_spent > state->time_left)
+		state->time_left = 0.0;
+	else
+		state->time_left -= time_spent;
+}
+
+static bool overall_timeout_exceeded(struct execute_state *state)
+{
+	return state->time_left == 0.0;
+}
+
 bool execute(struct execute_state *state,
 	     struct settings *settings,
 	     struct job_list *job_list)
 {
 	struct utsname unamebuf;
 	int resdirfd, testdirfd, unamefd, timefd;
+	double time_spent = 0.0;
+	bool status = true;
 
 	if ((resdirfd = open(settings->results_path, O_DIRECTORY | O_RDONLY)) < 0) {
 		/* Initialize state should have done this */
@@ -1045,20 +1102,36 @@ bool execute(struct execute_state *state,
 
 	for (; state->next < job_list->size;
 	     state->next++) {
-		int result = execute_entry(state->next,
-					   job_list->size,
-					   settings,
-					   &job_list->entries[state->next],
-					   testdirfd, resdirfd);
-		if (result != 0) {
+		int result = execute_next_entry(state,
+						job_list->size,
+						&time_spent,
+						settings,
+						&job_list->entries[state->next],
+						testdirfd, resdirfd);
+
+		if (result < 0) {
+			status = false;
+			break;
+		}
+
+		reduce_time_left(settings, state, time_spent);
+
+		if (overall_timeout_exceeded(state)) {
+			if (settings->log_level >= LOG_LEVEL_NORMAL) {
+				printf("Overall timeout time exceeded, stopping.\n");
+			}
+
+			break;
+		}
+
+		if (result > 0) {
+			double time_left = state->time_left;
+
 			close(testdirfd);
 			close_watchdogs(settings);
-			if (result > 0) {
-				initialize_execute_state_from_resume(resdirfd, state, settings, job_list);
-				return execute(state, settings, job_list);
-			}
-			close(resdirfd);
-			return false;
+			initialize_execute_state_from_resume(resdirfd, state, settings, job_list);
+			state->time_left = time_left;
+			return execute(state, settings, job_list);
 		}
 	}
 
@@ -1070,5 +1143,5 @@ bool execute(struct execute_state *state,
 	close(testdirfd);
 	close(resdirfd);
 	close_watchdogs(settings);
-	return true;
+	return status;
 }
diff --git a/runner/executor.h b/runner/executor.h
index 8fe1605b..252339ab 100644
--- a/runner/executor.h
+++ b/runner/executor.h
@@ -7,6 +7,12 @@
 struct execute_state
 {
 	size_t next;
+	/*
+	 * < 0 : No overall timeout used.
+	 * = 0 : Timeouted, don't execute any more.
+	 * > 0 : Timeout in use, time left.
+	 */
+	double time_left;
 };
 
 enum {
diff --git a/runner/runner_tests.c b/runner/runner_tests.c
index b18af3a0..9c0f9eb0 100644
--- a/runner/runner_tests.c
+++ b/runner/runner_tests.c
@@ -219,6 +219,7 @@ igt_main
 		igt_assert(!settings.overwrite);
 		igt_assert(!settings.multiple_mode);
 		igt_assert_eq(settings.inactivity_timeout, 0);
+		igt_assert_eq(settings.overall_timeout, 0);
 		igt_assert(!settings.use_watchdog);
 		igt_assert(strstr(settings.test_root, "test-root-dir") != NULL);
 		igt_assert(strstr(settings.results_path, "path-to-results") != NULL);
@@ -333,6 +334,7 @@ igt_main
 		igt_assert(!settings.overwrite);
 		igt_assert(!settings.multiple_mode);
 		igt_assert_eq(settings.inactivity_timeout, 0);
+		igt_assert_eq(settings.overall_timeout, 0);
 		igt_assert(!settings.use_watchdog);
 		igt_assert(strstr(settings.test_root, testdatadir) != NULL);
 		igt_assert(strstr(settings.results_path, "path-to-results") != NULL);
@@ -359,6 +361,7 @@ igt_main
 				 "--overwrite",
 				 "--multiple-mode",
 				 "--inactivity-timeout", "27",
+				 "--overall-timeout", "360",
 				 "--use-watchdog",
 				 "--piglit-style-dmesg",
 				 "test-root-dir",
@@ -382,6 +385,7 @@ igt_main
 		igt_assert(settings.overwrite);
 		igt_assert(settings.multiple_mode);
 		igt_assert_eq(settings.inactivity_timeout, 27);
+		igt_assert_eq(settings.overall_timeout, 360);
 		igt_assert(settings.use_watchdog);
 		igt_assert(strstr(settings.test_root, "test-root-dir") != NULL);
 		igt_assert(strstr(settings.results_path, "path-to-results") != NULL);
@@ -619,6 +623,7 @@ igt_main
 					 "--overwrite",
 					 "--multiple-mode",
 					 "--inactivity-timeout", "27",
+					 "--overall-timeout", "360",
 					 "--use-watchdog",
 					 "--piglit-style-dmesg",
 					 testdatadir,
diff --git a/runner/settings.c b/runner/settings.c
index 70fff3c0..e2401455 100644
--- a/runner/settings.c
+++ b/runner/settings.c
@@ -17,6 +17,7 @@ enum {
 	OPT_TEST_LIST,
 	OPT_IGNORE_MISSING,
 	OPT_PIGLIT_DMESG,
+	OPT_OVERALL_TIMEOUT,
 	OPT_HELP = 'h',
 	OPT_NAME = 'n',
 	OPT_DRY_RUN = 'd',
@@ -87,6 +88,8 @@ 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"
+	"  --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"
 	"                        above timeout. Killing the test process is still\n"
 	"                        attempted at timeout trigger.\n"
@@ -198,6 +201,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},
+		{"overall-timeout", required_argument, NULL, OPT_OVERALL_TIMEOUT},
 		{"use-watchdog", no_argument, NULL, OPT_WATCHDOG},
 		{"piglit-style-dmesg", no_argument, NULL, OPT_PIGLIT_DMESG},
 		{ 0, 0, 0, 0},
@@ -253,6 +257,9 @@ bool parse_options(int argc, char **argv,
 		case OPT_TIMEOUT:
 			settings->inactivity_timeout = atoi(optarg);
 			break;
+		case OPT_OVERALL_TIMEOUT:
+			settings->overall_timeout = atoi(optarg);
+			break;
 		case OPT_WATCHDOG:
 			settings->use_watchdog = true;
 			break;
@@ -448,6 +455,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, overall_timeout, "%d");
 	SERIALIZE_LINE(f, settings, use_watchdog, "%d");
 	SERIALIZE_LINE(f, settings, piglit_style_dmesg, "%d");
 	SERIALIZE_LINE(f, settings, test_root, "%s");
@@ -502,6 +510,7 @@ bool read_settings(struct settings *settings, int dirfd)
 		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, overall_timeout, numval);
 		PARSE_LINE(settings, name, val, use_watchdog, numval);
 		PARSE_LINE(settings, name, val, piglit_style_dmesg, numval);
 		PARSE_LINE(settings, name, val, test_root, val ? strdup(val) : NULL);
diff --git a/runner/settings.h b/runner/settings.h
index e534b845..b489abc5 100644
--- a/runner/settings.h
+++ b/runner/settings.h
@@ -30,6 +30,7 @@ struct settings {
 	bool overwrite;
 	bool multiple_mode;
 	int inactivity_timeout;
+	int overall_timeout;
 	bool use_watchdog;
 	char *test_root;
 	char *results_path;
-- 
2.18.0



More information about the igt-dev mailing list