All of lore.kernel.org
 help / color / mirror / Atom feed
* [igt-dev] [PATCH v2 i-g-t 0/5] Introduce KUnit
@ 2023-03-15  9:40 Dominik Karol Piatkowski
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 1/5] lib/igt_kmod: rename kselftest functions to ktest Dominik Karol Piatkowski
                   ` (7 more replies)
  0 siblings, 8 replies; 13+ messages in thread
From: Dominik Karol Piatkowski @ 2023-03-15  9:40 UTC (permalink / raw)
  To: igt-dev

This series is a continuation of Isabella's work on introducing
KUnit to IGT.

Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>

Dominik Karol Piatkowski (1):
  Change logic of ktap parser to run on a thread

Isabella Basso (4):
  lib/igt_kmod: rename kselftest functions to ktest
  lib/igt_kmod.c: check if module is builtin before attempting to unload
    it
  lib/igt_kmod: add compatibility for KUnit
  tests: DRM selftests: switch to KUnit

 lib/igt_kmod.c       | 108 +++++++++++--
 lib/igt_kmod.h       |  14 +-
 lib/igt_ktap.c       | 371 +++++++++++++++++++++++++++++++++++++++++++
 lib/igt_ktap.h       |  32 ++++
 lib/meson.build      |   1 +
 tests/drm_buddy.c    |   4 +-
 tests/drm_mm.c       |   4 +-
 tests/kms_selftest.c |   8 +
 8 files changed, 523 insertions(+), 19 deletions(-)
 create mode 100644 lib/igt_ktap.c
 create mode 100644 lib/igt_ktap.h

-- 
2.34.1



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [igt-dev] [PATCH i-g-t 1/5] lib/igt_kmod: rename kselftest functions to ktest
  2023-03-15  9:40 [igt-dev] [PATCH v2 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
@ 2023-03-15  9:40 ` Dominik Karol Piatkowski
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 2/5] lib/igt_kmod.c: check if module is builtin before attempting to unload it Dominik Karol Piatkowski
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Dominik Karol Piatkowski @ 2023-03-15  9:40 UTC (permalink / raw)
  To: igt-dev; +Cc: Isabella Basso

From: Isabella Basso <isabbasso@riseup.net>

This aims at making IGT's structure more general to different kernel
testing frameworks such as KUnit, as they use a lot of the same
functionality.

Reviewed-by: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Signed-off-by: Isabella Basso <isabbasso@riseup.net>

Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
 lib/igt_kmod.c | 22 +++++++++++-----------
 lib/igt_kmod.h | 12 ++++++------
 2 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 6d6ecf01..0b714ce3 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -749,8 +749,8 @@ static int open_parameters(const char *module_name)
 	return open(path, O_RDONLY);
 }
 
-int igt_kselftest_init(struct igt_kselftest *tst,
-		       const char *module_name)
+int igt_ktest_init(struct igt_ktest *tst,
+		   const char *module_name)
 {
 	int err;
 
@@ -769,7 +769,7 @@ int igt_kselftest_init(struct igt_kselftest *tst,
 	return 0;
 }
 
-int igt_kselftest_begin(struct igt_kselftest *tst)
+int igt_ktest_begin(struct igt_ktest *tst)
 {
 	int err;
 
@@ -784,7 +784,7 @@ int igt_kselftest_begin(struct igt_kselftest *tst)
 	return 0;
 }
 
-int igt_kselftest_execute(struct igt_kselftest *tst,
+int igt_kselftest_execute(struct igt_ktest *tst,
 			  struct igt_kselftest_list *tl,
 			  const char *options,
 			  const char *result)
@@ -822,13 +822,13 @@ int igt_kselftest_execute(struct igt_kselftest *tst,
 	return err;
 }
 
-void igt_kselftest_end(struct igt_kselftest *tst)
+void igt_ktest_end(struct igt_ktest *tst)
 {
 	kmod_module_remove_module(tst->kmod, KMOD_REMOVE_FORCE);
 	close(tst->kmsg);
 }
 
-void igt_kselftest_fini(struct igt_kselftest *tst)
+void igt_ktest_fini(struct igt_ktest *tst)
 {
 	free(tst->module_name);
 	kmod_module_unref(tst->kmod);
@@ -851,15 +851,15 @@ void igt_kselftests(const char *module_name,
 		    const char *result,
 		    const char *filter)
 {
-	struct igt_kselftest tst;
+	struct igt_ktest tst;
 	IGT_LIST_HEAD(tests);
 	struct igt_kselftest_list *tl, *tn;
 
-	if (igt_kselftest_init(&tst, module_name) != 0)
+	if (igt_ktest_init(&tst, module_name) != 0)
 		return;
 
 	igt_fixture
-		igt_require(igt_kselftest_begin(&tst) == 0);
+		igt_require(igt_ktest_begin(&tst) == 0);
 
 	igt_kselftest_get_tests(tst.kmod, filter, &tests);
 	igt_subtest_with_dynamic(filter ?: "all-tests") {
@@ -878,9 +878,9 @@ void igt_kselftests(const char *module_name,
 	}
 
 	igt_fixture {
-		igt_kselftest_end(&tst);
+		igt_ktest_end(&tst);
 		igt_require(!igt_list_empty(&tests));
 	}
 
-	igt_kselftest_fini(&tst);
+	igt_ktest_fini(&tst);
 }
diff --git a/lib/igt_kmod.h b/lib/igt_kmod.h
index f98dd29f..ceb10cd0 100644
--- a/lib/igt_kmod.h
+++ b/lib/igt_kmod.h
@@ -50,7 +50,7 @@ void igt_kselftests(const char *module_name,
 		    const char *result_option,
 		    const char *filter);
 
-struct igt_kselftest {
+struct igt_ktest {
 	struct kmod_module *kmod;
 	char *module_name;
 	int kmsg;
@@ -63,19 +63,19 @@ struct igt_kselftest_list {
 	char param[];
 };
 
-int igt_kselftest_init(struct igt_kselftest *tst,
+int igt_ktest_init(struct igt_ktest *tst,
 		       const char *module_name);
-int igt_kselftest_begin(struct igt_kselftest *tst);
+int igt_ktest_begin(struct igt_ktest *tst);
 
 void igt_kselftest_get_tests(struct kmod_module *kmod,
 			     const char *filter,
 			     struct igt_list_head *tests);
-int igt_kselftest_execute(struct igt_kselftest *tst,
+int igt_kselftest_execute(struct igt_ktest *tst,
 			  struct igt_kselftest_list *tl,
 			  const char *module_options,
 			  const char *result);
 
-void igt_kselftest_end(struct igt_kselftest *tst);
-void igt_kselftest_fini(struct igt_kselftest *tst);
+void igt_ktest_end(struct igt_ktest *tst);
+void igt_ktest_fini(struct igt_ktest *tst);
 
 #endif /* IGT_KMOD_H */
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [igt-dev] [PATCH i-g-t 2/5] lib/igt_kmod.c: check if module is builtin before attempting to unload it
  2023-03-15  9:40 [igt-dev] [PATCH v2 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 1/5] lib/igt_kmod: rename kselftest functions to ktest Dominik Karol Piatkowski
@ 2023-03-15  9:40 ` Dominik Karol Piatkowski
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 3/5] lib/igt_kmod: add compatibility for KUnit Dominik Karol Piatkowski
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Dominik Karol Piatkowski @ 2023-03-15  9:40 UTC (permalink / raw)
  To: igt-dev; +Cc: Isabella Basso

From: Isabella Basso <isabbasso@riseup.net>

This change makes `igt_kmod_unload_r` safer as it checks whether the
module can be unloaded before attempting it.

v2 -> v3:
- Fix commit message
- Make return value clearer

Acked-by: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Signed-off-by: Isabella Basso <isabbasso@riseup.net>

Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
 lib/igt_kmod.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 0b714ce3..fbda1aa6 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -259,6 +259,9 @@ static int igt_kmod_unload_r(struct kmod_module *kmod, unsigned int flags)
 	int err, tries;
 	const char *mod_name = kmod_module_get_name(kmod);
 
+	if (kmod_module_get_initstate(kmod) == KMOD_MODULE_BUILTIN)
+		return 0;
+
 	holders = kmod_module_get_holders(kmod);
 	kmod_list_foreach(pos, holders) {
 		struct kmod_module *it = kmod_module_get_module(pos);
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [igt-dev] [PATCH i-g-t 3/5] lib/igt_kmod: add compatibility for KUnit
  2023-03-15  9:40 [igt-dev] [PATCH v2 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 1/5] lib/igt_kmod: rename kselftest functions to ktest Dominik Karol Piatkowski
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 2/5] lib/igt_kmod.c: check if module is builtin before attempting to unload it Dominik Karol Piatkowski
@ 2023-03-15  9:40 ` Dominik Karol Piatkowski
  2023-03-15 13:07   ` Janusz Krzysztofik
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 4/5] tests: DRM selftests: switch to KUnit Dominik Karol Piatkowski
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Dominik Karol Piatkowski @ 2023-03-15  9:40 UTC (permalink / raw)
  To: igt-dev; +Cc: Isabella Basso

From: Isabella Basso <isabbasso@riseup.net>

This adds functions for both executing the tests as well as parsing (K)TAP
kmsg output, as per the KTAP spec [1].

[1] https://www.kernel.org/doc/html/latest/dev-tools/ktap.html

v1 -> v2:
- refactor igt_kunit function and ktap parser so that we have only one
  parser that we call only once (code size is now less than half the
  size as v1)
- add lookup_value helper
- fix parsing problems
v2 -> v3:
- move ktap parsing functions to own file
- rename to ktap_parser
- get rid of unneeded pointers in igt_kunit
- change return values to allow for subsequent call to igt_kselftests if
  needed
- add docs to parsing functions and helpers
- switch to line buffering
- add line buffering logging helper
- fix kunit module handling
- fix parsing of version lines
- use igt_subtest blocks to improve output handling on the CI
- fix output handling during crashes

Signed-off-by: Isabella Basso <isabbasso@riseup.net>

v3 -> v4:
- handle igt_ktap_parser fail with IGT_EXIT_ABORT code

v4 -> v5:
- added missing newlines in igt_warn
- removed setvbuf

Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
 lib/igt_kmod.c  |  79 ++++++++++++
 lib/igt_kmod.h  |   2 +
 lib/igt_ktap.c  | 334 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_ktap.h  |  31 +++++
 lib/meson.build |   1 +
 5 files changed, 447 insertions(+)
 create mode 100644 lib/igt_ktap.c
 create mode 100644 lib/igt_ktap.h

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index fbda1aa6..3b92cc94 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -29,6 +29,7 @@
 #include "igt_aux.h"
 #include "igt_core.h"
 #include "igt_kmod.h"
+#include "igt_ktap.h"
 #include "igt_sysfs.h"
 #include "igt_taints.h"
 
@@ -744,6 +745,84 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
 	kmod_module_info_free_list(pre);
 }
 
+/**
+ * igt_kunit:
+ * @module_name: the name of the module
+ * @opts: options to load the module
+ *
+ * Loads the test module, parses its (k)tap dmesg output, then unloads it
+ *
+ * Returns: IGT default codes
+ */
+int igt_kunit(const char *module_name, const char *opts)
+{
+	struct igt_ktest tst;
+	struct kmod_module *kunit_kmod;
+	char record[BUF_LEN + 1];
+	FILE *f;
+	bool is_builtin;
+	int ret;
+
+	ret = IGT_EXIT_INVALID;
+
+	/* get normalized module name */
+	if (igt_ktest_init(&tst, module_name) != 0) {
+		igt_warn("Unable to initialize ktest for %s\n", module_name);
+		return ret;
+	}
+
+	if (igt_ktest_begin(&tst) != 0) {
+		igt_warn("Unable to begin ktest for %s\n", module_name);
+
+		igt_ktest_fini(&tst);
+		return ret;
+	}
+
+	if (tst.kmsg < 0) {
+		igt_warn("Could not open /dev/kmsg\n");
+		goto unload;
+	}
+
+	if (lseek(tst.kmsg, 0, SEEK_END)) {
+		igt_warn("Could not seek the end of /dev/kmsg\n");
+		goto unload;
+	}
+
+	f = fdopen(tst.kmsg, "r");
+
+	if (f == NULL) {
+		igt_warn("Could not turn /dev/kmsg file descriptor into a FILE pointer\n");
+		goto unload;
+	}
+
+	/* The KUnit module is required for running any KUnit tests */
+	if (igt_kmod_load("kunit", NULL) != 0 ||
+	    kmod_module_new_from_name(kmod_ctx(), "kunit", &kunit_kmod) != 0) {
+		igt_warn("Unable to load KUnit\n");
+		igt_fail(IGT_EXIT_FAILURE);
+	}
+
+	is_builtin = kmod_module_get_initstate(kunit_kmod) == KMOD_MODULE_BUILTIN;
+
+	if (igt_kmod_load(module_name, opts) != 0) {
+		igt_warn("Unable to load %s module\n", module_name);
+		igt_fail(IGT_EXIT_FAILURE);
+	}
+
+	ret = igt_ktap_parser(f, record, is_builtin);
+	if (ret != 0)
+		ret = IGT_EXIT_ABORT;
+unload:
+	igt_ktest_end(&tst);
+
+	igt_ktest_fini(&tst);
+
+	if (ret == 0)
+		igt_success();
+
+	return ret;
+}
+
 static int open_parameters(const char *module_name)
 {
 	char path[256];
diff --git a/lib/igt_kmod.h b/lib/igt_kmod.h
index ceb10cd0..72f9f445 100644
--- a/lib/igt_kmod.h
+++ b/lib/igt_kmod.h
@@ -45,6 +45,8 @@ int __igt_i915_driver_unload(char **whom);
 int igt_amdgpu_driver_load(const char *opts);
 int igt_amdgpu_driver_unload(void);
 
+int igt_kunit(const char *module_name, const char *opts);
+
 void igt_kselftests(const char *module_name,
 		    const char *module_options,
 		    const char *result_option,
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
new file mode 100644
index 00000000..117598fa
--- /dev/null
+++ b/lib/igt_ktap.c
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Isabella Basso do Amaral <isabbasso@riseup.net>
+ */
+
+#include <ctype.h>
+#include <limits.h>
+
+#include "igt_aux.h"
+#include "igt_core.h"
+#include "igt_ktap.h"
+
+static int log_to_end(enum igt_log_level level, FILE *f,
+		      char *record, const char *format, ...) __attribute__((format(printf, 4, 5)));
+
+/**
+ * log_to_end:
+ * @level: #igt_log_level
+ * @record: record to store the read data
+ * @format: format string
+ * @...: optional arguments used in the format string
+ *
+ * This is an altered version of the generic structured logging helper function
+ * igt_log capable of reading to the end of a given line.
+ *
+ * Returns: 0 for success, or -2 if there's an error reading from the file
+ */
+static int log_to_end(enum igt_log_level level, FILE *f,
+		      char *record, const char *format, ...)
+{
+	va_list args;
+	const char *lend;
+
+	va_start(args, format);
+	igt_vlog(IGT_LOG_DOMAIN, level, format, args);
+	va_end(args);
+
+	lend = strchrnul(record, '\n');
+	while (*lend == '\0') {
+		igt_log(IGT_LOG_DOMAIN, level, "%s", record);
+		if (fgets(record, BUF_LEN, f) == NULL) {
+			igt_warn("kmsg truncated: unknown error (%m)\n");
+			return -2;
+		}
+		lend = strchrnul(record, '\n');
+	}
+	return 0;
+}
+
+/**
+ * lookup_value:
+ * @haystack: the string to search in
+ * @needle: the string to search for
+ *
+ * Returns: the value of the needle in the haystack, or -1 if not found.
+ */
+static long lookup_value(const char *haystack, const char *needle)
+{
+	const char *needle_rptr;
+	char *needle_end;
+	long num;
+
+	needle_rptr = strcasestr(haystack, needle);
+
+	if (needle_rptr == NULL)
+		return -1;
+
+	/* skip search string and whitespaces after it */
+	needle_rptr += strlen(needle);
+
+	num = strtol(needle_rptr, &needle_end, 10);
+
+	if (needle_rptr == needle_end)
+		return -1;
+
+	if (num == LONG_MIN || num == LONG_MAX)
+		return 0;
+
+	return num > 0 ? num : 0;
+}
+
+/**
+ * find_next_tap_subtest:
+ * @fp: FILE pointer
+ * @record: buffer used to read fp
+ * @is_builtin: whether KUnit is built-in or not
+ *
+ * Returns:
+ * 0 if there's missing information
+ * -1 if not found
+ * -2 if there are problems while reading the file.
+ * any other value corresponds to the amount of cases of the next (sub)test
+ */
+static int find_next_tap_subtest(FILE *fp, char *record, bool is_builtin)
+{
+	const char *test_lookup_str, *subtest_lookup_str, *name_rptr, *version_rptr;
+	char test_name[BUF_LEN + 1];
+	long test_count;
+
+	test_name[0] = '\0';
+	test_name[BUF_LEN] = '\0';
+
+	test_lookup_str = " subtest: ";
+	subtest_lookup_str = " test: ";
+
+	/*
+	 * "(K)TAP version XX" should be the first line on all (sub)tests as per
+	 * https://kernel.org/doc/html/latest/dev-tools/ktap.html#version-lines
+	 *
+	 * but actually isn't, as it currently depends on the KUnit module
+	 * being built-in, so we can't rely on it every time
+	 */
+	if (is_builtin) {
+		version_rptr = strcasestr(record, "TAP version ");
+		if (version_rptr == NULL)
+			return -1;
+
+		igt_info("%s", version_rptr);
+
+		if (fgets(record, BUF_LEN, fp) == NULL) {
+			igt_warn("kmsg truncated: unknown error (%m)\n");
+			return -2;
+		}
+	}
+
+	name_rptr = strcasestr(record, test_lookup_str);
+	if (name_rptr != NULL) {
+		name_rptr += strlen(test_lookup_str);
+	} else {
+		name_rptr = strcasestr(record, subtest_lookup_str);
+		if (name_rptr != NULL)
+			name_rptr += strlen(subtest_lookup_str);
+	}
+
+	if (name_rptr == NULL) {
+		if (!is_builtin)
+			/* we've probably found nothing */
+			return -1;
+		igt_info("Missing test name\n");
+	} else {
+		strncpy(test_name, name_rptr, BUF_LEN);
+		if (fgets(record, BUF_LEN, fp) == NULL) {
+			igt_warn("kmsg truncated: unknown error (%m)\n");
+			return -2;
+		}
+		/* now we can be sure we found tests */
+		if (!is_builtin)
+			igt_info("KUnit is not built-in, skipping version check...\n");
+	}
+
+	/*
+	 * total test count will almost always appear as 0..N at the beginning
+	 * of a run, so we use it to reliably identify a new run
+	 */
+	test_count = lookup_value(record, "..");
+
+	if (test_count <= 0) {
+		igt_info("Missing test count\n");
+		if (test_name[0] == '\0')
+			return 0;
+		if (log_to_end(IGT_LOG_INFO, fp, record,
+				"Running some tests in: %s",
+				test_name) < 0)
+			return -2;
+		return 0;
+	} else if (test_name[0] == '\0') {
+		igt_info("Running %ld tests...\n", test_count);
+		return 0;
+	}
+
+	if (log_to_end(IGT_LOG_INFO, fp, record,
+			"Executing %ld tests in: %s",
+			test_count, test_name) < 0)
+		return -2;
+
+	return test_count;
+}
+
+/**
+ * find_next_tap_test:
+ * @fp: FILE pointer
+ * @record: buffer used to read fp
+ * @test_name: buffer to store the test name
+ *
+ * Returns:
+ * 1 if no results were found
+ * 0 if a test succeded
+ * -1 if a test failed
+ * -2 if there are problems reading the file
+ */
+static int parse_kmsg_for_tap(FILE *fp, char *record, char *test_name)
+{
+	const char *lstart, *ok_lookup_str, *nok_lookup_str,
+	      *ok_rptr, *nok_rptr, *comment_start, *value_parse_start;
+	char *test_name_end;
+
+	ok_lookup_str = "ok ";
+	nok_lookup_str = "not ok ";
+
+	lstart = strchrnul(record, ';');
+
+	if (*lstart == '\0') {
+		igt_warn("kmsg truncated: output malformed (%m)\n");
+		return -2;
+	}
+
+	lstart++;
+	while (isspace(*lstart))
+		lstart++;
+
+	nok_rptr = strstr(lstart, nok_lookup_str);
+	if (nok_rptr != NULL) {
+		nok_rptr += strlen(nok_lookup_str);
+		while (isdigit(*nok_rptr) || isspace(*nok_rptr) || *nok_rptr == '-')
+			nok_rptr++;
+		test_name_end = strncpy(test_name, nok_rptr, BUF_LEN);
+		while (!isspace(*test_name_end))
+			test_name_end++;
+		*test_name_end = '\0';
+		if (log_to_end(IGT_LOG_WARN, fp, record,
+			       "%s", lstart) < 0)
+			return -2;
+		return -1;
+	}
+
+	comment_start = strchrnul(lstart, '#');
+
+	/* check if we're still in a subtest */
+	if (*comment_start != '\0') {
+		comment_start++;
+		value_parse_start = comment_start;
+
+		if (lookup_value(value_parse_start, "fail: ") > 0) {
+			if (log_to_end(IGT_LOG_WARN, fp, record,
+				       "%s", lstart) < 0)
+				return -2;
+			return -1;
+		}
+	}
+
+	ok_rptr = strstr(lstart, ok_lookup_str);
+	if (ok_rptr != NULL) {
+		ok_rptr += strlen(ok_lookup_str);
+		while (isdigit(*ok_rptr) || isspace(*ok_rptr) || *ok_rptr == '-')
+			ok_rptr++;
+		test_name_end = strncpy(test_name, ok_rptr, BUF_LEN);
+		while (!isspace(*test_name_end))
+			test_name_end++;
+		*test_name_end = '\0';
+		return 0;
+	}
+
+	return 1;
+}
+
+/**
+ * igt_ktap_parser:
+ * @fp: FILE pointer
+ * @record: buffer used to read fp
+ * @is_builtin: whether the KUnit module is built-in or not
+ *
+ * This function parses the output of a ktap script and prints the test results,
+ * as well as any other output to stdout.
+ *
+ * Returns: IGT default codes
+ */
+int igt_ktap_parser(FILE *fp, char *record, bool is_builtin)
+{
+	char test_name[BUF_LEN + 1];
+	bool failed_tests, found_tests;
+	int sublevel = 0;
+
+	test_name[0] = '\0';
+	test_name[BUF_LEN] = '\0';
+
+	failed_tests = false;
+	found_tests = false;
+
+	while (sublevel >= 0) {
+		if (fgets(record, BUF_LEN, fp) == NULL) {
+			if (!found_tests)
+				igt_warn("kmsg truncated: unknown error (%m)\n");
+			break;
+		}
+
+		switch (find_next_tap_subtest(fp, record, is_builtin)) {
+		case -2:
+			/* no more data to read */
+			return IGT_EXIT_FAILURE;
+		case -1:
+			/* no test found, so we keep parsing */
+			break;
+		case 0:
+			/*
+			 * tests found, but they're missing info, so we might
+			 * have read into test output
+			 */
+			found_tests = true;
+			sublevel++;
+			break;
+		default:
+			if (fgets(record, BUF_LEN, fp) == NULL) {
+				igt_warn("kmsg truncated: unknown error (%m)\n");
+				return -2;
+			}
+			found_tests = true;
+			sublevel++;
+			break;
+		}
+
+		switch (parse_kmsg_for_tap(fp, record, test_name)) {
+		case -2:
+			return IGT_EXIT_FAILURE;
+		case -1:
+			sublevel--;
+			failed_tests = true;
+			igt_subtest(test_name)
+				igt_fail(IGT_EXIT_FAILURE);
+			test_name[0] = '\0';
+			break;
+		case 0: /* fallthrough */
+			igt_subtest(test_name)
+				igt_success();
+			test_name[0] = '\0';
+		default:
+			break;
+		}
+	}
+
+	if (failed_tests || !found_tests)
+		return IGT_EXIT_FAILURE;
+
+	return IGT_EXIT_SUCCESS;
+}
diff --git a/lib/igt_ktap.h b/lib/igt_ktap.h
new file mode 100644
index 00000000..b2f69df2
--- /dev/null
+++ b/lib/igt_ktap.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2022 Isabella Basso do Amaral <isabbasso@riseup.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef IGT_KTAP_H
+#define IGT_KTAP_H
+
+#define BUF_LEN 4096
+
+int igt_ktap_parser(FILE *fp, char *record, bool is_builtin);
+
+#endif /* IGT_KTAP_H */
diff --git a/lib/meson.build b/lib/meson.build
index 768ce90b..45b9626a 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -87,6 +87,7 @@ lib_sources = [
 	'igt_store.c',
 	'uwildmat/uwildmat.c',
 	'igt_kmod.c',
+	'igt_ktap.c',
 	'igt_panfrost.c',
 	'igt_v3d.c',
 	'igt_vc4.c',
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [igt-dev] [PATCH i-g-t 4/5] tests: DRM selftests: switch to KUnit
  2023-03-15  9:40 [igt-dev] [PATCH v2 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
                   ` (2 preceding siblings ...)
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 3/5] lib/igt_kmod: add compatibility for KUnit Dominik Karol Piatkowski
@ 2023-03-15  9:40 ` Dominik Karol Piatkowski
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 5/5] Change logic of ktap parser to run on a thread Dominik Karol Piatkowski
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Dominik Karol Piatkowski @ 2023-03-15  9:40 UTC (permalink / raw)
  To: igt-dev; +Cc: Isabella Basso

From: Isabella Basso <isabbasso@riseup.net>

As the DRM selftests are now using KUnit [1], update IGT tests as well.

[1] - https://lore.kernel.org/all/20220708203052.236290-1-maira.canal@usp.br/

Signed-off-by: Isabella Basso <isabbasso@riseup.net>

v1 -> v2:
- drm_buddy|drm_mm: fallback to igt_kselftests if igt_kunit failed
  with code other than IGT_EXIT_ABORT
- kms_selftest: move igt_kunit tests to separate subtests
- kms_selftest: fallback to igt_kselftests if all subtests failed

v2 -> v3:
- expose all subtests

Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
 tests/drm_buddy.c    | 4 +++-
 tests/drm_mm.c       | 4 +++-
 tests/kms_selftest.c | 8 ++++++++
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/tests/drm_buddy.c b/tests/drm_buddy.c
index 06876e0c..3261f0d6 100644
--- a/tests/drm_buddy.c
+++ b/tests/drm_buddy.c
@@ -10,5 +10,7 @@ IGT_TEST_DESCRIPTION("Basic sanity check of DRM's buddy allocator (struct drm_bu
 
 igt_main
 {
-	igt_kselftests("test-drm_buddy", NULL, NULL, NULL);
+	int ret = igt_kunit("drm_buddy_test", NULL);
+	if (ret != 0 && ret != IGT_EXIT_ABORT)
+		igt_kselftests("test-drm_buddy", NULL, NULL, NULL);
 }
diff --git a/tests/drm_mm.c b/tests/drm_mm.c
index 2052b115..46d0142f 100644
--- a/tests/drm_mm.c
+++ b/tests/drm_mm.c
@@ -28,5 +28,7 @@ IGT_TEST_DESCRIPTION("Basic sanity check of DRM's range manager (struct drm_mm)"
 
 igt_main
 {
-	igt_kselftests("test-drm_mm", NULL, NULL, NULL);
+	int ret = igt_kunit("drm_mm_test", NULL);
+	if (ret != 0 && ret != IGT_EXIT_ABORT)
+		igt_kselftests("test-drm_mm", NULL, NULL, NULL);
 }
diff --git a/tests/kms_selftest.c b/tests/kms_selftest.c
index abc4bfe9..b27f60fb 100644
--- a/tests/kms_selftest.c
+++ b/tests/kms_selftest.c
@@ -28,5 +28,13 @@ IGT_TEST_DESCRIPTION("Basic sanity check of KMS selftests.");
 
 igt_main
 {
+	static const char *kunit_subtests[] = { "drm_cmdline_parser_test", "drm_damage_helper_test",
+						"drm_dp_mst_helper_test", "drm_format_helper_test",
+						"drm_format_test", "drm_framebuffer_test",
+						"drm_plane_helper_test", NULL };
+
+	for (int i = 0; kunit_subtests[i] != NULL; i++)
+		igt_kunit(kunit_subtests[i], NULL);
+
 	igt_kselftests("test-drm_modeset", NULL, NULL, NULL);
 }
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [igt-dev] [PATCH i-g-t 5/5] Change logic of ktap parser to run on a thread
  2023-03-15  9:40 [igt-dev] [PATCH v2 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
                   ` (3 preceding siblings ...)
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 4/5] tests: DRM selftests: switch to KUnit Dominik Karol Piatkowski
@ 2023-03-15  9:40 ` Dominik Karol Piatkowski
  2023-03-15 12:49   ` Mauro Carvalho Chehab
  2023-03-15 10:02 ` [igt-dev] ✗ GitLab.Pipeline: warning for Introduce KUnit (rev2) Patchwork
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 13+ messages in thread
From: Dominik Karol Piatkowski @ 2023-03-15  9:40 UTC (permalink / raw)
  To: igt-dev

The ktap parser should be listening and parsing messages as the tests
are executed, and not after the end of module load.

Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
---
 lib/igt_kmod.c |  12 +++--
 lib/igt_ktap.c | 137 +++++++++++++++++++++++++++++++------------------
 lib/igt_ktap.h |   3 +-
 3 files changed, 97 insertions(+), 55 deletions(-)

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 3b92cc94..23b92742 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -758,7 +758,6 @@ int igt_kunit(const char *module_name, const char *opts)
 {
 	struct igt_ktest tst;
 	struct kmod_module *kunit_kmod;
-	char record[BUF_LEN + 1];
 	FILE *f;
 	bool is_builtin;
 	int ret;
@@ -804,19 +803,24 @@ int igt_kunit(const char *module_name, const char *opts)
 
 	is_builtin = kmod_module_get_initstate(kunit_kmod) == KMOD_MODULE_BUILTIN;
 
+	ktap_parser_start(f, is_builtin);
+
 	if (igt_kmod_load(module_name, opts) != 0) {
 		igt_warn("Unable to load %s module\n", module_name);
+		ret = ktap_parser_stop();
 		igt_fail(IGT_EXIT_FAILURE);
 	}
 
-	ret = igt_ktap_parser(f, record, is_builtin);
-	if (ret != 0)
-		ret = IGT_EXIT_ABORT;
 unload:
 	igt_ktest_end(&tst);
 
 	igt_ktest_fini(&tst);
 
+	ret = ktap_parser_stop();
+
+	if (ret != 0)
+		ret = IGT_EXIT_ABORT;
+
 	if (ret == 0)
 		igt_success();
 
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 117598fa..acbb76ba 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -10,6 +10,10 @@
 #include "igt_core.h"
 #include "igt_ktap.h"
 
+#include <libkmod.h>
+
+#include <pthread.h>
+
 static int log_to_end(enum igt_log_level level, FILE *f,
 		      char *record, const char *format, ...) __attribute__((format(printf, 4, 5)));
 
@@ -253,6 +257,13 @@ static int parse_kmsg_for_tap(FILE *fp, char *record, char *test_name)
 	return 1;
 }
 
+struct ktap_parser_args {
+	FILE *fp;
+	bool is_builtin;
+	volatile bool is_running;
+	int ret;
+} ktap_args;
+
 /**
  * igt_ktap_parser:
  * @fp: FILE pointer
@@ -264,71 +275,97 @@ static int parse_kmsg_for_tap(FILE *fp, char *record, char *test_name)
  *
  * Returns: IGT default codes
  */
-int igt_ktap_parser(FILE *fp, char *record, bool is_builtin)
+void *igt_ktap_parser(void* unused)
 {
+	FILE *fp = ktap_args.fp;
+	char record[BUF_LEN + 1];
+	bool is_builtin = ktap_args.is_builtin;
+
 	char test_name[BUF_LEN + 1];
 	bool failed_tests, found_tests;
 	int sublevel = 0;
 
-	test_name[0] = '\0';
-	test_name[BUF_LEN] = '\0';
-
 	failed_tests = false;
 	found_tests = false;
 
-	while (sublevel >= 0) {
-		if (fgets(record, BUF_LEN, fp) == NULL) {
-			if (!found_tests)
-				igt_warn("kmsg truncated: unknown error (%m)\n");
-			break;
+igt_ktap_parser_start:
+	while (ktap_args.is_running) {
+		test_name[0] = '\0';
+		test_name[BUF_LEN] = '\0';
+
+		while (fgets(record, BUF_LEN, fp) != NULL) {
+			if (!ktap_args.is_running)
+				return NULL;
+			usleep(1000);
 		}
 
-		switch (find_next_tap_subtest(fp, record, is_builtin)) {
-		case -2:
-			/* no more data to read */
-			return IGT_EXIT_FAILURE;
-		case -1:
-			/* no test found, so we keep parsing */
-			break;
-		case 0:
-			/*
-			 * tests found, but they're missing info, so we might
-			 * have read into test output
-			 */
-			found_tests = true;
-			sublevel++;
-			break;
-		default:
-			if (fgets(record, BUF_LEN, fp) == NULL) {
-				igt_warn("kmsg truncated: unknown error (%m)\n");
-				return -2;
+		while (sublevel >= 0) {
+			switch (find_next_tap_subtest(fp, record, is_builtin)) {
+			case -2:
+				/* no more data to read */
+				goto igt_ktap_parser_start;
+			case -1:
+				/* no test found, so we keep parsing */
+				break;
+			case 0:
+				/*
+				 * tests found, but they're missing info, so we might
+				 * have read into test output
+				 */
+				found_tests = true;
+				sublevel++;
+				break;
+			default:
+				if (fgets(record, BUF_LEN, fp) == NULL) {
+					igt_warn("kmsg truncated: unknown error (%m)\n");
+					goto igt_ktap_parser_start;
+				}
+				found_tests = true;
+				sublevel++;
+				break;
 			}
-			found_tests = true;
-			sublevel++;
-			break;
-		}
 
-		switch (parse_kmsg_for_tap(fp, record, test_name)) {
-		case -2:
-			return IGT_EXIT_FAILURE;
-		case -1:
-			sublevel--;
-			failed_tests = true;
-			igt_subtest(test_name)
-				igt_fail(IGT_EXIT_FAILURE);
-			test_name[0] = '\0';
-			break;
-		case 0: /* fallthrough */
-			igt_subtest(test_name)
-				igt_success();
-			test_name[0] = '\0';
-		default:
-			break;
+			switch (parse_kmsg_for_tap(fp, record, test_name)) {
+			case -2:
+				goto igt_ktap_parser_start;
+			case -1:
+				sublevel--;
+				failed_tests = true;
+				igt_subtest(test_name)
+					igt_fail(IGT_EXIT_FAILURE);
+				test_name[0] = '\0';
+				break;
+			case 0: /* fallthrough */
+				igt_subtest(test_name)
+					igt_success();
+				test_name[0] = '\0';
+			default:
+				break;
+			}
 		}
 	}
 
 	if (failed_tests || !found_tests)
-		return IGT_EXIT_FAILURE;
+		ktap_args.ret = IGT_EXIT_FAILURE;
+	else
+		ktap_args.ret = IGT_EXIT_SUCCESS;
+
+	return NULL;
+}
+
+static pthread_t ktap_parser_thread;
 
-	return IGT_EXIT_SUCCESS;
+void ktap_parser_start(FILE *fp, bool is_builtin)
+{
+	ktap_args.fp = fp;
+	ktap_args.is_builtin = is_builtin;
+	ktap_args.is_running = true;
+	pthread_create(&ktap_parser_thread, NULL, igt_ktap_parser, NULL);
+}
+
+int ktap_parser_stop(void)
+{
+	ktap_args.is_running = false;
+	pthread_join(ktap_parser_thread, NULL);
+	return ktap_args.ret;
 }
diff --git a/lib/igt_ktap.h b/lib/igt_ktap.h
index b2f69df2..461df6f5 100644
--- a/lib/igt_ktap.h
+++ b/lib/igt_ktap.h
@@ -26,6 +26,7 @@
 
 #define BUF_LEN 4096
 
-int igt_ktap_parser(FILE *fp, char *record, bool is_builtin);
+void ktap_parser_start(FILE *fp, bool is_builtin);
+int ktap_parser_stop(void);
 
 #endif /* IGT_KTAP_H */
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [igt-dev] ✗ GitLab.Pipeline: warning for Introduce KUnit (rev2)
  2023-03-15  9:40 [igt-dev] [PATCH v2 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
                   ` (4 preceding siblings ...)
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 5/5] Change logic of ktap parser to run on a thread Dominik Karol Piatkowski
@ 2023-03-15 10:02 ` Patchwork
  2023-03-15 10:17 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
  2023-03-16  0:29 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  7 siblings, 0 replies; 13+ messages in thread
From: Patchwork @ 2023-03-15 10:02 UTC (permalink / raw)
  To: Dominik Karol Piatkowski; +Cc: igt-dev

== Series Details ==

Series: Introduce KUnit (rev2)
URL   : https://patchwork.freedesktop.org/series/114612/
State : warning

== Summary ==

Pipeline status: FAILED.

see https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/830209 for the overview.

test:ninja-test has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/38098739):
  367/371 assembler test/rnde-intsrc              OK       0.01 s 
  368/371 assembler test/rndz                     OK       0.01 s 
  369/371 assembler test/lzd                      OK       0.01 s 
  370/371 assembler test/not                      OK       0.01 s 
  371/371 assembler test/immediate                OK       0.01 s 
  
  Ok:                  364
  Expected Fail:         4
  Fail:                  3
  Unexpected Pass:       0
  Skipped:               0
  Timeout:               0
  
  Full log written to /builds/gfx-ci/igt-ci-tags/build/meson-logs/testlog.txt
  section_end:1678874355:step_script
  section_start:1678874355:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1678874357:cleanup_file_variables
  ERROR: Job failed: exit code 1
  

test:ninja-test-clang has failed (https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/jobs/38098740):
  367/371 assembler test/rnde-intsrc              OK       0.01 s 
  368/371 assembler test/rndz                     OK       0.01 s 
  369/371 assembler test/lzd                      OK       0.01 s 
  370/371 assembler test/not                      OK       0.01 s 
  371/371 assembler test/immediate                OK       0.01 s 
  
  Ok:                  363
  Expected Fail:         4
  Fail:                  4
  Unexpected Pass:       0
  Skipped:               0
  Timeout:               0
  
  Full log written to /builds/gfx-ci/igt-ci-tags/build/meson-logs/testlog.txt
  section_end:1678874355:step_script
  section_start:1678874355:cleanup_file_variables
  Cleaning up project directory and file based variables
  section_end:1678874357:cleanup_file_variables
  ERROR: Job failed: exit code 1

== Logs ==

For more details see: https://gitlab.freedesktop.org/gfx-ci/igt-ci-tags/-/pipelines/830209

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [igt-dev] ✓ Fi.CI.BAT: success for Introduce KUnit (rev2)
  2023-03-15  9:40 [igt-dev] [PATCH v2 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
                   ` (5 preceding siblings ...)
  2023-03-15 10:02 ` [igt-dev] ✗ GitLab.Pipeline: warning for Introduce KUnit (rev2) Patchwork
@ 2023-03-15 10:17 ` Patchwork
  2023-03-16  0:29 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
  7 siblings, 0 replies; 13+ messages in thread
From: Patchwork @ 2023-03-15 10:17 UTC (permalink / raw)
  To: Dominik Karol Piatkowski; +Cc: igt-dev

[-- Attachment #1: Type: text/plain, Size: 6072 bytes --]

== Series Details ==

Series: Introduce KUnit (rev2)
URL   : https://patchwork.freedesktop.org/series/114612/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_12861 -> IGTPW_8608
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/index.html

Participating hosts (35 -> 37)
------------------------------

  Additional (3): fi-kbl-x1275 fi-bsw-n3050 fi-pnv-d510 
  Missing    (1): fi-snb-2520m 

Known issues
------------

  Here are the changes found in IGTPW_8608 that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@core_hotunplug@unbind-rebind:
    - fi-apl-guc:         [PASS][1] -> [ABORT][2] ([i915#8225])
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/fi-apl-guc/igt@core_hotunplug@unbind-rebind.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/fi-apl-guc/igt@core_hotunplug@unbind-rebind.html

  * igt@gem_huc_copy@huc-copy:
    - fi-kbl-x1275:       NOTRUN -> [SKIP][3] ([fdo#109271] / [i915#2190])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/fi-kbl-x1275/igt@gem_huc_copy@huc-copy.html

  * igt@gem_lmem_swapping@random-engines:
    - fi-bsw-n3050:       NOTRUN -> [SKIP][4] ([fdo#109271]) +29 similar issues
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/fi-bsw-n3050/igt@gem_lmem_swapping@random-engines.html

  * igt@gem_lmem_swapping@verify-random:
    - fi-kbl-x1275:       NOTRUN -> [SKIP][5] ([fdo#109271] / [i915#4613]) +3 similar issues
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/fi-kbl-x1275/igt@gem_lmem_swapping@verify-random.html

  * igt@i915_selftest@live@guc:
    - bat-rpls-1:         [PASS][6] -> [DMESG-WARN][7] ([i915#7852])
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/bat-rpls-1/igt@i915_selftest@live@guc.html
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/bat-rpls-1/igt@i915_selftest@live@guc.html

  * igt@kms_chamelium_hpd@common-hpd-after-suspend:
    - bat-adlm-1:         NOTRUN -> [SKIP][8] ([i915#7828])
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/bat-adlm-1/igt@kms_chamelium_hpd@common-hpd-after-suspend.html
    - bat-rpls-1:         NOTRUN -> [SKIP][9] ([i915#7828])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/bat-rpls-1/igt@kms_chamelium_hpd@common-hpd-after-suspend.html

  * igt@kms_pipe_crc_basic@read-crc:
    - fi-kbl-x1275:       NOTRUN -> [SKIP][10] ([fdo#109271]) +45 similar issues
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/fi-kbl-x1275/igt@kms_pipe_crc_basic@read-crc.html

  * igt@kms_pipe_crc_basic@suspend-read-crc:
    - bat-adlm-1:         NOTRUN -> [SKIP][11] ([i915#1845])
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/bat-adlm-1/igt@kms_pipe_crc_basic@suspend-read-crc.html
    - bat-rpls-1:         NOTRUN -> [SKIP][12] ([i915#1845])
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/bat-rpls-1/igt@kms_pipe_crc_basic@suspend-read-crc.html

  * igt@kms_psr@primary_page_flip:
    - fi-pnv-d510:        NOTRUN -> [SKIP][13] ([fdo#109271]) +38 similar issues
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/fi-pnv-d510/igt@kms_psr@primary_page_flip.html

  
#### Possible fixes ####

  * igt@gem_exec_suspend@basic-s3@smem:
    - bat-rpls-1:         [ABORT][14] ([i915#6687] / [i915#7978]) -> [PASS][15]
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/bat-rpls-1/igt@gem_exec_suspend@basic-s3@smem.html
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/bat-rpls-1/igt@gem_exec_suspend@basic-s3@smem.html

  * igt@i915_selftest@live@migrate:
    - bat-rplp-1:         [DMESG-FAIL][16] ([i915#7699]) -> [PASS][17]
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/bat-rplp-1/igt@i915_selftest@live@migrate.html
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/bat-rplp-1/igt@i915_selftest@live@migrate.html

  * igt@i915_selftest@live@workarounds:
    - bat-rpls-1:         [DMESG-WARN][18] ([i915#7852]) -> [PASS][19]
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/bat-rpls-1/igt@i915_selftest@live@workarounds.html
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/bat-rpls-1/igt@i915_selftest@live@workarounds.html
    - bat-adlm-1:         [INCOMPLETE][20] ([i915#4983] / [i915#7677]) -> [PASS][21]
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/bat-adlm-1/igt@i915_selftest@live@workarounds.html
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/bat-adlm-1/igt@i915_selftest@live@workarounds.html

  
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [i915#1845]: https://gitlab.freedesktop.org/drm/intel/issues/1845
  [i915#2190]: https://gitlab.freedesktop.org/drm/intel/issues/2190
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4983]: https://gitlab.freedesktop.org/drm/intel/issues/4983
  [i915#6687]: https://gitlab.freedesktop.org/drm/intel/issues/6687
  [i915#7677]: https://gitlab.freedesktop.org/drm/intel/issues/7677
  [i915#7699]: https://gitlab.freedesktop.org/drm/intel/issues/7699
  [i915#7828]: https://gitlab.freedesktop.org/drm/intel/issues/7828
  [i915#7852]: https://gitlab.freedesktop.org/drm/intel/issues/7852
  [i915#7978]: https://gitlab.freedesktop.org/drm/intel/issues/7978
  [i915#8225]: https://gitlab.freedesktop.org/drm/intel/issues/8225


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_7195 -> IGTPW_8608

  CI-20190529: 20190529
  CI_DRM_12861: a2cdd75e9e48ef31a52b0472f7a3537423a9748e @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_8608: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/index.html
  IGT_7195: 4976e86efa7f7657e0a175e6375508764ea58d95 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git


Testlist changes
----------------

-igt@drm_buddy@all-tests
-igt@drm_mm@all-tests
-igt@kms_selftest@all-tests

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/index.html

[-- Attachment #2: Type: text/html, Size: 7501 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 5/5] Change logic of ktap parser to run on a thread
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 5/5] Change logic of ktap parser to run on a thread Dominik Karol Piatkowski
@ 2023-03-15 12:49   ` Mauro Carvalho Chehab
  2023-03-24  8:11     ` Piatkowski, Dominik Karol
  0 siblings, 1 reply; 13+ messages in thread
From: Mauro Carvalho Chehab @ 2023-03-15 12:49 UTC (permalink / raw)
  To: Dominik Karol Piatkowski; +Cc: igt-dev

On Wed, 15 Mar 2023 10:40:42 +0100
Dominik Karol Piatkowski <dominik.karol.piatkowski@intel.com> wrote:

> The ktap parser should be listening and parsing messages as the tests
> are executed, and not after the end of module load.
> 
> Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
> Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
> Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
> ---
>  lib/igt_kmod.c |  12 +++--
>  lib/igt_ktap.c | 137 +++++++++++++++++++++++++++++++------------------
>  lib/igt_ktap.h |   3 +-
>  3 files changed, 97 insertions(+), 55 deletions(-)
> 
> diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
> index 3b92cc94..23b92742 100644
> --- a/lib/igt_kmod.c
> +++ b/lib/igt_kmod.c
> @@ -758,7 +758,6 @@ int igt_kunit(const char *module_name, const char *opts)
>  {
>  	struct igt_ktest tst;
>  	struct kmod_module *kunit_kmod;
> -	char record[BUF_LEN + 1];
>  	FILE *f;
>  	bool is_builtin;
>  	int ret;
> @@ -804,19 +803,24 @@ int igt_kunit(const char *module_name, const char *opts)
>  
>  	is_builtin = kmod_module_get_initstate(kunit_kmod) == KMOD_MODULE_BUILTIN;
>  
> +	ktap_parser_start(f, is_builtin);
> +
>  	if (igt_kmod_load(module_name, opts) != 0) {
>  		igt_warn("Unable to load %s module\n", module_name);
> +		ret = ktap_parser_stop();
>  		igt_fail(IGT_EXIT_FAILURE);
>  	}
>  
> -	ret = igt_ktap_parser(f, record, is_builtin);
> -	if (ret != 0)
> -		ret = IGT_EXIT_ABORT;
>  unload:
>  	igt_ktest_end(&tst);
>  
>  	igt_ktest_fini(&tst);
>  
> +	ret = ktap_parser_stop();
> +
> +	if (ret != 0)
> +		ret = IGT_EXIT_ABORT;
> +
>  	if (ret == 0)
>  		igt_success();
>  
> diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
> index 117598fa..acbb76ba 100644
> --- a/lib/igt_ktap.c
> +++ b/lib/igt_ktap.c
> @@ -10,6 +10,10 @@
>  #include "igt_core.h"
>  #include "igt_ktap.h"
>  
> +#include <libkmod.h>
> +


> +#include <pthread.h>

Hmm... IGT has some pthread handlers. You should use them.


> +
>  static int log_to_end(enum igt_log_level level, FILE *f,
>  		      char *record, const char *format, ...) __attribute__((format(printf, 4, 5)));
>  
> @@ -253,6 +257,13 @@ static int parse_kmsg_for_tap(FILE *fp, char *record, char *test_name)
>  	return 1;
>  }
>  
> +struct ktap_parser_args {
> +	FILE *fp;
> +	bool is_builtin;
> +	volatile bool is_running;
> +	int ret;
> +} ktap_args;
> +
>  /**
>   * igt_ktap_parser:
>   * @fp: FILE pointer
> @@ -264,71 +275,97 @@ static int parse_kmsg_for_tap(FILE *fp, char *record, char *test_name)
>   *
>   * Returns: IGT default codes
>   */
> -int igt_ktap_parser(FILE *fp, char *record, bool is_builtin)
> +void *igt_ktap_parser(void* unused)

Nitpick: as we use Kernel coding style, it should be:

	void *igt_ktap_parser(void *unused)


>  {
> +	FILE *fp = ktap_args.fp;
> +	char record[BUF_LEN + 1];
> +	bool is_builtin = ktap_args.is_builtin;
> +
>  	char test_name[BUF_LEN + 1];
>  	bool failed_tests, found_tests;
>  	int sublevel = 0;
>  
> -	test_name[0] = '\0';
> -	test_name[BUF_LEN] = '\0';
> -
>  	failed_tests = false;
>  	found_tests = false;
>  
> -	while (sublevel >= 0) {
> -		if (fgets(record, BUF_LEN, fp) == NULL) {
> -			if (!found_tests)
> -				igt_warn("kmsg truncated: unknown error (%m)\n");
> -			break;
> +igt_ktap_parser_start:
> +	while (ktap_args.is_running) {
> +		test_name[0] = '\0';
> +		test_name[BUF_LEN] = '\0';
> +
> +		while (fgets(record, BUF_LEN, fp) != NULL) {
> +			if (!ktap_args.is_running)
> +				return NULL;
> +			usleep(1000);
>  		}

Please don't add sleep, as it might lose messages on crashes.

You should probably check ferror() and/or  feof() if it returns NULL, as 
it can indicate either:

	- that modprobe ended - so, feof() would be nonzero;
	- some error happened - so, ferror() would be nonzero. 
	  On such case, it should likely print the error.

Also, don't call usleep(). If fp was opened on sync mode (usually the default),
usleep is not needed at all, as fgets() will block until an error or read. 

Otherwise, if fp is in async mode, you can switch to sync mode with:

	s = fcntl(*fd, F_GETFL);
	s |= O_SYNC;
	result = fcntl(*fd, F_SETFL, s);

and avoid the usleep().

Btw, you probably need to add error check logic too. Maybe, you could do 
something like (untested):

	while (!feof(record)) {
		if (fgets(record, BUF_LEN, fp) == NULL) {
			if (ferror(record))
				igt_warn("klog read failed: %s\n", strerror(errno));

			if (!ktap_args.is_running)
				return NULL;
  		}

here and the calls to fgets() below.
 
> -		switch (find_next_tap_subtest(fp, record, is_builtin)) {
> -		case -2:
> -			/* no more data to read */
> -			return IGT_EXIT_FAILURE;
> -		case -1:
> -			/* no test found, so we keep parsing */
> -			break;
> -		case 0:
> -			/*
> -			 * tests found, but they're missing info, so we might
> -			 * have read into test output
> -			 */
> -			found_tests = true;
> -			sublevel++;
> -			break;
> -		default:
> -			if (fgets(record, BUF_LEN, fp) == NULL) {
> -				igt_warn("kmsg truncated: unknown error (%m)\n");
> -				return -2;
> +		while (sublevel >= 0) {
> +			switch (find_next_tap_subtest(fp, record, is_builtin)) {
> +			case -2:
> +				/* no more data to read */
> +				goto igt_ktap_parser_start;
> +			case -1:
> +				/* no test found, so we keep parsing */
> +				break;
> +			case 0:
> +				/*
> +				 * tests found, but they're missing info, so we might
> +				 * have read into test output
> +				 */
> +				found_tests = true;
> +				sublevel++;
> +				break;
> +			default:
> +				if (fgets(record, BUF_LEN, fp) == NULL) {
> +					igt_warn("kmsg truncated: unknown error (%m)\n");
> +					goto igt_ktap_parser_start;
> +				}
> +				found_tests = true;
> +				sublevel++;
> +				break;
>  			}
> -			found_tests = true;
> -			sublevel++;
> -			break;
> -		}
>  
> -		switch (parse_kmsg_for_tap(fp, record, test_name)) {
> -		case -2:
> -			return IGT_EXIT_FAILURE;
> -		case -1:
> -			sublevel--;
> -			failed_tests = true;
> -			igt_subtest(test_name)
> -				igt_fail(IGT_EXIT_FAILURE);
> -			test_name[0] = '\0';
> -			break;
> -		case 0: /* fallthrough */
> -			igt_subtest(test_name)
> -				igt_success();
> -			test_name[0] = '\0';
> -		default:
> -			break;
> +			switch (parse_kmsg_for_tap(fp, record, test_name)) {
> +			case -2:
> +				goto igt_ktap_parser_start;
> +			case -1:
> +				sublevel--;
> +				failed_tests = true;
> +				igt_subtest(test_name)
> +					igt_fail(IGT_EXIT_FAILURE);
> +				test_name[0] = '\0';
> +				break;
> +			case 0: /* fallthrough */
> +				igt_subtest(test_name)
> +					igt_success();
> +				test_name[0] = '\0';
> +			default:
> +				break;
> +			}
>  		}
>  	}
>  
>  	if (failed_tests || !found_tests)
> -		return IGT_EXIT_FAILURE;
> +		ktap_args.ret = IGT_EXIT_FAILURE;
> +	else
> +		ktap_args.ret = IGT_EXIT_SUCCESS;
> +
> +	return NULL;
> +}
> +
> +static pthread_t ktap_parser_thread;
>  
> -	return IGT_EXIT_SUCCESS;
> +void ktap_parser_start(FILE *fp, bool is_builtin)
> +{
> +	ktap_args.fp = fp;
> +	ktap_args.is_builtin = is_builtin;
> +	ktap_args.is_running = true;
> +	pthread_create(&ktap_parser_thread, NULL, igt_ktap_parser, NULL);
> +}
> +
> +int ktap_parser_stop(void)
> +{
> +	ktap_args.is_running = false;
> +	pthread_join(ktap_parser_thread, NULL);
> +	return ktap_args.ret;
>  }
> diff --git a/lib/igt_ktap.h b/lib/igt_ktap.h
> index b2f69df2..461df6f5 100644
> --- a/lib/igt_ktap.h
> +++ b/lib/igt_ktap.h
> @@ -26,6 +26,7 @@
>  
>  #define BUF_LEN 4096
>  
> -int igt_ktap_parser(FILE *fp, char *record, bool is_builtin);
> +void ktap_parser_start(FILE *fp, bool is_builtin);
> +int ktap_parser_stop(void);
>  
>  #endif /* IGT_KTAP_H */

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 3/5] lib/igt_kmod: add compatibility for KUnit
  2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 3/5] lib/igt_kmod: add compatibility for KUnit Dominik Karol Piatkowski
@ 2023-03-15 13:07   ` Janusz Krzysztofik
  0 siblings, 0 replies; 13+ messages in thread
From: Janusz Krzysztofik @ 2023-03-15 13:07 UTC (permalink / raw)
  To: igt-dev; +Cc: Isabella Basso

Hi Dominik,

On Wednesday, 15 March 2023 10:40:40 CET Dominik Karol Piatkowski wrote:
> From: Isabella Basso <isabbasso@riseup.net>
> 
> This adds functions for both executing the tests as well as parsing (K)TAP
> kmsg output, as per the KTAP spec [1].
> 
> [1] https://www.kernel.org/doc/html/latest/dev-tools/ktap.html
> 
> v1 -> v2:
> - refactor igt_kunit function and ktap parser so that we have only one
>   parser that we call only once (code size is now less than half the
>   size as v1)
> - add lookup_value helper
> - fix parsing problems
> v2 -> v3:
> - move ktap parsing functions to own file
> - rename to ktap_parser
> - get rid of unneeded pointers in igt_kunit
> - change return values to allow for subsequent call to igt_kselftests if
>   needed
> - add docs to parsing functions and helpers
> - switch to line buffering
> - add line buffering logging helper
> - fix kunit module handling
> - fix parsing of version lines
> - use igt_subtest blocks to improve output handling on the CI
> - fix output handling during crashes
> 
> Signed-off-by: Isabella Basso <isabbasso@riseup.net>
> 
> v3 -> v4:
> - handle igt_ktap_parser fail with IGT_EXIT_ABORT code
> 
> v4 -> v5:
> - added missing newlines in igt_warn
> - removed setvbuf
> 
> Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
> ---
>  lib/igt_kmod.c  |  79 ++++++++++++
>  lib/igt_kmod.h  |   2 +
>  lib/igt_ktap.c  | 334 ++++++++++++++++++++++++++++++++++++++++++++++++
>  lib/igt_ktap.h  |  31 +++++
>  lib/meson.build |   1 +
>  5 files changed, 447 insertions(+)
>  create mode 100644 lib/igt_ktap.c
>  create mode 100644 lib/igt_ktap.h
> 
> diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
> index fbda1aa6..3b92cc94 100644
> --- a/lib/igt_kmod.c
> +++ b/lib/igt_kmod.c
> @@ -29,6 +29,7 @@
>  #include "igt_aux.h"
>  #include "igt_core.h"
>  #include "igt_kmod.h"
> +#include "igt_ktap.h"
>  #include "igt_sysfs.h"
>  #include "igt_taints.h"
>  
> @@ -744,6 +745,84 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
>  	kmod_module_info_free_list(pre);
>  }
>  
> +/**
> + * igt_kunit:
> + * @module_name: the name of the module
> + * @opts: options to load the module
> + *
> + * Loads the test module, parses its (k)tap dmesg output, then unloads it
> + *
> + * Returns: IGT default codes
> + */
> +int igt_kunit(const char *module_name, const char *opts)
> +{
> +	struct igt_ktest tst;
> +	struct kmod_module *kunit_kmod;
> +	char record[BUF_LEN + 1];
> +	FILE *f;
> +	bool is_builtin;
> +	int ret;
> +
> +	ret = IGT_EXIT_INVALID;
> +
> +	/* get normalized module name */
> +	if (igt_ktest_init(&tst, module_name) != 0) {
> +		igt_warn("Unable to initialize ktest for %s\n", module_name);
> +		return ret;
> +	}
> +
> +	if (igt_ktest_begin(&tst) != 0) {


AFAICT, igt_ktest_begin() as is must be called from either igt_fixture or 
igt_subtest section.

I think we are still too far from a typical internal structure of an IGT test.  
Maybe you should have a more closer look at igt_kselftest() and, 
since the same igt_ktest_*() functions are used here and there, follow the 
structure of igt_kselftest() more closely, or its head and tail at least, for 
best CI experience.

Thanks,
Janusz

> +		igt_warn("Unable to begin ktest for %s\n", module_name);
> +
> +		igt_ktest_fini(&tst);
> +		return ret;
> +	}
> +
> +	if (tst.kmsg < 0) {
> +		igt_warn("Could not open /dev/kmsg\n");
> +		goto unload;
> +	}
> +
> +	if (lseek(tst.kmsg, 0, SEEK_END)) {
> +		igt_warn("Could not seek the end of /dev/kmsg\n");
> +		goto unload;
> +	}
> +
> +	f = fdopen(tst.kmsg, "r");
> +
> +	if (f == NULL) {
> +		igt_warn("Could not turn /dev/kmsg file descriptor into a FILE pointer\n");
> +		goto unload;
> +	}
> +
> +	/* The KUnit module is required for running any KUnit tests */
> +	if (igt_kmod_load("kunit", NULL) != 0 ||
> +	    kmod_module_new_from_name(kmod_ctx(), "kunit", &kunit_kmod) != 0) {
> +		igt_warn("Unable to load KUnit\n");
> +		igt_fail(IGT_EXIT_FAILURE);
> +	}
> +
> +	is_builtin = kmod_module_get_initstate(kunit_kmod) == KMOD_MODULE_BUILTIN;
> +
> +	if (igt_kmod_load(module_name, opts) != 0) {
> +		igt_warn("Unable to load %s module\n", module_name);
> +		igt_fail(IGT_EXIT_FAILURE);
> +	}
> +
> +	ret = igt_ktap_parser(f, record, is_builtin);
> +	if (ret != 0)
> +		ret = IGT_EXIT_ABORT;
> +unload:
> +	igt_ktest_end(&tst);
> +
> +	igt_ktest_fini(&tst);
> +
> +	if (ret == 0)
> +		igt_success();
> +
> +	return ret;
> +}
> +
>  static int open_parameters(const char *module_name)
>  {
>  	char path[256];
> diff --git a/lib/igt_kmod.h b/lib/igt_kmod.h
> index ceb10cd0..72f9f445 100644
> --- a/lib/igt_kmod.h
> +++ b/lib/igt_kmod.h
> @@ -45,6 +45,8 @@ int __igt_i915_driver_unload(char **whom);
>  int igt_amdgpu_driver_load(const char *opts);
>  int igt_amdgpu_driver_unload(void);
>  
> +int igt_kunit(const char *module_name, const char *opts);
> +
>  void igt_kselftests(const char *module_name,
>  		    const char *module_options,
>  		    const char *result_option,
> diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
> new file mode 100644
> index 00000000..117598fa
> --- /dev/null
> +++ b/lib/igt_ktap.c
> @@ -0,0 +1,334 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2023 Isabella Basso do Amaral <isabbasso@riseup.net>
> + */
> +
> +#include <ctype.h>
> +#include <limits.h>
> +
> +#include "igt_aux.h"
> +#include "igt_core.h"
> +#include "igt_ktap.h"
> +
> +static int log_to_end(enum igt_log_level level, FILE *f,
> +		      char *record, const char *format, ...) __attribute__((format(printf, 4, 5)));
> +
> +/**
> + * log_to_end:
> + * @level: #igt_log_level
> + * @record: record to store the read data
> + * @format: format string
> + * @...: optional arguments used in the format string
> + *
> + * This is an altered version of the generic structured logging helper function
> + * igt_log capable of reading to the end of a given line.
> + *
> + * Returns: 0 for success, or -2 if there's an error reading from the file
> + */
> +static int log_to_end(enum igt_log_level level, FILE *f,
> +		      char *record, const char *format, ...)
> +{
> +	va_list args;
> +	const char *lend;
> +
> +	va_start(args, format);
> +	igt_vlog(IGT_LOG_DOMAIN, level, format, args);
> +	va_end(args);
> +
> +	lend = strchrnul(record, '\n');
> +	while (*lend == '\0') {
> +		igt_log(IGT_LOG_DOMAIN, level, "%s", record);
> +		if (fgets(record, BUF_LEN, f) == NULL) {
> +			igt_warn("kmsg truncated: unknown error (%m)\n");
> +			return -2;
> +		}
> +		lend = strchrnul(record, '\n');
> +	}
> +	return 0;
> +}
> +
> +/**
> + * lookup_value:
> + * @haystack: the string to search in
> + * @needle: the string to search for
> + *
> + * Returns: the value of the needle in the haystack, or -1 if not found.
> + */
> +static long lookup_value(const char *haystack, const char *needle)
> +{
> +	const char *needle_rptr;
> +	char *needle_end;
> +	long num;
> +
> +	needle_rptr = strcasestr(haystack, needle);
> +
> +	if (needle_rptr == NULL)
> +		return -1;
> +
> +	/* skip search string and whitespaces after it */
> +	needle_rptr += strlen(needle);
> +
> +	num = strtol(needle_rptr, &needle_end, 10);
> +
> +	if (needle_rptr == needle_end)
> +		return -1;
> +
> +	if (num == LONG_MIN || num == LONG_MAX)
> +		return 0;
> +
> +	return num > 0 ? num : 0;
> +}
> +
> +/**
> + * find_next_tap_subtest:
> + * @fp: FILE pointer
> + * @record: buffer used to read fp
> + * @is_builtin: whether KUnit is built-in or not
> + *
> + * Returns:
> + * 0 if there's missing information
> + * -1 if not found
> + * -2 if there are problems while reading the file.
> + * any other value corresponds to the amount of cases of the next (sub)test
> + */
> +static int find_next_tap_subtest(FILE *fp, char *record, bool is_builtin)
> +{
> +	const char *test_lookup_str, *subtest_lookup_str, *name_rptr, *version_rptr;
> +	char test_name[BUF_LEN + 1];
> +	long test_count;
> +
> +	test_name[0] = '\0';
> +	test_name[BUF_LEN] = '\0';
> +
> +	test_lookup_str = " subtest: ";
> +	subtest_lookup_str = " test: ";
> +
> +	/*
> +	 * "(K)TAP version XX" should be the first line on all (sub)tests as per
> +	 * https://kernel.org/doc/html/latest/dev-tools/ktap.html#version-lines
> +	 *
> +	 * but actually isn't, as it currently depends on the KUnit module
> +	 * being built-in, so we can't rely on it every time
> +	 */
> +	if (is_builtin) {
> +		version_rptr = strcasestr(record, "TAP version ");
> +		if (version_rptr == NULL)
> +			return -1;
> +
> +		igt_info("%s", version_rptr);
> +
> +		if (fgets(record, BUF_LEN, fp) == NULL) {
> +			igt_warn("kmsg truncated: unknown error (%m)\n");
> +			return -2;
> +		}
> +	}
> +
> +	name_rptr = strcasestr(record, test_lookup_str);
> +	if (name_rptr != NULL) {
> +		name_rptr += strlen(test_lookup_str);
> +	} else {
> +		name_rptr = strcasestr(record, subtest_lookup_str);
> +		if (name_rptr != NULL)
> +			name_rptr += strlen(subtest_lookup_str);
> +	}
> +
> +	if (name_rptr == NULL) {
> +		if (!is_builtin)
> +			/* we've probably found nothing */
> +			return -1;
> +		igt_info("Missing test name\n");
> +	} else {
> +		strncpy(test_name, name_rptr, BUF_LEN);
> +		if (fgets(record, BUF_LEN, fp) == NULL) {
> +			igt_warn("kmsg truncated: unknown error (%m)\n");
> +			return -2;
> +		}
> +		/* now we can be sure we found tests */
> +		if (!is_builtin)
> +			igt_info("KUnit is not built-in, skipping version check...\n");
> +	}
> +
> +	/*
> +	 * total test count will almost always appear as 0..N at the beginning
> +	 * of a run, so we use it to reliably identify a new run
> +	 */
> +	test_count = lookup_value(record, "..");
> +
> +	if (test_count <= 0) {
> +		igt_info("Missing test count\n");
> +		if (test_name[0] == '\0')
> +			return 0;
> +		if (log_to_end(IGT_LOG_INFO, fp, record,
> +				"Running some tests in: %s",
> +				test_name) < 0)
> +			return -2;
> +		return 0;
> +	} else if (test_name[0] == '\0') {
> +		igt_info("Running %ld tests...\n", test_count);
> +		return 0;
> +	}
> +
> +	if (log_to_end(IGT_LOG_INFO, fp, record,
> +			"Executing %ld tests in: %s",
> +			test_count, test_name) < 0)
> +		return -2;
> +
> +	return test_count;
> +}
> +
> +/**
> + * find_next_tap_test:
> + * @fp: FILE pointer
> + * @record: buffer used to read fp
> + * @test_name: buffer to store the test name
> + *
> + * Returns:
> + * 1 if no results were found
> + * 0 if a test succeded
> + * -1 if a test failed
> + * -2 if there are problems reading the file
> + */
> +static int parse_kmsg_for_tap(FILE *fp, char *record, char *test_name)
> +{
> +	const char *lstart, *ok_lookup_str, *nok_lookup_str,
> +	      *ok_rptr, *nok_rptr, *comment_start, *value_parse_start;
> +	char *test_name_end;
> +
> +	ok_lookup_str = "ok ";
> +	nok_lookup_str = "not ok ";
> +
> +	lstart = strchrnul(record, ';');
> +
> +	if (*lstart == '\0') {
> +		igt_warn("kmsg truncated: output malformed (%m)\n");
> +		return -2;
> +	}
> +
> +	lstart++;
> +	while (isspace(*lstart))
> +		lstart++;
> +
> +	nok_rptr = strstr(lstart, nok_lookup_str);
> +	if (nok_rptr != NULL) {
> +		nok_rptr += strlen(nok_lookup_str);
> +		while (isdigit(*nok_rptr) || isspace(*nok_rptr) || *nok_rptr == '-')
> +			nok_rptr++;
> +		test_name_end = strncpy(test_name, nok_rptr, BUF_LEN);
> +		while (!isspace(*test_name_end))
> +			test_name_end++;
> +		*test_name_end = '\0';
> +		if (log_to_end(IGT_LOG_WARN, fp, record,
> +			       "%s", lstart) < 0)
> +			return -2;
> +		return -1;
> +	}
> +
> +	comment_start = strchrnul(lstart, '#');
> +
> +	/* check if we're still in a subtest */
> +	if (*comment_start != '\0') {
> +		comment_start++;
> +		value_parse_start = comment_start;
> +
> +		if (lookup_value(value_parse_start, "fail: ") > 0) {
> +			if (log_to_end(IGT_LOG_WARN, fp, record,
> +				       "%s", lstart) < 0)
> +				return -2;
> +			return -1;
> +		}
> +	}
> +
> +	ok_rptr = strstr(lstart, ok_lookup_str);
> +	if (ok_rptr != NULL) {
> +		ok_rptr += strlen(ok_lookup_str);
> +		while (isdigit(*ok_rptr) || isspace(*ok_rptr) || *ok_rptr == '-')
> +			ok_rptr++;
> +		test_name_end = strncpy(test_name, ok_rptr, BUF_LEN);
> +		while (!isspace(*test_name_end))
> +			test_name_end++;
> +		*test_name_end = '\0';
> +		return 0;
> +	}
> +
> +	return 1;
> +}
> +
> +/**
> + * igt_ktap_parser:
> + * @fp: FILE pointer
> + * @record: buffer used to read fp
> + * @is_builtin: whether the KUnit module is built-in or not
> + *
> + * This function parses the output of a ktap script and prints the test results,
> + * as well as any other output to stdout.
> + *
> + * Returns: IGT default codes
> + */
> +int igt_ktap_parser(FILE *fp, char *record, bool is_builtin)
> +{
> +	char test_name[BUF_LEN + 1];
> +	bool failed_tests, found_tests;
> +	int sublevel = 0;
> +
> +	test_name[0] = '\0';
> +	test_name[BUF_LEN] = '\0';
> +
> +	failed_tests = false;
> +	found_tests = false;
> +
> +	while (sublevel >= 0) {
> +		if (fgets(record, BUF_LEN, fp) == NULL) {
> +			if (!found_tests)
> +				igt_warn("kmsg truncated: unknown error (%m)\n");
> +			break;
> +		}
> +
> +		switch (find_next_tap_subtest(fp, record, is_builtin)) {
> +		case -2:
> +			/* no more data to read */
> +			return IGT_EXIT_FAILURE;
> +		case -1:
> +			/* no test found, so we keep parsing */
> +			break;
> +		case 0:
> +			/*
> +			 * tests found, but they're missing info, so we might
> +			 * have read into test output
> +			 */
> +			found_tests = true;
> +			sublevel++;
> +			break;
> +		default:
> +			if (fgets(record, BUF_LEN, fp) == NULL) {
> +				igt_warn("kmsg truncated: unknown error (%m)\n");
> +				return -2;
> +			}
> +			found_tests = true;
> +			sublevel++;
> +			break;
> +		}
> +
> +		switch (parse_kmsg_for_tap(fp, record, test_name)) {
> +		case -2:
> +			return IGT_EXIT_FAILURE;
> +		case -1:
> +			sublevel--;
> +			failed_tests = true;
> +			igt_subtest(test_name)
> +				igt_fail(IGT_EXIT_FAILURE);
> +			test_name[0] = '\0';
> +			break;
> +		case 0: /* fallthrough */
> +			igt_subtest(test_name)
> +				igt_success();
> +			test_name[0] = '\0';
> +		default:
> +			break;
> +		}
> +	}
> +
> +	if (failed_tests || !found_tests)
> +		return IGT_EXIT_FAILURE;
> +
> +	return IGT_EXIT_SUCCESS;
> +}
> diff --git a/lib/igt_ktap.h b/lib/igt_ktap.h
> new file mode 100644
> index 00000000..b2f69df2
> --- /dev/null
> +++ b/lib/igt_ktap.h
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright © 2022 Isabella Basso do Amaral <isabbasso@riseup.net>
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice (including the next
> + * paragraph) shall be included in all copies or substantial portions of the
> + * Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
> + * IN THE SOFTWARE.
> + */
> +
> +#ifndef IGT_KTAP_H
> +#define IGT_KTAP_H
> +
> +#define BUF_LEN 4096
> +
> +int igt_ktap_parser(FILE *fp, char *record, bool is_builtin);
> +
> +#endif /* IGT_KTAP_H */
> diff --git a/lib/meson.build b/lib/meson.build
> index 768ce90b..45b9626a 100644
> --- a/lib/meson.build
> +++ b/lib/meson.build
> @@ -87,6 +87,7 @@ lib_sources = [
>  	'igt_store.c',
>  	'uwildmat/uwildmat.c',
>  	'igt_kmod.c',
> +	'igt_ktap.c',
>  	'igt_panfrost.c',
>  	'igt_v3d.c',
>  	'igt_vc4.c',
> 




^ permalink raw reply	[flat|nested] 13+ messages in thread

* [igt-dev] ✓ Fi.CI.IGT: success for Introduce KUnit (rev2)
  2023-03-15  9:40 [igt-dev] [PATCH v2 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
                   ` (6 preceding siblings ...)
  2023-03-15 10:17 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
@ 2023-03-16  0:29 ` Patchwork
  7 siblings, 0 replies; 13+ messages in thread
From: Patchwork @ 2023-03-16  0:29 UTC (permalink / raw)
  To: Dominik Karol Piatkowski; +Cc: igt-dev

[-- Attachment #1: Type: text/plain, Size: 30821 bytes --]

== Series Details ==

Series: Introduce KUnit (rev2)
URL   : https://patchwork.freedesktop.org/series/114612/
State : success

== Summary ==

CI Bug Log - changes from CI_DRM_12861_full -> IGTPW_8608_full
====================================================

Summary
-------

  **SUCCESS**

  No regressions found.

  External URL: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/index.html

Participating hosts (8 -> 8)
------------------------------

  No changes in participating hosts

Known issues
------------

  Here are the changes found in IGTPW_8608_full that come from known issues:

### IGT changes ###

#### Issues hit ####

  * igt@gem_exec_fair@basic-none-rrul@rcs0:
    - shard-glk:          [PASS][1] -> [FAIL][2] ([i915#2842]) +1 similar issue
   [1]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-glk5/igt@gem_exec_fair@basic-none-rrul@rcs0.html
   [2]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-glk2/igt@gem_exec_fair@basic-none-rrul@rcs0.html

  * igt@gem_exec_fair@basic-pace-solo@rcs0:
    - shard-apl:          [PASS][3] -> [FAIL][4] ([i915#2842])
   [3]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-apl7/igt@gem_exec_fair@basic-pace-solo@rcs0.html
   [4]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-apl7/igt@gem_exec_fair@basic-pace-solo@rcs0.html

  * igt@gen9_exec_parse@allowed-all:
    - shard-apl:          [PASS][5] -> [ABORT][6] ([i915#5566])
   [5]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-apl6/igt@gen9_exec_parse@allowed-all.html
   [6]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-apl6/igt@gen9_exec_parse@allowed-all.html

  * igt@gen9_exec_parse@allowed-single:
    - shard-glk:          [PASS][7] -> [ABORT][8] ([i915#5566])
   [7]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-glk5/igt@gen9_exec_parse@allowed-single.html
   [8]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-glk4/igt@gen9_exec_parse@allowed-single.html

  * igt@i915_pm_dc@dc9-dpms:
    - shard-apl:          [PASS][9] -> [FAIL][10] ([i915#4275])
   [9]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-apl4/igt@i915_pm_dc@dc9-dpms.html
   [10]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-apl4/igt@i915_pm_dc@dc9-dpms.html

  * igt@i915_selftest@live@gt_heartbeat:
    - shard-apl:          [PASS][11] -> [DMESG-FAIL][12] ([i915#5334])
   [11]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-apl7/igt@i915_selftest@live@gt_heartbeat.html
   [12]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-apl3/igt@i915_selftest@live@gt_heartbeat.html

  * igt@i915_selftest@mock@sanitycheck:
    - shard-snb:          [PASS][13] -> [ABORT][14] ([i915#4528])
   [13]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-snb5/igt@i915_selftest@mock@sanitycheck.html
   [14]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-snb2/igt@i915_selftest@mock@sanitycheck.html

  * igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions-varying-size:
    - shard-apl:          [PASS][15] -> [FAIL][16] ([i915#2346])
   [15]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-apl3/igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions-varying-size.html
   [16]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-apl6/igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions-varying-size.html
    - shard-glk:          [PASS][17] -> [FAIL][18] ([i915#2346])
   [17]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-glk1/igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions-varying-size.html
   [18]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-glk8/igt@kms_cursor_legacy@flip-vs-cursor-atomic-transitions-varying-size.html

  * igt@kms_flip@2x-flip-vs-expired-vblank-interruptible@ab-hdmi-a1-hdmi-a2:
    - shard-glk:          [PASS][19] -> [FAIL][20] ([i915#79])
   [19]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-glk4/igt@kms_flip@2x-flip-vs-expired-vblank-interruptible@ab-hdmi-a1-hdmi-a2.html
   [20]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-glk6/igt@kms_flip@2x-flip-vs-expired-vblank-interruptible@ab-hdmi-a1-hdmi-a2.html

  * igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-draw-mmap-wc:
    - shard-glk:          NOTRUN -> [SKIP][21] ([fdo#109271]) +5 similar issues
   [21]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-glk3/igt@kms_frontbuffer_tracking@fbcpsr-2p-primscrn-spr-indfb-draw-mmap-wc.html

  * igt@kms_plane_scaling@plane-scaler-with-clipping-clamping-pixel-formats@pipe-a-vga-1:
    - shard-snb:          NOTRUN -> [SKIP][22] ([fdo#109271]) +6 similar issues
   [22]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-snb2/igt@kms_plane_scaling@plane-scaler-with-clipping-clamping-pixel-formats@pipe-a-vga-1.html

  * igt@kms_psr2_sf@overlay-plane-update-continuous-sf:
    - shard-glk:          NOTRUN -> [SKIP][23] ([fdo#109271] / [i915#658])
   [23]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-glk2/igt@kms_psr2_sf@overlay-plane-update-continuous-sf.html

  * igt@perf@stress-open-close:
    - shard-glk:          [PASS][24] -> [ABORT][25] ([i915#5213])
   [24]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-glk5/igt@perf@stress-open-close.html
   [25]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-glk2/igt@perf@stress-open-close.html

  
#### Possible fixes ####

  * igt@device_reset@unbind-reset-rebind:
    - {shard-rkl}:        [FAIL][26] ([i915#4778]) -> [PASS][27]
   [26]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-5/igt@device_reset@unbind-reset-rebind.html
   [27]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-1/igt@device_reset@unbind-reset-rebind.html

  * igt@drm_fdinfo@virtual-idle:
    - {shard-rkl}:        [FAIL][28] ([i915#7742]) -> [PASS][29] +1 similar issue
   [28]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-2/igt@drm_fdinfo@virtual-idle.html
   [29]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-4/igt@drm_fdinfo@virtual-idle.html

  * igt@fbdev@pan:
    - {shard-rkl}:        [SKIP][30] ([i915#2582]) -> [PASS][31] +1 similar issue
   [30]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-4/igt@fbdev@pan.html
   [31]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-1/igt@fbdev@pan.html

  * igt@fbdev@write:
    - {shard-tglu}:       [SKIP][32] ([i915#2582]) -> [PASS][33] +1 similar issue
   [32]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-tglu-9/igt@fbdev@write.html
   [33]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-tglu-8/igt@fbdev@write.html

  * igt@feature_discovery@psr1:
    - {shard-rkl}:        [SKIP][34] ([i915#658]) -> [PASS][35]
   [34]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-4/igt@feature_discovery@psr1.html
   [35]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-6/igt@feature_discovery@psr1.html

  * igt@gem_ctx_persistence@hang:
    - {shard-rkl}:        [SKIP][36] ([i915#6252]) -> [PASS][37]
   [36]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-5/igt@gem_ctx_persistence@hang.html
   [37]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-1/igt@gem_ctx_persistence@hang.html

  * igt@gem_eio@in-flight-external:
    - {shard-rkl}:        [ABORT][38] ([i915#7811]) -> [PASS][39]
   [38]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-3/igt@gem_eio@in-flight-external.html
   [39]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-1/igt@gem_eio@in-flight-external.html

  * igt@gem_exec_fair@basic-deadline:
    - {shard-rkl}:        [FAIL][40] ([i915#2846]) -> [PASS][41]
   [40]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-2/igt@gem_exec_fair@basic-deadline.html
   [41]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-1/igt@gem_exec_fair@basic-deadline.html

  * igt@gem_exec_fair@basic-none-share@rcs0:
    - shard-apl:          [SKIP][42] ([fdo#109271]) -> [PASS][43]
   [42]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-apl7/igt@gem_exec_fair@basic-none-share@rcs0.html
   [43]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-apl4/igt@gem_exec_fair@basic-none-share@rcs0.html

  * igt@gem_exec_fair@basic-none-solo@rcs0:
    - {shard-rkl}:        [FAIL][44] ([i915#2842]) -> [PASS][45]
   [44]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-3/igt@gem_exec_fair@basic-none-solo@rcs0.html
   [45]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-5/igt@gem_exec_fair@basic-none-solo@rcs0.html

  * igt@gem_exec_flush@basic-batch-kernel-default-cmd:
    - {shard-rkl}:        [SKIP][46] ([fdo#109313]) -> [PASS][47]
   [46]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-2/igt@gem_exec_flush@basic-batch-kernel-default-cmd.html
   [47]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-5/igt@gem_exec_flush@basic-batch-kernel-default-cmd.html

  * igt@gem_exec_reloc@basic-scanout@vcs0:
    - {shard-tglu}:       [SKIP][48] ([i915#3639]) -> [PASS][49] +4 similar issues
   [48]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-tglu-9/igt@gem_exec_reloc@basic-scanout@vcs0.html
   [49]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-tglu-7/igt@gem_exec_reloc@basic-scanout@vcs0.html

  * igt@gem_exec_reloc@basic-write-read-noreloc:
    - {shard-rkl}:        [SKIP][50] ([i915#3281]) -> [PASS][51] +6 similar issues
   [50]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-2/igt@gem_exec_reloc@basic-write-read-noreloc.html
   [51]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-5/igt@gem_exec_reloc@basic-write-read-noreloc.html

  * igt@gem_partial_pwrite_pread@writes-after-reads-display:
    - {shard-rkl}:        [SKIP][52] ([i915#3282]) -> [PASS][53] +5 similar issues
   [52]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-1/igt@gem_partial_pwrite_pread@writes-after-reads-display.html
   [53]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-5/igt@gem_partial_pwrite_pread@writes-after-reads-display.html

  * igt@gen9_exec_parse@unaligned-access:
    - {shard-rkl}:        [SKIP][54] ([i915#2527]) -> [PASS][55] +1 similar issue
   [54]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-3/igt@gen9_exec_parse@unaligned-access.html
   [55]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-5/igt@gen9_exec_parse@unaligned-access.html

  * igt@i915_hangman@gt-engine-error@bcs0:
    - {shard-rkl}:        [SKIP][56] ([i915#6258]) -> [PASS][57]
   [56]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-5/igt@i915_hangman@gt-engine-error@bcs0.html
   [57]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-6/igt@i915_hangman@gt-engine-error@bcs0.html

  * igt@i915_pm_rpm@modeset-lpsp-stress:
    - {shard-tglu}:       [SKIP][58] ([i915#1397]) -> [PASS][59]
   [58]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-tglu-9/igt@i915_pm_rpm@modeset-lpsp-stress.html
   [59]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-tglu-4/igt@i915_pm_rpm@modeset-lpsp-stress.html

  * igt@i915_pm_rpm@pm-tiling:
    - {shard-rkl}:        [SKIP][60] ([i915#5174]) -> [PASS][61]
   [60]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-5/igt@i915_pm_rpm@pm-tiling.html
   [61]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-6/igt@i915_pm_rpm@pm-tiling.html

  * {igt@i915_power@sanity}:
    - {shard-rkl}:        [SKIP][62] ([i915#7984]) -> [PASS][63]
   [62]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-6/igt@i915_power@sanity.html
   [63]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-5/igt@i915_power@sanity.html

  * igt@kms_atomic@atomic_plane_damage:
    - {shard-rkl}:        [SKIP][64] ([i915#4098]) -> [PASS][65] +2 similar issues
   [64]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-2/igt@kms_atomic@atomic_plane_damage.html
   [65]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-6/igt@kms_atomic@atomic_plane_damage.html

  * igt@kms_ccs@pipe-c-crc-primary-rotation-180-y_tiled_gen12_rc_ccs:
    - {shard-tglu}:       [SKIP][66] ([i915#1845] / [i915#7651]) -> [PASS][67] +27 similar issues
   [66]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-tglu-9/igt@kms_ccs@pipe-c-crc-primary-rotation-180-y_tiled_gen12_rc_ccs.html
   [67]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-tglu-6/igt@kms_ccs@pipe-c-crc-primary-rotation-180-y_tiled_gen12_rc_ccs.html

  * igt@kms_ccs@pipe-d-random-ccs-data-y_tiled_gen12_rc_ccs:
    - {shard-tglu}:       [SKIP][68] ([i915#1845]) -> [PASS][69] +24 similar issues
   [68]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-tglu-10/igt@kms_ccs@pipe-d-random-ccs-data-y_tiled_gen12_rc_ccs.html
   [69]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-tglu-6/igt@kms_ccs@pipe-d-random-ccs-data-y_tiled_gen12_rc_ccs.html

  * igt@kms_dp_aux_dev:
    - {shard-rkl}:        [SKIP][70] ([i915#1257]) -> [PASS][71]
   [70]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-1/igt@kms_dp_aux_dev.html
   [71]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-6/igt@kms_dp_aux_dev.html

  * igt@kms_fbcon_fbt@psr:
    - {shard-rkl}:        [SKIP][72] ([fdo#110189] / [i915#3955]) -> [PASS][73]
   [72]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-1/igt@kms_fbcon_fbt@psr.html
   [73]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-6/igt@kms_fbcon_fbt@psr.html

  * igt@kms_flip@flip-vs-suspend-interruptible@c-hdmi-a4:
    - {shard-dg1}:        [FAIL][74] ([fdo#103375]) -> [PASS][75] +3 similar issues
   [74]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-dg1-18/igt@kms_flip@flip-vs-suspend-interruptible@c-hdmi-a4.html
   [75]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-dg1-15/igt@kms_flip@flip-vs-suspend-interruptible@c-hdmi-a4.html

  * igt@kms_frontbuffer_tracking@fbc-1p-primscrn-pri-indfb-draw-mmap-gtt:
    - {shard-tglu}:       [SKIP][76] ([i915#1849]) -> [PASS][77] +12 similar issues
   [76]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-tglu-9/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-pri-indfb-draw-mmap-gtt.html
   [77]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-tglu-7/igt@kms_frontbuffer_tracking@fbc-1p-primscrn-pri-indfb-draw-mmap-gtt.html

  * igt@kms_frontbuffer_tracking@fbc-badstride:
    - {shard-rkl}:        [SKIP][78] ([i915#1849] / [i915#4098]) -> [PASS][79] +20 similar issues
   [78]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-4/igt@kms_frontbuffer_tracking@fbc-badstride.html
   [79]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-6/igt@kms_frontbuffer_tracking@fbc-badstride.html

  * igt@kms_plane@pixel-format@pipe-b-planes:
    - {shard-rkl}:        [SKIP][80] ([i915#1849]) -> [PASS][81] +2 similar issues
   [80]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-1/igt@kms_plane@pixel-format@pipe-b-planes.html
   [81]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-6/igt@kms_plane@pixel-format@pipe-b-planes.html

  * igt@kms_plane@plane-position-hole-dpms@pipe-a-planes:
    - {shard-tglu}:       [SKIP][82] ([i915#1849] / [i915#3558]) -> [PASS][83] +3 similar issues
   [82]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-tglu-9/igt@kms_plane@plane-position-hole-dpms@pipe-a-planes.html
   [83]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-tglu-3/igt@kms_plane@plane-position-hole-dpms@pipe-a-planes.html

  * igt@kms_psr@sprite_plane_onoff:
    - {shard-rkl}:        [SKIP][84] ([i915#1072]) -> [PASS][85] +2 similar issues
   [84]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-4/igt@kms_psr@sprite_plane_onoff.html
   [85]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-6/igt@kms_psr@sprite_plane_onoff.html

  * igt@kms_rotation_crc@primary-rotation-90:
    - {shard-rkl}:        [SKIP][86] ([i915#1845] / [i915#4098]) -> [PASS][87] +33 similar issues
   [86]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-3/igt@kms_rotation_crc@primary-rotation-90.html
   [87]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-6/igt@kms_rotation_crc@primary-rotation-90.html

  * igt@kms_universal_plane@disable-primary-vs-flip-pipe-a:
    - {shard-tglu}:       [SKIP][88] ([fdo#109274]) -> [PASS][89] +3 similar issues
   [88]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-tglu-10/igt@kms_universal_plane@disable-primary-vs-flip-pipe-a.html
   [89]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-tglu-4/igt@kms_universal_plane@disable-primary-vs-flip-pipe-a.html

  * igt@perf@polling-small-buf:
    - {shard-tglu}:       [FAIL][90] ([i915#1722]) -> [PASS][91]
   [90]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-tglu-9/igt@perf@polling-small-buf.html
   [91]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-tglu-7/igt@perf@polling-small-buf.html

  * igt@perf_pmu@idle@rcs0:
    - {shard-rkl}:        [FAIL][92] ([i915#4349]) -> [PASS][93]
   [92]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-6/igt@perf_pmu@idle@rcs0.html
   [93]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-3/igt@perf_pmu@idle@rcs0.html

  * igt@perf_pmu@module-unload:
    - shard-snb:          [ABORT][94] ([i915#4528]) -> [PASS][95]
   [94]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-snb2/igt@perf_pmu@module-unload.html
   [95]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-snb5/igt@perf_pmu@module-unload.html

  * igt@prime_self_import@basic-with_one_bo:
    - {shard-rkl}:        [SKIP][96] ([fdo#109315]) -> [PASS][97] +12 similar issues
   [96]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-5/igt@prime_self_import@basic-with_one_bo.html
   [97]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-4/igt@prime_self_import@basic-with_one_bo.html

  * igt@prime_vgem@coherency-gtt:
    - {shard-rkl}:        [SKIP][98] ([fdo#109295] / [fdo#111656] / [i915#3708]) -> [PASS][99]
   [98]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-6/igt@prime_vgem@coherency-gtt.html
   [99]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-5/igt@prime_vgem@coherency-gtt.html

  * igt@syncobj_timeline@wait-all-for-submit-delayed-submit:
    - {shard-rkl}:        [SKIP][100] ([i915#2575]) -> [PASS][101] +2 similar issues
   [100]: https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_12861/shard-rkl-5/igt@syncobj_timeline@wait-all-for-submit-delayed-submit.html
   [101]: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/shard-rkl-4/igt@syncobj_timeline@wait-all-for-submit-delayed-submit.html

  
  {name}: This element is suppressed. This means it is ignored when computing
          the status of the difference (SUCCESS, WARNING, or FAILURE).

  [fdo#103375]: https://bugs.freedesktop.org/show_bug.cgi?id=103375
  [fdo#109271]: https://bugs.freedesktop.org/show_bug.cgi?id=109271
  [fdo#109274]: https://bugs.freedesktop.org/show_bug.cgi?id=109274
  [fdo#109279]: https://bugs.freedesktop.org/show_bug.cgi?id=109279
  [fdo#109280]: https://bugs.freedesktop.org/show_bug.cgi?id=109280
  [fdo#109289]: https://bugs.freedesktop.org/show_bug.cgi?id=109289
  [fdo#109295]: https://bugs.freedesktop.org/show_bug.cgi?id=109295
  [fdo#109302]: https://bugs.freedesktop.org/show_bug.cgi?id=109302
  [fdo#109307]: https://bugs.freedesktop.org/show_bug.cgi?id=109307
  [fdo#109308]: https://bugs.freedesktop.org/show_bug.cgi?id=109308
  [fdo#109309]: https://bugs.freedesktop.org/show_bug.cgi?id=109309
  [fdo#109313]: https://bugs.freedesktop.org/show_bug.cgi?id=109313
  [fdo#109314]: https://bugs.freedesktop.org/show_bug.cgi?id=109314
  [fdo#109315]: https://bugs.freedesktop.org/show_bug.cgi?id=109315
  [fdo#109506]: https://bugs.freedesktop.org/show_bug.cgi?id=109506
  [fdo#110189]: https://bugs.freedesktop.org/show_bug.cgi?id=110189
  [fdo#110723]: https://bugs.freedesktop.org/show_bug.cgi?id=110723
  [fdo#111068]: https://bugs.freedesktop.org/show_bug.cgi?id=111068
  [fdo#111614]: https://bugs.freedesktop.org/show_bug.cgi?id=111614
  [fdo#111615]: https://bugs.freedesktop.org/show_bug.cgi?id=111615
  [fdo#111656]: https://bugs.freedesktop.org/show_bug.cgi?id=111656
  [fdo#111825]: https://bugs.freedesktop.org/show_bug.cgi?id=111825
  [fdo#111827]: https://bugs.freedesktop.org/show_bug.cgi?id=111827
  [fdo#112054]: https://bugs.freedesktop.org/show_bug.cgi?id=112054
  [fdo#112283]: https://bugs.freedesktop.org/show_bug.cgi?id=112283
  [i915#1072]: https://gitlab.freedesktop.org/drm/intel/issues/1072
  [i915#1257]: https://gitlab.freedesktop.org/drm/intel/issues/1257
  [i915#132]: https://gitlab.freedesktop.org/drm/intel/issues/132
  [i915#1397]: https://gitlab.freedesktop.org/drm/intel/issues/1397
  [i915#1722]: https://gitlab.freedesktop.org/drm/intel/issues/1722
  [i915#1769]: https://gitlab.freedesktop.org/drm/intel/issues/1769
  [i915#1825]: https://gitlab.freedesktop.org/drm/intel/issues/1825
  [i915#1839]: https://gitlab.freedesktop.org/drm/intel/issues/1839
  [i915#1845]: https://gitlab.freedesktop.org/drm/intel/issues/1845
  [i915#1849]: https://gitlab.freedesktop.org/drm/intel/issues/1849
  [i915#1937]: https://gitlab.freedesktop.org/drm/intel/issues/1937
  [i915#2346]: https://gitlab.freedesktop.org/drm/intel/issues/2346
  [i915#2433]: https://gitlab.freedesktop.org/drm/intel/issues/2433
  [i915#2437]: https://gitlab.freedesktop.org/drm/intel/issues/2437
  [i915#2527]: https://gitlab.freedesktop.org/drm/intel/issues/2527
  [i915#2532]: https://gitlab.freedesktop.org/drm/intel/issues/2532
  [i915#2575]: https://gitlab.freedesktop.org/drm/intel/issues/2575
  [i915#2582]: https://gitlab.freedesktop.org/drm/intel/issues/2582
  [i915#2587]: https://gitlab.freedesktop.org/drm/intel/issues/2587
  [i915#2672]: https://gitlab.freedesktop.org/drm/intel/issues/2672
  [i915#2705]: https://gitlab.freedesktop.org/drm/intel/issues/2705
  [i915#280]: https://gitlab.freedesktop.org/drm/intel/issues/280
  [i915#284]: https://gitlab.freedesktop.org/drm/intel/issues/284
  [i915#2842]: https://gitlab.freedesktop.org/drm/intel/issues/2842
  [i915#2846]: https://gitlab.freedesktop.org/drm/intel/issues/2846
  [i915#2920]: https://gitlab.freedesktop.org/drm/intel/issues/2920
  [i915#3116]: https://gitlab.freedesktop.org/drm/intel/issues/3116
  [i915#3281]: https://gitlab.freedesktop.org/drm/intel/issues/3281
  [i915#3282]: https://gitlab.freedesktop.org/drm/intel/issues/3282
  [i915#3297]: https://gitlab.freedesktop.org/drm/intel/issues/3297
  [i915#3299]: https://gitlab.freedesktop.org/drm/intel/issues/3299
  [i915#3359]: https://gitlab.freedesktop.org/drm/intel/issues/3359
  [i915#3361]: https://gitlab.freedesktop.org/drm/intel/issues/3361
  [i915#3458]: https://gitlab.freedesktop.org/drm/intel/issues/3458
  [i915#3536]: https://gitlab.freedesktop.org/drm/intel/issues/3536
  [i915#3539]: https://gitlab.freedesktop.org/drm/intel/issues/3539
  [i915#3546]: https://gitlab.freedesktop.org/drm/intel/issues/3546
  [i915#3555]: https://gitlab.freedesktop.org/drm/intel/issues/3555
  [i915#3558]: https://gitlab.freedesktop.org/drm/intel/issues/3558
  [i915#3591]: https://gitlab.freedesktop.org/drm/intel/issues/3591
  [i915#3637]: https://gitlab.freedesktop.org/drm/intel/issues/3637
  [i915#3638]: https://gitlab.freedesktop.org/drm/intel/issues/3638
  [i915#3639]: https://gitlab.freedesktop.org/drm/intel/issues/3639
  [i915#3689]: https://gitlab.freedesktop.org/drm/intel/issues/3689
  [i915#3708]: https://gitlab.freedesktop.org/drm/intel/issues/3708
  [i915#3734]: https://gitlab.freedesktop.org/drm/intel/issues/3734
  [i915#3742]: https://gitlab.freedesktop.org/drm/intel/issues/3742
  [i915#3804]: https://gitlab.freedesktop.org/drm/intel/issues/3804
  [i915#3840]: https://gitlab.freedesktop.org/drm/intel/issues/3840
  [i915#3886]: https://gitlab.freedesktop.org/drm/intel/issues/3886
  [i915#3936]: https://gitlab.freedesktop.org/drm/intel/issues/3936
  [i915#3952]: https://gitlab.freedesktop.org/drm/intel/issues/3952
  [i915#3955]: https://gitlab.freedesktop.org/drm/intel/issues/3955
  [i915#4070]: https://gitlab.freedesktop.org/drm/intel/issues/4070
  [i915#4077]: https://gitlab.freedesktop.org/drm/intel/issues/4077
  [i915#4078]: https://gitlab.freedesktop.org/drm/intel/issues/4078
  [i915#4079]: https://gitlab.freedesktop.org/drm/intel/issues/4079
  [i915#4083]: https://gitlab.freedesktop.org/drm/intel/issues/4083
  [i915#4098]: https://gitlab.freedesktop.org/drm/intel/issues/4098
  [i915#4103]: https://gitlab.freedesktop.org/drm/intel/issues/4103
  [i915#4212]: https://gitlab.freedesktop.org/drm/intel/issues/4212
  [i915#4213]: https://gitlab.freedesktop.org/drm/intel/issues/4213
  [i915#4270]: https://gitlab.freedesktop.org/drm/intel/issues/4270
  [i915#4275]: https://gitlab.freedesktop.org/drm/intel/issues/4275
  [i915#4349]: https://gitlab.freedesktop.org/drm/intel/issues/4349
  [i915#4525]: https://gitlab.freedesktop.org/drm/intel/issues/4525
  [i915#4528]: https://gitlab.freedesktop.org/drm/intel/issues/4528
  [i915#4538]: https://gitlab.freedesktop.org/drm/intel/issues/4538
  [i915#4565]: https://gitlab.freedesktop.org/drm/intel/issues/4565
  [i915#4613]: https://gitlab.freedesktop.org/drm/intel/issues/4613
  [i915#4771]: https://gitlab.freedesktop.org/drm/intel/issues/4771
  [i915#4778]: https://gitlab.freedesktop.org/drm/intel/issues/4778
  [i915#4812]: https://gitlab.freedesktop.org/drm/intel/issues/4812
  [i915#4833]: https://gitlab.freedesktop.org/drm/intel/issues/4833
  [i915#4852]: https://gitlab.freedesktop.org/drm/intel/issues/4852
  [i915#4854]: https://gitlab.freedesktop.org/drm/intel/issues/4854
  [i915#4859]: https://gitlab.freedesktop.org/drm/intel/issues/4859
  [i915#4860]: https://gitlab.freedesktop.org/drm/intel/issues/4860
  [i915#4879]: https://gitlab.freedesktop.org/drm/intel/issues/4879
  [i915#4880]: https://gitlab.freedesktop.org/drm/intel/issues/4880
  [i915#4881]: https://gitlab.freedesktop.org/drm/intel/issues/4881
  [i915#4885]: https://gitlab.freedesktop.org/drm/intel/issues/4885
  [i915#5115]: https://gitlab.freedesktop.org/drm/intel/issues/5115
  [i915#5174]: https://gitlab.freedesktop.org/drm/intel/issues/5174
  [i915#5176]: https://gitlab.freedesktop.org/drm/intel/issues/5176
  [i915#5213]: https://gitlab.freedesktop.org/drm/intel/issues/5213
  [i915#5235]: https://gitlab.freedesktop.org/drm/intel/issues/5235
  [i915#5286]: https://gitlab.freedesktop.org/drm/intel/issues/5286
  [i915#5288]: https://gitlab.freedesktop.org/drm/intel/issues/5288
  [i915#5289]: https://gitlab.freedesktop.org/drm/intel/issues/5289
  [i915#5325]: https://gitlab.freedesktop.org/drm/intel/issues/5325
  [i915#533]: https://gitlab.freedesktop.org/drm/intel/issues/533
  [i915#5334]: https://gitlab.freedesktop.org/drm/intel/issues/5334
  [i915#5439]: https://gitlab.freedesktop.org/drm/intel/issues/5439
  [i915#5461]: https://gitlab.freedesktop.org/drm/intel/issues/5461
  [i915#5563]: https://gitlab.freedesktop.org/drm/intel/issues/5563
  [i915#5566]: https://gitlab.freedesktop.org/drm/intel/issues/5566
  [i915#5723]: https://gitlab.freedesktop.org/drm/intel/issues/5723
  [i915#5775]: https://gitlab.freedesktop.org/drm/intel/issues/5775
  [i915#5784]: https://gitlab.freedesktop.org/drm/intel/issues/5784
  [i915#6095]: https://gitlab.freedesktop.org/drm/intel/issues/6095
  [i915#6227]: https://gitlab.freedesktop.org/drm/intel/issues/6227
  [i915#6248]: https://gitlab.freedesktop.org/drm/intel/issues/6248
  [i915#6252]: https://gitlab.freedesktop.org/drm/intel/issues/6252
  [i915#6258]: https://gitlab.freedesktop.org/drm/intel/issues/6258
  [i915#6268]: https://gitlab.freedesktop.org/drm/intel/issues/6268
  [i915#6334]: https://gitlab.freedesktop.org/drm/intel/issues/6334
  [i915#6335]: https://gitlab.freedesktop.org/drm/intel/issues/6335
  [i915#6355]: https://gitlab.freedesktop.org/drm/intel/issues/6355
  [i915#6497]: https://gitlab.freedesktop.org/drm/intel/issues/6497
  [i915#6524]: https://gitlab.freedesktop.org/drm/intel/issues/6524
  [i915#658]: https://gitlab.freedesktop.org/drm/intel/issues/658
  [i915#6590]: https://gitlab.freedesktop.org/drm/intel/issues/6590
  [i915#6621]: https://gitlab.freedesktop.org/drm/intel/issues/6621
  [i915#6768]: https://gitlab.freedesktop.org/drm/intel/issues/6768
  [i915#6944]: https://gitlab.freedesktop.org/drm/intel/issues/6944
  [i915#6953]: https://gitlab.freedesktop.org/drm/intel/issues/6953
  [i915#7052]: https://gitlab.freedesktop.org/drm/intel/issues/7052
  [i915#7116]: https://gitlab.freedesktop.org/drm/intel/issues/7116
  [i915#7118]: https://gitlab.freedesktop.org/drm/intel/issues/7118
  [i915#7561]: https://gitlab.freedesktop.org/drm/intel/issues/7561
  [i915#7651]: https://gitlab.freedesktop.org/drm/intel/issues/7651
  [i915#7697]: https://gitlab.freedesktop.org/drm/intel/issues/7697
  [i915#7701]: https://gitlab.freedesktop.org/drm/intel/issues/7701
  [i915#7707]: https://gitlab.freedesktop.org/drm/intel/issues/7707
  [i915#7711]: https://gitlab.freedesktop.org/drm/intel/issues/7711
  [i915#7742]: https://gitlab.freedesktop.org/drm/intel/issues/7742
  [i915#7811]: https://gitlab.freedesktop.org/drm/intel/issues/7811
  [i915#7828]: https://gitlab.freedesktop.org/drm/intel/issues/7828
  [i915#79]: https://gitlab.freedesktop.org/drm/intel/issues/79
  [i915#7957]: https://gitlab.freedesktop.org/drm/intel/issues/7957
  [i915#7975]: https://gitlab.freedesktop.org/drm/intel/issues/7975
  [i915#7984]: https://gitlab.freedesktop.org/drm/intel/issues/7984
  [i915#8018]: https://gitlab.freedesktop.org/drm/intel/issues/8018
  [i915#8152]: https://gitlab.freedesktop.org/drm/intel/issues/8152
  [i915#8154]: https://gitlab.freedesktop.org/drm/intel/issues/8154
  [i915#8228]: https://gitlab.freedesktop.org/drm/intel/issues/8228
  [i915#8273]: https://gitlab.freedesktop.org/drm/intel/issues/8273
  [i915#8282]: https://gitlab.freedesktop.org/drm/intel/issues/8282


Build changes
-------------

  * CI: CI-20190529 -> None
  * IGT: IGT_7195 -> IGTPW_8608
  * Piglit: piglit_4509 -> None

  CI-20190529: 20190529
  CI_DRM_12861: a2cdd75e9e48ef31a52b0472f7a3537423a9748e @ git://anongit.freedesktop.org/gfx-ci/linux
  IGTPW_8608: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/index.html
  IGT_7195: 4976e86efa7f7657e0a175e6375508764ea58d95 @ https://gitlab.freedesktop.org/drm/igt-gpu-tools.git
  piglit_4509: fdc5a4ca11124ab8413c7988896eec4c97336694 @ git://anongit.freedesktop.org/piglit

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/IGTPW_8608/index.html

[-- Attachment #2: Type: text/html, Size: 25631 bytes --]

^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [igt-dev] [PATCH i-g-t 5/5] Change logic of ktap parser to run on a thread
  2023-03-15 12:49   ` Mauro Carvalho Chehab
@ 2023-03-24  8:11     ` Piatkowski, Dominik Karol
  0 siblings, 0 replies; 13+ messages in thread
From: Piatkowski, Dominik Karol @ 2023-03-24  8:11 UTC (permalink / raw)
  To: Mauro Carvalho Chehab; +Cc: igt-dev



> -----Original Message-----
> From: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
> Sent: Wednesday, March 15, 2023 13:49
> To: Piatkowski, Dominik Karol <dominik.karol.piatkowski@intel.com>
> Cc: igt-dev@lists.freedesktop.org; Janusz Krzysztofik
> <janusz.krzysztofik@linux.intel.com>
> Subject: Re: [PATCH i-g-t 5/5] Change logic of ktap parser to run on a thread
> 
> On Wed, 15 Mar 2023 10:40:42 +0100
> Dominik Karol Piatkowski <dominik.karol.piatkowski@intel.com> wrote:
> 
> > The ktap parser should be listening and parsing messages as the tests
> > are executed, and not after the end of module load.
> >
> > Signed-off-by: Dominik Karol Piątkowski
> > <dominik.karol.piatkowski@intel.com>
> > Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
> > Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
> > ---
> >  lib/igt_kmod.c |  12 +++--
> >  lib/igt_ktap.c | 137 +++++++++++++++++++++++++++++++------------------
> >  lib/igt_ktap.h |   3 +-
> >  3 files changed, 97 insertions(+), 55 deletions(-)
> >
> > diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c index 3b92cc94..23b92742
> > 100644
> > --- a/lib/igt_kmod.c
> > +++ b/lib/igt_kmod.c
> > @@ -758,7 +758,6 @@ int igt_kunit(const char *module_name, const char
> > *opts)  {
> >  	struct igt_ktest tst;
> >  	struct kmod_module *kunit_kmod;
> > -	char record[BUF_LEN + 1];
> >  	FILE *f;
> >  	bool is_builtin;
> >  	int ret;
> > @@ -804,19 +803,24 @@ int igt_kunit(const char *module_name, const
> > char *opts)
> >
> >  	is_builtin = kmod_module_get_initstate(kunit_kmod) ==
> > KMOD_MODULE_BUILTIN;
> >
> > +	ktap_parser_start(f, is_builtin);
> > +
> >  	if (igt_kmod_load(module_name, opts) != 0) {
> >  		igt_warn("Unable to load %s module\n", module_name);
> > +		ret = ktap_parser_stop();
> >  		igt_fail(IGT_EXIT_FAILURE);
> >  	}
> >
> > -	ret = igt_ktap_parser(f, record, is_builtin);
> > -	if (ret != 0)
> > -		ret = IGT_EXIT_ABORT;
> >  unload:
> >  	igt_ktest_end(&tst);
> >
> >  	igt_ktest_fini(&tst);
> >
> > +	ret = ktap_parser_stop();
> > +
> > +	if (ret != 0)
> > +		ret = IGT_EXIT_ABORT;
> > +
> >  	if (ret == 0)
> >  		igt_success();
> >
> > diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c index 117598fa..acbb76ba
> > 100644
> > --- a/lib/igt_ktap.c
> > +++ b/lib/igt_ktap.c
> > @@ -10,6 +10,10 @@
> >  #include "igt_core.h"
> >  #include "igt_ktap.h"
> >
> > +#include <libkmod.h>
> > +
> 
> 
> > +#include <pthread.h>
> 
> Hmm... IGT has some pthread handlers. You should use them.

I could not find them, but I found out that there are some tests in this repository that use pthread.h directly. If there is a particular handler that you suggest to use, I will happily look into that.

> 
> 
> > +
> >  static int log_to_end(enum igt_log_level level, FILE *f,
> >  		      char *record, const char *format, ...)
> > __attribute__((format(printf, 4, 5)));
> >
> > @@ -253,6 +257,13 @@ static int parse_kmsg_for_tap(FILE *fp, char
> *record, char *test_name)
> >  	return 1;
> >  }
> >
> > +struct ktap_parser_args {
> > +	FILE *fp;
> > +	bool is_builtin;
> > +	volatile bool is_running;
> > +	int ret;
> > +} ktap_args;
> > +
> >  /**
> >   * igt_ktap_parser:
> >   * @fp: FILE pointer
> > @@ -264,71 +275,97 @@ static int parse_kmsg_for_tap(FILE *fp, char
> *record, char *test_name)
> >   *
> >   * Returns: IGT default codes
> >   */
> > -int igt_ktap_parser(FILE *fp, char *record, bool is_builtin)
> > +void *igt_ktap_parser(void* unused)
> 
> Nitpick: as we use Kernel coding style, it should be:
> 
> 	void *igt_ktap_parser(void *unused)
> 
> 
> >  {
> > +	FILE *fp = ktap_args.fp;
> > +	char record[BUF_LEN + 1];
> > +	bool is_builtin = ktap_args.is_builtin;
> > +
> >  	char test_name[BUF_LEN + 1];
> >  	bool failed_tests, found_tests;
> >  	int sublevel = 0;
> >
> > -	test_name[0] = '\0';
> > -	test_name[BUF_LEN] = '\0';
> > -
> >  	failed_tests = false;
> >  	found_tests = false;
> >
> > -	while (sublevel >= 0) {
> > -		if (fgets(record, BUF_LEN, fp) == NULL) {
> > -			if (!found_tests)
> > -				igt_warn("kmsg truncated: unknown error
> (%m)\n");
> > -			break;
> > +igt_ktap_parser_start:
> > +	while (ktap_args.is_running) {
> > +		test_name[0] = '\0';
> > +		test_name[BUF_LEN] = '\0';
> > +
> > +		while (fgets(record, BUF_LEN, fp) != NULL) {
> > +			if (!ktap_args.is_running)
> > +				return NULL;
> > +			usleep(1000);
> >  		}
> 
> Please don't add sleep, as it might lose messages on crashes.
> 
> You should probably check ferror() and/or  feof() if it returns NULL, as it can
> indicate either:
> 
> 	- that modprobe ended - so, feof() would be nonzero;
> 	- some error happened - so, ferror() would be nonzero.
> 	  On such case, it should likely print the error.
> 
> Also, don't call usleep(). If fp was opened on sync mode (usually the default),
> usleep is not needed at all, as fgets() will block until an error or read.
> 
> Otherwise, if fp is in async mode, you can switch to sync mode with:
> 
> 	s = fcntl(*fd, F_GETFL);
> 	s |= O_SYNC;
> 	result = fcntl(*fd, F_SETFL, s);
> 
> and avoid the usleep().
> 
> Btw, you probably need to add error check logic too. Maybe, you could do
> something like (untested):
> 
> 	while (!feof(record)) {
> 		if (fgets(record, BUF_LEN, fp) == NULL) {
> 			if (ferror(record))
> 				igt_warn("klog read failed: %s\n",
> strerror(errno));
> 
> 			if (!ktap_args.is_running)
> 				return NULL;
>   		}
> 
> here and the calls to fgets() below.
> 
> > -		switch (find_next_tap_subtest(fp, record, is_builtin)) {
> > -		case -2:
> > -			/* no more data to read */
> > -			return IGT_EXIT_FAILURE;
> > -		case -1:
> > -			/* no test found, so we keep parsing */
> > -			break;
> > -		case 0:
> > -			/*
> > -			 * tests found, but they're missing info, so we might
> > -			 * have read into test output
> > -			 */
> > -			found_tests = true;
> > -			sublevel++;
> > -			break;
> > -		default:
> > -			if (fgets(record, BUF_LEN, fp) == NULL) {
> > -				igt_warn("kmsg truncated: unknown error
> (%m)\n");
> > -				return -2;
> > +		while (sublevel >= 0) {
> > +			switch (find_next_tap_subtest(fp, record, is_builtin))
> {
> > +			case -2:
> > +				/* no more data to read */
> > +				goto igt_ktap_parser_start;
> > +			case -1:
> > +				/* no test found, so we keep parsing */
> > +				break;
> > +			case 0:
> > +				/*
> > +				 * tests found, but they're missing info, so we
> might
> > +				 * have read into test output
> > +				 */
> > +				found_tests = true;
> > +				sublevel++;
> > +				break;
> > +			default:
> > +				if (fgets(record, BUF_LEN, fp) == NULL) {
> > +					igt_warn("kmsg truncated: unknown
> error (%m)\n");
> > +					goto igt_ktap_parser_start;
> > +				}
> > +				found_tests = true;
> > +				sublevel++;
> > +				break;
> >  			}
> > -			found_tests = true;
> > -			sublevel++;
> > -			break;
> > -		}
> >
> > -		switch (parse_kmsg_for_tap(fp, record, test_name)) {
> > -		case -2:
> > -			return IGT_EXIT_FAILURE;
> > -		case -1:
> > -			sublevel--;
> > -			failed_tests = true;
> > -			igt_subtest(test_name)
> > -				igt_fail(IGT_EXIT_FAILURE);
> > -			test_name[0] = '\0';
> > -			break;
> > -		case 0: /* fallthrough */
> > -			igt_subtest(test_name)
> > -				igt_success();
> > -			test_name[0] = '\0';
> > -		default:
> > -			break;
> > +			switch (parse_kmsg_for_tap(fp, record, test_name))
> {
> > +			case -2:
> > +				goto igt_ktap_parser_start;
> > +			case -1:
> > +				sublevel--;
> > +				failed_tests = true;
> > +				igt_subtest(test_name)
> > +					igt_fail(IGT_EXIT_FAILURE);
> > +				test_name[0] = '\0';
> > +				break;
> > +			case 0: /* fallthrough */
> > +				igt_subtest(test_name)
> > +					igt_success();
> > +				test_name[0] = '\0';
> > +			default:
> > +				break;
> > +			}
> >  		}
> >  	}
> >
> >  	if (failed_tests || !found_tests)
> > -		return IGT_EXIT_FAILURE;
> > +		ktap_args.ret = IGT_EXIT_FAILURE;
> > +	else
> > +		ktap_args.ret = IGT_EXIT_SUCCESS;
> > +
> > +	return NULL;
> > +}
> > +
> > +static pthread_t ktap_parser_thread;
> >
> > -	return IGT_EXIT_SUCCESS;
> > +void ktap_parser_start(FILE *fp, bool is_builtin) {
> > +	ktap_args.fp = fp;
> > +	ktap_args.is_builtin = is_builtin;
> > +	ktap_args.is_running = true;
> > +	pthread_create(&ktap_parser_thread, NULL, igt_ktap_parser,
> NULL); }
> > +
> > +int ktap_parser_stop(void)
> > +{
> > +	ktap_args.is_running = false;
> > +	pthread_join(ktap_parser_thread, NULL);
> > +	return ktap_args.ret;
> >  }
> > diff --git a/lib/igt_ktap.h b/lib/igt_ktap.h index b2f69df2..461df6f5
> > 100644
> > --- a/lib/igt_ktap.h
> > +++ b/lib/igt_ktap.h
> > @@ -26,6 +26,7 @@
> >
> >  #define BUF_LEN 4096
> >
> > -int igt_ktap_parser(FILE *fp, char *record, bool is_builtin);
> > +void ktap_parser_start(FILE *fp, bool is_builtin); int
> > +ktap_parser_stop(void);
> >
> >  #endif /* IGT_KTAP_H */

^ permalink raw reply	[flat|nested] 13+ messages in thread

* [igt-dev] [PATCH i-g-t 3/5] lib/igt_kmod: add compatibility for KUnit
  2023-03-24  8:11 [igt-dev] [PATCH v3 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
@ 2023-03-24  8:11 ` Dominik Karol Piatkowski
  0 siblings, 0 replies; 13+ messages in thread
From: Dominik Karol Piatkowski @ 2023-03-24  8:11 UTC (permalink / raw)
  To: igt-dev; +Cc: Isabella Basso

From: Isabella Basso <isabbasso@riseup.net>

This adds functions for both executing the tests as well as parsing (K)TAP
kmsg output, as per the KTAP spec [1].

[1] https://www.kernel.org/doc/html/latest/dev-tools/ktap.html

v1 -> v2:
- refactor igt_kunit function and ktap parser so that we have only one
  parser that we call only once (code size is now less than half the
  size as v1)
- add lookup_value helper
- fix parsing problems
v2 -> v3:
- move ktap parsing functions to own file
- rename to ktap_parser
- get rid of unneeded pointers in igt_kunit
- change return values to allow for subsequent call to igt_kselftests if
  needed
- add docs to parsing functions and helpers
- switch to line buffering
- add line buffering logging helper
- fix kunit module handling
- fix parsing of version lines
- use igt_subtest blocks to improve output handling on the CI
- fix output handling during crashes

Signed-off-by: Isabella Basso <isabbasso@riseup.net>

v3 -> v4:
- handle igt_ktap_parser fail with IGT_EXIT_ABORT code

v4 -> v5:
- added missing newlines in igt_warn
- removed setvbuf

Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
---
 lib/igt_kmod.c  |  79 ++++++++++++
 lib/igt_kmod.h  |   2 +
 lib/igt_ktap.c  | 334 ++++++++++++++++++++++++++++++++++++++++++++++++
 lib/igt_ktap.h  |  31 +++++
 lib/meson.build |   1 +
 5 files changed, 447 insertions(+)
 create mode 100644 lib/igt_ktap.c
 create mode 100644 lib/igt_ktap.h

diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 26d58e29..21e801bd 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -29,6 +29,7 @@
 #include "igt_aux.h"
 #include "igt_core.h"
 #include "igt_kmod.h"
+#include "igt_ktap.h"
 #include "igt_sysfs.h"
 #include "igt_taints.h"
 
@@ -744,6 +745,84 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
 	kmod_module_info_free_list(pre);
 }
 
+/**
+ * igt_kunit:
+ * @module_name: the name of the module
+ * @opts: options to load the module
+ *
+ * Loads the test module, parses its (k)tap dmesg output, then unloads it
+ *
+ * Returns: IGT default codes
+ */
+int igt_kunit(const char *module_name, const char *opts)
+{
+	struct igt_ktest tst;
+	struct kmod_module *kunit_kmod;
+	char record[BUF_LEN + 1];
+	FILE *f;
+	bool is_builtin;
+	int ret;
+
+	ret = IGT_EXIT_INVALID;
+
+	/* get normalized module name */
+	if (igt_ktest_init(&tst, module_name) != 0) {
+		igt_warn("Unable to initialize ktest for %s\n", module_name);
+		return ret;
+	}
+
+	if (igt_ktest_begin(&tst) != 0) {
+		igt_warn("Unable to begin ktest for %s\n", module_name);
+
+		igt_ktest_fini(&tst);
+		return ret;
+	}
+
+	if (tst.kmsg < 0) {
+		igt_warn("Could not open /dev/kmsg\n");
+		goto unload;
+	}
+
+	if (lseek(tst.kmsg, 0, SEEK_END)) {
+		igt_warn("Could not seek the end of /dev/kmsg\n");
+		goto unload;
+	}
+
+	f = fdopen(tst.kmsg, "r");
+
+	if (f == NULL) {
+		igt_warn("Could not turn /dev/kmsg file descriptor into a FILE pointer\n");
+		goto unload;
+	}
+
+	/* The KUnit module is required for running any KUnit tests */
+	if (igt_kmod_load("kunit", NULL) != 0 ||
+	    kmod_module_new_from_name(kmod_ctx(), "kunit", &kunit_kmod) != 0) {
+		igt_warn("Unable to load KUnit\n");
+		igt_fail(IGT_EXIT_FAILURE);
+	}
+
+	is_builtin = kmod_module_get_initstate(kunit_kmod) == KMOD_MODULE_BUILTIN;
+
+	if (igt_kmod_load(module_name, opts) != 0) {
+		igt_warn("Unable to load %s module\n", module_name);
+		igt_fail(IGT_EXIT_FAILURE);
+	}
+
+	ret = igt_ktap_parser(f, record, is_builtin);
+	if (ret != 0)
+		ret = IGT_EXIT_ABORT;
+unload:
+	igt_ktest_end(&tst);
+
+	igt_ktest_fini(&tst);
+
+	if (ret == 0)
+		igt_success();
+
+	return ret;
+}
+
 static int open_parameters(const char *module_name)
 {
 	char path[256];
diff --git a/lib/igt_kmod.h b/lib/igt_kmod.h
index ff59f1ec..ce17c714 100644
--- a/lib/igt_kmod.h
+++ b/lib/igt_kmod.h
@@ -71,6 +71,8 @@ static inline int igt_xe_driver_unload(void)
 int igt_amdgpu_driver_load(const char *opts);
 int igt_amdgpu_driver_unload(void);
 
+int igt_kunit(const char *module_name, const char *opts);
+
 void igt_kselftests(const char *module_name,
 		    const char *module_options,
 		    const char *result_option,
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
new file mode 100644
index 00000000..117598fa
--- /dev/null
+++ b/lib/igt_ktap.c
@@ -0,0 +1,334 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2023 Isabella Basso do Amaral <isabbasso@riseup.net>
+ */
+
+#include <ctype.h>
+#include <limits.h>
+
+#include "igt_aux.h"
+#include "igt_core.h"
+#include "igt_ktap.h"
+
+static int log_to_end(enum igt_log_level level, FILE *f,
+		      char *record, const char *format, ...) __attribute__((format(printf, 4, 5)));
+
+/**
+ * log_to_end:
+ * @level: #igt_log_level
+ * @record: record to store the read data
+ * @format: format string
+ * @...: optional arguments used in the format string
+ *
+ * This is an altered version of the generic structured logging helper function
+ * igt_log capable of reading to the end of a given line.
+ *
+ * Returns: 0 for success, or -2 if there's an error reading from the file
+ */
+static int log_to_end(enum igt_log_level level, FILE *f,
+		      char *record, const char *format, ...)
+{
+	va_list args;
+	const char *lend;
+
+	va_start(args, format);
+	igt_vlog(IGT_LOG_DOMAIN, level, format, args);
+	va_end(args);
+
+	lend = strchrnul(record, '\n');
+	while (*lend == '\0') {
+		igt_log(IGT_LOG_DOMAIN, level, "%s", record);
+		if (fgets(record, BUF_LEN, f) == NULL) {
+			igt_warn("kmsg truncated: unknown error (%m)\n");
+			return -2;
+		}
+		lend = strchrnul(record, '\n');
+	}
+	return 0;
+}
+
+/**
+ * lookup_value:
+ * @haystack: the string to search in
+ * @needle: the string to search for
+ *
+ * Returns: the value of the needle in the haystack, or -1 if not found.
+ */
+static long lookup_value(const char *haystack, const char *needle)
+{
+	const char *needle_rptr;
+	char *needle_end;
+	long num;
+
+	needle_rptr = strcasestr(haystack, needle);
+
+	if (needle_rptr == NULL)
+		return -1;
+
+	/* skip search string and whitespaces after it */
+	needle_rptr += strlen(needle);
+
+	num = strtol(needle_rptr, &needle_end, 10);
+
+	if (needle_rptr == needle_end)
+		return -1;
+
+	if (num == LONG_MIN || num == LONG_MAX)
+		return 0;
+
+	return num > 0 ? num : 0;
+}
+
+/**
+ * find_next_tap_subtest:
+ * @fp: FILE pointer
+ * @record: buffer used to read fp
+ * @is_builtin: whether KUnit is built-in or not
+ *
+ * Returns:
+ * 0 if there's missing information
+ * -1 if not found
+ * -2 if there are problems while reading the file.
+ * any other value corresponds to the amount of cases of the next (sub)test
+ */
+static int find_next_tap_subtest(FILE *fp, char *record, bool is_builtin)
+{
+	const char *test_lookup_str, *subtest_lookup_str, *name_rptr, *version_rptr;
+	char test_name[BUF_LEN + 1];
+	long test_count;
+
+	test_name[0] = '\0';
+	test_name[BUF_LEN] = '\0';
+
+	test_lookup_str = " subtest: ";
+	subtest_lookup_str = " test: ";
+
+	/*
+	 * "(K)TAP version XX" should be the first line on all (sub)tests as per
+	 * https://kernel.org/doc/html/latest/dev-tools/ktap.html#version-lines
+	 *
+	 * but actually isn't, as it currently depends on the KUnit module
+	 * being built-in, so we can't rely on it every time
+	 */
+	if (is_builtin) {
+		version_rptr = strcasestr(record, "TAP version ");
+		if (version_rptr == NULL)
+			return -1;
+
+		igt_info("%s", version_rptr);
+
+		if (fgets(record, BUF_LEN, fp) == NULL) {
+			igt_warn("kmsg truncated: unknown error (%m)\n");
+			return -2;
+		}
+	}
+
+	name_rptr = strcasestr(record, test_lookup_str);
+	if (name_rptr != NULL) {
+		name_rptr += strlen(test_lookup_str);
+	} else {
+		name_rptr = strcasestr(record, subtest_lookup_str);
+		if (name_rptr != NULL)
+			name_rptr += strlen(subtest_lookup_str);
+	}
+
+	if (name_rptr == NULL) {
+		if (!is_builtin)
+			/* we've probably found nothing */
+			return -1;
+		igt_info("Missing test name\n");
+	} else {
+		strncpy(test_name, name_rptr, BUF_LEN);
+		if (fgets(record, BUF_LEN, fp) == NULL) {
+			igt_warn("kmsg truncated: unknown error (%m)\n");
+			return -2;
+		}
+		/* now we can be sure we found tests */
+		if (!is_builtin)
+			igt_info("KUnit is not built-in, skipping version check...\n");
+	}
+
+	/*
+	 * total test count will almost always appear as 0..N at the beginning
+	 * of a run, so we use it to reliably identify a new run
+	 */
+	test_count = lookup_value(record, "..");
+
+	if (test_count <= 0) {
+		igt_info("Missing test count\n");
+		if (test_name[0] == '\0')
+			return 0;
+		if (log_to_end(IGT_LOG_INFO, fp, record,
+				"Running some tests in: %s",
+				test_name) < 0)
+			return -2;
+		return 0;
+	} else if (test_name[0] == '\0') {
+		igt_info("Running %ld tests...\n", test_count);
+		return 0;
+	}
+
+	if (log_to_end(IGT_LOG_INFO, fp, record,
+			"Executing %ld tests in: %s",
+			test_count, test_name) < 0)
+		return -2;
+
+	return test_count;
+}
+
+/**
+ * find_next_tap_test:
+ * @fp: FILE pointer
+ * @record: buffer used to read fp
+ * @test_name: buffer to store the test name
+ *
+ * Returns:
+ * 1 if no results were found
+ * 0 if a test succeded
+ * -1 if a test failed
+ * -2 if there are problems reading the file
+ */
+static int parse_kmsg_for_tap(FILE *fp, char *record, char *test_name)
+{
+	const char *lstart, *ok_lookup_str, *nok_lookup_str,
+	      *ok_rptr, *nok_rptr, *comment_start, *value_parse_start;
+	char *test_name_end;
+
+	ok_lookup_str = "ok ";
+	nok_lookup_str = "not ok ";
+
+	lstart = strchrnul(record, ';');
+
+	if (*lstart == '\0') {
+		igt_warn("kmsg truncated: output malformed (%m)\n");
+		return -2;
+	}
+
+	lstart++;
+	while (isspace(*lstart))
+		lstart++;
+
+	nok_rptr = strstr(lstart, nok_lookup_str);
+	if (nok_rptr != NULL) {
+		nok_rptr += strlen(nok_lookup_str);
+		while (isdigit(*nok_rptr) || isspace(*nok_rptr) || *nok_rptr == '-')
+			nok_rptr++;
+		test_name_end = strncpy(test_name, nok_rptr, BUF_LEN);
+		while (!isspace(*test_name_end))
+			test_name_end++;
+		*test_name_end = '\0';
+		if (log_to_end(IGT_LOG_WARN, fp, record,
+			       "%s", lstart) < 0)
+			return -2;
+		return -1;
+	}
+
+	comment_start = strchrnul(lstart, '#');
+
+	/* check if we're still in a subtest */
+	if (*comment_start != '\0') {
+		comment_start++;
+		value_parse_start = comment_start;
+
+		if (lookup_value(value_parse_start, "fail: ") > 0) {
+			if (log_to_end(IGT_LOG_WARN, fp, record,
+				       "%s", lstart) < 0)
+				return -2;
+			return -1;
+		}
+	}
+
+	ok_rptr = strstr(lstart, ok_lookup_str);
+	if (ok_rptr != NULL) {
+		ok_rptr += strlen(ok_lookup_str);
+		while (isdigit(*ok_rptr) || isspace(*ok_rptr) || *ok_rptr == '-')
+			ok_rptr++;
+		test_name_end = strncpy(test_name, ok_rptr, BUF_LEN);
+		while (!isspace(*test_name_end))
+			test_name_end++;
+		*test_name_end = '\0';
+		return 0;
+	}
+
+	return 1;
+}
+
+/**
+ * igt_ktap_parser:
+ * @fp: FILE pointer
+ * @record: buffer used to read fp
+ * @is_builtin: whether the KUnit module is built-in or not
+ *
+ * This function parses the output of a ktap script and prints the test results,
+ * as well as any other output to stdout.
+ *
+ * Returns: IGT default codes
+ */
+int igt_ktap_parser(FILE *fp, char *record, bool is_builtin)
+{
+	char test_name[BUF_LEN + 1];
+	bool failed_tests, found_tests;
+	int sublevel = 0;
+
+	test_name[0] = '\0';
+	test_name[BUF_LEN] = '\0';
+
+	failed_tests = false;
+	found_tests = false;
+
+	while (sublevel >= 0) {
+		if (fgets(record, BUF_LEN, fp) == NULL) {
+			if (!found_tests)
+				igt_warn("kmsg truncated: unknown error (%m)\n");
+			break;
+		}
+
+		switch (find_next_tap_subtest(fp, record, is_builtin)) {
+		case -2:
+			/* no more data to read */
+			return IGT_EXIT_FAILURE;
+		case -1:
+			/* no test found, so we keep parsing */
+			break;
+		case 0:
+			/*
+			 * tests found, but they're missing info, so we might
+			 * have read into test output
+			 */
+			found_tests = true;
+			sublevel++;
+			break;
+		default:
+			if (fgets(record, BUF_LEN, fp) == NULL) {
+				igt_warn("kmsg truncated: unknown error (%m)\n");
+				return -2;
+			}
+			found_tests = true;
+			sublevel++;
+			break;
+		}
+
+		switch (parse_kmsg_for_tap(fp, record, test_name)) {
+		case -2:
+			return IGT_EXIT_FAILURE;
+		case -1:
+			sublevel--;
+			failed_tests = true;
+			igt_subtest(test_name)
+				igt_fail(IGT_EXIT_FAILURE);
+			test_name[0] = '\0';
+			break;
+		case 0: /* fallthrough */
+			igt_subtest(test_name)
+				igt_success();
+			test_name[0] = '\0';
+		default:
+			break;
+		}
+	}
+
+	if (failed_tests || !found_tests)
+		return IGT_EXIT_FAILURE;
+
+	return IGT_EXIT_SUCCESS;
+}
diff --git a/lib/igt_ktap.h b/lib/igt_ktap.h
new file mode 100644
index 00000000..b2f69df2
--- /dev/null
+++ b/lib/igt_ktap.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2022 Isabella Basso do Amaral <isabbasso@riseup.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef IGT_KTAP_H
+#define IGT_KTAP_H
+
+#define BUF_LEN 4096
+
+int igt_ktap_parser(FILE *fp, char *record, bool is_builtin);
+
+#endif /* IGT_KTAP_H */
diff --git a/lib/meson.build b/lib/meson.build
index 768ce90b..45b9626a 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -87,6 +87,7 @@ lib_sources = [
 	'igt_store.c',
 	'uwildmat/uwildmat.c',
 	'igt_kmod.c',
+	'igt_ktap.c',
 	'igt_panfrost.c',
 	'igt_v3d.c',
 	'igt_vc4.c',
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2023-03-24  8:11 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-15  9:40 [igt-dev] [PATCH v2 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 1/5] lib/igt_kmod: rename kselftest functions to ktest Dominik Karol Piatkowski
2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 2/5] lib/igt_kmod.c: check if module is builtin before attempting to unload it Dominik Karol Piatkowski
2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 3/5] lib/igt_kmod: add compatibility for KUnit Dominik Karol Piatkowski
2023-03-15 13:07   ` Janusz Krzysztofik
2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 4/5] tests: DRM selftests: switch to KUnit Dominik Karol Piatkowski
2023-03-15  9:40 ` [igt-dev] [PATCH i-g-t 5/5] Change logic of ktap parser to run on a thread Dominik Karol Piatkowski
2023-03-15 12:49   ` Mauro Carvalho Chehab
2023-03-24  8:11     ` Piatkowski, Dominik Karol
2023-03-15 10:02 ` [igt-dev] ✗ GitLab.Pipeline: warning for Introduce KUnit (rev2) Patchwork
2023-03-15 10:17 ` [igt-dev] ✓ Fi.CI.BAT: success " Patchwork
2023-03-16  0:29 ` [igt-dev] ✓ Fi.CI.IGT: " Patchwork
2023-03-24  8:11 [igt-dev] [PATCH v3 i-g-t 0/5] Introduce KUnit Dominik Karol Piatkowski
2023-03-24  8:11 ` [igt-dev] [PATCH i-g-t 3/5] lib/igt_kmod: add compatibility for KUnit Dominik Karol Piatkowski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.