* [igt-dev] [PATCH i-g-t 01/10] lib/igt_kmod: rename kselftest functions to ktest
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
@ 2023-06-14 10:58 ` Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 02/10] lib/igt_kmod.c: check if module is builtin before attempting to unload it Dominik Karol Piatkowski
` (9 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Dominik Karol Piatkowski @ 2023-06-14 10:58 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>
Reviewed-by: Mauro Carvalho Chehab <mchehab@kernel.org>
---
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 ccf0063ca..93fa20067 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 d05af4a69..ff59f1ec1 100644
--- a/lib/igt_kmod.h
+++ b/lib/igt_kmod.h
@@ -76,7 +76,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;
@@ -89,19 +89,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] 14+ messages in thread* [igt-dev] [PATCH i-g-t 02/10] lib/igt_kmod.c: check if module is builtin before attempting to unload it
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 01/10] lib/igt_kmod: rename kselftest functions to ktest Dominik Karol Piatkowski
@ 2023-06-14 10:58 ` Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 03/10] lib/igt_kmod: add compatibility for KUnit Dominik Karol Piatkowski
` (8 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Dominik Karol Piatkowski @ 2023-06-14 10:58 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>
Acked-by: Mauro Carvalho Chehab <mchehab@kernel.org>
---
lib/igt_kmod.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 93fa20067..26d58e293 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] 14+ messages in thread* [igt-dev] [PATCH i-g-t 03/10] lib/igt_kmod: add compatibility for KUnit
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 01/10] lib/igt_kmod: rename kselftest functions to ktest Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 02/10] lib/igt_kmod.c: check if module is builtin before attempting to unload it Dominik Karol Piatkowski
@ 2023-06-14 10:58 ` Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 04/10] tests: DRM selftests: switch to KUnit Dominik Karol Piatkowski
` (7 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Dominik Karol Piatkowski @ 2023-06-14 10:58 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>
Acked-by: Mauro Carvalho Chehab <mchehab@kernel.org>
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 26d58e293..21e801bde 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 ff59f1ec1..ce17c714e 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 000000000..117598faa
--- /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 000000000..b2f69df2d
--- /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 ad5d999d9..8e9977083 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -88,6 +88,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] 14+ messages in thread* [igt-dev] [PATCH i-g-t 04/10] tests: DRM selftests: switch to KUnit
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
` (2 preceding siblings ...)
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 03/10] lib/igt_kmod: add compatibility for KUnit Dominik Karol Piatkowski
@ 2023-06-14 10:58 ` Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 05/10] Change logic of ktap parser to run on a thread Dominik Karol Piatkowski
` (6 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Dominik Karol Piatkowski @ 2023-06-14 10:58 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>
Acked-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Mauro Carvalho Chehab <mauro.chehab@linux.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 06876e0cd..3261f0d61 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 0bce7139d..88f76a57c 100644
--- a/tests/drm_mm.c
+++ b/tests/drm_mm.c
@@ -156,5 +156,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 abc4bfe98..b27f60fb3 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] 14+ messages in thread* [igt-dev] [PATCH i-g-t 05/10] Change logic of ktap parser to run on a thread
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
` (3 preceding siblings ...)
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 04/10] tests: DRM selftests: switch to KUnit Dominik Karol Piatkowski
@ 2023-06-14 10:58 ` Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 06/10] kunit tests: add an optional name for the selftests Dominik Karol Piatkowski
` (5 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Dominik Karol Piatkowski @ 2023-06-14 10:58 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.
v1 -> v2:
- fix coding style
- remove usleep
- add error check logic
- follow the structure of igt_kselftests more closely
v2 -> v3:
- fixed sublevel issues by rewriting tap parser flow
v3 -> v4:
- fixed delimiter
- squashed lib/igt_kmod: fix nesting igt_fixture in igt_subtest
Fix the following issue:
$ ./build/tests/drm_buddy
Starting subtest: all-tests
nesting igt_fixture in igt_subtest is invalid
please refer to lib/igt_core documentation
- squashed lib/igt_kmod: place KUnit tests on a subtest
There's a hidden bug at KUnit implementation: as it doesn't
place tests inside a subtest, trying to use it with igt_main
causes a crash:
$ ./build/tests/drm_mm --list
skipping is allowed only in fixtures, subtests or igt_simple_main
please refer to lib/igt_core documentation
drm_mm: ../lib/igt_core.c:437: internal_assert: Assertion `0' failed.
Received signal SIGABRT.
Stack trace:
#0 [fatal_sig_handler+0x17b]
#1 [__sigaction+0x50]
#2 [__pthread_kill_implementation+0x114]
#3 [gsignal+0x1e]
#4 [abort+0xdf]
#5 [__assert_fail_base.cold+0xe]
#6 [__assert_fail+0x47]
#7 [internal_assert+0xe5]
#8 [igt_skip+0x169]
#9 [__igt_skip_check+0x1bb]
#10 [igt_ktest_begin+0xa6]
#11 [igt_kunit+0x70]
#12 [main+0x2a]
#13 [__libc_start_call_main+0x7a]
#14 [__libc_start_main+0x8b]
#15 [_start+0x25]
Fix it by using igt_subtests() before actually implememnting
KUnit logic.
After the patch, it should now report subtests:
$ ./build/tests/drm_mm --list
all-tests
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Acked-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
---
lib/igt_kmod.c | 51 +++++-
lib/igt_ktap.c | 431 ++++++++++++++++++++++++++++++++++++++++---------
lib/igt_ktap.h | 21 ++-
3 files changed, 421 insertions(+), 82 deletions(-)
diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 21e801bde..73478f75e 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -754,14 +754,15 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
*
* Returns: IGT default codes
*/
-int igt_kunit(const char *module_name, const char *opts)
+static 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;
+ struct ktap_test_results *results;
+ struct ktap_test_results_element *temp;
ret = IGT_EXIT_INVALID;
@@ -804,25 +805,63 @@ int igt_kunit(const char *module_name, const char *opts)
is_builtin = kmod_module_get_initstate(kunit_kmod) == KMOD_MODULE_BUILTIN;
+ results = 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;
+ while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != NULL)
+ {
+ if (READ_ONCE(results->head) != NULL) {
+ pthread_mutex_lock(&results->mutex);
+
+ igt_dynamic(results->head->test_name) {
+ if (READ_ONCE(results->head->passed))
+ igt_success();
+ else
+ igt_fail(IGT_EXIT_FAILURE);
+ }
+
+ temp = results->head;
+ results->head = results->head->next;
+ free(temp);
+
+ pthread_mutex_unlock(&results->mutex);
+ }
+ }
+
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();
-
return ret;
}
+int igt_kunit(const char *module_name, const char *opts)
+{
+ /*
+ * We need to use igt_subtest here, as otherwise it may crash with:
+ * skipping is allowed only in fixtures, subtests or igt_simple_main
+ * if used on igt_main. This is also needed in order to provide
+ * proper namespace for dynamic subtests, with is required for CI
+ * and for documentation.
+ */
+ igt_subtest_with_dynamic("all-tests")
+ return __igt_kunit(module_name, opts);
+ return 0;
+}
+
static int open_parameters(const char *module_name)
{
char path[256];
diff --git a/lib/igt_ktap.c b/lib/igt_ktap.c
index 117598faa..ecdcb8d83 100644
--- a/lib/igt_ktap.c
+++ b/lib/igt_ktap.c
@@ -5,11 +5,25 @@
#include <ctype.h>
#include <limits.h>
+#include <libkmod.h>
+#include <pthread.h>
+#include <errno.h>
#include "igt_aux.h"
#include "igt_core.h"
#include "igt_ktap.h"
+#define DELIMITER "-"
+
+struct ktap_parser_args {
+ FILE *fp;
+ bool is_builtin;
+ volatile bool is_running;
+ int ret;
+} ktap_args;
+
+static struct ktap_test_results results;
+
static int log_to_end(enum igt_log_level level, FILE *f,
char *record, const char *format, ...) __attribute__((format(printf, 4, 5)));
@@ -30,6 +44,14 @@ static int log_to_end(enum igt_log_level level, FILE *f,
{
va_list args;
const char *lend;
+ int f_fd = fileno(f);
+
+ /* Cutoff after newline character, in order to not display garbage */
+ char *cutoff = strchr(record, '\n');
+ if (cutoff) {
+ if (cutoff - record < BUF_LEN)
+ cutoff[1] = '\0';
+ }
va_start(args, format);
igt_vlog(IGT_LOG_DOMAIN, level, format, args);
@@ -38,10 +60,29 @@ static int log_to_end(enum igt_log_level level, FILE *f,
lend = strchrnul(record, '\n');
while (*lend == '\0') {
igt_log(IGT_LOG_DOMAIN, level, "%s", record);
- if (fgets(record, BUF_LEN, f) == NULL) {
+
+ while (read(f_fd, record, BUF_LEN) < 0) {
+ if (!READ_ONCE(ktap_args.is_running)) {
+ igt_warn("ktap parser stopped\n");
+ return -2;
+ }
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EPIPE) {
+ igt_warn("kmsg truncated: too many messages. You may want to increase log_buf_len in kmcdline\n");
+ return -2;
+ }
+
+ if (errno == EAGAIN)
+ /* No records available */
+ continue;
+
igt_warn("kmsg truncated: unknown error (%m)\n");
return -2;
}
+
lend = strchrnul(record, '\n');
}
return 0;
@@ -65,7 +106,7 @@ static long lookup_value(const char *haystack, const char *needle)
if (needle_rptr == NULL)
return -1;
- /* skip search string and whitespaces after it */
+ /* Skip search string and whitespaces after it */
needle_rptr += strlen(needle);
num = strtol(needle_rptr, &needle_end, 10);
@@ -79,6 +120,41 @@ static long lookup_value(const char *haystack, const char *needle)
return num > 0 ? num : 0;
}
+/**
+ * tap_version_present:
+ * @record: buffer with tap data
+ * @print_info: whether tap version should be printed or not
+ *
+ * Returns:
+ * 0 if not found
+ * 1 if found
+ */
+static int tap_version_present(char* record, bool print_info)
+{
+ /*
+ * "(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
+ */
+ const char *version_rptr = strcasestr(record, "TAP version ");
+ char *cutoff;
+
+ if (version_rptr == NULL)
+ return 0;
+
+ /* Cutoff after newline character, in order to not display garbage */
+ cutoff = strchr(version_rptr, '\n');
+ if (cutoff)
+ cutoff[0] = '\0';
+
+ if (print_info)
+ igt_info("%s\n", version_rptr);
+
+ return 1;
+}
+
/**
* find_next_tap_subtest:
* @fp: FILE pointer
@@ -91,11 +167,12 @@ static long lookup_value(const char *haystack, const char *needle)
* -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)
+static int find_next_tap_subtest(FILE *fp, char *record, char *test_name, bool is_builtin)
{
- const char *test_lookup_str, *subtest_lookup_str, *name_rptr, *version_rptr;
- char test_name[BUF_LEN + 1];
+ const char *test_lookup_str, *subtest_lookup_str, *name_rptr;
long test_count;
+ int fp_fd = fileno(fp);
+ char *cutoff;
test_name[0] = '\0';
test_name[BUF_LEN] = '\0';
@@ -103,21 +180,28 @@ static int find_next_tap_subtest(FILE *fp, char *record, bool is_builtin)
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 (!tap_version_present(record, true))
+ return -1;
+
if (is_builtin) {
- version_rptr = strcasestr(record, "TAP version ");
- if (version_rptr == NULL)
- return -1;
+ while (read(fp_fd, record, BUF_LEN) < 0) {
+ if (!READ_ONCE(ktap_args.is_running)) {
+ igt_warn("ktap parser stopped\n");
+ return -2;
+ }
+
+ if (errno == EINTR)
+ continue;
- igt_info("%s", version_rptr);
+ if (errno == EPIPE) {
+ igt_warn("kmsg truncated: too many messages. You may want to increase log_buf_len in kmcdline\n");
+ return -2;
+ }
+
+ if (errno == EAGAIN)
+ /* No records available */
+ continue;
- if (fgets(record, BUF_LEN, fp) == NULL) {
igt_warn("kmsg truncated: unknown error (%m)\n");
return -2;
}
@@ -134,22 +218,45 @@ static int find_next_tap_subtest(FILE *fp, char *record, bool is_builtin)
if (name_rptr == NULL) {
if (!is_builtin)
- /* we've probably found nothing */
+ /* 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) {
+ /* Cutoff after newline character, in order to not display garbage */
+ cutoff = strchr(test_name, '\n');
+ if (cutoff)
+ cutoff[0] = '\0';
+
+ while (read(fp_fd, record, BUF_LEN) < 0) {
+ if (!READ_ONCE(ktap_args.is_running)) {
+ igt_warn("ktap parser stopped\n");
+ return -2;
+ }
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EPIPE) {
+ igt_warn("kmsg truncated: too many messages. You may want to increase log_buf_len in kmcdline\n");
+ return -2;
+ }
+
+ if (errno == EAGAIN)
+ /* No records available */
+ continue;
+
igt_warn("kmsg truncated: unknown error (%m)\n");
return -2;
}
- /* now we can be sure we found tests */
+
+ /* 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
+ * 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, "..");
@@ -159,7 +266,7 @@ static int find_next_tap_subtest(FILE *fp, char *record, bool is_builtin)
if (test_name[0] == '\0')
return 0;
if (log_to_end(IGT_LOG_INFO, fp, record,
- "Running some tests in: %s",
+ "Running some tests in: %s\n",
test_name) < 0)
return -2;
return 0;
@@ -169,7 +276,7 @@ static int find_next_tap_subtest(FILE *fp, char *record, bool is_builtin)
}
if (log_to_end(IGT_LOG_INFO, fp, record,
- "Executing %ld tests in: %s",
+ "Executing %ld tests in: %s\n",
test_count, test_name) < 0)
return -2;
@@ -177,7 +284,7 @@ static int find_next_tap_subtest(FILE *fp, char *record, bool is_builtin)
}
/**
- * find_next_tap_test:
+ * parse_kmsg_for_tap:
* @fp: FILE pointer
* @record: buffer used to read fp
* @test_name: buffer to store the test name
@@ -225,7 +332,7 @@ static int parse_kmsg_for_tap(FILE *fp, char *record, char *test_name)
comment_start = strchrnul(lstart, '#');
- /* check if we're still in a subtest */
+ /* Check if we're still in a subtest */
if (*comment_start != '\0') {
comment_start++;
value_parse_start = comment_start;
@@ -254,81 +361,255 @@ static int parse_kmsg_for_tap(FILE *fp, char *record, char *test_name)
}
/**
- * igt_ktap_parser:
+ * parse_tap_level:
* @fp: FILE pointer
- * @record: buffer used to read fp
+ * @base_test_name: test_name from upper recursion level
+ * @test_count: test_count of this level
+ * @failed_tests: top level failed_tests pointer
+ * @found_tests: top level found_tests pointer
* @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
+ * Returns:
+ * 0 if succeded
+ * -1 if error occurred
*/
-int igt_ktap_parser(FILE *fp, char *record, bool is_builtin)
+static int parse_tap_level(FILE *fp, char *base_test_name, int test_count, bool *failed_tests,
+ bool *found_tests, bool is_builtin)
{
+ int fp_fd = fileno(fp);
+ char record[BUF_LEN + 1];
+ struct ktap_test_results_element *r, *temp;
+ int internal_test_count;
char test_name[BUF_LEN + 1];
- bool failed_tests, found_tests;
- int sublevel = 0;
+ char base_test_name_for_next_level[BUF_LEN + 1];
- test_name[0] = '\0';
- test_name[BUF_LEN] = '\0';
+ for (int i = 0; i < test_count; i++) {
+ while (read(fp_fd, record, BUF_LEN) < 0) {
+ if (!READ_ONCE(ktap_args.is_running)) {
+ igt_warn("ktap parser stopped\n");
+ return -1;
+ }
- failed_tests = false;
- found_tests = false;
+ if (errno == EINTR)
+ continue;
- while (sublevel >= 0) {
- if (fgets(record, BUF_LEN, fp) == NULL) {
- if (!found_tests)
- igt_warn("kmsg truncated: unknown error (%m)\n");
- break;
+ if (errno == EAGAIN)
+ /* No records available */
+ continue;
+
+ if (errno == EPIPE) {
+ igt_warn("kmsg truncated: too many messages. You may want to increase log_buf_len in kmcdline\n");
+ return -1;
+ }
+
+ igt_warn("kmsg truncated: unknown error (%m)\n");
+ return -1;
}
- 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;
+ /* Sublevel found */
+ if (tap_version_present(record, false))
+ {
+ internal_test_count = find_next_tap_subtest(fp, record, test_name,
+ is_builtin);
+ switch (internal_test_count) {
+ case -2:
+ /* No more data to read */
+ return -1;
+ case -1:
+ /* No test found */
+ return -1;
+ case 0:
+ /* Tests found, but they're missing info */
+ *found_tests = true;
+ return -1;
+ default:
+ *found_tests = true;
+
+ memcpy(base_test_name_for_next_level, base_test_name, BUF_LEN);
+ if (strlen(base_test_name_for_next_level) < BUF_LEN - 1 &&
+ base_test_name_for_next_level[0])
+ strncat(base_test_name_for_next_level, DELIMITER,
+ BUF_LEN - strlen(base_test_name_for_next_level));
+ memcpy(base_test_name_for_next_level + strlen(base_test_name_for_next_level),
+ test_name, BUF_LEN - strlen(base_test_name_for_next_level));
+
+ if (parse_tap_level(fp, base_test_name_for_next_level,
+ internal_test_count, failed_tests, found_tests,
+ is_builtin) == -1)
+ return -1;
+ break;
}
- found_tests = true;
- sublevel++;
- break;
}
switch (parse_kmsg_for_tap(fp, record, test_name)) {
case -2:
- return IGT_EXIT_FAILURE;
+ return -1;
case -1:
- sublevel--;
- failed_tests = true;
- igt_subtest(test_name)
- igt_fail(IGT_EXIT_FAILURE);
+ *failed_tests = true;
+
+ r = malloc(sizeof(*r));
+
+ memcpy(r->test_name, base_test_name, BUF_LEN);
+ if (strlen(r->test_name) < BUF_LEN - 1)
+ if (r->test_name[0])
+ strncat(r->test_name, DELIMITER,
+ BUF_LEN - strlen(r->test_name));
+ memcpy(r->test_name + strlen(r->test_name), test_name,
+ BUF_LEN - strlen(r->test_name));
+ r->test_name[BUF_LEN] = '\0';
+
+ r->passed = false;
+ r->next = NULL;
+
+ pthread_mutex_lock(&results.mutex);
+ if (results.head == NULL) {
+ results.head = r;
+ } else {
+ temp = results.head;
+ while (temp->next != NULL)
+ temp = temp->next;
+ temp->next = r;
+ }
+ pthread_mutex_unlock(&results.mutex);
+
test_name[0] = '\0';
break;
- case 0: /* fallthrough */
- igt_subtest(test_name)
- igt_success();
+ case 0:
+ r = malloc(sizeof(*r));
+
+ memcpy(r->test_name, base_test_name, BUF_LEN);
+ if (strlen(r->test_name) < BUF_LEN - 1)
+ if (r->test_name[0])
+ strncat(r->test_name, DELIMITER,
+ BUF_LEN - strlen(r->test_name));
+ memcpy(r->test_name + strlen(r->test_name), test_name,
+ BUF_LEN - strlen(r->test_name));
+ r->test_name[BUF_LEN] = '\0';
+
+ r->passed = true;
+ r->next = NULL;
+
+ pthread_mutex_lock(&results.mutex);
+ if (results.head == NULL) {
+ results.head = r;
+ } else {
+ temp = results.head;
+ while (temp->next != NULL)
+ temp = temp->next;
+ temp->next = r;
+ }
+ pthread_mutex_unlock(&results.mutex);
+
test_name[0] = '\0';
+ break;
default:
break;
}
}
+ return 0;
+}
+
+/**
+ * igt_ktap_parser:
+ *
+ * This function parses the output of a ktap script and passes it to main thread.
+ */
+void *igt_ktap_parser(void *unused)
+{
+ FILE *fp = ktap_args.fp;
+ int fp_fd = fileno(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 test_count;
+
+ failed_tests = false;
+ found_tests = false;
+
+ if (!READ_ONCE(ktap_args.is_running))
+ goto igt_ktap_parser_end;
+
+igt_ktap_parser_start:
+ test_name[0] = '\0';
+ test_name[BUF_LEN] = '\0';
+
+ while (read(fp_fd, record, BUF_LEN) < 0) {
+ if (!READ_ONCE(ktap_args.is_running)) {
+ igt_warn("ktap parser stopped\n");
+ goto igt_ktap_parser_end;
+ }
+
+ if (errno == EAGAIN)
+ /* No records available */
+ continue;
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno == EPIPE) {
+ igt_warn("kmsg truncated: too many messages. You may want to increase log_buf_len in kmcdline\n");
+ goto igt_ktap_parser_end;
+ }
+ }
+
+ test_count = find_next_tap_subtest(fp, record, test_name, is_builtin);
+
+ switch (test_count) {
+ case -2:
+ /* Problems while reading the file */
+ goto igt_ktap_parser_end;
+ case -1:
+ /* No test found */
+ goto igt_ktap_parser_start;
+ case 0:
+ /* Tests found, but they're missing info */
+ found_tests = true;
+ goto igt_ktap_parser_end;
+ default:
+ found_tests = true;
+
+ if (parse_tap_level(fp, test_name, test_count, &failed_tests, &found_tests,
+ is_builtin) == -1)
+ goto igt_ktap_parser_end;
+
+ break;
+ }
+
+ /* Parse topmost level */
+ test_name[0] = '\0';
+ parse_tap_level(fp, test_name, test_count, &failed_tests, &found_tests, is_builtin);
+
+igt_ktap_parser_end:
+ results.still_running = false;
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;
+
+struct ktap_test_results *ktap_parser_start(FILE *fp, bool is_builtin)
+{
+ results.head = NULL;
+ pthread_mutex_init(&results.mutex, NULL);
+ results.still_running = true;
- return IGT_EXIT_SUCCESS;
+ 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);
+
+ return &results;
+}
+
+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 b2f69df2d..34fe09572 100644
--- a/lib/igt_ktap.h
+++ b/lib/igt_ktap.h
@@ -26,6 +26,25 @@
#define BUF_LEN 4096
-int igt_ktap_parser(FILE *fp, char *record, bool is_builtin);
+#include <pthread.h>
+
+void *igt_ktap_parser(void *unused);
+
+typedef struct ktap_test_results_element {
+ char test_name[BUF_LEN + 1];
+ bool passed;
+ struct ktap_test_results_element *next;
+} ktap_test_results_element;
+
+struct ktap_test_results {
+ ktap_test_results_element *head;
+ pthread_mutex_t mutex;
+ bool still_running;
+};
+
+
+
+struct ktap_test_results *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] 14+ messages in thread* [igt-dev] [PATCH i-g-t 06/10] kunit tests: add an optional name for the selftests
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
` (4 preceding siblings ...)
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 05/10] Change logic of ktap parser to run on a thread Dominik Karol Piatkowski
@ 2023-06-14 10:58 ` Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 07/10] KUnit: Remove igt_kselftest fallback Dominik Karol Piatkowski
` (4 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Dominik Karol Piatkowski @ 2023-06-14 10:58 UTC (permalink / raw)
To: igt-dev
From: Mauro Carvalho Chehab <mchehab@kernel.org>
When multiple KUnit tests are called by the same program, it is
interesting to group them with a name. This would allow IGT
namespace to better refer to the KUnit tests and will give some
filtering capability to it.
After those changes, the IGT kUnit tests will be better named:
$ for i in kms_selftest drm_buddy drm_mm; do echo $i:; build/tests/$i --list; echo; done
kms_selftest:
drm_cmdline
drm_damage
drm_dp_mst
drm_format_helper
drm_format
framebuffer
drm_plane
all-tests
drm_buddy:
all-tests
drm_mm:
all-tests
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
lib/igt_kmod.c | 7 +++++--
lib/igt_kmod.h | 2 +-
tests/drm_buddy.c | 2 +-
tests/drm_mm.c | 3 ++-
tests/kms_selftest.c | 23 +++++++++++++++++------
5 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 73478f75e..2c0cc026d 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -848,7 +848,7 @@ unload:
return ret;
}
-int igt_kunit(const char *module_name, const char *opts)
+int igt_kunit(const char *module_name, const char *name, const char *opts)
{
/*
* We need to use igt_subtest here, as otherwise it may crash with:
@@ -857,7 +857,10 @@ int igt_kunit(const char *module_name, const char *opts)
* proper namespace for dynamic subtests, with is required for CI
* and for documentation.
*/
- igt_subtest_with_dynamic("all-tests")
+ if (name == NULL)
+ name = "all-tests";
+
+ igt_subtest_with_dynamic(name)
return __igt_kunit(module_name, opts);
return 0;
}
diff --git a/lib/igt_kmod.h b/lib/igt_kmod.h
index ce17c714e..248955475 100644
--- a/lib/igt_kmod.h
+++ b/lib/igt_kmod.h
@@ -71,7 +71,7 @@ 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);
+int igt_kunit(const char *module_name, const char *name, const char *opts);
void igt_kselftests(const char *module_name,
const char *module_options,
diff --git a/tests/drm_buddy.c b/tests/drm_buddy.c
index 3261f0d61..09feaf635 100644
--- a/tests/drm_buddy.c
+++ b/tests/drm_buddy.c
@@ -10,7 +10,7 @@ IGT_TEST_DESCRIPTION("Basic sanity check of DRM's buddy allocator (struct drm_bu
igt_main
{
- int ret = igt_kunit("drm_buddy_test", NULL);
+ int ret = igt_kunit("drm_buddy_test", NULL, 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 88f76a57c..ada8cb936 100644
--- a/tests/drm_mm.c
+++ b/tests/drm_mm.c
@@ -156,7 +156,8 @@ IGT_TEST_DESCRIPTION("Basic sanity check of DRM's range manager (struct drm_mm)"
igt_main
{
- int ret = igt_kunit("drm_mm_test", NULL);
+ int ret = igt_kunit("drm_mm_test", NULL, 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 b27f60fb3..d83e5ff4b 100644
--- a/tests/kms_selftest.c
+++ b/tests/kms_selftest.c
@@ -26,15 +26,26 @@
IGT_TEST_DESCRIPTION("Basic sanity check of KMS selftests.");
+struct kms_kunittests {
+ const char *kunit;
+ const char *name;
+};
+
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 };
+ static const struct kms_kunittests kunit_subtests[] = {
+ { "drm_cmdline_parser_test", "drm_cmdline" },
+ { "drm_damage_helper_test", "drm_damage" },
+ { "drm_dp_mst_helper_test", "drm_dp_mst" },
+ { "drm_format_helper_test", "drm_format_helper" },
+ { "drm_format_test", "drm_format" },
+ { "drm_framebuffer_test", "framebuffer" },
+ { "drm_plane_helper_test", "drm_plane" },
+ { NULL, NULL}
+ };
- for (int i = 0; kunit_subtests[i] != NULL; i++)
- igt_kunit(kunit_subtests[i], NULL);
+ for (int i = 0; kunit_subtests[i].kunit != NULL; i++)
+ igt_kunit(kunit_subtests[i].kunit, kunit_subtests[i].name, NULL);
igt_kselftests("test-drm_modeset", NULL, NULL, NULL);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [igt-dev] [PATCH i-g-t 07/10] KUnit: Remove igt_kselftest fallback
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
` (5 preceding siblings ...)
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 06/10] kunit tests: add an optional name for the selftests Dominik Karol Piatkowski
@ 2023-06-14 10:58 ` Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 08/10] KUnit: Change subtest name from all-tests to module name Dominik Karol Piatkowski
` (3 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Dominik Karol Piatkowski @ 2023-06-14 10:58 UTC (permalink / raw)
To: igt-dev
As igt_kselftest fallback is removed, igt_kunit does not need
to return a value.
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Reviewed-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
---
lib/igt_kmod.c | 16 ++++++----------
lib/igt_kmod.h | 2 +-
tests/drm_buddy.c | 4 +---
tests/drm_mm.c | 5 +----
tests/kms_selftest.c | 2 --
5 files changed, 9 insertions(+), 20 deletions(-)
diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 2c0cc026d..a6e751482 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -754,7 +754,7 @@ void igt_kselftest_get_tests(struct kmod_module *kmod,
*
* Returns: IGT default codes
*/
-static int __igt_kunit(const char *module_name, const char *opts)
+static void __igt_kunit(const char *module_name, const char *opts)
{
struct igt_ktest tst;
struct kmod_module *kunit_kmod;
@@ -764,19 +764,17 @@ static int __igt_kunit(const char *module_name, const char *opts)
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
- 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;
+ igt_fail(IGT_EXIT_SKIP);
}
if (igt_ktest_begin(&tst) != 0) {
igt_warn("Unable to begin ktest for %s\n", module_name);
igt_ktest_fini(&tst);
- return ret;
+ igt_fail(IGT_EXIT_SKIP);
}
if (tst.kmsg < 0) {
@@ -841,14 +839,13 @@ unload:
ret = ktap_parser_stop();
if (ret != 0)
- ret = IGT_EXIT_ABORT;
+ igt_fail(IGT_EXIT_ABORT);
if (ret == 0)
igt_success();
- return ret;
}
-int igt_kunit(const char *module_name, const char *name, const char *opts)
+void igt_kunit(const char *module_name, const char *name, const char *opts)
{
/*
* We need to use igt_subtest here, as otherwise it may crash with:
@@ -861,8 +858,7 @@ int igt_kunit(const char *module_name, const char *name, const char *opts)
name = "all-tests";
igt_subtest_with_dynamic(name)
- return __igt_kunit(module_name, opts);
- return 0;
+ __igt_kunit(module_name, opts);
}
static int open_parameters(const char *module_name)
diff --git a/lib/igt_kmod.h b/lib/igt_kmod.h
index 248955475..990e5309d 100644
--- a/lib/igt_kmod.h
+++ b/lib/igt_kmod.h
@@ -71,7 +71,7 @@ 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 *name, const char *opts);
+void igt_kunit(const char *module_name, const char *name, const char *opts);
void igt_kselftests(const char *module_name,
const char *module_options,
diff --git a/tests/drm_buddy.c b/tests/drm_buddy.c
index 09feaf635..4f411464a 100644
--- a/tests/drm_buddy.c
+++ b/tests/drm_buddy.c
@@ -10,7 +10,5 @@ IGT_TEST_DESCRIPTION("Basic sanity check of DRM's buddy allocator (struct drm_bu
igt_main
{
- int ret = igt_kunit("drm_buddy_test", NULL, NULL);
- if (ret != 0 && ret != IGT_EXIT_ABORT)
- igt_kselftests("test-drm_buddy", NULL, NULL, NULL);
+ igt_kunit("drm_buddy_test", NULL, NULL);
}
diff --git a/tests/drm_mm.c b/tests/drm_mm.c
index ada8cb936..089eae2b9 100644
--- a/tests/drm_mm.c
+++ b/tests/drm_mm.c
@@ -156,8 +156,5 @@ IGT_TEST_DESCRIPTION("Basic sanity check of DRM's range manager (struct drm_mm)"
igt_main
{
- int ret = igt_kunit("drm_mm_test", NULL, NULL);
-
- if (ret != 0 && ret != IGT_EXIT_ABORT)
- igt_kselftests("test-drm_mm", NULL, NULL, NULL);
+ igt_kunit("drm_mm_test", NULL, NULL);
}
diff --git a/tests/kms_selftest.c b/tests/kms_selftest.c
index d83e5ff4b..5495c24f2 100644
--- a/tests/kms_selftest.c
+++ b/tests/kms_selftest.c
@@ -46,6 +46,4 @@ igt_main
for (int i = 0; kunit_subtests[i].kunit != NULL; i++)
igt_kunit(kunit_subtests[i].kunit, kunit_subtests[i].name, NULL);
-
- igt_kselftests("test-drm_modeset", NULL, NULL, NULL);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [igt-dev] [PATCH i-g-t 08/10] KUnit: Change subtest name from all-tests to module name
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
` (6 preceding siblings ...)
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 07/10] KUnit: Remove igt_kselftest fallback Dominik Karol Piatkowski
@ 2023-06-14 10:58 ` Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 09/10] tests/xe: Add a test that launches the xe driver live kunit tests Dominik Karol Piatkowski
` (2 subsequent siblings)
10 siblings, 0 replies; 14+ messages in thread
From: Dominik Karol Piatkowski @ 2023-06-14 10:58 UTC (permalink / raw)
To: igt-dev
Use KUnit module name instead of all-tests when no name is specified.
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
Reviewed-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: Janusz Krzysztofik <janusz.krzysztofik@linux.intel.com>
Cc: Mauro Carvalho Chehab <mauro.chehab@linux.intel.com>
---
lib/igt_kmod.c | 2 +-
tests/drm_mm.c | 42 +++++++++++++++++++++---------------------
2 files changed, 22 insertions(+), 22 deletions(-)
diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index a6e751482..1511bdef4 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -855,7 +855,7 @@ void igt_kunit(const char *module_name, const char *name, const char *opts)
* and for documentation.
*/
if (name == NULL)
- name = "all-tests";
+ name = module_name;
igt_subtest_with_dynamic(name)
__igt_kunit(module_name, opts);
diff --git a/tests/drm_mm.c b/tests/drm_mm.c
index 089eae2b9..9a8b3f3fc 100644
--- a/tests/drm_mm.c
+++ b/tests/drm_mm.c
@@ -29,123 +29,123 @@
* Feature: mapping
* Run type: FULL
*
- * SUBTEST: all-tests
+ * SUBTEST: drm_mm_test
*
- * SUBTEST: all-tests@align
+ * SUBTEST: drm_mm_test@align
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@align32
+ * SUBTEST: drm_mm_test@align32
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@align64
+ * SUBTEST: drm_mm_test@align64
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@bottomup
+ * SUBTEST: drm_mm_test@bottomup
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@color
+ * SUBTEST: drm_mm_test@color
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@color_evict
+ * SUBTEST: drm_mm_test@color_evict
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@color_evict_range
+ * SUBTEST: drm_mm_test@color_evict_range
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@debug
+ * SUBTEST: drm_mm_test@debug
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@evict
+ * SUBTEST: drm_mm_test@evict
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@evict_range
+ * SUBTEST: drm_mm_test@evict_range
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@frag
+ * SUBTEST: drm_mm_test@frag
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@highest
+ * SUBTEST: drm_mm_test@highest
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@init
+ * SUBTEST: drm_mm_test@init
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@insert
+ * SUBTEST: drm_mm_test@insert
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@insert_range
+ * SUBTEST: drm_mm_test@insert_range
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@lowest
+ * SUBTEST: drm_mm_test@lowest
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@replace
+ * SUBTEST: drm_mm_test@replace
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@reserve
+ * SUBTEST: drm_mm_test@reserve
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@sanitycheck
+ * SUBTEST: drm_mm_test@sanitycheck
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
* Test category: GEM_Legacy
*
- * SUBTEST: all-tests@topdown
+ * SUBTEST: drm_mm_test@topdown
* Category: Infrastructure
* Description: drm_mm range manager SW validation
* Functionality: DRM memory mangemnt
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [igt-dev] [PATCH i-g-t 09/10] tests/xe: Add a test that launches the xe driver live kunit tests
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
` (7 preceding siblings ...)
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 08/10] KUnit: Change subtest name from all-tests to module name Dominik Karol Piatkowski
@ 2023-06-14 10:58 ` Dominik Karol Piatkowski
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 10/10] KUnit: gracefully skip on missing KUnit or tested module, fail otherwise Dominik Karol Piatkowski
2023-06-14 14:44 ` [igt-dev] ✗ Fi.CI.BUILD: failure for Introduce KUnit (rev8) Patchwork
10 siblings, 0 replies; 14+ messages in thread
From: Dominik Karol Piatkowski @ 2023-06-14 10:58 UTC (permalink / raw)
To: igt-dev; +Cc: Thomas Hellström
From: Mauro Carvalho Chehab <mchehab@kernel.org>
The xe driver live kunit tests live in the xe driver tests/
subdirectory and are intended to be launched by this igt test.
To begin with we only have one test ("dma-buf").
[mchehab: updated to reflect current KUnit tests]
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
Signed-off-by: Dominik Karol Piątkowski <dominik.karol.piatkowski@intel.com>
---
tests/meson.build | 1 +
tests/xe/xe_live_ktest.c | 52 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+)
create mode 100644 tests/xe/xe_live_ktest.c
diff --git a/tests/meson.build b/tests/meson.build
index f908ae885..61dcc0769 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -259,6 +259,7 @@ xe_progs = [
'xe_guc_pc',
'xe_huc_copy',
'xe_intel_bb',
+ 'xe_live_ktest',
'xe_mmap',
'xe_mmio',
'xe_module_load',
diff --git a/tests/xe/xe_live_ktest.c b/tests/xe/xe_live_ktest.c
new file mode 100644
index 000000000..7dcf67906
--- /dev/null
+++ b/tests/xe/xe_live_ktest.c
@@ -0,0 +1,52 @@
+#include "igt.h"
+#include "igt_kmod.h"
+
+/**
+ * TEST: Xe driver live kunit tests
+ * Description: Xe driver live dmabuf unit tests
+ * Category: Software building block
+ * Sub-category: kunit
+ * Functionality: kunit
+ * Test category: functionality test
+ * Run type: BAT
+ *
+ * SUBTEST: bo
+ * Functionality: bo
+ *
+ * SUBTEST: dmabuf
+ * Functionality: dmabuf
+ *
+ * SUBTEST: migrate
+ * Functionality: migrate
+ *
+ * SUBTEST: pci
+ * Functionality: pci
+ *
+ * SUBTEST: rtp
+ * Functionality: rtp
+ *
+ * SUBTEST: wa
+ * Functionality: workarounds
+ */
+
+struct kunit_tests {
+ const char *kunit;
+ const char *name;
+};
+
+static const struct kunit_tests live_tests[] = {
+ { "xe_bo_test", "bo" },
+ { "xe_dma_buf_test", "dmabuf" },
+ { "xe_migrate_test", "migrate" },
+ { "xe_pci_test", "pci" },
+ { "xe_rtp_test", "rtp" },
+ { "xe_wa_test", "wa" },
+};
+
+igt_main
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(live_tests); i++)
+ igt_kunit(live_tests[i].kunit, live_tests[i].name, NULL);
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* [igt-dev] [PATCH i-g-t 10/10] KUnit: gracefully skip on missing KUnit or tested module, fail otherwise
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
` (8 preceding siblings ...)
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 09/10] tests/xe: Add a test that launches the xe driver live kunit tests Dominik Karol Piatkowski
@ 2023-06-14 10:58 ` Dominik Karol Piatkowski
2023-06-14 11:02 ` Mauro Carvalho Chehab
2023-06-14 14:00 ` Kamil Konieczny
2023-06-14 14:44 ` [igt-dev] ✗ Fi.CI.BUILD: failure for Introduce KUnit (rev8) Patchwork
10 siblings, 2 replies; 14+ messages in thread
From: Dominik Karol Piatkowski @ 2023-06-14 10:58 UTC (permalink / raw)
To: igt-dev
Sample drm_buddy output with missing KUnit module:
Starting subtest: drm_buddy_test
(drm_buddy:32218) igt_kmod-WARNING: Unable to load KUnit
Subtest drm_buddy_test: SKIP (0.001s)
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 | 21 +++++++++++++++++----
1 file changed, 17 insertions(+), 4 deletions(-)
diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
index 1511bdef4..66c3028b3 100644
--- a/lib/igt_kmod.c
+++ b/lib/igt_kmod.c
@@ -763,27 +763,31 @@ static void __igt_kunit(const char *module_name, const char *opts)
int ret;
struct ktap_test_results *results;
struct ktap_test_results_element *temp;
+ bool skip = false;
+ bool fail = false;
/* get normalized module name */
if (igt_ktest_init(&tst, module_name) != 0) {
igt_warn("Unable to initialize ktest for %s\n", module_name);
- igt_fail(IGT_EXIT_SKIP);
+ igt_fail(IGT_EXIT_ABORT);
}
if (igt_ktest_begin(&tst) != 0) {
igt_warn("Unable to begin ktest for %s\n", module_name);
igt_ktest_fini(&tst);
- igt_fail(IGT_EXIT_SKIP);
+ igt_fail(IGT_EXIT_ABORT);
}
if (tst.kmsg < 0) {
igt_warn("Could not open /dev/kmsg\n");
+ fail = true;
goto unload;
}
if (lseek(tst.kmsg, 0, SEEK_END)) {
igt_warn("Could not seek the end of /dev/kmsg\n");
+ fail = true;
goto unload;
}
@@ -791,6 +795,7 @@ static void __igt_kunit(const char *module_name, const char *opts)
if (f == NULL) {
igt_warn("Could not turn /dev/kmsg file descriptor into a FILE pointer\n");
+ fail = true;
goto unload;
}
@@ -798,7 +803,8 @@ static void __igt_kunit(const char *module_name, const char *opts)
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);
+ skip = true;
+ goto unload;
}
is_builtin = kmod_module_get_initstate(kunit_kmod) == KMOD_MODULE_BUILTIN;
@@ -808,7 +814,8 @@ static void __igt_kunit(const char *module_name, const char *opts)
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);
+ skip = true;
+ goto unload;
}
while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != NULL)
@@ -836,6 +843,12 @@ unload:
igt_ktest_fini(&tst);
+ if (skip)
+ igt_skip("");
+
+ if (fail)
+ igt_fail(IGT_EXIT_ABORT);
+
ret = ktap_parser_stop();
if (ret != 0)
--
2.34.1
^ permalink raw reply related [flat|nested] 14+ messages in thread* Re: [igt-dev] [PATCH i-g-t 10/10] KUnit: gracefully skip on missing KUnit or tested module, fail otherwise
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 10/10] KUnit: gracefully skip on missing KUnit or tested module, fail otherwise Dominik Karol Piatkowski
@ 2023-06-14 11:02 ` Mauro Carvalho Chehab
2023-06-14 14:00 ` Kamil Konieczny
1 sibling, 0 replies; 14+ messages in thread
From: Mauro Carvalho Chehab @ 2023-06-14 11:02 UTC (permalink / raw)
To: Dominik Karol Piatkowski; +Cc: igt-dev
On Wed, 14 Jun 2023 12:58:11 +0200
Dominik Karol Piatkowski <dominik.karol.piatkowski@intel.com> wrote:
> Sample drm_buddy output with missing KUnit module:
> Starting subtest: drm_buddy_test
> (drm_buddy:32218) igt_kmod-WARNING: Unable to load KUnit
> Subtest drm_buddy_test: SKIP (0.001s)
>
> 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>
Works for me.
Acked-by: Mauro Carvalho Chehab <mchehab@kernel.org>
> ---
> lib/igt_kmod.c | 21 +++++++++++++++++----
> 1 file changed, 17 insertions(+), 4 deletions(-)
>
> diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
> index 1511bdef4..66c3028b3 100644
> --- a/lib/igt_kmod.c
> +++ b/lib/igt_kmod.c
> @@ -763,27 +763,31 @@ static void __igt_kunit(const char *module_name, const char *opts)
> int ret;
> struct ktap_test_results *results;
> struct ktap_test_results_element *temp;
> + bool skip = false;
> + bool fail = false;
>
> /* get normalized module name */
> if (igt_ktest_init(&tst, module_name) != 0) {
> igt_warn("Unable to initialize ktest for %s\n", module_name);
> - igt_fail(IGT_EXIT_SKIP);
> + igt_fail(IGT_EXIT_ABORT);
> }
>
> if (igt_ktest_begin(&tst) != 0) {
> igt_warn("Unable to begin ktest for %s\n", module_name);
>
> igt_ktest_fini(&tst);
> - igt_fail(IGT_EXIT_SKIP);
> + igt_fail(IGT_EXIT_ABORT);
> }
>
> if (tst.kmsg < 0) {
> igt_warn("Could not open /dev/kmsg\n");
> + fail = true;
> goto unload;
> }
>
> if (lseek(tst.kmsg, 0, SEEK_END)) {
> igt_warn("Could not seek the end of /dev/kmsg\n");
> + fail = true;
> goto unload;
> }
>
> @@ -791,6 +795,7 @@ static void __igt_kunit(const char *module_name, const char *opts)
>
> if (f == NULL) {
> igt_warn("Could not turn /dev/kmsg file descriptor into a FILE pointer\n");
> + fail = true;
> goto unload;
> }
>
> @@ -798,7 +803,8 @@ static void __igt_kunit(const char *module_name, const char *opts)
> 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);
> + skip = true;
> + goto unload;
> }
>
> is_builtin = kmod_module_get_initstate(kunit_kmod) == KMOD_MODULE_BUILTIN;
> @@ -808,7 +814,8 @@ static void __igt_kunit(const char *module_name, const char *opts)
> 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);
> + skip = true;
> + goto unload;
> }
>
> while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != NULL)
> @@ -836,6 +843,12 @@ unload:
>
> igt_ktest_fini(&tst);
>
> + if (skip)
> + igt_skip("");
> +
> + if (fail)
> + igt_fail(IGT_EXIT_ABORT);
> +
> ret = ktap_parser_stop();
>
> if (ret != 0)
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [igt-dev] [PATCH i-g-t 10/10] KUnit: gracefully skip on missing KUnit or tested module, fail otherwise
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 10/10] KUnit: gracefully skip on missing KUnit or tested module, fail otherwise Dominik Karol Piatkowski
2023-06-14 11:02 ` Mauro Carvalho Chehab
@ 2023-06-14 14:00 ` Kamil Konieczny
1 sibling, 0 replies; 14+ messages in thread
From: Kamil Konieczny @ 2023-06-14 14:00 UTC (permalink / raw)
To: igt-dev
Hi Dominik,
On 2023-06-14 at 12:58:11 +0200, Dominik Karol Piatkowski wrote:
> Sample drm_buddy output with missing KUnit module:
> Starting subtest: drm_buddy_test
> (drm_buddy:32218) igt_kmod-WARNING: Unable to load KUnit
> Subtest drm_buddy_test: SKIP (0.001s)
>
> 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 | 21 +++++++++++++++++----
> 1 file changed, 17 insertions(+), 4 deletions(-)
>
> diff --git a/lib/igt_kmod.c b/lib/igt_kmod.c
> index 1511bdef4..66c3028b3 100644
> --- a/lib/igt_kmod.c
> +++ b/lib/igt_kmod.c
> @@ -763,27 +763,31 @@ static void __igt_kunit(const char *module_name, const char *opts)
> int ret;
> struct ktap_test_results *results;
> struct ktap_test_results_element *temp;
> + bool skip = false;
> + bool fail = false;
>
> /* get normalized module name */
> if (igt_ktest_init(&tst, module_name) != 0) {
> igt_warn("Unable to initialize ktest for %s\n", module_name);
> - igt_fail(IGT_EXIT_SKIP);
> + igt_fail(IGT_EXIT_ABORT);
> }
>
> if (igt_ktest_begin(&tst) != 0) {
> igt_warn("Unable to begin ktest for %s\n", module_name);
>
> igt_ktest_fini(&tst);
> - igt_fail(IGT_EXIT_SKIP);
> + igt_fail(IGT_EXIT_ABORT);
> }
>
> if (tst.kmsg < 0) {
> igt_warn("Could not open /dev/kmsg\n");
> + fail = true;
> goto unload;
> }
>
> if (lseek(tst.kmsg, 0, SEEK_END)) {
> igt_warn("Could not seek the end of /dev/kmsg\n");
> + fail = true;
> goto unload;
> }
>
> @@ -791,6 +795,7 @@ static void __igt_kunit(const char *module_name, const char *opts)
>
> if (f == NULL) {
> igt_warn("Could not turn /dev/kmsg file descriptor into a FILE pointer\n");
> + fail = true;
> goto unload;
> }
>
> @@ -798,7 +803,8 @@ static void __igt_kunit(const char *module_name, const char *opts)
> 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);
> + skip = true;
> + goto unload;
> }
>
> is_builtin = kmod_module_get_initstate(kunit_kmod) == KMOD_MODULE_BUILTIN;
> @@ -808,7 +814,8 @@ static void __igt_kunit(const char *module_name, const char *opts)
> 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);
> + skip = true;
> + goto unload;
> }
>
> while (READ_ONCE(results->still_running) || READ_ONCE(results->head) != NULL)
> @@ -836,6 +843,12 @@ unload:
>
> igt_ktest_fini(&tst);
>
> + if (skip)
> + igt_skip("");
------------------------ ^^
This empty string leads to compiler warning:
[188/1383] Compiling C object lib/libigt-igt_kmod_c.a.p/igt_kmod.c.o
../lib/igt_kmod.c: In function ‘__igt_kunit’:
../lib/igt_kmod.c:847:26: warning: zero-length gnu_printf format string [-Wformat-zero-length]
847 | igt_skip("");
| ^~
imho better to provide some explanation for skipping.
Regards,
Kamil
> +
> + if (fail)
> + igt_fail(IGT_EXIT_ABORT);
> +
> ret = ktap_parser_stop();
>
> if (ret != 0)
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* [igt-dev] ✗ Fi.CI.BUILD: failure for Introduce KUnit (rev8)
2023-06-14 10:58 [igt-dev] [PATCH v8 i-g-t 00/10] Introduce KUnit Dominik Karol Piatkowski
` (9 preceding siblings ...)
2023-06-14 10:58 ` [igt-dev] [PATCH i-g-t 10/10] KUnit: gracefully skip on missing KUnit or tested module, fail otherwise Dominik Karol Piatkowski
@ 2023-06-14 14:44 ` Patchwork
10 siblings, 0 replies; 14+ messages in thread
From: Patchwork @ 2023-06-14 14:44 UTC (permalink / raw)
To: Dominik Karol Piatkowski; +Cc: igt-dev
== Series Details ==
Series: Introduce KUnit (rev8)
URL : https://patchwork.freedesktop.org/series/114612/
State : failure
== Summary ==
Applying: lib/igt_kmod: rename kselftest functions to ktest
Using index info to reconstruct a base tree...
M lib/igt_kmod.c
M lib/igt_kmod.h
Falling back to patching base and 3-way merge...
Auto-merging lib/igt_kmod.h
Auto-merging lib/igt_kmod.c
No changes -- Patch already applied.
Applying: lib/igt_kmod.c: check if module is builtin before attempting to unload it
Using index info to reconstruct a base tree...
M lib/igt_kmod.c
Falling back to patching base and 3-way merge...
Auto-merging lib/igt_kmod.c
No changes -- Patch already applied.
Applying: lib/igt_kmod: add compatibility for KUnit
Using index info to reconstruct a base tree...
M lib/igt_kmod.c
M lib/igt_kmod.h
M lib/meson.build
Falling back to patching base and 3-way merge...
CONFLICT (add/add): Merge conflict in lib/igt_ktap.h
Auto-merging lib/igt_ktap.h
CONFLICT (add/add): Merge conflict in lib/igt_ktap.c
Auto-merging lib/igt_ktap.c
Auto-merging lib/igt_kmod.h
CONFLICT (content): Merge conflict in lib/igt_kmod.h
Auto-merging lib/igt_kmod.c
CONFLICT (content): Merge conflict in lib/igt_kmod.c
Patch failed at 0003 lib/igt_kmod: add compatibility for KUnit
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
^ permalink raw reply [flat|nested] 14+ messages in thread