[PATCH i-g-t 11/28] resultgen close to done
Petri Latvala
petri.latvala at intel.com
Mon Mar 22 11:34:03 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