[PATCH i-g-t 11/16] resultgen close to done

Petri Latvala petri.latvala at intel.com
Mon Mar 1 12:58:40 UTC 2021


---
 runner/resultgen.c | 338 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 333 insertions(+), 5 deletions(-)

diff --git a/runner/resultgen.c b/runner/resultgen.c
index b74970a6..48b756cb 100644
--- a/runner/resultgen.c
+++ b/runner/resultgen.c
@@ -12,6 +12,7 @@
 
 #include "igt_aux.h"
 #include "igt_core.h"
+#include "runnercomms.h"
 #include "resultgen.h"
 #include "settings.h"
 #include "executor.h"
@@ -147,7 +148,7 @@ static const char *next_line(const char *line, const char *bufend)
 		return NULL;
 }
 
-static void append_line(char **buf, size_t *buflen, char *line)
+static void append_line(char **buf, size_t *buflen, const char *line)
 {
 	size_t linelen = strlen(line);
 
@@ -1226,6 +1227,316 @@ static void fill_from_journal(int fd,
 	fclose(f);
 }
 
+struct comms_context
+{
+	struct json_object *current_test;
+	char *current_subtest_name;
+	char *outbuf, *errbuf;
+	size_t outbuflen, errbuflen;
+	ssize_t commonoutbufmarker, commonerrbufmarker;
+	char *igt_version;
+	char *subtestresult;
+	char *cmdline;
+	int exitcode;
+};
+
+static void comms_init_context(struct comms_context *context)
+{
+	memset(context, 0, sizeof(*context));
+
+	context->commonoutbufmarker = -1;
+	context->commonerrbufmarker = -1;
+}
+
+static void comms_free_context(struct comms_context *context)
+{
+	
+}
+
+static void comms_append_log(struct comms_context *context,
+			     union runnerpacket_read_helper helper)
+{
+	char **textbuf;
+	size_t *textlen;
+
+	if (helper.log.stream == STDOUT_FILENO) {
+		textbuf = &context->outbuf;
+		textlen = &context->outbuflen;
+	} else {
+		textbuf = &context->errbuf;
+		textlen = &context->errbuflen;
+	}
+	append_line(textbuf, textlen, helper.log.text);
+}
+
+static void comms_inject_subtest_start_log(struct comms_context *context,
+					   const char *prefix,
+					   const char *subtestname)
+{
+	char msg[512];
+
+	snprintf(msg, sizeof(msg), "%s%s\n", prefix, subtestname);
+	append_line(&context->outbuf, &context->outbuflen, msg);
+	append_line(&context->errbuf, &context->errbuflen, msg);
+}
+
+static void comms_inject_subtest_end_log(struct comms_context *context,
+					 const char *prefix,
+					 const char *subtestname,
+					 const char *subtestresult,
+					 const char *timeused)
+{
+	char msg[512];
+
+	snprintf(msg, sizeof(msg), "%s%s: %s (%ss)\n", prefix, subtestname, subtestresult, timeused);
+	append_line(&context->outbuf, &context->outbuflen, msg);
+	append_line(&context->errbuf, &context->errbuflen, msg);
+}
+
+static void comms_finish_subtest(struct comms_context *context)
+{
+	size_t commonoutlen = 0;
+	size_t commonerrlen = 0;
+
+	json_object_object_add(context->current_test, "out",
+			       new_escaped_json_string(context->outbuf, context->outbuflen));
+	json_object_object_add(context->current_test, "err",
+			       new_escaped_json_string(context->errbuf, context->errbuflen));
+
+	if (context->igt_version)
+		add_igt_version(context->current_test, context->igt_version, strlen(context->igt_version));
+
+	if (context->subtestresult == NULL)
+		context->subtestresult = strdup("incomplete");
+	set_result(context->current_test, context->subtestresult);
+
+	free(context->subtestresult);
+	context->subtestresult = NULL;
+
+	/* If we have commonbuf markers, we have overlapping logs that need to be also added to the next subtest */
+	if (context->commonoutbufmarker >= 0) {
+		commonoutlen = context->outbuflen - context->commonoutbufmarker;
+		memmove(context->outbuf, context->outbuf + context->commonoutbufmarker, commonoutlen);
+	}
+	if (context->commonerrbufmarker >= 0) {
+		commonerrlen = context->errbuflen - context->commonerrbufmarker;
+		memmove(context->errbuf, context->errbuf + context->commonerrbufmarker, commonerrlen);
+	}
+
+	context->outbuflen = commonoutlen;
+	context->errbuflen = commonerrlen;
+	context->commonoutbufmarker = -1;
+	context->commonerrbufmarker = -1;
+}
+
+static const int COMMSPARSE_SUCCESS = 0;
+static const int COMMSPARSE_ERROR = -1;
+static const int COMMSPARSE_EMPTY = 1;
+
+static int fill_from_comms(int fd, const char *binary,
+			   struct subtest_list *subtests,
+			   struct results *results)
+{
+	struct comms_context context;
+	struct json_object *obj;
+	struct stat statbuf;
+	char *buf, *bufend, *p;
+	int ret = COMMSPARSE_EMPTY;
+	char piglit_name[256];
+	bool subtest_has_started = false;
+
+	if (fd < 0)
+		return COMMSPARSE_EMPTY;
+
+	if (fstat(fd, &statbuf))
+		return COMMSPARSE_ERROR;
+
+	if (statbuf.st_size == 0)
+		return COMMSPARSE_EMPTY;
+
+	buf = mmap(NULL, statbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+	if (buf == MAP_FAILED)
+		return COMMSPARSE_ERROR;
+
+	bufend = buf + statbuf.st_size;
+	p = buf;
+
+	comms_init_context(&context);
+
+	generate_piglit_name(binary, NULL, piglit_name, sizeof(piglit_name));
+	obj = get_or_create_json_object(results->runtimes, piglit_name);
+
+	while (p != NULL && p != bufend) {
+		const struct runnerpacket *packet;
+		union runnerpacket_read_helper helper;
+
+		if (bufend - p >= sizeof(uint32_t)) {
+			uint32_t canary;
+
+			memcpy(&canary, p, sizeof(canary));
+			if (canary != socket_dump_canary()) {
+				fprintf(stderr,
+					"Invalid canary while parsing comms.txt: %"PRIu32", expected %"PRIu32"\n",
+					canary, socket_dump_canary());
+				munmap(buf, statbuf.st_size);
+				return COMMSPARSE_ERROR;
+			}
+		}
+		p += sizeof(uint32_t);
+
+		if (bufend - p < sizeof(struct runnerpacket)) {
+			fprintf(stderr,
+				"Error parsing comms.txt: Expected runnerpacket after canary, truncated file?\n");
+			munmap(buf, statbuf.st_size);
+			return COMMSPARSE_ERROR;
+		}
+
+		packet = (struct runnerpacket *)p;
+		if (bufend - p < packet->size) {
+			fprintf(stderr,
+				"Error parsing comms.txt: Unexpected end of file, truncated file?\n");
+			munmap(buf, statbuf.st_size);
+			return COMMSPARSE_ERROR;
+		}
+		p += packet->size;
+
+		helper = read_runnerpacket(packet);
+
+		/*
+		 * runner sends EXEC itself before executing the test,
+		 * other types indicate the test really uses socket
+		 * comms
+		 */
+		if (helper.type != PACKETTYPE_EXEC)
+			ret = COMMSPARSE_SUCCESS;
+
+		switch (helper.type) {
+		case PACKETTYPE_INVALID:
+			fprintf(stderr, "Error parsing runnerpacket (type=%"PRIu32")\n", packet->type);
+			munmap(buf, statbuf.st_size);
+			return COMMSPARSE_ERROR;
+
+		case PACKETTYPE_LOG:
+			comms_append_log(&context, helper);
+			break;
+
+		case PACKETTYPE_EXEC:
+			if (context.current_test != NULL)
+				comms_finish_subtest(&context);
+
+			context.cmdline = strdup(helper.exec.cmdline);
+			break;
+
+		case PACKETTYPE_EXIT:
+			context.exitcode = helper.exit.exitcode;
+			add_runtime(obj, strtod(helper.exit.timeused, NULL));
+			break;
+
+		case PACKETTYPE_SUBTEST_START:
+			if (context.current_test != NULL) {
+				/* Already collecting for a subtest, finish it up */
+				comms_finish_subtest(&context);
+			}
+
+			add_subtest(subtests, strdup(helper.subteststart.name));
+			generate_piglit_name(binary, helper.subteststart.name, piglit_name, sizeof(piglit_name));
+			context.current_test = get_or_create_json_object(results->tests, piglit_name);
+			free(context.current_subtest_name);
+			context.current_subtest_name = strdup(helper.subteststart.name);
+
+			/* Subtest starting message is not in logs with socket comms, inject it manually here */
+			comms_inject_subtest_start_log(&context, STARTING_SUBTEST, helper.subteststart.name);
+
+			subtest_has_started = true;
+
+			break;
+
+		case PACKETTYPE_SUBTEST_RESULT:
+			if (!subtest_has_started) {
+				/* Result without start, a skip/fail from fixture */
+				if (context.current_test != NULL &&
+				    context.current_subtest_name != NULL &&
+				    strcmp(helper.subtestresult.name, context.current_subtest_name) != 0)
+					comms_finish_subtest(&context);
+
+				add_subtest(subtests, strdup(helper.subtestresult.name));
+				generate_piglit_name(binary, helper.subtestresult.name, piglit_name, sizeof(piglit_name));
+				context.current_test = get_or_create_json_object(results->tests, piglit_name);
+
+				free(context.current_subtest_name);
+				context.current_subtest_name = strdup(helper.subtestresult.name);
+
+			}
+
+			comms_inject_subtest_end_log(&context,
+						     SUBTEST_RESULT,
+						     helper.subtestresult.name,
+						     helper.subtestresult.result,
+						     helper.subtestresult.timeused);
+			comms_inject_subtest_end_log(&context,
+						     SUBTEST_RESULT,
+						     helper.subtestresult.name,
+						     helper.subtestresult.result,
+						     helper.subtestresult.timeused);
+
+			/*
+			 * Only store the actual result from the
+			 * packet if we don't already have one. If we
+			 * do, it's from an override.
+			 */
+			if (context.subtestresult == NULL) {
+				const char *mappedresult;
+
+				parse_result_string(helper.subtestresult.result,
+						    strlen(helper.subtestresult.result),
+						    &mappedresult, NULL);
+				context.subtestresult = strdup(mappedresult);
+			}
+
+			subtest_has_started = false;
+
+			/* Drop the marker here for the log lines shared between this test and the next */
+			context.commonoutbufmarker = context.outbuflen;
+			context.commonerrbufmarker = context.errbuflen;
+			break;
+
+		case PACKETTYPE_DYNAMIC_SUBTEST_START:
+			break;
+
+		case PACKETTYPE_DYNAMIC_SUBTEST_RESULT:
+			break;
+
+		case PACKETTYPE_VERSIONSTRING:
+			free(context.igt_version);
+			context.igt_version = strdup(helper.versionstring.text);
+			break;
+
+		case PACKETTYPE_RESULT_OVERRIDE:
+			{
+				const char *mappedresult;
+
+				parse_result_string(helper.resultoverride.result,
+						    strlen(helper.resultoverride.result),
+						    &mappedresult, NULL);
+				free(context.subtestresult);
+				context.subtestresult = strdup(mappedresult);
+			}
+
+			break;
+
+		default:
+			printf("Warning: Unknown packet type %"PRIu32"\n", helper.type);
+			break;
+		}
+	}
+
+	comms_finish_subtest(&context);
+	comms_free_context(&context);
+	munmap(buf, statbuf.st_size);
+
+	return ret;
+}
+
 static void prune_subtests_with_dynamic_subtests(const char *binary,
 						 struct subtest_list *subtests,
 						 struct json_object *tests)
@@ -1460,6 +1771,7 @@ static bool parse_test_directory(int dirfd,
 	int fds[_F_LAST];
 	struct subtest_list subtests = {};
 	bool status = true;
+	int commsparsed;
 
 	if (!open_output_files(dirfd, fds, false)) {
 		fprintf(stderr, "Error opening output files\n");
@@ -1472,10 +1784,26 @@ static bool parse_test_directory(int dirfd,
 	 */
 	fill_from_journal(fds[_F_JOURNAL], entry, &subtests, results);
 
-	if (!fill_from_output(fds[_F_OUT], entry->binary, "out", &subtests, results->tests) ||
-	    !fill_from_output(fds[_F_ERR], entry->binary, "err", &subtests, results->tests) ||
-	    !fill_from_dmesg(fds[_F_DMESG], settings, entry->binary, &subtests, results->tests)) {
-		fprintf(stderr, "Error parsing output files\n");
+	/*
+	 * Get test output from socket comms if it exists, otherwise parse stdout/stderr */
+	commsparsed = fill_from_comms(fds[_F_SOCKET], entry->binary, &subtests, results);
+	if (commsparsed == COMMSPARSE_ERROR) {
+		fprintf(stderr, "Error parsing output files (comms.txt)\n");
+		status = false;
+		goto parse_output_end;
+	}
+
+	if (commsparsed == COMMSPARSE_EMPTY) {
+		if (!fill_from_output(fds[_F_OUT], entry->binary, "out", &subtests, results->tests) ||
+		    !fill_from_output(fds[_F_ERR], entry->binary, "err", &subtests, results->tests)) {
+			fprintf(stderr, "Error parsing output files (out.txt, err.txt)\n");
+			status = false;
+			goto parse_output_end;
+		}
+	}
+
+	if (!fill_from_dmesg(fds[_F_DMESG], settings, entry->binary, &subtests, results->tests)) {
+		fprintf(stderr, "Error parsing output files (dmesg.txt)\n");
 		status = false;
 		goto parse_output_end;
 	}
-- 
2.29.2



More information about the Intel-gfx-trybot mailing list