2023-07-25 21:48:29

by Rae Moar

[permalink] [raw]
Subject: [PATCH v3 0/9] kunit: Add test attributes API

Hello everyone,

This patch series adds a test attributes framework to KUnit.

There has been interest in filtering out "slow" KUnit tests. Most notably,
a new config, CONFIG_MEMCPY_SLOW_KUNIT_TEST, has been added to exclude a
particularly slow memcpy test
(https://lore.kernel.org/all/[email protected]/).

This attributes framework can be used to save and access test associated
data, including whether a test is slow. These attributes are reportable
(via KTAP and command line output) and are also filterable.

This framework is designed to allow for the addition of other attributes in
the future. These attributes could include whether the test can be run
concurrently, test file path, etc.

To try out the framework I suggest running:
"./tools/testing/kunit/kunit.py run --filter speed!=slow"

This patch series was originally sent out as an RFC. Here is a link to the
RFC v2:
https://lore.kernel.org/all/[email protected]/

Thanks!
Rae

Rae Moar (9):
kunit: Add test attributes API structure
kunit: Add speed attribute
kunit: Add module attribute
kunit: Add ability to filter attributes
kunit: tool: Add command line interface to filter and report
attributes
kunit: memcpy: Mark tests as slow using test attributes
kunit: time: Mark test as slow using test attributes
kunit: add tests for filtering attributes
kunit: Add documentation of KUnit test attributes

Documentation/dev-tools/kunit/run_wrapper.rst | 12 +
.../dev-tools/kunit/running_tips.rst | 166 +++++++
include/kunit/attributes.h | 50 +++
include/kunit/test.h | 70 ++-
kernel/time/time_test.c | 2 +-
lib/Kconfig.debug | 3 +
lib/kunit/Makefile | 3 +-
lib/kunit/attributes.c | 418 ++++++++++++++++++
lib/kunit/executor.c | 114 ++++-
lib/kunit/executor_test.c | 128 +++++-
lib/kunit/kunit-example-test.c | 9 +
lib/kunit/test.c | 27 +-
lib/memcpy_kunit.c | 8 +-
tools/testing/kunit/kunit.py | 70 ++-
tools/testing/kunit/kunit_kernel.py | 8 +-
tools/testing/kunit/kunit_parser.py | 11 +-
tools/testing/kunit/kunit_tool_test.py | 39 +-
17 files changed, 1062 insertions(+), 76 deletions(-)
create mode 100644 include/kunit/attributes.h
create mode 100644 lib/kunit/attributes.c


base-commit: 64bd4641310c41a1ecf07c13c67bc0ed61045dfd
--
2.41.0.487.g6d72f3e995-goog



2023-07-25 22:01:27

by Rae Moar

[permalink] [raw]
Subject: [PATCH v3 8/9] kunit: add tests for filtering attributes

Add four tests to executor_test.c to test behavior of filtering attributes.

- parse_filter_attr_test - to test the parsing of inputted filters

- filter_attr_test - to test the filtering procedure on attributes

- filter_attr_empty_test - to test the behavior when all tests are filtered
out

- filter_attr_skip_test - to test the configurable filter_action=skip
option

Reviewed-by: David Gow <[email protected]>
Signed-off-by: Rae Moar <[email protected]>
---

Changes since v2:
- No changes.
Changes since v1:
- No changes.
Changes since RFC v2:
- Change fake suite and test case names.
- Add a few ASSERT statements.
Changes since RFC v1:
- This is a new patch

lib/kunit/executor_test.c | 116 ++++++++++++++++++++++++++++++++++++++
1 file changed, 116 insertions(+)

diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c
index d7ab069324b5..01280cb8d451 100644
--- a/lib/kunit/executor_test.c
+++ b/lib/kunit/executor_test.c
@@ -7,6 +7,7 @@
*/

#include <kunit/test.h>
+#include <kunit/attributes.h>

static void kfree_at_end(struct kunit *test, const void *to_free);
static struct kunit_suite *alloc_fake_suite(struct kunit *test,
@@ -108,11 +109,126 @@ static void filter_suites_to_empty_test(struct kunit *test)
"should be empty to indicate no match");
}

+static void parse_filter_attr_test(struct kunit *test)
+{
+ int j, filter_count;
+ struct kunit_attr_filter *parsed_filters;
+ char *filters = "speed>slow, module!=example";
+ int err = 0;
+
+ filter_count = kunit_get_filter_count(filters);
+ KUNIT_EXPECT_EQ(test, filter_count, 2);
+
+ parsed_filters = kunit_kcalloc(test, filter_count + 1, sizeof(*parsed_filters),
+ GFP_KERNEL);
+ for (j = 0; j < filter_count; j++) {
+ parsed_filters[j] = kunit_next_attr_filter(&filters, &err);
+ KUNIT_ASSERT_EQ_MSG(test, err, 0, "failed to parse filter '%s'", filters[j]);
+ }
+
+ KUNIT_EXPECT_STREQ(test, kunit_attr_filter_name(parsed_filters[0]), "speed");
+ KUNIT_EXPECT_STREQ(test, parsed_filters[0].input, ">slow");
+
+ KUNIT_EXPECT_STREQ(test, kunit_attr_filter_name(parsed_filters[1]), "module");
+ KUNIT_EXPECT_STREQ(test, parsed_filters[1].input, "!=example");
+}
+
+static struct kunit_case dummy_attr_test_cases[] = {
+ /* .run_case is not important, just needs to be non-NULL */
+ { .name = "slow", .run_case = dummy_test, .module_name = "dummy",
+ .attr.speed = KUNIT_SPEED_SLOW },
+ { .name = "normal", .run_case = dummy_test, .module_name = "dummy" },
+ {},
+};
+
+static void filter_attr_test(struct kunit *test)
+{
+ struct kunit_suite *subsuite[3] = {NULL, NULL};
+ struct suite_set suite_set = {.start = subsuite, .end = &subsuite[2]};
+ struct suite_set got;
+ int err = 0;
+
+ subsuite[0] = alloc_fake_suite(test, "normal_suite", dummy_attr_test_cases);
+ subsuite[1] = alloc_fake_suite(test, "slow_suite", dummy_attr_test_cases);
+ subsuite[1]->attr.speed = KUNIT_SPEED_SLOW; // Set suite attribute
+
+ /*
+ * Want: normal_suite(slow, normal), slow_suite(slow, normal),
+ * NULL -> normal_suite(normal), NULL
+ *
+ * The normal test in slow_suite is filtered out because the speed
+ * attribute is unset and thus, the filtering is based on the parent attribute
+ * of slow.
+ */
+ got = kunit_filter_suites(&suite_set, NULL, "speed>slow", NULL, &err);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
+ KUNIT_ASSERT_EQ(test, err, 0);
+ kfree_at_end(test, got.start);
+
+ /* Validate we just have normal_suite */
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
+ KUNIT_EXPECT_STREQ(test, got.start[0]->name, "normal_suite");
+ KUNIT_ASSERT_EQ(test, got.end - got.start, 1);
+
+ /* Now validate we just have normal test case */
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases);
+ KUNIT_EXPECT_STREQ(test, got.start[0]->test_cases[0].name, "normal");
+ KUNIT_EXPECT_FALSE(test, got.start[0]->test_cases[1].name);
+}
+
+static void filter_attr_empty_test(struct kunit *test)
+{
+ struct kunit_suite *subsuite[3] = {NULL, NULL};
+ struct suite_set suite_set = {.start = subsuite, .end = &subsuite[2]};
+ struct suite_set got;
+ int err = 0;
+
+ subsuite[0] = alloc_fake_suite(test, "suite1", dummy_attr_test_cases);
+ subsuite[1] = alloc_fake_suite(test, "suite2", dummy_attr_test_cases);
+
+ got = kunit_filter_suites(&suite_set, NULL, "module!=dummy", NULL, &err);
+ KUNIT_ASSERT_EQ(test, err, 0);
+ kfree_at_end(test, got.start); /* just in case */
+
+ KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end,
+ "should be empty to indicate no match");
+}
+
+static void filter_attr_skip_test(struct kunit *test)
+{
+ struct kunit_suite *subsuite[2] = {NULL};
+ struct suite_set suite_set = {.start = subsuite, .end = &subsuite[1]};
+ struct suite_set got;
+ int err = 0;
+
+ subsuite[0] = alloc_fake_suite(test, "suite", dummy_attr_test_cases);
+
+ /* Want: suite(slow, normal), NULL -> suite(slow with SKIP, normal), NULL */
+ got = kunit_filter_suites(&suite_set, NULL, "speed>slow", "skip", &err);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
+ KUNIT_ASSERT_EQ(test, err, 0);
+ kfree_at_end(test, got.start);
+
+ /* Validate we have both the slow and normal test */
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases);
+ KUNIT_ASSERT_EQ(test, kunit_suite_num_test_cases(got.start[0]), 2);
+ KUNIT_EXPECT_STREQ(test, got.start[0]->test_cases[0].name, "slow");
+ KUNIT_EXPECT_STREQ(test, got.start[0]->test_cases[1].name, "normal");
+
+ /* Now ensure slow is skipped and normal is not */
+ KUNIT_EXPECT_EQ(test, got.start[0]->test_cases[0].status, KUNIT_SKIPPED);
+ KUNIT_EXPECT_FALSE(test, got.start[0]->test_cases[1].status);
+}
+
static struct kunit_case executor_test_cases[] = {
KUNIT_CASE(parse_filter_test),
KUNIT_CASE(filter_suites_test),
KUNIT_CASE(filter_suites_test_glob_test),
KUNIT_CASE(filter_suites_to_empty_test),
+ KUNIT_CASE(parse_filter_attr_test),
+ KUNIT_CASE(filter_attr_test),
+ KUNIT_CASE(filter_attr_empty_test),
+ KUNIT_CASE(filter_attr_skip_test),
{}
};

--
2.41.0.487.g6d72f3e995-goog


2023-07-25 22:02:36

by Rae Moar

[permalink] [raw]
Subject: [PATCH v3 4/9] kunit: Add ability to filter attributes

Add filtering of test attributes. Users can filter tests using the
module_param called "filter".

Filters are imputed in the format: <attribute_name><operation><value>

Example: kunit.filter="speed>slow"

Operations include: >, <, >=, <=, !=, and =. These operations will act the
same for attributes of the same type but may not between types.

Note multiple filters can be inputted by separating them with a comma.
Example: kunit.filter="speed=slow, module!=example"

Since both suites and test cases can have attributes, there may be
conflicts. The process of filtering follows these rules:
- Filtering always operates at a per-test level.
- If a test has an attribute set, then the test's value is filtered on.
- Otherwise, the value falls back to the suite's value.
- If neither are set, the attribute has a global "default" value, which
is used.

Filtered tests will not be run or show in output. The tests can instead be
skipped using the configurable option "kunit.filter_action=skip".

Note the default settings for running tests remains unfiltered.

Finally, add "filter" methods for the speed and module attributes to parse
and compare attribute values.

Note this filtering functionality will be added to kunit.py in the next
patch.

Reviewed-by: David Gow <[email protected]>
Signed-off-by: Rae Moar <[email protected]>
---

Changes since v2:
- Remove extra line.
Changes since v1:
- Fix compile warning of use of uninitialized variable
Changes since RFC v2:
- Change to output only one error before exiting.
Changes since RFC v1:
- Change method for inputting filters to allow for spaces in filtering
values
- Add option to skip filtered tests instead of not run or show them with
the- –filter_skip flag

include/kunit/attributes.h | 31 +++++
lib/kunit/attributes.c | 271 +++++++++++++++++++++++++++++++++++++
lib/kunit/executor.c | 93 ++++++++++---
lib/kunit/executor_test.c | 12 +-
lib/kunit/test.c | 10 +-
5 files changed, 389 insertions(+), 28 deletions(-)

diff --git a/include/kunit/attributes.h b/include/kunit/attributes.h
index 9fcd184cce36..bc76a0b786d2 100644
--- a/include/kunit/attributes.h
+++ b/include/kunit/attributes.h
@@ -9,6 +9,20 @@
#ifndef _KUNIT_ATTRIBUTES_H
#define _KUNIT_ATTRIBUTES_H

+/*
+ * struct kunit_attr_filter - representation of attributes filter with the
+ * attribute object and string input
+ */
+struct kunit_attr_filter {
+ struct kunit_attr *attr;
+ char *input;
+};
+
+/*
+ * Returns the name of the filter's attribute.
+ */
+const char *kunit_attr_filter_name(struct kunit_attr_filter filter);
+
/*
* Print all test attributes for a test case or suite.
* Output format for test cases: "# <test_name>.<attribute>: <value>"
@@ -16,4 +30,21 @@
*/
void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level);

+/*
+ * Returns the number of fitlers in input.
+ */
+int kunit_get_filter_count(char *input);
+
+/*
+ * Parse attributes filter input and return an objects containing the
+ * attribute object and the string input of the next filter.
+ */
+struct kunit_attr_filter kunit_next_attr_filter(char **filters, int *err);
+
+/*
+ * Returns a copy of the suite containing only tests that pass the filter.
+ */
+struct kunit_suite *kunit_filter_attr_tests(const struct kunit_suite *const suite,
+ struct kunit_attr_filter filter, char *action, int *err);
+
#endif /* _KUNIT_ATTRIBUTES_H */
diff --git a/lib/kunit/attributes.c b/lib/kunit/attributes.c
index 9dce4f4d726c..d37c40c0ce4f 100644
--- a/lib/kunit/attributes.c
+++ b/lib/kunit/attributes.c
@@ -67,6 +67,104 @@ static const char *attr_string_to_string(void *attr, bool *to_free)
return (char *) attr;
}

+/* Filter Methods */
+
+static const char op_list[] = "<>!=";
+
+/*
+ * Returns whether the inputted integer value matches the filter given
+ * by the operation string and inputted integer.
+ */
+static int int_filter(long val, const char *op, int input, int *err)
+{
+ if (!strncmp(op, "<=", 2))
+ return (val <= input);
+ else if (!strncmp(op, ">=", 2))
+ return (val >= input);
+ else if (!strncmp(op, "!=", 2))
+ return (val != input);
+ else if (!strncmp(op, ">", 1))
+ return (val > input);
+ else if (!strncmp(op, "<", 1))
+ return (val < input);
+ else if (!strncmp(op, "=", 1))
+ return (val == input);
+ *err = -EINVAL;
+ pr_err("kunit executor: invalid filter operation: %s\n", op);
+ return false;
+}
+
+/*
+ * Returns whether the inputted enum value "attr" matches the filter given
+ * by the input string. Note: the str_list includes the corresponding string
+ * list to the enum values.
+ */
+static int attr_enum_filter(void *attr, const char *input, int *err,
+ const char * const str_list[], int max)
+{
+ int i, j, input_int;
+ long test_val = (long)attr;
+ const char *input_val = NULL;
+
+ for (i = 0; input[i]; i++) {
+ if (!strchr(op_list, input[i])) {
+ input_val = input + i;
+ break;
+ }
+ }
+
+ if (!input_val) {
+ *err = -EINVAL;
+ pr_err("kunit executor: filter value not found: %s\n", input);
+ return false;
+ }
+
+ for (j = 0; j <= max; j++) {
+ if (!strcmp(input_val, str_list[j]))
+ input_int = j;
+ }
+
+ if (!input_int) {
+ *err = -EINVAL;
+ pr_err("kunit executor: invalid filter input: %s\n", input);
+ return false;
+ }
+
+ return int_filter(test_val, input, input_int, err);
+}
+
+static int attr_speed_filter(void *attr, const char *input, int *err)
+{
+ return attr_enum_filter(attr, input, err, speed_str_list, KUNIT_SPEED_MAX);
+}
+
+/*
+ * Returns whether the inputted string value (attr) matches the filter given
+ * by the input string.
+ */
+static int attr_string_filter(void *attr, const char *input, int *err)
+{
+ char *str = attr;
+
+ if (!strncmp(input, "<", 1)) {
+ *err = -EINVAL;
+ pr_err("kunit executor: invalid filter input: %s\n", input);
+ return false;
+ } else if (!strncmp(input, ">", 1)) {
+ *err = -EINVAL;
+ pr_err("kunit executor: invalid filter input: %s\n", input);
+ return false;
+ } else if (!strncmp(input, "!=", 2)) {
+ return (strcmp(input + 2, str) != 0);
+ } else if (!strncmp(input, "=", 1)) {
+ return (strcmp(input + 1, str) == 0);
+ }
+ *err = -EINVAL;
+ pr_err("kunit executor: invalid filter operation: %s\n", input);
+ return false;
+}
+
+
/* Get Attribute Methods */

static void *attr_speed_get(void *test_or_suite, bool is_test)
@@ -99,6 +197,7 @@ static struct kunit_attr kunit_attr_list[] = {
.name = "speed",
.get_attr = attr_speed_get,
.to_string = attr_speed_to_string,
+ .filter = attr_speed_filter,
.attr_default = (void *)KUNIT_SPEED_NORMAL,
.print = PRINT_ALWAYS,
},
@@ -106,6 +205,7 @@ static struct kunit_attr kunit_attr_list[] = {
.name = "module",
.get_attr = attr_module_get,
.to_string = attr_string_to_string,
+ .filter = attr_string_filter,
.attr_default = (void *)"",
.print = PRINT_SUITE,
}
@@ -113,6 +213,11 @@ static struct kunit_attr kunit_attr_list[] = {

/* Helper Functions to Access Attributes */

+const char *kunit_attr_filter_name(struct kunit_attr_filter filter)
+{
+ return filter.attr->name;
+}
+
void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level)
{
int i;
@@ -145,3 +250,169 @@ void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level
}
}
}
+
+/* Helper Functions to Filter Attributes */
+
+int kunit_get_filter_count(char *input)
+{
+ int i, comma_index, count = 0;
+
+ for (i = 0; input[i]; i++) {
+ if (input[i] == ',') {
+ if ((i - comma_index) > 1)
+ count++;
+ comma_index = i;
+ }
+ }
+ if ((i - comma_index) > 0)
+ count++;
+ return count;
+}
+
+struct kunit_attr_filter kunit_next_attr_filter(char **filters, int *err)
+{
+ struct kunit_attr_filter filter = {};
+ int i, j, comma_index, new_start_index;
+ int op_index = -1, attr_index = -1;
+ char op;
+ char *input = *filters;
+
+ /* Parse input until operation */
+ for (i = 0; input[i]; i++) {
+ if (op_index < 0 && strchr(op_list, input[i])) {
+ op_index = i;
+ } else if (!comma_index && input[i] == ',') {
+ comma_index = i;
+ } else if (comma_index && input[i] != ' ') {
+ new_start_index = i;
+ break;
+ }
+ }
+
+ if (op_index <= 0) {
+ *err = -EINVAL;
+ pr_err("kunit executor: filter operation not found: %s\n", input);
+ return filter;
+ }
+
+ /* Temporarily set operator to \0 character. */
+ op = input[op_index];
+ input[op_index] = '\0';
+
+ /* Find associated kunit_attr object */
+ for (j = 0; j < ARRAY_SIZE(kunit_attr_list); j++) {
+ if (!strcmp(input, kunit_attr_list[j].name)) {
+ attr_index = j;
+ break;
+ }
+ }
+
+ input[op_index] = op;
+
+ if (attr_index < 0) {
+ *err = -EINVAL;
+ pr_err("kunit executor: attribute not found: %s\n", input);
+ } else {
+ filter.attr = &kunit_attr_list[attr_index];
+ }
+
+ if (comma_index) {
+ input[comma_index] = '\0';
+ filter.input = input + op_index;
+ input = input + new_start_index;
+ } else {
+ filter.input = input + op_index;
+ input = NULL;
+ }
+
+ *filters = input;
+
+ return filter;
+}
+
+struct kunit_suite *kunit_filter_attr_tests(const struct kunit_suite *const suite,
+ struct kunit_attr_filter filter, char *action, int *err)
+{
+ int n = 0;
+ struct kunit_case *filtered, *test_case;
+ struct kunit_suite *copy;
+ void *suite_val, *test_val;
+ bool suite_result, test_result, default_result, result;
+
+ /* Allocate memory for new copy of suite and list of test cases */
+ copy = kmemdup(suite, sizeof(*copy), GFP_KERNEL);
+ if (!copy)
+ return ERR_PTR(-ENOMEM);
+
+ kunit_suite_for_each_test_case(suite, test_case) { n++; }
+
+ filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL);
+ if (!filtered) {
+ kfree(copy);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ n = 0;
+
+ /* Save filtering result on default value */
+ default_result = filter.attr->filter(filter.attr->attr_default, filter.input, err);
+ if (*err) {
+ kfree(copy);
+ kfree(filtered);
+ return NULL;
+ }
+
+ /* Save suite attribute value and filtering result on that value */
+ suite_val = filter.attr->get_attr((void *)suite, false);
+ suite_result = filter.attr->filter(suite_val, filter.input, err);
+ if (*err) {
+ kfree(copy);
+ kfree(filtered);
+ return NULL;
+ }
+
+ /* For each test case, save test case if passes filtering. */
+ kunit_suite_for_each_test_case(suite, test_case) {
+ test_val = filter.attr->get_attr((void *) test_case, true);
+ test_result = filter.attr->filter(filter.attr->get_attr(test_case, true),
+ filter.input, err);
+ if (*err) {
+ kfree(copy);
+ kfree(filtered);
+ return NULL;
+ }
+
+ /*
+ * If attribute value of test case is set, filter on that value.
+ * If not, filter on suite value if set. If not, filter on
+ * default value.
+ */
+ result = false;
+ if (test_val) {
+ if (test_result)
+ result = true;
+ } else if (suite_val) {
+ if (suite_result)
+ result = true;
+ } else if (default_result) {
+ result = true;
+ }
+
+ if (result) {
+ filtered[n++] = *test_case;
+ } else if (action && strcmp(action, "skip") == 0) {
+ test_case->status = KUNIT_SKIPPED;
+ filtered[n++] = *test_case;
+ }
+ }
+
+ if (n == 0) {
+ kfree(copy);
+ kfree(filtered);
+ return NULL;
+ }
+
+ copy->test_cases = filtered;
+
+ return copy;
+}
diff --git a/lib/kunit/executor.c b/lib/kunit/executor.c
index 12e38a48a5cc..483f7b7873a7 100644
--- a/lib/kunit/executor.c
+++ b/lib/kunit/executor.c
@@ -17,6 +17,8 @@ extern struct kunit_suite * const __kunit_suites_end[];

static char *filter_glob_param;
static char *action_param;
+static char *filter_param;
+static char *filter_action_param;

module_param_named(filter_glob, filter_glob_param, charp, 0);
MODULE_PARM_DESC(filter_glob,
@@ -27,15 +29,23 @@ MODULE_PARM_DESC(action,
"<none>: run the tests like normal\n"
"'list' to list test names instead of running them.\n"
"'list_attr' to list test names and attributes instead of running them.\n");
+module_param_named(filter, filter_param, charp, 0);
+MODULE_PARM_DESC(filter,
+ "Filter which KUnit test suites/tests run at boot-time using attributes, e.g. speed>slow");
+module_param_named(filter_action, filter_action_param, charp, 0);
+MODULE_PARM_DESC(filter_action,
+ "Changes behavior of filtered tests using attributes, valid values are:\n"
+ "<none>: do not run filtered tests as normal\n"
+ "'skip': skip all filtered tests instead so tests will appear in output\n");

/* glob_match() needs NULL terminated strings, so we need a copy of filter_glob_param. */
-struct kunit_test_filter {
+struct kunit_glob_filter {
char *suite_glob;
char *test_glob;
};

/* Split "suite_glob.test_glob" into two. Assumes filter_glob is not empty. */
-static void kunit_parse_filter_glob(struct kunit_test_filter *parsed,
+static void kunit_parse_glob_filter(struct kunit_glob_filter *parsed,
const char *filter_glob)
{
const int len = strlen(filter_glob);
@@ -57,7 +67,7 @@ static void kunit_parse_filter_glob(struct kunit_test_filter *parsed,

/* Create a copy of suite with only tests that match test_glob. */
static struct kunit_suite *
-kunit_filter_tests(const struct kunit_suite *const suite, const char *test_glob)
+kunit_filter_glob_tests(const struct kunit_suite *const suite, const char *test_glob)
{
int n = 0;
struct kunit_case *filtered, *test_case;
@@ -111,12 +121,15 @@ static void kunit_free_suite_set(struct suite_set suite_set)

static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
const char *filter_glob,
+ char *filters,
+ char *filter_action,
int *err)
{
- int i;
- struct kunit_suite **copy, *filtered_suite;
+ int i, j, k, filter_count;
+ struct kunit_suite **copy, *filtered_suite, *new_filtered_suite;
struct suite_set filtered;
- struct kunit_test_filter filter;
+ struct kunit_glob_filter parsed_glob;
+ struct kunit_attr_filter *parsed_filters;

const size_t max = suite_set->end - suite_set->start;

@@ -127,17 +140,52 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
return filtered;
}

- kunit_parse_filter_glob(&filter, filter_glob);
+ if (filter_glob)
+ kunit_parse_glob_filter(&parsed_glob, filter_glob);

- for (i = 0; &suite_set->start[i] != suite_set->end; i++) {
- if (!glob_match(filter.suite_glob, suite_set->start[i]->name))
- continue;
-
- filtered_suite = kunit_filter_tests(suite_set->start[i], filter.test_glob);
- if (IS_ERR(filtered_suite)) {
- *err = PTR_ERR(filtered_suite);
+ /* Parse attribute filters */
+ if (filters) {
+ filter_count = kunit_get_filter_count(filters);
+ parsed_filters = kcalloc(filter_count + 1, sizeof(*parsed_filters), GFP_KERNEL);
+ for (j = 0; j < filter_count; j++)
+ parsed_filters[j] = kunit_next_attr_filter(&filters, err);
+ if (*err)
return filtered;
+ }
+
+ for (i = 0; &suite_set->start[i] != suite_set->end; i++) {
+ filtered_suite = suite_set->start[i];
+ if (filter_glob) {
+ if (!glob_match(parsed_glob.suite_glob, filtered_suite->name))
+ continue;
+ filtered_suite = kunit_filter_glob_tests(filtered_suite,
+ parsed_glob.test_glob);
+ if (IS_ERR(filtered_suite)) {
+ *err = PTR_ERR(filtered_suite);
+ return filtered;
+ }
}
+ if (filter_count) {
+ for (k = 0; k < filter_count; k++) {
+ new_filtered_suite = kunit_filter_attr_tests(filtered_suite,
+ parsed_filters[k], filter_action, err);
+
+ /* Free previous copy of suite */
+ if (k > 0 || filter_glob)
+ kfree(filtered_suite);
+ filtered_suite = new_filtered_suite;
+
+ if (*err)
+ return filtered;
+ if (IS_ERR(filtered_suite)) {
+ *err = PTR_ERR(filtered_suite);
+ return filtered;
+ }
+ if (!filtered_suite)
+ break;
+ }
+ }
+
if (!filtered_suite)
continue;

@@ -145,8 +193,14 @@ static struct suite_set kunit_filter_suites(const struct suite_set *suite_set,
}
filtered.end = copy;

- kfree(filter.suite_glob);
- kfree(filter.test_glob);
+ if (filter_glob) {
+ kfree(parsed_glob.suite_glob);
+ kfree(parsed_glob.test_glob);
+ }
+
+ if (filter_count)
+ kfree(parsed_filters);
+
return filtered;
}

@@ -206,8 +260,9 @@ int kunit_run_all_tests(void)
goto out;
}

- if (filter_glob_param) {
- suite_set = kunit_filter_suites(&suite_set, filter_glob_param, &err);
+ if (filter_glob_param || filter_param) {
+ suite_set = kunit_filter_suites(&suite_set, filter_glob_param,
+ filter_param, filter_action_param, &err);
if (err) {
pr_err("kunit executor: error filtering suites: %d\n", err);
goto out;
@@ -223,7 +278,7 @@ int kunit_run_all_tests(void)
else
pr_err("kunit executor: unknown action '%s'\n", action_param);

- if (filter_glob_param) { /* a copy was made of each suite */
+ if (filter_glob_param || filter_param) { /* a copy was made of each suite */
kunit_free_suite_set(suite_set);
}

diff --git a/lib/kunit/executor_test.c b/lib/kunit/executor_test.c
index ce6749af374d..d7ab069324b5 100644
--- a/lib/kunit/executor_test.c
+++ b/lib/kunit/executor_test.c
@@ -24,15 +24,15 @@ static struct kunit_case dummy_test_cases[] = {

static void parse_filter_test(struct kunit *test)
{
- struct kunit_test_filter filter = {NULL, NULL};
+ struct kunit_glob_filter filter = {NULL, NULL};

- kunit_parse_filter_glob(&filter, "suite");
+ kunit_parse_glob_filter(&filter, "suite");
KUNIT_EXPECT_STREQ(test, filter.suite_glob, "suite");
KUNIT_EXPECT_FALSE(test, filter.test_glob);
kfree(filter.suite_glob);
kfree(filter.test_glob);

- kunit_parse_filter_glob(&filter, "suite.test");
+ kunit_parse_glob_filter(&filter, "suite.test");
KUNIT_EXPECT_STREQ(test, filter.suite_glob, "suite");
KUNIT_EXPECT_STREQ(test, filter.test_glob, "test");
kfree(filter.suite_glob);
@@ -50,7 +50,7 @@ static void filter_suites_test(struct kunit *test)
subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases);

/* Want: suite1, suite2, NULL -> suite2, NULL */
- got = kunit_filter_suites(&suite_set, "suite2", &err);
+ got = kunit_filter_suites(&suite_set, "suite2", NULL, NULL, &err);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
KUNIT_ASSERT_EQ(test, err, 0);
kfree_at_end(test, got.start);
@@ -74,7 +74,7 @@ static void filter_suites_test_glob_test(struct kunit *test)
subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases);

/* Want: suite1, suite2, NULL -> suite2 (just test1), NULL */
- got = kunit_filter_suites(&suite_set, "suite2.test2", &err);
+ got = kunit_filter_suites(&suite_set, "suite2.test2", NULL, NULL, &err);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
KUNIT_ASSERT_EQ(test, err, 0);
kfree_at_end(test, got.start);
@@ -100,7 +100,7 @@ static void filter_suites_to_empty_test(struct kunit *test)
subsuite[0] = alloc_fake_suite(test, "suite1", dummy_test_cases);
subsuite[1] = alloc_fake_suite(test, "suite2", dummy_test_cases);

- got = kunit_filter_suites(&suite_set, "not_found", &err);
+ got = kunit_filter_suites(&suite_set, "not_found", NULL, NULL, &err);
KUNIT_ASSERT_EQ(test, err, 0);
kfree_at_end(test, got.start); /* just in case */

diff --git a/lib/kunit/test.c b/lib/kunit/test.c
index 9ee55139ecd1..cb9797fa6303 100644
--- a/lib/kunit/test.c
+++ b/lib/kunit/test.c
@@ -613,18 +613,22 @@ int kunit_run_tests(struct kunit_suite *suite)
kunit_suite_for_each_test_case(suite, test_case) {
struct kunit test = { .param_value = NULL, .param_index = 0 };
struct kunit_result_stats param_stats = { 0 };
- test_case->status = KUNIT_SKIPPED;

kunit_init_test(&test, test_case->name, test_case->log);
-
- if (!test_case->generate_params) {
+ if (test_case->status == KUNIT_SKIPPED) {
+ /* Test marked as skip */
+ test.status = KUNIT_SKIPPED;
+ kunit_update_stats(&param_stats, test.status);
+ } else if (!test_case->generate_params) {
/* Non-parameterised test. */
+ test_case->status = KUNIT_SKIPPED;
kunit_run_case_catch_errors(suite, test_case, &test);
kunit_update_stats(&param_stats, test.status);
} else {
/* Get initial param. */
param_desc[0] = '\0';
test.param_value = test_case->generate_params(NULL, param_desc);
+ test_case->status = KUNIT_SKIPPED;
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
"KTAP version 1\n");
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
--
2.41.0.487.g6d72f3e995-goog


2023-07-25 22:02:54

by Rae Moar

[permalink] [raw]
Subject: [PATCH v3 6/9] kunit: memcpy: Mark tests as slow using test attributes

Mark slow memcpy KUnit tests using test attributes.

Tests marked as slow are as follows: memcpy_large_test, memmove_test,
memmove_large_test, and memmove_overlap_test. These tests were the slowest
of the memcpy tests and relatively slower to most other KUnit tests. Most
of these tests are already skipped when CONFIG_MEMCPY_SLOW_KUNIT_TEST is
not enabled.

These tests can now be filtered using the KUnit test attribute filtering
feature. Example: --filter "speed>slow". This will run only the tests that
have speeds faster than slow. The slow attribute will also be outputted in
KTAP.

Note: This patch is intended to replace the use of
CONFIG_MEMCPY_SLOW_KUNIT_TEST and to potentially deprecate this feature.
This patch does not remove the config option but does add a note to the
config definition commenting on this future shift.

Reviewed-by: David Gow <[email protected]>
Acked-by: Kees Cook <[email protected]>
Signed-off-by: Rae Moar <[email protected]>
---

Changes since v2:
- No changes.
Changes since v1:
- No major changes
Changes since RFC v2:
- No changes.
Changes since RFC v1:
- Added note under CONFIG_MEMCPY_SLOW_KUNIT_TEST.

lib/Kconfig.debug | 3 +++
lib/memcpy_kunit.c | 8 ++++----
2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 550cb967b668..1b3894e861f2 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2701,6 +2701,9 @@ config MEMCPY_SLOW_KUNIT_TEST
and bit ranges. These can be very slow, so they are split out
as a separate config, in case they need to be disabled.

+ Note this config option will be replaced by the use of KUnit test
+ attributes.
+
config IS_SIGNED_TYPE_KUNIT_TEST
tristate "Test is_signed_type() macro" if !KUNIT_ALL_TESTS
depends on KUNIT
diff --git a/lib/memcpy_kunit.c b/lib/memcpy_kunit.c
index 887926f04731..440aee705ccc 100644
--- a/lib/memcpy_kunit.c
+++ b/lib/memcpy_kunit.c
@@ -551,10 +551,10 @@ static void strtomem_test(struct kunit *test)
static struct kunit_case memcpy_test_cases[] = {
KUNIT_CASE(memset_test),
KUNIT_CASE(memcpy_test),
- KUNIT_CASE(memcpy_large_test),
- KUNIT_CASE(memmove_test),
- KUNIT_CASE(memmove_large_test),
- KUNIT_CASE(memmove_overlap_test),
+ KUNIT_CASE_SLOW(memcpy_large_test),
+ KUNIT_CASE_SLOW(memmove_test),
+ KUNIT_CASE_SLOW(memmove_large_test),
+ KUNIT_CASE_SLOW(memmove_overlap_test),
KUNIT_CASE(strtomem_test),
{}
};
--
2.41.0.487.g6d72f3e995-goog


2023-07-25 22:03:53

by Rae Moar

[permalink] [raw]
Subject: [PATCH v3 3/9] kunit: Add module attribute

Add module attribute to the test attribute API. This attribute stores the
module name associated with the test using KBUILD_MODNAME.

The name of a test suite and the module name often do not match. A
reference to the module name associated with the suite could be extremely
helpful in running tests as modules without needing to check the codebase.

This attribute will be printed for each suite.

Reviewed-by: David Gow <[email protected]>
Signed-off-by: Rae Moar <[email protected]>
---

Changes since v2:
- No changes.
Changes since v1:
- Change kunit_attr_list definition to fix compile error
Changes since RFC v2:
- No changes.
Changes: since RFC v1:
- This is a new patch.

include/kunit/test.h | 13 ++++++++-----
lib/kunit/attributes.c | 25 +++++++++++++++++++++++++
2 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/include/kunit/test.h b/include/kunit/test.h
index ed5f5000a095..011e0d6bb506 100644
--- a/include/kunit/test.h
+++ b/include/kunit/test.h
@@ -131,6 +131,7 @@ struct kunit_case {

/* private: internal use only. */
enum kunit_status status;
+ char *module_name;
char *log;
};

@@ -155,7 +156,9 @@ static inline char *kunit_status_to_ok_not_ok(enum kunit_status status)
* &struct kunit_case object from it. See the documentation for
* &struct kunit_case for an example on how to use it.
*/
-#define KUNIT_CASE(test_name) { .run_case = test_name, .name = #test_name }
+#define KUNIT_CASE(test_name) \
+ { .run_case = test_name, .name = #test_name, \
+ .module_name = KBUILD_MODNAME}

/**
* KUNIT_CASE_ATTR - A helper for creating a &struct kunit_case
@@ -167,7 +170,7 @@ static inline char *kunit_status_to_ok_not_ok(enum kunit_status status)
*/
#define KUNIT_CASE_ATTR(test_name, attributes) \
{ .run_case = test_name, .name = #test_name, \
- .attr = attributes }
+ .attr = attributes, .module_name = KBUILD_MODNAME}

/**
* KUNIT_CASE_SLOW - A helper for creating a &struct kunit_case
@@ -178,7 +181,7 @@ static inline char *kunit_status_to_ok_not_ok(enum kunit_status status)

#define KUNIT_CASE_SLOW(test_name) \
{ .run_case = test_name, .name = #test_name, \
- .attr.speed = KUNIT_SPEED_SLOW }
+ .attr.speed = KUNIT_SPEED_SLOW, .module_name = KBUILD_MODNAME}

/**
* KUNIT_CASE_PARAM - A helper for creation a parameterized &struct kunit_case
@@ -199,7 +202,7 @@ static inline char *kunit_status_to_ok_not_ok(enum kunit_status status)
*/
#define KUNIT_CASE_PARAM(test_name, gen_params) \
{ .run_case = test_name, .name = #test_name, \
- .generate_params = gen_params }
+ .generate_params = gen_params, .module_name = KBUILD_MODNAME}

/**
* KUNIT_CASE_PARAM_ATTR - A helper for creating a parameterized &struct
@@ -213,7 +216,7 @@ static inline char *kunit_status_to_ok_not_ok(enum kunit_status status)
#define KUNIT_CASE_PARAM_ATTR(test_name, gen_params, attributes) \
{ .run_case = test_name, .name = #test_name, \
.generate_params = gen_params, \
- .attr = attributes }
+ .attr = attributes, .module_name = KBUILD_MODNAME}

/**
* struct kunit_suite - describes a related collection of &struct kunit_case
diff --git a/lib/kunit/attributes.c b/lib/kunit/attributes.c
index ffd0d692b334..9dce4f4d726c 100644
--- a/lib/kunit/attributes.c
+++ b/lib/kunit/attributes.c
@@ -61,6 +61,12 @@ static const char *attr_speed_to_string(void *attr, bool *to_free)
return attr_enum_to_string(attr, speed_str_list, to_free);
}

+static const char *attr_string_to_string(void *attr, bool *to_free)
+{
+ *to_free = false;
+ return (char *) attr;
+}
+
/* Get Attribute Methods */

static void *attr_speed_get(void *test_or_suite, bool is_test)
@@ -74,6 +80,18 @@ static void *attr_speed_get(void *test_or_suite, bool is_test)
return ((void *) suite->attr.speed);
}

+static void *attr_module_get(void *test_or_suite, bool is_test)
+{
+ struct kunit_suite *suite = is_test ? NULL : test_or_suite;
+ struct kunit_case *test = is_test ? test_or_suite : NULL;
+
+ // Suites get their module attribute from their first test_case
+ if (test)
+ return ((void *) test->module_name);
+ else
+ return ((void *) suite->test_cases[0].module_name);
+}
+
/* List of all Test Attributes */

static struct kunit_attr kunit_attr_list[] = {
@@ -84,6 +102,13 @@ static struct kunit_attr kunit_attr_list[] = {
.attr_default = (void *)KUNIT_SPEED_NORMAL,
.print = PRINT_ALWAYS,
},
+ {
+ .name = "module",
+ .get_attr = attr_module_get,
+ .to_string = attr_string_to_string,
+ .attr_default = (void *)"",
+ .print = PRINT_SUITE,
+ }
};

/* Helper Functions to Access Attributes */
--
2.41.0.487.g6d72f3e995-goog


2023-07-26 15:15:19

by Arthur Grillo

[permalink] [raw]
Subject: Re: [PATCH v3 0/9] kunit: Add test attributes API



On 25/07/23 18:25, 'Rae Moar' via KUnit Development wrote:
> Hello everyone,
>
> This patch series adds a test attributes framework to KUnit.
>
> There has been interest in filtering out "slow" KUnit tests. Most notably,
> a new config, CONFIG_MEMCPY_SLOW_KUNIT_TEST, has been added to exclude a
> particularly slow memcpy test
> (https://lore.kernel.org/all/[email protected]/).
>
> This attributes framework can be used to save and access test associated
> data, including whether a test is slow. These attributes are reportable
> (via KTAP and command line output) and are also filterable.
>
> This framework is designed to allow for the addition of other attributes in
> the future. These attributes could include whether the test can be run
> concurrently, test file path, etc.
>
> To try out the framework I suggest running:
> "./tools/testing/kunit/kunit.py run --filter speed!=slow"
>
> This patch series was originally sent out as an RFC. Here is a link to the
> RFC v2:
> https://lore.kernel.org/all/[email protected]/
>
> Thanks!
> Rae
>

Great addition to the KUnit framework!

On all the patch set

Reviewed-by: Arthur Grillo <[email protected]>

Best Regards,
~Arthur Grillo

> Rae Moar (9):
> kunit: Add test attributes API structure
> kunit: Add speed attribute
> kunit: Add module attribute
> kunit: Add ability to filter attributes
> kunit: tool: Add command line interface to filter and report
> attributes
> kunit: memcpy: Mark tests as slow using test attributes
> kunit: time: Mark test as slow using test attributes
> kunit: add tests for filtering attributes
> kunit: Add documentation of KUnit test attributes
>
> Documentation/dev-tools/kunit/run_wrapper.rst | 12 +
> .../dev-tools/kunit/running_tips.rst | 166 +++++++
> include/kunit/attributes.h | 50 +++
> include/kunit/test.h | 70 ++-
> kernel/time/time_test.c | 2 +-
> lib/Kconfig.debug | 3 +
> lib/kunit/Makefile | 3 +-
> lib/kunit/attributes.c | 418 ++++++++++++++++++
> lib/kunit/executor.c | 114 ++++-
> lib/kunit/executor_test.c | 128 +++++-
> lib/kunit/kunit-example-test.c | 9 +
> lib/kunit/test.c | 27 +-
> lib/memcpy_kunit.c | 8 +-
> tools/testing/kunit/kunit.py | 70 ++-
> tools/testing/kunit/kunit_kernel.py | 8 +-
> tools/testing/kunit/kunit_parser.py | 11 +-
> tools/testing/kunit/kunit_tool_test.py | 39 +-
> 17 files changed, 1062 insertions(+), 76 deletions(-)
> create mode 100644 include/kunit/attributes.h
> create mode 100644 lib/kunit/attributes.c
>
>
> base-commit: 64bd4641310c41a1ecf07c13c67bc0ed61045dfd

2023-07-26 16:05:14

by Arthur Grillo

[permalink] [raw]
Subject: Re: [PATCH v3 0/9] kunit: Add test attributes API



On 25/07/23 18:25, 'Rae Moar' via KUnit Development wrote:
> Hello everyone,
>
> This patch series adds a test attributes framework to KUnit.
>
> There has been interest in filtering out "slow" KUnit tests. Most notably,
> a new config, CONFIG_MEMCPY_SLOW_KUNIT_TEST, has been added to exclude a
> particularly slow memcpy test
> (https://lore.kernel.org/all/[email protected]/).
>
> This attributes framework can be used to save and access test associated
> data, including whether a test is slow. These attributes are reportable
> (via KTAP and command line output) and are also filterable.
>
> This framework is designed to allow for the addition of other attributes in
> the future. These attributes could include whether the test can be run
> concurrently, test file path, etc.
>
> To try out the framework I suggest running:
> "./tools/testing/kunit/kunit.py run --filter speed!=slow"
>
> This patch series was originally sent out as an RFC. Here is a link to the
> RFC v2:
> https://lore.kernel.org/all/[email protected]/
>
> Thanks!
> Rae
>

Great addition to the KUnit framework!

On all the patch set

Reviewed-by: Arthur Grillo <[email protected]>

Best Regards,
~Arthur Grillo

> Rae Moar (9):
> kunit: Add test attributes API structure
> kunit: Add speed attribute
> kunit: Add module attribute
> kunit: Add ability to filter attributes
> kunit: tool: Add command line interface to filter and report
> attributes
> kunit: memcpy: Mark tests as slow using test attributes
> kunit: time: Mark test as slow using test attributes
> kunit: add tests for filtering attributes
> kunit: Add documentation of KUnit test attributes
>
> Documentation/dev-tools/kunit/run_wrapper.rst | 12 +
> .../dev-tools/kunit/running_tips.rst | 166 +++++++
> include/kunit/attributes.h | 50 +++
> include/kunit/test.h | 70 ++-
> kernel/time/time_test.c | 2 +-
> lib/Kconfig.debug | 3 +
> lib/kunit/Makefile | 3 +-
> lib/kunit/attributes.c | 418 ++++++++++++++++++
> lib/kunit/executor.c | 114 ++++-
> lib/kunit/executor_test.c | 128 +++++-
> lib/kunit/kunit-example-test.c | 9 +
> lib/kunit/test.c | 27 +-
> lib/memcpy_kunit.c | 8 +-
> tools/testing/kunit/kunit.py | 70 ++-
> tools/testing/kunit/kunit_kernel.py | 8 +-
> tools/testing/kunit/kunit_parser.py | 11 +-
> tools/testing/kunit/kunit_tool_test.py | 39 +-
> 17 files changed, 1062 insertions(+), 76 deletions(-)
> create mode 100644 include/kunit/attributes.h
> create mode 100644 lib/kunit/attributes.c
>
>
> base-commit: 64bd4641310c41a1ecf07c13c67bc0ed61045dfd

2023-07-28 11:58:36

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH v3 0/9] kunit: Add test attributes API

On Tue, Jul 25, 2023 at 09:25:11PM +0000, Rae Moar wrote:
> Hello everyone,
>
> This patch series adds a test attributes framework to KUnit.
>

With this series in linux-next, almost 50% of my boot tests crash,
and many others show warnings tracebacks.

Example crash from x86_64 boot attempt attached.

Guenter

---
[ 6.165419] ok 6 lib_sort
[ 6.166044] KTAP version 1
[ 6.166139] # Subtest: kunit_executor_test
[ 6.166247] # module: kunit
[ 6.166261] 1..8
[ 6.168252] ok 1 parse_filter_test
[ 6.169579] BUG: unable to handle page fault for address: ffffd757e80004c8
[ 6.169872] #PF: supervisor read access in kernel mode
[ 6.169990] #PF: error_code(0x0000) - not-present page
[ 6.170142] PGD ffd4067 P4D ffd4067 PUD 0
[ 6.170346] Oops: 0000 [#1] PREEMPT SMP PTI
[ 6.170521] CPU: 0 PID: 182 Comm: kunit_try_catch Tainted: G N 6.5.0-rc3-next-20230728 #1
[ 6.170735] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014
[ 6.171024] RIP: 0010:kfree+0x61/0x140
[ 6.171313] Code: 80 48 01 e8 0f 82 ec 00 00 00 48 c7 c2 00 00 00 80 48 2b 15 29 bf aa 01 48 01 d0 48 c1 e8 0c 48 c1 e0 06 48 03 05 07 bf aa 01 <48> 8b 50 08 48 89 c7 f6 c2 01 0f 85 b3 00 00 00 66 90 48 8b 07 f6
[ 6.171715] RSP: 0000:ffffb48f80267dc8 EFLAGS: 00000286
[ 6.171847] RAX: ffffd757e80004c0 RBX: ffffa34583aef5d0 RCX: 0000000000000000
[ 6.171998] RDX: 00005cba00000000 RSI: ffffffff95cb1ad5 RDI: ffffb48f80013cd0
[ 6.172146] RBP: ffffb48f80013cd0 R08: 0000000000000001 R09: 0000000000000001
[ 6.172293] R10: 0000000000000001 R11: 0000000000000001 R12: ffffb48f80267e74
[ 6.172445] R13: 0000000000000000 R14: ffffa34583bf4000 R15: 0000000000000002
[ 6.172620] FS: 0000000000000000(0000) GS:ffffa3458f800000(0000) knlGS:0000000000000000
[ 6.172793] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 6.172917] CR2: ffffd757e80004c8 CR3: 0000000009048000 CR4: 00000000007506f0
[ 6.173089] PKRU: 55555554
[ 6.173177] Call Trace:
[ 6.173313] <TASK>
[ 6.173494] ? __die+0x1f/0x70
[ 6.173600] ? page_fault_oops+0x14a/0x460
[ 6.173693] ? search_exception_tables+0x37/0x50
[ 6.173793] ? fixup_exception+0x21/0x310
[ 6.173887] ? exc_page_fault+0xee/0x1c0
[ 6.173977] ? asm_exc_page_fault+0x26/0x30
[ 6.174076] ? kunit_filter_suites+0x3a5/0x460
[ 6.174192] ? kfree+0x61/0x140
[ 6.174271] ? kfree+0x106/0x140
[ 6.174353] kunit_filter_suites+0x3a5/0x460
[ 6.174473] ? __pfx_kunit_generic_run_threadfn_adapter+0x10/0x10
[ 6.174604] filter_suites_test+0xea/0x2c0
[ 6.174702] ? __pfx_kunit_generic_run_threadfn_adapter+0x10/0x10
[ 6.174828] kunit_generic_run_threadfn_adapter+0x15/0x20
[ 6.174941] kthread+0xef/0x120
[ 6.175012] ? __pfx_kthread+0x10/0x10
[ 6.175098] ret_from_fork+0x2f/0x50
[ 6.175177] ? __pfx_kthread+0x10/0x10
[ 6.175260] ret_from_fork_asm+0x1b/0x30
[ 6.175387] </TASK>
[ 6.175466] Modules linked in:
[ 6.175640] CR2: ffffd757e80004c8
[ 6.175887] ---[ end trace 0000000000000000 ]---
[ 6.176029] RIP: 0010:kfree+0x61/0x140
[ 6.176119] Code: 80 48 01 e8 0f 82 ec 00 00 00 48 c7 c2 00 00 00 80 48 2b 15 29 bf aa 01 48 01 d0 48 c1 e8 0c 48 c1 e0 06 48 03 05 07 bf aa 01 <48> 8b 50 08 48 89 c7 f6 c2 01 0f 85 b3 00 00 00 66 90 48 8b 07 f6
[ 6.176478] RSP: 0000:ffffb48f80267dc8 EFLAGS: 00000286
[ 6.176589] RAX: ffffd757e80004c0 RBX: ffffa34583aef5d0 RCX: 0000000000000000
[ 6.176729] RDX: 00005cba00000000 RSI: ffffffff95cb1ad5 RDI: ffffb48f80013cd0
[ 6.176869] RBP: ffffb48f80013cd0 R08: 0000000000000001 R09: 0000000000000001
[ 6.177008] R10: 0000000000000001 R11: 0000000000000001 R12: ffffb48f80267e74
[ 6.177150] R13: 0000000000000000 R14: ffffa34583bf4000 R15: 0000000000000002
[ 6.177290] FS: 0000000000000000(0000) GS:ffffa3458f800000(0000) knlGS:0000000000000000
[ 6.177448] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 6.177564] CR2: ffffd757e80004c8 CR3: 0000000009048000 CR4: 00000000007506f0
[ 6.177704] PKRU: 55555554
[ 6.177807] note: kunit_try_catch[182] exited with irqs disabled


2023-07-29 09:15:01

by David Gow

[permalink] [raw]
Subject: Re: [PATCH v3 0/9] kunit: Add test attributes API

On Fri, 28 Jul 2023 at 18:38, Guenter Roeck <[email protected]> wrote:
>
> On Tue, Jul 25, 2023 at 09:25:11PM +0000, Rae Moar wrote:
> > Hello everyone,
> >
> > This patch series adds a test attributes framework to KUnit.
> >
>
> With this series in linux-next, almost 50% of my boot tests crash,
> and many others show warnings tracebacks.
>
> Example crash from x86_64 boot attempt attached.
>
> Guenter
>
> ---

Hmm... It's not reproducing here (even with KASAN), which is strange.

Does the patch here help?
https://lore.kernel.org/linux-kselftest/[email protected]/

-- David

> [ 6.165419] ok 6 lib_sort
> [ 6.166044] KTAP version 1
> [ 6.166139] # Subtest: kunit_executor_test
> [ 6.166247] # module: kunit
> [ 6.166261] 1..8
> [ 6.168252] ok 1 parse_filter_test
> [ 6.169579] BUG: unable to handle page fault for address: ffffd757e80004c8
> [ 6.169872] #PF: supervisor read access in kernel mode
> [ 6.169990] #PF: error_code(0x0000) - not-present page
> [ 6.170142] PGD ffd4067 P4D ffd4067 PUD 0
> [ 6.170346] Oops: 0000 [#1] PREEMPT SMP PTI
> [ 6.170521] CPU: 0 PID: 182 Comm: kunit_try_catch Tainted: G N 6.5.0-rc3-next-20230728 #1
> [ 6.170735] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS rel-1.16.2-0-gea1b7a073390-prebuilt.qemu.org 04/01/2014
> [ 6.171024] RIP: 0010:kfree+0x61/0x140
> [ 6.171313] Code: 80 48 01 e8 0f 82 ec 00 00 00 48 c7 c2 00 00 00 80 48 2b 15 29 bf aa 01 48 01 d0 48 c1 e8 0c 48 c1 e0 06 48 03 05 07 bf aa 01 <48> 8b 50 08 48 89 c7 f6 c2 01 0f 85 b3 00 00 00 66 90 48 8b 07 f6
> [ 6.171715] RSP: 0000:ffffb48f80267dc8 EFLAGS: 00000286
> [ 6.171847] RAX: ffffd757e80004c0 RBX: ffffa34583aef5d0 RCX: 0000000000000000
> [ 6.171998] RDX: 00005cba00000000 RSI: ffffffff95cb1ad5 RDI: ffffb48f80013cd0
> [ 6.172146] RBP: ffffb48f80013cd0 R08: 0000000000000001 R09: 0000000000000001
> [ 6.172293] R10: 0000000000000001 R11: 0000000000000001 R12: ffffb48f80267e74
> [ 6.172445] R13: 0000000000000000 R14: ffffa34583bf4000 R15: 0000000000000002
> [ 6.172620] FS: 0000000000000000(0000) GS:ffffa3458f800000(0000) knlGS:0000000000000000
> [ 6.172793] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 6.172917] CR2: ffffd757e80004c8 CR3: 0000000009048000 CR4: 00000000007506f0
> [ 6.173089] PKRU: 55555554
> [ 6.173177] Call Trace:
> [ 6.173313] <TASK>
> [ 6.173494] ? __die+0x1f/0x70
> [ 6.173600] ? page_fault_oops+0x14a/0x460
> [ 6.173693] ? search_exception_tables+0x37/0x50
> [ 6.173793] ? fixup_exception+0x21/0x310
> [ 6.173887] ? exc_page_fault+0xee/0x1c0
> [ 6.173977] ? asm_exc_page_fault+0x26/0x30
> [ 6.174076] ? kunit_filter_suites+0x3a5/0x460
> [ 6.174192] ? kfree+0x61/0x140
> [ 6.174271] ? kfree+0x106/0x140
> [ 6.174353] kunit_filter_suites+0x3a5/0x460
> [ 6.174473] ? __pfx_kunit_generic_run_threadfn_adapter+0x10/0x10
> [ 6.174604] filter_suites_test+0xea/0x2c0
> [ 6.174702] ? __pfx_kunit_generic_run_threadfn_adapter+0x10/0x10
> [ 6.174828] kunit_generic_run_threadfn_adapter+0x15/0x20
> [ 6.174941] kthread+0xef/0x120
> [ 6.175012] ? __pfx_kthread+0x10/0x10
> [ 6.175098] ret_from_fork+0x2f/0x50
> [ 6.175177] ? __pfx_kthread+0x10/0x10
> [ 6.175260] ret_from_fork_asm+0x1b/0x30
> [ 6.175387] </TASK>
> [ 6.175466] Modules linked in:
> [ 6.175640] CR2: ffffd757e80004c8
> [ 6.175887] ---[ end trace 0000000000000000 ]---
> [ 6.176029] RIP: 0010:kfree+0x61/0x140
> [ 6.176119] Code: 80 48 01 e8 0f 82 ec 00 00 00 48 c7 c2 00 00 00 80 48 2b 15 29 bf aa 01 48 01 d0 48 c1 e8 0c 48 c1 e0 06 48 03 05 07 bf aa 01 <48> 8b 50 08 48 89 c7 f6 c2 01 0f 85 b3 00 00 00 66 90 48 8b 07 f6
> [ 6.176478] RSP: 0000:ffffb48f80267dc8 EFLAGS: 00000286
> [ 6.176589] RAX: ffffd757e80004c0 RBX: ffffa34583aef5d0 RCX: 0000000000000000
> [ 6.176729] RDX: 00005cba00000000 RSI: ffffffff95cb1ad5 RDI: ffffb48f80013cd0
> [ 6.176869] RBP: ffffb48f80013cd0 R08: 0000000000000001 R09: 0000000000000001
> [ 6.177008] R10: 0000000000000001 R11: 0000000000000001 R12: ffffb48f80267e74
> [ 6.177150] R13: 0000000000000000 R14: ffffa34583bf4000 R15: 0000000000000002
> [ 6.177290] FS: 0000000000000000(0000) GS:ffffa3458f800000(0000) knlGS:0000000000000000
> [ 6.177448] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 6.177564] CR2: ffffd757e80004c8 CR3: 0000000009048000 CR4: 00000000007506f0
> [ 6.177704] PKRU: 55555554
> [ 6.177807] note: kunit_try_catch[182] exited with irqs disabled
>
> --
> You received this message because you are subscribed to the Google Groups "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
> To view this discussion on the web visit https://groups.google.com/d/msgid/kunit-dev/59dc28b1-298c-4e7b-b35f-0b94071f4cb5%40roeck-us.net.

2023-07-29 15:05:50

by Guenter Roeck

[permalink] [raw]
Subject: Re: [PATCH v3 0/9] kunit: Add test attributes API

On 7/29/23 00:53, David Gow wrote:
> On Fri, 28 Jul 2023 at 18:38, Guenter Roeck <[email protected]> wrote:
>>
>> On Tue, Jul 25, 2023 at 09:25:11PM +0000, Rae Moar wrote:
>>> Hello everyone,
>>>
>>> This patch series adds a test attributes framework to KUnit.
>>>
>>
>> With this series in linux-next, almost 50% of my boot tests crash,
>> and many others show warnings tracebacks.
>>
>> Example crash from x86_64 boot attempt attached.
>>
>> Guenter
>>
>> ---
>
> Hmm... It's not reproducing here (even with KASAN), which is strange.
>
> Does the patch here help?
> https://lore.kernel.org/linux-kselftest/[email protected]/
>

Yes, it does.

Guenter