From: "Bernatowicz, Marcin" <marcin.bernatowicz@linux.intel.com>
To: "Piórkowski, Piotr" <piotr.piorkowski@intel.com>,
igt-dev@lists.freedesktop.org
Cc: Peter Senna Tschudin <peter.senna@linux.intel.com>,
Rodrigo Vivi <rodrigo.vivi@intel.com>
Subject: Re: [PATCH v1 3/5] tests/intel/debugfs: Rewrite tests to use array-based required debugfs file lists
Date: Thu, 20 Nov 2025 09:58:03 +0100 [thread overview]
Message-ID: <49b337e7-7e42-4e77-9dc0-b61deb0e06ae@linux.intel.com> (raw)
In-Reply-To: <20251113114615.3736269-4-piotr.piorkowski@intel.com>
On 11/13/2025 12:46 PM, Piórkowski, Piotr wrote:
> From: Piotr Piórkowski <piotr.piorkowski@intel.com>
>
> The previous version of debugfs test contained inconsistent logic.
> Lets rewrite the test to use a single array-based list of required files.
> Add support for conditional requirements and dynamic index generation
> for entries like gt and tile dir.
>
> Also split out a dedicated subtest for validating the contents of the
> info debugfs node.
>
> Signed-off-by: Piotr Piórkowski <piotr.piorkowski@intel.com>
> Cc: Peter Senna Tschudin <peter.senna@linux.intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> ---
> tests/intel/xe_debugfs.c | 385 ++++++++++++++++++++++++++++-----------
> 1 file changed, 283 insertions(+), 102 deletions(-)
>
> diff --git a/tests/intel/xe_debugfs.c b/tests/intel/xe_debugfs.c
> index 1005047132..2600880a7e 100644
> --- a/tests/intel/xe_debugfs.c
> +++ b/tests/intel/xe_debugfs.c
> @@ -30,75 +30,284 @@ struct {
> *
> */
>
> -IGT_TEST_DESCRIPTION("Read entries from debugfs, and sysfs paths.");
> +IGT_TEST_DESCRIPTION("Validate Xe debugfs devnodes and their contents");
> +
> +#define for_each_set_bit(i, mask) \
> + for (unsigned int _m = (mask); \
> + _m && ((i) = __builtin_ctz(_m), 1); \
> + _m &= _m - 1)
> +
> +struct check_entry {
> + const char *name_fmt;
> + int mode;
> + bool (*condition)(struct xe_device *xe_dev);
> + unsigned int (*iter_mask)(struct xe_device *xe_dev);
> +};
> +
> +static unsigned int gt_iter_mask(struct xe_device *xe_dev)
> +{
> + return xe_dev->gt_mask;
> +}
> +
> +static unsigned int tile_iter_mask(struct xe_device *xe_dev)
> +{
> + return xe_dev->tile_mask;
> +}
> +
> +static bool has_vram(struct xe_device *xe_dev)
> +{
> + return xe_dev->has_vram;
> +}
> +
> +/* Validate the format of debugfs fmt file, allow only one %u literal */
> +static bool validate_debugfs_fmt(const char *fmt)
> +{
> + bool found_u = false;
> +
> + for (const char *p = fmt; *p; p++) {
> + if (*p != '%')
> + continue;
> +
> + /* % at end of string → invalid */
> + if (!p[1])
> + return false;
> +
> + /* must be exactly %u */
> + if (p[1] != 'u')
> + return false;
> +
> + /* only one %u allowed */
> + if (found_u)
> + return false;
> +
> + found_u = true;
> +
> + /* skip u */
> + p++; /* caller loop increments p again */
> + }
> +
> + return found_u;
> +}
> +
> +struct hit_entry {
> + struct igt_list_head link;
> + char name[64];
> +};
>
> -static int xe_validate_entries(igt_dir_t *igt_dir,
> - const char * const str_val[], int str_cnt)
> +static bool find_no_tested_files(int dir_fd, struct igt_list_head *hit_entries)
NIT: s/find_no_tested_files/find_not_tested_files/ or warn_untested_files ?
> {
> igt_dir_file_list_t *file_list_entry;
> + bool found_not_tested = false;
> + igt_dir_t *dir = igt_dir_create(dir_fd);
> + int ret;
>
> - if (!igt_dir)
> - return -1;
> + igt_assert_f(dir, "Failed to create igt_dir_t for debugfs dir\n");
>
> - igt_dir_scan_dirfd(igt_dir, -1);
> + ret = igt_dir_scan_dirfd(dir, 0);
> + igt_assert_f(ret == 0, "Failed to scan debugfs directory\n");
>
> - for (int i = 0; i < str_cnt; i++) {
> - int hit = 0;
>
> - igt_list_for_each_entry(file_list_entry,
> - &igt_dir->file_list_head, link) {
> - if (strcmp(file_list_entry->relative_path,
> - str_val[i]) == 0) {
> - hit = 1;
> + igt_list_for_each_entry(file_list_entry, &dir->file_list_head, link) {
> + struct hit_entry *e;
> + bool hit = false;
> +
> + igt_list_for_each_entry(e, hit_entries, link) {
> + if (strcmp(file_list_entry->relative_path, e->name) == 0) {
> + hit = true;
> break;
> }
> }
>
> - if (!hit && opt.warn_on_not_hit)
> - igt_warn("no test for: %s\n", str_val[i]);
> + if (!hit) {
> + igt_warn("No test for: %s\n", file_list_entry->relative_path);
> + found_not_tested = true;
> + }
> }
>
> - return 0;
> + igt_dir_destroy(dir);
> +
> + return found_not_tested;
> +}
> +
> +static bool file_in_dir_exists(int dirfd, const char *file_name, int mode)
> +{
> + int fd = openat(dirfd, file_name, mode);
> +
> + if (fd >= 0) {
> + close(fd);
> + return true;
> + }
> +
> + return false;
> +}
> +
> +/*
> + * Return: negative error code on failure, or number of missing files
> + */
> +static int debugfs_validate_entries(struct xe_device *xe_dev, int dir_fd,
> + const struct check_entry *expected_files, size_t size)
> +{
> + struct igt_list_head hit_entries;
> + int missing_count = 0;
> + int err = 0;
> +
> + IGT_INIT_LIST_HEAD(&hit_entries);
> +
> + for (int i = 0; i < size; i++) {
> + const struct check_entry *check = &expected_files[i];
> + unsigned int mask;
> + unsigned int j;
> +
> + if (check->condition && !check->condition(xe_dev))
> + continue;
> +
> + if (!check->iter_mask)
> + mask = BIT(0); /* to iterate once */
> + else
> + mask = check->iter_mask(xe_dev);
> +
> + for_each_set_bit(j, mask) {
> + struct hit_entry *entry;
> +
> + entry = malloc(sizeof(*entry));
> + if (!entry) {
> + igt_warn("Failed to allocate memory for hit entry\n");
> + err = -ENOMEM;
> + goto out;
> + }
> +
> + igt_list_add(&entry->link, &hit_entries);
> +
> + if (!check->iter_mask) {
> + snprintf(entry->name, sizeof(entry->name), "%s", check->name_fmt);
> + } else {
> + int ret;
> +
> +#pragma GCC diagnostic push
> +#pragma GCC diagnostic ignored "-Wformat-nonliteral"
> + /**
> + * XXX: We ignore the compiler warning, but
> + * validate fmt at runtime.
> + */
> + if (!validate_debugfs_fmt(check->name_fmt)) {
> + igt_warn("Invalid debugfs name fmt: %s.\n",
> + check->name_fmt);
> + err = -EBADF;
> + goto out;
> + }
> +
> + ret = snprintf(entry->name, sizeof(entry->name),
> + check->name_fmt, j);
> + if (ret < 0 || ret >= sizeof(entry->name)) {
> + igt_warn("Debugfs format failed for: %s\n",
> + check->name_fmt);
> + err = -EINVAL;
> + goto out;
> + }
> +#pragma GCC diagnostic pop
> + }
> +
> + if (!file_in_dir_exists(dir_fd, entry->name, check->mode)) {
> + igt_warn("Missing debugfs file: %s\n", entry->name);
> + missing_count++;
> + }
> + }
> + }
> +
> + if (opt.warn_on_not_hit)
> + find_no_tested_files(dir_fd, &hit_entries);
> +
> +out:
> + if (!igt_list_empty(&hit_entries)) {
> + struct hit_entry *entry, *tmp;
> +
> + igt_list_for_each_entry_safe(entry, tmp, &hit_entries, link) {
> + igt_list_del(&entry->link);
> + free(entry);
> + }
> + }
> +
> + return (err < 0) ? err : missing_count;
> }
>
> /**
> - * SUBTEST: xe-base
> - * Description: Check if various debugfs devnodes exist and test reading them
> + * SUBTEST: root-dir
> + * Description: Check required debugfs devnodes exist in the root debugfs directory
> */
> -static void
> -xe_test_base(int fd, struct drm_xe_query_config *config, igt_dir_t *igt_dir)
> +static void test_root_dir(struct xe_device *xe_dev)
> {
> - uint16_t devid = intel_get_drm_devid(fd);
> - static const char * const expected_files[] = {
> - "gt0",
> - "gt1",
> - "stolen_mm",
> - "gtt_mm",
> - "vram0_mm",
> - "forcewake_all",
> - "info",
> - "gem_names",
> - "clients",
> - "name"
> + const struct check_entry expected_files[] = {
> + { "clients", O_RDONLY },
> + { "forcewake_all", O_WRONLY },
> + { "gem_names", O_RDONLY },
> + { "gt%u", O_RDONLY, NULL, gt_iter_mask }, /* gt0, gt1, ... */
> + { "gtt_mm", O_RDONLY },
> + { "info", O_RDONLY },
> + { "name", O_RDONLY },
> + { "tile%u", O_RDONLY, NULL, tile_iter_mask }, /* tile0, tile1, ... */
> + { "vram%u_mm", O_RDONLY, has_vram, tile_iter_mask }, /* vram0_mm, vram1_mm, ... */
> };
> - char reference[4096];
> - int val = 0;
> + int debugfs_fd = igt_debugfs_dir(xe_dev->fd);
> + int missing_count;
>
> - igt_assert(config);
> - sprintf(reference, "devid 0x%llx",
> - config->info[DRM_XE_QUERY_CONFIG_REV_AND_DEVICE_ID] & 0xffff);
> - igt_assert(igt_debugfs_search(fd, "info", reference));
> + if (debugfs_fd < 0)
> + goto skip;
>
> - sprintf(reference, "revid %lld",
> - config->info[DRM_XE_QUERY_CONFIG_REV_AND_DEVICE_ID] >> 16);
> - igt_assert(igt_debugfs_search(fd, "info", reference));
> + missing_count = debugfs_validate_entries(xe_dev, debugfs_fd, expected_files,
> + ARRAY_SIZE(expected_files));
>
> - sprintf(reference, "is_dgfx %s", config->info[DRM_XE_QUERY_CONFIG_FLAGS] &
> - DRM_XE_QUERY_CONFIG_FLAG_HAS_VRAM ? "yes" : "no");
> + close(debugfs_fd);
> +
> + igt_fail_on_f(missing_count > 0, "Found %d missing debugfs files (see warnings above)\n",
> + missing_count);
> +
> + return;
> +skip:
> + igt_skip("Failed to open debugfs directory\n");
> +}
> +
> +/**
> + * SUBTEST: info-read
> + * Description: Check info debugfs devnode contents
> + */
> +static void test_info_read(struct xe_device *xe_dev)
> +{
> + uint16_t devid = intel_get_drm_devid(xe_dev->fd);
> + struct drm_xe_query_config *config;
> + const char *name = "info";
> + bool failed = false;
> + char buf[4096];
> + int val;
> +
> + config = xe_config(xe_dev->fd);
> +
> + igt_assert_f(config, "Failed to get xe config\n");
> +
> + snprintf(buf, sizeof(buf), "devid 0x%llx",
> + config->info[DRM_XE_QUERY_CONFIG_REV_AND_DEVICE_ID] & 0xffff);
> + if (!igt_debugfs_search(xe_dev->fd, name, buf)) {
> + igt_warn("Missing devid in info debugfs\n");
> + failed = true;
> + }
> +
> + snprintf(buf, sizeof(buf), "revid %lld",
> + config->info[DRM_XE_QUERY_CONFIG_REV_AND_DEVICE_ID] >> 16);
> + if (!igt_debugfs_search(xe_dev->fd, name, buf)) {
> + igt_warn("Missing revid in info debugfs\n");
> + failed = true;
> + }
>
> - igt_assert(igt_debugfs_search(fd, "info", reference));
> + snprintf(buf, sizeof(buf),
> + "is_dgfx %s", config->info[DRM_XE_QUERY_CONFIG_FLAGS] &
> + DRM_XE_QUERY_CONFIG_FLAG_HAS_VRAM ? "yes" : "no");
> + if (!igt_debugfs_search(xe_dev->fd, name, buf)) {
> + igt_warn("Missing is_dgfx in info debugfs\n");
> + failed = true;
> + }
>
> if (intel_gen(devid) < 20) {
> + val = -1;
> +
> switch (config->info[DRM_XE_QUERY_CONFIG_VA_BITS]) {
> case 48:
> val = 3;
> @@ -106,57 +315,38 @@ xe_test_base(int fd, struct drm_xe_query_config *config, igt_dir_t *igt_dir)
> case 57:
> val = 4;
> break;
> + default:
> + igt_warn("Unexpected va_bits value: %lld\n",
> + config->info[DRM_XE_QUERY_CONFIG_VA_BITS]);
> + failed = true;
> + break;
> }
>
> - sprintf(reference, "vm_max_level %d", val);
> - igt_assert(igt_debugfs_search(fd, "info", reference));
> + if (val != -1) {
> + snprintf(buf, sizeof(buf), "vm_max_level %d", val);
> + if (!igt_debugfs_search(xe_dev->fd, name, buf)) {
> + igt_warn("Missing vm_max_level in info debugfs\n");
> + failed = true;
> + }
> + }
> }
>
> - snprintf(reference, sizeof(reference), "tile_count %d", xe_sysfs_get_num_tiles(fd));
> - igt_assert(igt_debugfs_search(fd, "info", reference));
> -
> - igt_assert(igt_debugfs_exists(fd, "gt0", O_RDONLY));
> -
> - igt_assert(igt_debugfs_exists(fd, "gtt_mm", O_RDONLY));
> - igt_debugfs_dump(fd, "gtt_mm");
> -
> - if (config->info[DRM_XE_QUERY_CONFIG_FLAGS] & DRM_XE_QUERY_CONFIG_FLAG_HAS_VRAM) {
> - igt_assert(igt_debugfs_exists(fd, "vram0_mm", O_RDONLY));
> - igt_debugfs_dump(fd, "vram0_mm");
> + snprintf(buf, sizeof(buf), "tile_count %d", xe_sysfs_get_num_tiles(xe_dev->fd));
> + if (!igt_debugfs_search(xe_dev->fd, name, buf)) {
> + igt_warn("Missing tile_count in info debugfs\n");
> + failed = true;
> }
>
> - if (igt_debugfs_exists(fd, "stolen_mm", O_RDONLY))
> - igt_debugfs_dump(fd, "stolen_mm");
> -
> - igt_assert(igt_debugfs_exists(fd, "clients", O_RDONLY));
> - igt_debugfs_dump(fd, "clients");
> -
> - igt_assert(igt_debugfs_exists(fd, "gem_names", O_RDONLY));
> - igt_debugfs_dump(fd, "gem_names");
> + igt_fail_on_f(failed, "Some required info debugfs entries are missing\n");
>
> - xe_validate_entries(igt_dir, expected_files,
> - ARRAY_SIZE(expected_files));
> -}
> -
> -/**
> - * SUBTEST: xe-forcewake
> - * Description: Check forcewake debugfs devnode
> - */
> -static void
> -xe_test_forcewake(int fd)
> -{
> - int handle = igt_debugfs_open(fd, "forcewake_all", O_WRONLY);
> -
> - igt_assert_neq(handle, -1);
> - close(handle);
> }
>
> const char *help_str =
> - " -w\t--warn-not-hit Produce warnings if it founds a devfs node without tests";
> + " --warn-not-hit|--w\tWarn about devfs nodes that have no tests";
>
> struct option long_options[] = {
> - { "--warn-not-hit", no_argument, NULL, 'w'},
> - { 0, 0, 0, 0 }
> + { "warn-not-hit", no_argument, NULL, 'w'},
> + { }
> };
>
> static int opt_handler(int option, int option_index, void *input)
> @@ -174,34 +364,25 @@ static int opt_handler(int option, int option_index, void *input)
>
> igt_main_args("", long_options, help_str, opt_handler, NULL)
> {
> - int debugfs = -1;
> + struct xe_device *xe_dev;
> int fd = -1;
> - igt_dir_t *igt_dir = NULL;
>
> igt_fixture {
> fd = drm_open_driver_master(DRIVER_XE);
> - __igt_debugfs_dump(fd, "info", IGT_LOG_INFO);
> - debugfs = igt_debugfs_dir(fd);
> -
> - igt_dir = igt_dir_create(debugfs);
> - igt_require(igt_dir);
> -
> + xe_dev = xe_device_get(fd);
> + igt_assert_f(xe_dev, "Failed to get xe device\n");
> kmstest_set_vt_graphics_mode();
> }
>
> - igt_describe("Check if various debugfs devnodes exist and test reading them.");
> - igt_subtest("xe-base") {
> - xe_test_base(fd, xe_config(fd), igt_dir);
> - }
> -
> - igt_describe("Check forcewake debugfs devnode");
> - igt_subtest("xe-forcewake") {
> - xe_test_forcewake(fd);
> - }
> + igt_describe("Check required debugfs devnodes exist in the root debugfs directory.");
> + igt_subtest("root-dir")
> + test_root_dir(xe_dev);
>
> + igt_describe("Check info debugfs devnode contents.");
> + igt_subtest("info-read")
> + test_info_read(xe_dev);
> igt_fixture {
> - igt_dir_destroy(igt_dir);
> - close(debugfs);
> + xe_device_put(fd);
NIT: not needed, drm_close_driver should handle it
> drm_close_driver(fd);
> }
> }
With some nits, LGTM
Reviewed-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
next prev parent reply other threads:[~2025-11-20 8:58 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-11-13 11:46 [PATCH v1 0/5] Redesign of the xe_debugfs test Piórkowski, Piotr
2025-11-13 11:46 ` [PATCH v1 1/5] lib/igt_dir: Allow scanning only the current directory Piórkowski, Piotr
2025-11-19 14:32 ` Bernatowicz, Marcin
2025-11-13 11:46 ` [PATCH v1 2/5] lib/debugfs: Add debugfs helpers to open tile directory Piórkowski, Piotr
2025-11-20 9:10 ` Bernatowicz, Marcin
2025-11-13 11:46 ` [PATCH v1 3/5] tests/intel/debugfs: Rewrite tests to use array-based required debugfs file lists Piórkowski, Piotr
2025-11-20 8:58 ` Bernatowicz, Marcin [this message]
2025-11-13 11:46 ` [PATCH v1 4/5] tests/intel/debugfs: Add tile-dir subtest for per-tile debugfs validation Piórkowski, Piotr
2025-11-20 9:21 ` Bernatowicz, Marcin
2025-11-13 11:46 ` [PATCH v1 5/5] tests/intel/debugfs: Move VRAM MM checks from root to tile-dir validation Piórkowski, Piotr
2025-11-13 21:14 ` ✗ Xe.CI.BAT: failure for Redesign of the xe_debugfs test Patchwork
2025-11-13 23:45 ` ✓ i915.CI.BAT: success " Patchwork
2025-11-14 4:46 ` ✗ Xe.CI.Full: failure " Patchwork
2025-11-14 17:59 ` ✗ i915.CI.Full: " Patchwork
2025-11-18 16:56 ` [PATCH v1 0/5] " Peter Senna Tschudin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=49b337e7-7e42-4e77-9dc0-b61deb0e06ae@linux.intel.com \
--to=marcin.bernatowicz@linux.intel.com \
--cc=igt-dev@lists.freedesktop.org \
--cc=peter.senna@linux.intel.com \
--cc=piotr.piorkowski@intel.com \
--cc=rodrigo.vivi@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox