Igt-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH i-g-t] tests/intel/xe_bo_shrink: Add a user-space shrinker test
@ 2026-10-21 12:33 Thomas Hellström
  2026-10-21 15:03 ` ✗ Xe.CI.FULL: failure for " Patchwork
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Thomas Hellström @ 2026-10-21 12:33 UTC (permalink / raw)
  To: igt-dev; +Cc: Thomas Hellström, Kamil Konieczny, Matthew Auld,
	Matthew Brost

Add a user-space counterpart of the xe_bo_shrink kunit test, now that
user-space can mark buffer objects purgeable using the madvise IOCTL.

The test creates 64 MiB system buffer objects corresponding to twice
the amount of free system memory, fills them with pseudo-random data
through CPU mappings that are kept alive until readback, and verifies
the contents after the overcommit has forced the shrinker to back up
or purge them. As in the kunit test, the share of the memory that
doesn't fit in free RAM and swap is marked purgeable (DONTNEED) and
allocated first. Purgeable objects are only verified if found retained
when marked WILLNEED again; purged objects are never accessed.

Subtests:
- shrink: The kunit test equivalent.
- purge: Ignore swap space when sizing the purgeable share, so that
  the shrinker needs to purge rather than swap.
- shrink-fault-inject: Enable TTM backup / restore fault injection
  through debugfs, if available, making the shrinker back up only part
  of the objects and making backup and restore of individual pages
  fail. The number of injected faults is checked to be non-zero.
- *-blit: Rather than restoring objects by CPU faults, restore them
  through a GPU bind and read them back by a MEM_COPY blit to a dummy
  object in a separate VM. On discrete devices, objects are created
  with system and VRAM placements, prefetched to system memory on
  creation and prefetched to VRAM before the copy, so that they are
  restored by the migration to VRAM.
- *-private: Create the objects private to the test VM rather than as
  external objects.
- *-fast: Allocate at most the free system memory, half of it
  purgeable, capped to 8 GiB purgeable and 8 GiB non-purgeable, and
  shrink using drop_caches rather than memory overcommit.

The non-fast subtests are slow and require a substantial amount of
swap space for meaningful coverage, so block them in CI and run only
the fast subtests.

Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Cc: Matthew Auld <matthew.auld@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Assisted-by: GitHub_Copilot:claude-opus-5.5
---
 tests/intel-ci/xe.blocklist.txt |   3 +-
 tests/intel/xe_bo_shrink.c      | 610 ++++++++++++++++++++++++++++++++
 tests/meson.build               |   1 +
 3 files changed, 613 insertions(+), 1 deletion(-)
 create mode 100644 tests/intel/xe_bo_shrink.c

diff --git a/tests/intel-ci/xe.blocklist.txt b/tests/intel-ci/xe.blocklist.txt
index c1dd3c7a8..ba589aac2 100644
--- a/tests/intel-ci/xe.blocklist.txt
+++ b/tests/intel-ci/xe.blocklist.txt
@@ -35,9 +35,10 @@ igt@gpu_buddy
 igt@drm_mm
 igt@kms_selftest.*
 ##################################################################
-# Exclude slow KUnit test which should run as manual test
+# Exclude slow shrinker tests which should run as manual tests
 ##################################################################
 igt@xe_live_ktest@xe_bo_shrink
+igt@xe_bo_shrink@(?!.*-fast$).*
 ##################################################################
 # Exclude all other non-Xe tests
 ##################################################################
diff --git a/tests/intel/xe_bo_shrink.c b/tests/intel/xe_bo_shrink.c
new file mode 100644
index 000000000..6210923af
--- /dev/null
+++ b/tests/intel/xe_bo_shrink.c
@@ -0,0 +1,610 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2026 Intel Corporation
+ */
+
+/**
+ * TEST: Exercise the xe buffer object shrinker from user-space
+ * Category: Core
+ * Mega feature: General Core features
+ * Sub-category: Memory management tests
+ * Functionality: shrinker, swap, purgeable
+ *
+ * This is a user-space counterpart of the xe_bo_shrink kunit test.
+ * It creates system memory buffer objects corresponding to twice the
+ * amount of free system memory. All objects are filled with pseudo-random
+ * data through a CPU mapping that is kept alive until the data is verified
+ * after the overcommit. Purgeable objects are additionally marked DONTNEED
+ * using the madvise IOCTL so that the shrinker may discard their contents.
+ * Those are only verified if still retained when marked WILLNEED again.
+ *
+ * The blit variants never read the bos using the CPU. Instead each bo is
+ * bound to a separate VM and copied to a dummy bo using the MEM_COPY
+ * blitter command, so that bos are restored by the GPU paths rather than
+ * by CPU faults, and the content of the dummy bo is verified. On discrete
+ * devices, the blit variants create the bos with both system and VRAM
+ * placements and immediately prefetch them to system memory. Before the
+ * copy, each bo is prefetched to VRAM, so that it is restored by the
+ * migration to VRAM.
+ *
+ * The private variants create the bos private to the test VM, sharing
+ * the VM's reservation object, rather than as external bos.
+ *
+ * The fast variants instead create bos corresponding to the amount of
+ * free system memory, half of them purgeable, capped to
+ * XE_BO_SHRINK_FAST_MAX purgeable and non-purgeable each, and shrink
+ * them by writing to /proc/sys/vm/drop_caches rather than relying on
+ * reclaim caused by memory overcommit.
+ */
+
+#include <sys/random.h>
+#include <sys/sysinfo.h>
+
+#include "igt.h"
+#include "igt_debugfs.h"
+#include "igt_rand.h"
+#include "igt_sysfs.h"
+#include "intel_blt.h"
+#include "intel_mocs.h"
+#include "xe_drm.h"
+
+#include "intel_reg.h"
+#include "xe/xe_ioctl.h"
+#include "xe/xe_query.h"
+
+#define XE_BO_SHRINK_SIZE	(64ull << 20)
+#define XE_BO_SHRINK_VA_BASE	(1ull << 32)
+/* Max purgeable and max non-purgeable memory, each, for fast variants. */
+#define XE_BO_SHRINK_FAST_MAX	(8ull << 30)
+
+#define BLIT_BATCH_ADDR		(1ull << 20)
+#define BLIT_DST_ADDR		(1ull << 32)
+#define BLIT_SRC_ADDR		(2ull << 32)
+
+#define SHRINK_PURGE		(0x1 << 0)
+#define SHRINK_FAULT_INJECT	(0x1 << 1)
+#define SHRINK_BLIT		(0x1 << 2)
+#define SHRINK_FAST		(0x1 << 3)
+#define SHRINK_PRIVATE		(0x1 << 4)
+
+/**
+ * struct shrink_bo - A shrinker test bo
+ * @map: Persistent CPU mapping of the bo, kept from fill until readback.
+ * @handle: GEM handle of the bo.
+ * @addr: GPU virtual address of the bo in the test VM, if @bound.
+ * @val: The first pseudo-random value written, used to detect a PRNG
+ * that is out of sync on readback.
+ * @purgeable: Whether the bo is marked DONTNEED and thus may be purged.
+ * @bound: Whether the bo is bound at @addr in the test VM.
+ */
+struct shrink_bo {
+	uint32_t *map;
+	uint32_t handle;
+	uint64_t addr;
+	uint32_t val;
+	bool purgeable;
+	bool bound;
+};
+
+/**
+ * struct shrink_blit - State for blitter readback of bos
+ * @vm: A separate VM used for the copies.
+ * @exec_queue: Copy engine exec queue in @vm.
+ * @batch: Batch bo holding the MEM_COPY command.
+ * @dst: Dummy destination bo, in system memory.
+ * @dst_map: CPU mapping of @dst, used to verify the copied content.
+ */
+struct shrink_blit {
+	uint32_t vm;
+	uint32_t exec_queue;
+	uint32_t batch;
+	uint32_t dst;
+	uint32_t *dst_map;
+};
+
+/**
+ * struct ttm_fault_inject - TTM backup / restore fault injection state
+ * @dir: Debugfs directory fd of the fault attributes, or -1 if not opened.
+ * @probability: Original probability, restored after the test.
+ * @interval: Original interval, restored after the test.
+ * @times: Original times, restored after the test.
+ * @verbose: Original verbosity, restored after the test.
+ * @task_filter: Original task-filter setting, restored after the test.
+ */
+static struct ttm_fault_inject {
+	int dir;
+	uint32_t probability;
+	uint32_t interval;
+	int32_t times;
+	uint32_t verbose;
+	bool task_filter;
+} ttm_fi = { .dir = -1 };
+
+static void ttm_fault_inject_restore(int sig)
+{
+	if (ttm_fi.dir < 0)
+		return;
+
+	__igt_sysfs_set_u32(ttm_fi.dir, "probability", ttm_fi.probability);
+	__igt_sysfs_set_u32(ttm_fi.dir, "interval", ttm_fi.interval);
+	__igt_sysfs_set_s32(ttm_fi.dir, "times", ttm_fi.times);
+	__igt_sysfs_set_u32(ttm_fi.dir, "verbose", ttm_fi.verbose);
+	__igt_sysfs_set_boolean(ttm_fi.dir, "task-filter", ttm_fi.task_filter);
+	close(ttm_fi.dir);
+	ttm_fi.dir = -1;
+}
+
+/*
+ * Enable the TTM backup_fault_inject attribute, which makes the shrinker
+ * back up only part of a bo, fails backup of individual folios and makes
+ * interruptible restores fail with -EINTR. Requires CONFIG_FAULT_INJECTION
+ * and CONFIG_FAULT_INJECTION_DEBUG_FS.
+ */
+static void ttm_fault_inject_enable(void)
+{
+	const char *debugfs_root = igt_debugfs_mount();
+	char path[PATH_MAX];
+
+	igt_require_f(debugfs_root, "debugfs not available\n");
+	snprintf(path, sizeof(path), "%s/ttm/backup_fault_inject", debugfs_root);
+	ttm_fi.dir = open(path, O_RDONLY | O_DIRECTORY);
+	igt_require_f(ttm_fi.dir >= 0,
+		      "TTM backup fault injection not available (%s)\n", path);
+
+	ttm_fi.probability = igt_sysfs_get_u32(ttm_fi.dir, "probability");
+	ttm_fi.interval = igt_sysfs_get_u32(ttm_fi.dir, "interval");
+	ttm_fi.times = igt_sysfs_get_s32(ttm_fi.dir, "times");
+	ttm_fi.verbose = igt_sysfs_get_u32(ttm_fi.dir, "verbose");
+	ttm_fi.task_filter = igt_sysfs_get_boolean(ttm_fi.dir, "task-filter");
+	igt_install_exit_handler(ttm_fault_inject_restore);
+
+	igt_sysfs_set_boolean(ttm_fi.dir, "task-filter", false);
+	igt_sysfs_set_u32(ttm_fi.dir, "verbose", 0);
+	igt_sysfs_set_u32(ttm_fi.dir, "interval", 1);
+	/* The kernel decrements times on each injection. */
+	igt_sysfs_set_s32(ttm_fi.dir, "times", INT32_MAX);
+	igt_sysfs_set_u32(ttm_fi.dir, "probability", 10);
+}
+
+static int32_t ttm_fault_inject_count(void)
+{
+	return INT32_MAX - igt_sysfs_get_s32(ttm_fi.dir, "times");
+}
+
+static bool xe_has_purgeable_support(int fd)
+{
+	struct drm_xe_query_config *config = xe_config(fd);
+
+	return config->info[DRM_XE_QUERY_CONFIG_FLAGS] &
+		DRM_XE_QUERY_CONFIG_FLAG_HAS_PURGING_SUPPORT;
+}
+
+/*
+ * The CPU mapping is kept until shrink_verify(), so that the shrinker
+ * needs to zap the PTEs of a live mapping and readback restores the
+ * bo through that same mapping.
+ */
+static void shrink_fill_random(int fd, struct shrink_bo *bo, uint32_t *prng)
+{
+	uint32_t *map = xe_bo_map(fd, bo->handle, XE_BO_SHRINK_SIZE);
+	size_t i;
+
+	for (i = 0; i < XE_BO_SHRINK_SIZE / sizeof(*map); i++)
+		map[i] = hars_petruska_f54_1_random(prng);
+
+	bo->val = map[0];
+	bo->map = map;
+}
+
+static void shrink_verify(const uint32_t *map, uint32_t first_val,
+			  unsigned int bo_nr, uint32_t *prng)
+{
+	size_t i;
+
+	for (i = 0; i < XE_BO_SHRINK_SIZE / sizeof(*map); i++) {
+		uint32_t val = hars_petruska_f54_1_random(prng);
+
+		igt_assert_f(map[i] == val,
+			     "Content not preserved, bo %u offset 0x%016zx. "
+			     "Failed value is 0x%08x, recorded 0x%08x.%s\n",
+			     bo_nr, i * sizeof(*map), map[i], val,
+			     (i == 0 && val != first_val) ?
+			     " Looks like PRNG is out of sync." : "");
+	}
+}
+
+/*
+ * The bo was purged. Never touch its mapping, but advance the
+ * pseudo-random sequence to keep it in sync for the following bos.
+ */
+static void shrink_skip(struct shrink_bo *bo, uint32_t *prng)
+{
+	size_t i;
+
+	for (i = 0; i < XE_BO_SHRINK_SIZE / sizeof(*bo->map); i++)
+		hars_petruska_f54_1_random(prng);
+
+	munmap(bo->map, XE_BO_SHRINK_SIZE);
+}
+
+/*
+ * Set up a separate VM with a dummy destination bo and a batch copying
+ * a bo bound at BLIT_SRC_ADDR to the dummy bo. A separate VM is used so
+ * that exec doesn't need to revalidate any other shrinker test bos.
+ */
+static void shrink_blit_init(int fd, struct shrink_blit *blit)
+{
+	uint32_t width = XE_BO_SHRINK_SIZE / 256;
+	uint32_t devid = intel_get_drm_devid(fd);
+	uint32_t mocs = intel_get_uc_mocs_index(fd);
+	uint64_t bb_size = xe_bb_size(fd, SZ_4K);
+	uint32_t *cmd;
+	int i = 0;
+
+	blit->vm = xe_vm_create(fd, 0, 0);
+	blit->exec_queue = xe_exec_queue_create_class(fd, blit->vm,
+						      DRM_XE_ENGINE_CLASS_COPY);
+
+	blit->dst = xe_bo_create_caching(fd, 0, XE_BO_SHRINK_SIZE,
+					 system_memory(fd), 0,
+					 DRM_XE_GEM_CPU_CACHING_WB);
+	blit->dst_map = xe_bo_map(fd, blit->dst, XE_BO_SHRINK_SIZE);
+	xe_vm_bind_sync(fd, blit->vm, blit->dst, 0, BLIT_DST_ADDR,
+			XE_BO_SHRINK_SIZE);
+
+	blit->batch = xe_bo_create(fd, 0, bb_size, system_memory(fd), 0);
+	cmd = xe_bo_map(fd, blit->batch, bb_size);
+	/* Linear page mode copy, 256 byte units. */
+	cmd[i++] = MEM_COPY_CMD | (1 << 19);
+	cmd[i++] = width - 1;
+	cmd[i++] = 0;
+	cmd[i++] = width - 1;
+	cmd[i++] = width - 1;
+	cmd[i++] = lower_32_bits(BLIT_SRC_ADDR);
+	cmd[i++] = upper_32_bits(BLIT_SRC_ADDR);
+	cmd[i++] = lower_32_bits(BLIT_DST_ADDR);
+	cmd[i++] = upper_32_bits(BLIT_DST_ADDR);
+	if (intel_graphics_ver(devid) >= IP_VER(20, 0))
+		cmd[i++] = mocs << XE2_MEM_COPY_SRC_MOCS_SHIFT | mocs;
+	else
+		cmd[i++] = mocs << GEN12_MEM_COPY_MOCS_SHIFT | mocs;
+	cmd[i++] = MI_BATCH_BUFFER_END;
+	munmap(cmd, bb_size);
+	xe_vm_bind_sync(fd, blit->vm, blit->batch, 0, BLIT_BATCH_ADDR, bb_size);
+}
+
+static void shrink_blit_fini(int fd, struct shrink_blit *blit)
+{
+	munmap(blit->dst_map, XE_BO_SHRINK_SIZE);
+	xe_exec_queue_destroy(fd, blit->exec_queue);
+	xe_vm_destroy(fd, blit->vm);
+	gem_close(fd, blit->batch);
+	gem_close(fd, blit->dst);
+}
+
+/* Restore @bo through a GPU bind and copy, and return the copy. */
+static const uint32_t *shrink_blit_copy(int fd, struct shrink_blit *blit,
+					struct shrink_bo *bo)
+{
+	xe_vm_bind_sync(fd, blit->vm, bo->handle, 0, BLIT_SRC_ADDR,
+			XE_BO_SHRINK_SIZE);
+	xe_exec_wait(fd, blit->exec_queue, BLIT_BATCH_ADDR);
+	xe_vm_unbind_sync(fd, blit->vm, 0, BLIT_SRC_ADDR, XE_BO_SHRINK_SIZE);
+
+	return blit->dst_map;
+}
+
+/**
+ * SUBTEST: shrink
+ * Description:
+ *	Create system bos corresponding to twice the amount of free system
+ *	memory to test shrinker functionality. If no swap space is available
+ *	to accommodate the memory overcommit, mark bos purgeable.
+ * Test category: functionality test
+ *
+ * SUBTEST: purge
+ * Description:
+ *	Create system bos corresponding to twice the amount of free system
+ *	memory and mark the bos needed to accommodate the memory overcommit
+ *	purgeable regardless of available swap space, to make sure the
+ *	shrinker purges rather than swaps.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-fault-inject
+ * Description:
+ *	Same as shrink, but with TTM backup and restore fault injection
+ *	enabled, making the shrinker back up only part of the bos and
+ *	making backup and restore of individual pages fail.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-blit
+ * Description:
+ *	Same as shrink, but restore and read back bos using a blitter copy
+ *	to a dummy bo instead of CPU access. On discrete devices, bos are
+ *	restored by a prefetch to VRAM.
+ * Test category: functionality test
+ *
+ * SUBTEST: purge-blit
+ * Description:
+ *	Same as purge, but restore and read back bos using a blitter copy
+ *	to a dummy bo instead of CPU access. On discrete devices, bos are
+ *	restored by a prefetch to VRAM.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-fault-inject-blit
+ * Description:
+ *	Same as shrink-fault-inject, but restore and read back bos using a
+ *	blitter copy to a dummy bo instead of CPU access. On discrete
+ *	devices, bos are restored by a prefetch to VRAM.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-fast
+ * Description:
+ *	Create system bos corresponding to the amount of free system memory,
+ *	half of them purgeable, and shrink them using drop_caches rather
+ *	than memory overcommit.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-blit-fast
+ * Description:
+ *	Same as shrink-fast, but restore and read back bos using a blitter
+ *	copy to a dummy bo instead of CPU access. On discrete devices, bos
+ *	are restored by a prefetch to VRAM.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-fault-inject-fast
+ * Description:
+ *	Same as shrink-fast, but with TTM backup and restore fault injection
+ *	enabled.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-fault-inject-blit-fast
+ * Description:
+ *	Same as shrink-blit-fast, but with TTM backup and restore fault
+ *	injection enabled.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-private-fast
+ * Description:
+ *	Same as shrink-fast, but with bos private to the test VM.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-fault-inject-private-fast
+ * Description:
+ *	Same as shrink-fault-inject-fast, but with bos private to the test VM.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-private
+ * Description:
+ *	Same as shrink, but with bos private to the test VM.
+ * Test category: functionality test
+ *
+ * SUBTEST: purge-private
+ * Description:
+ *	Same as purge, but with bos private to the test VM.
+ * Test category: functionality test
+ *
+ * SUBTEST: shrink-fault-inject-private
+ * Description:
+ *	Same as shrink-fault-inject, but with bos private to the test VM.
+ * Test category: functionality test
+ */
+static void shrink_test_run_device(int fd, unsigned int flags)
+{
+	uint64_t ram, ram_and_swap, purgeable = 0, alloced, to_alloc, limit;
+	unsigned int count = 0, nr_bos = 0, purged = 0, retained = 0;
+	struct shrink_bo *bos;
+	struct sysinfo si;
+	struct shrink_blit blit;
+	uint64_t placement = system_memory(fd);
+	uint16_t cpu_caching = DRM_XE_GEM_CPU_CACHING_WB;
+	uint32_t seed, prng, vram_region = 0;
+	bool prefetch = false;
+	uint32_t vm;
+	int ret;
+
+	if (flags & SHRINK_BLIT) {
+		igt_require_f(blt_has_mem_copy(fd), "MEM_COPY not supported\n");
+		prefetch = xe_has_vram(fd);
+	}
+
+	if (prefetch) {
+		placement |= vram_memory(fd, 0);
+		cpu_caching = DRM_XE_GEM_CPU_CACHING_WC;
+		vram_region = xe_mem_region(fd, vram_memory(fd, 0))->instance;
+	}
+
+	igt_assert_eq(getrandom(&seed, sizeof(seed), 0), sizeof(seed));
+	igt_info("Random seed is 0x%08x.\n", seed);
+
+	/* Skip if execution time is expected to be too long. */
+	limit = 32ull << 30;
+	/* IGFX with flat CCS needs to copy when swapping / shrinking */
+	if (!xe_has_vram(fd) && blt_platform_has_flat_ccs_enabled(fd))
+		limit = 16ull << 30;
+
+	igt_assert_eq(sysinfo(&si), 0);
+	ram = (uint64_t)si.freeram * si.mem_unit;
+
+	if (flags & SHRINK_FAST) {
+		/* No overcommit. Shrinking is triggered using drop_caches. */
+		purgeable = min_t(uint64_t, ram / 2, XE_BO_SHRINK_FAST_MAX);
+		to_alloc = purgeable + min_t(uint64_t, ram - purgeable,
+					   XE_BO_SHRINK_FAST_MAX);
+	} else {
+		igt_require_f(ram <= limit, "Too long expected execution time.\n");
+		to_alloc = ram * 2;
+
+		ram_and_swap = (flags & SHRINK_PURGE) ? ram :
+			ram + (uint64_t)si.freeswap * si.mem_unit;
+		if (to_alloc > ram_and_swap)
+			purgeable = to_alloc - ram_and_swap;
+		purgeable += purgeable / 5;
+	}
+
+	igt_info("Free ram is %" PRIu64 " bytes. Will allocate %" PRIu64
+		 " bytes, %" PRIu64 " bytes purgeable.\n",
+		 ram, to_alloc, purgeable);
+	igt_require_f(!purgeable || xe_has_purgeable_support(fd),
+		      "Kernel does not support purgeable buffer objects\n");
+
+	if (flags & SHRINK_FAULT_INJECT)
+		ttm_fault_inject_enable();
+
+	bos = calloc(DIV_ROUND_UP(to_alloc, XE_BO_SHRINK_SIZE), sizeof(*bos));
+	igt_assert(bos);
+
+	if (flags & SHRINK_BLIT)
+		shrink_blit_init(fd, &blit);
+
+	vm = xe_vm_create(fd, 0, 0);
+	prng = seed;
+	for (alloced = 0; alloced < to_alloc; alloced += XE_BO_SHRINK_SIZE) {
+		struct shrink_bo *bo = &bos[nr_bos];
+
+		/* The uAPI requires WC with VRAM placement. */
+		ret = __xe_bo_create_caching(fd,
+					     (flags & SHRINK_PRIVATE) ? vm : 0,
+					     XE_BO_SHRINK_SIZE,
+					     placement, 0, cpu_caching,
+					     &bo->handle);
+		if (ret) {
+			igt_assert_f(ret == -ENOMEM || ret == -ENOSPC ||
+				     ret == -EINTR,
+				     "Error creating bo: %d\n", ret);
+			igt_info("Bo creation failed with %d after %" PRIu64
+				 " bytes.\n", ret, alloced);
+			break;
+		}
+		nr_bos++;
+
+		/*
+		 * Allocate purgeable bos first, because if we do it the
+		 * other way around, they may not be subject to swapping...
+		 * Purgeable state and prefetch are set per VMA, so bind
+		 * the bo first.
+		 */
+		bo->purgeable = alloced < purgeable;
+		bo->bound = bo->purgeable || prefetch;
+		bo->addr = XE_BO_SHRINK_VA_BASE + alloced;
+		if (bo->bound)
+			xe_vm_bind_sync(fd, vm, bo->handle, 0, bo->addr,
+					XE_BO_SHRINK_SIZE);
+		/* CPU faults wait for the migration to complete. */
+		if (prefetch)
+			xe_vm_prefetch_async(fd, vm, 0, 0, bo->addr,
+					     XE_BO_SHRINK_SIZE, NULL, 0, 0);
+
+		/* mmap() is blocked in DONTNEED state, so fill first. */
+		shrink_fill_random(fd, bo, &prng);
+
+		/*
+		 * The CPU mapping is kept, but must not be accessed until
+		 * the bo is marked WILLNEED and found retained.
+		 */
+		if (bo->purgeable)
+			xe_vm_madvise_purgeable(fd, vm, bo->addr,
+						XE_BO_SHRINK_SIZE,
+						DRM_XE_VMA_PURGEABLE_STATE_DONTNEED);
+	}
+
+	if (flags & SHRINK_FAST)
+		igt_purge_vm_caches(fd);
+
+	/*
+	 * Read back and destroy bos. Reset the pseudo-random seed to get an
+	 * identical pseudo-random number sequence for readback.
+	 */
+	prng = seed;
+	for (count = 0; count < nr_bos; count++) {
+		struct shrink_bo *bo = &bos[count];
+
+		if (bo->purgeable &&
+		    !xe_vm_madvise_purgeable(fd, vm, bo->addr,
+					     XE_BO_SHRINK_SIZE,
+					     DRM_XE_VMA_PURGEABLE_STATE_WILLNEED)) {
+			purged++;
+			shrink_skip(bo, &prng);
+		} else {
+			const uint32_t *map = bo->map;
+
+			retained += bo->purgeable;
+			/* The blit bind and exec wait for the migration. */
+			if (prefetch)
+				xe_vm_prefetch_async(fd, vm, 0, 0, bo->addr,
+						     XE_BO_SHRINK_SIZE, NULL, 0,
+						     vram_region);
+			if (flags & SHRINK_BLIT)
+				map = shrink_blit_copy(fd, &blit, bo);
+			shrink_verify(map, bo->val, count + 1, &prng);
+			munmap(bo->map, XE_BO_SHRINK_SIZE);
+		}
+
+		if (bo->bound)
+			xe_vm_unbind_sync(fd, vm, 0, bo->addr, XE_BO_SHRINK_SIZE);
+		gem_close(fd, bo->handle);
+	}
+
+	igt_info("Readbacks successful: %u (%u purgeable retained), purgeable bos purged: %u\n",
+		 nr_bos - purged, retained, purged);
+
+	if (flags & SHRINK_BLIT)
+		shrink_blit_fini(fd, &blit);
+	xe_vm_destroy(fd, vm);
+	free(bos);
+
+	if (flags & SHRINK_FAST)
+		igt_assert_f(purged > 0, "No purgeable bos were purged\n");
+
+	if (flags & SHRINK_FAULT_INJECT) {
+		int32_t injected = ttm_fault_inject_count();
+
+		ttm_fault_inject_restore(0);
+		igt_info("TTM backup / restore faults injected: %d\n", injected);
+		igt_assert_f(injected > 0,
+			     "No TTM backup / restore faults were injected\n");
+	}
+}
+
+int igt_main()
+{
+	const struct section {
+		const char *name;
+		unsigned int flags;
+	} sections[] = {
+		{ "shrink-fast", SHRINK_FAST },
+		{ "shrink-blit-fast", SHRINK_FAST | SHRINK_BLIT },
+		{ "shrink-fault-inject-fast", SHRINK_FAST | SHRINK_FAULT_INJECT },
+		{ "shrink-fault-inject-blit-fast",
+		  SHRINK_FAST | SHRINK_FAULT_INJECT | SHRINK_BLIT },
+		{ "shrink-private-fast", SHRINK_FAST | SHRINK_PRIVATE },
+		{ "shrink-fault-inject-private-fast",
+		  SHRINK_FAST | SHRINK_FAULT_INJECT | SHRINK_PRIVATE },
+		{ "shrink", 0 },
+		{ "shrink-blit", SHRINK_BLIT },
+		{ "purge", SHRINK_PURGE },
+		{ "purge-blit", SHRINK_PURGE | SHRINK_BLIT },
+		{ "shrink-fault-inject", SHRINK_FAULT_INJECT },
+		{ "shrink-fault-inject-blit", SHRINK_FAULT_INJECT | SHRINK_BLIT },
+		{ "shrink-private", SHRINK_PRIVATE },
+		{ "purge-private", SHRINK_PURGE | SHRINK_PRIVATE },
+		{ "shrink-fault-inject-private", SHRINK_FAULT_INJECT | SHRINK_PRIVATE },
+		{ }
+	};
+	int fd;
+
+	igt_fixture() {
+		fd = drm_open_driver(DRIVER_XE);
+		xe_device_get(fd);
+	}
+
+	for (const struct section *s = sections; s->name; s++)
+		igt_subtest(s->name)
+			shrink_test_run_device(fd, s->flags);
+
+	igt_fixture() {
+		ttm_fault_inject_restore(0);
+		xe_device_put(fd);
+		drm_close_driver(fd);
+	}
+}
diff --git a/tests/meson.build b/tests/meson.build
index 519a9e727..2f50f000d 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -284,6 +284,7 @@ intel_kms_progs = [
 
 intel_xe_progs = [
 	'xe_wedged',
+	'xe_bo_shrink',
 	'xe_ccs',
 	'xe_create',
 	'xe_compute',
-- 
2.56.0


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

* ✗ Xe.CI.FULL: failure for tests/intel/xe_bo_shrink: Add a user-space shrinker test
  2026-10-21 12:33 [PATCH i-g-t] tests/intel/xe_bo_shrink: Add a user-space shrinker test Thomas Hellström
@ 2026-10-21 15:03 ` Patchwork
  2026-10-21 19:09 ` [PATCH i-g-t] " Matthew Brost
  2026-10-22 11:22 ` Matthew Auld
  2 siblings, 0 replies; 4+ messages in thread
From: Patchwork @ 2026-10-21 15:03 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: igt-dev

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

== Series Details ==

Series: tests/intel/xe_bo_shrink: Add a user-space shrinker test
URL   : https://patchwork.freedesktop.org/series/176563/
State : failure

== Summary ==

CI Bug Log - changes from XEIGT_9156_FULL -> XEIGTPW_16022_FULL
====================================================

Summary
-------

  **FAILURE**

  Serious unknown changes coming with XEIGTPW_16022_FULL absolutely need to be
  verified manually.
  
  If you think the reported changes have nothing to do with the changes
  introduced in XEIGTPW_16022_FULL, please notify your bug team (I915-ci-infra@lists.freedesktop.org) to allow them
  to document this new failure mode, which will reduce false positives in CI.

  

Participating hosts (3 -> 1)
------------------------------

  ERROR: It appears as if the changes made in XEIGTPW_16022_FULL prevented too many machines from booting.

  Missing    (2): shard-ptl shard-lnl 

New tests
---------

  New tests have been introduced between XEIGT_9156_FULL and XEIGTPW_16022_FULL:

### New IGT tests (6) ###

  * igt@xe_bo_shrink@shrink-blit-fast:
    - Statuses : 1 pass(s)
    - Exec time: [28.54] s

  * igt@xe_bo_shrink@shrink-fast:
    - Statuses : 1 pass(s)
    - Exec time: [24.67] s

  * igt@xe_bo_shrink@shrink-fault-inject-blit-fast:
    - Statuses : 1 pass(s)
    - Exec time: [46.00] s

  * igt@xe_bo_shrink@shrink-fault-inject-fast:
    - Statuses : 1 pass(s)
    - Exec time: [24.82] s

  * igt@xe_bo_shrink@shrink-fault-inject-private-fast:
    - Statuses : 1 pass(s)
    - Exec time: [24.67] s

  * igt@xe_bo_shrink@shrink-private-fast:
    - Statuses : 1 pass(s)
    - Exec time: [24.69] s

  

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

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

### IGT changes ###

#### Issues hit ####

  * igt@kms_async_flips@alternate-sync-async-flip:
    - shard-bmg:          [PASS][1] -> [FAIL][2] ([Intel XE#3718] / [Intel XE#6078])
   [1]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-2/igt@kms_async_flips@alternate-sync-async-flip.html
   [2]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-9/igt@kms_async_flips@alternate-sync-async-flip.html

  * igt@kms_async_flips@alternate-sync-async-flip@pipe-a-dp-2:
    - shard-bmg:          [PASS][3] -> [FAIL][4] ([Intel XE#6078])
   [3]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-2/igt@kms_async_flips@alternate-sync-async-flip@pipe-a-dp-2.html
   [4]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-9/igt@kms_async_flips@alternate-sync-async-flip@pipe-a-dp-2.html

  * igt@kms_big_fb@linear-8bpp-rotate-270:
    - shard-bmg:          NOTRUN -> [SKIP][5] ([Intel XE#2327]) +3 other tests skip
   [5]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-9/igt@kms_big_fb@linear-8bpp-rotate-270.html

  * igt@kms_big_fb@yf-tiled-addfb-size-offset-overflow:
    - shard-bmg:          NOTRUN -> [SKIP][6] ([Intel XE#607] / [Intel XE#7361])
   [6]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-8/igt@kms_big_fb@yf-tiled-addfb-size-offset-overflow.html

  * igt@kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180-async-flip:
    - shard-bmg:          NOTRUN -> [SKIP][7] ([Intel XE#1124]) +4 other tests skip
   [7]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-2/igt@kms_big_fb@yf-tiled-max-hw-stride-64bpp-rotate-180-async-flip.html

  * igt@kms_bw@connected-linear-tiling-4-displays-target-2560x1440p:
    - shard-bmg:          NOTRUN -> [SKIP][8] ([Intel XE#7679]) +1 other test skip
   [8]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-4/igt@kms_bw@connected-linear-tiling-4-displays-target-2560x1440p.html

  * igt@kms_bw@linear-tiling-1-displays-target-2160x1440p:
    - shard-bmg:          NOTRUN -> [SKIP][9] ([Intel XE#367])
   [9]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-1/igt@kms_bw@linear-tiling-1-displays-target-2160x1440p.html

  * igt@kms_ccs@crc-primary-rotation-180-y-tiled-gen12-rc-ccs-cc:
    - shard-bmg:          NOTRUN -> [SKIP][10] ([Intel XE#2887]) +6 other tests skip
   [10]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@kms_ccs@crc-primary-rotation-180-y-tiled-gen12-rc-ccs-cc.html

  * igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs:
    - shard-bmg:          [PASS][11] -> [ABORT][12] ([Intel XE#9393] / [Intel XE#9406] / [Intel XE#9422])
   [11]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-6/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs.html
   [12]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs.html

  * igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-b-hdmi-a-3:
    - shard-bmg:          [PASS][13] -> [ABORT][14] ([Intel XE#9406] / [Intel XE#9422])
   [13]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-6/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-b-hdmi-a-3.html
   [14]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@kms_ccs@crc-primary-suspend-4-tiled-bmg-ccs@pipe-b-hdmi-a-3.html

  * igt@kms_cdclk@mode-rejected-max-dotclock:
    - shard-bmg:          NOTRUN -> [SKIP][15] ([Intel XE#9311])
   [15]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@kms_cdclk@mode-rejected-max-dotclock.html

  * igt@kms_chamelium_color_pipeline@plane-fixed-matrix-yuv-rgb-bt2020-lim-lut1d:
    - shard-bmg:          NOTRUN -> [SKIP][16] ([Intel XE#7358]) +2 other tests skip
   [16]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@kms_chamelium_color_pipeline@plane-fixed-matrix-yuv-rgb-bt2020-lim-lut1d.html

  * igt@kms_chamelium_edid@dp-edid-stress-resolution-non-4k:
    - shard-bmg:          NOTRUN -> [SKIP][17] ([Intel XE#2252]) +1 other test skip
   [17]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-1/igt@kms_chamelium_edid@dp-edid-stress-resolution-non-4k.html

  * igt@kms_content_protection@atomic-dpms-hdcp14@pipe-a-dp-2:
    - shard-bmg:          NOTRUN -> [FAIL][18] ([Intel XE#3304] / [Intel XE#7374]) +1 other test fail
   [18]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@kms_content_protection@atomic-dpms-hdcp14@pipe-a-dp-2.html

  * igt@kms_content_protection@type1:
    - shard-bmg:          NOTRUN -> [SKIP][19] ([Intel XE#7642])
   [19]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@kms_content_protection@type1.html

  * igt@kms_cursor_crc@cursor-onscreen-32x32:
    - shard-bmg:          NOTRUN -> [SKIP][20] ([Intel XE#2320]) +3 other tests skip
   [20]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@kms_cursor_crc@cursor-onscreen-32x32.html

  * igt@kms_cursor_crc@cursor-sliding-512x512:
    - shard-bmg:          NOTRUN -> [SKIP][21] ([Intel XE#2321] / [Intel XE#7355])
   [21]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-8/igt@kms_cursor_crc@cursor-sliding-512x512.html

  * igt@kms_dp_link_training@non-uhbr-sst-tbtalt-train:
    - shard-bmg:          NOTRUN -> [SKIP][22] ([Intel XE#9539])
   [22]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-3/igt@kms_dp_link_training@non-uhbr-sst-tbtalt-train.html

  * igt@kms_dp_link_training@uhbr-mst:
    - shard-bmg:          NOTRUN -> [SKIP][23] ([Intel XE#9533])
   [23]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-6/igt@kms_dp_link_training@uhbr-mst.html

  * igt@kms_dsc@dsc-with-output-formats-with-bpc:
    - shard-bmg:          NOTRUN -> [SKIP][24] ([Intel XE#8265]) +2 other tests skip
   [24]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-2/igt@kms_dsc@dsc-with-output-formats-with-bpc.html

  * igt@kms_fbc_dirty_rect@fbc-dirty-rectangle-out-visible-area:
    - shard-bmg:          NOTRUN -> [SKIP][25] ([Intel XE#4422] / [Intel XE#7442])
   [25]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-2/igt@kms_fbc_dirty_rect@fbc-dirty-rectangle-out-visible-area.html

  * igt@kms_fbcon_fbt@psr:
    - shard-bmg:          NOTRUN -> [SKIP][26] ([Intel XE#8680])
   [26]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-8/igt@kms_fbcon_fbt@psr.html

  * igt@kms_feature_discovery@dp-mst:
    - shard-bmg:          NOTRUN -> [SKIP][27] ([Intel XE#2375])
   [27]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-9/igt@kms_feature_discovery@dp-mst.html

  * igt@kms_flip@2x-flip-vs-suspend-interruptible:
    - shard-bmg:          [PASS][28] -> [DMESG-WARN][29] ([Intel XE#9365])
   [28]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-6/igt@kms_flip@2x-flip-vs-suspend-interruptible.html
   [29]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@kms_flip@2x-flip-vs-suspend-interruptible.html

  * igt@kms_flip@2x-flip-vs-suspend-interruptible@ad-dp1-hdmi-a3:
    - shard-bmg:          NOTRUN -> [DMESG-WARN][30] ([Intel XE#9365])
   [30]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@kms_flip@2x-flip-vs-suspend-interruptible@ad-dp1-hdmi-a3.html

  * igt@kms_flip_scaled_crc@flip-32bpp-yftileccs-to-64bpp-yftile-upscaling:
    - shard-bmg:          NOTRUN -> [SKIP][31] ([Intel XE#7178] / [Intel XE#7351]) +1 other test skip
   [31]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@kms_flip_scaled_crc@flip-32bpp-yftileccs-to-64bpp-yftile-upscaling.html

  * igt@kms_flip_scaled_crc@flip-32bpp-yuv-linear-to-32bpp-yuv-linear-reflect-x:
    - shard-bmg:          NOTRUN -> [SKIP][32] ([Intel XE#7179])
   [32]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-8/igt@kms_flip_scaled_crc@flip-32bpp-yuv-linear-to-32bpp-yuv-linear-reflect-x.html

  * igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-onoff:
    - shard-bmg:          NOTRUN -> [SKIP][33] ([Intel XE#4141]) +10 other tests skip
   [33]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-9/igt@kms_frontbuffer_tracking@fbc-2p-scndscrn-spr-indfb-onoff.html

  * igt@kms_frontbuffer_tracking@fbcdrrshdr-1p-primscrn-pri-indfb-draw-render:
    - shard-bmg:          NOTRUN -> [SKIP][34] ([Intel XE#2311]) +35 other tests skip
   [34]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@kms_frontbuffer_tracking@fbcdrrshdr-1p-primscrn-pri-indfb-draw-render.html

  * igt@kms_frontbuffer_tracking@fbcpsr-indfb-scaledprimary:
    - shard-bmg:          NOTRUN -> [SKIP][35] ([Intel XE#2313]) +29 other tests skip
   [35]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@kms_frontbuffer_tracking@fbcpsr-indfb-scaledprimary.html

  * igt@kms_frontbuffer_tracking@hdr-argb161616f-draw-blt:
    - shard-bmg:          NOTRUN -> [SKIP][36] ([Intel XE#7061]) +2 other tests skip
   [36]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-6/igt@kms_frontbuffer_tracking@hdr-argb161616f-draw-blt.html

  * igt@kms_hdr@invalid-hdr:
    - shard-bmg:          NOTRUN -> [SKIP][37] ([Intel XE#1503])
   [37]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@kms_hdr@invalid-hdr.html

  * igt@kms_pipe_stress@stress-xrgb8888-yftiled:
    - shard-bmg:          NOTRUN -> [SKIP][38] ([Intel XE#6912] / [Intel XE#7375])
   [38]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-6/igt@kms_pipe_stress@stress-xrgb8888-yftiled.html

  * igt@kms_plane@pixel-format-yf-tiled-ccs-modifier:
    - shard-bmg:          NOTRUN -> [SKIP][39] ([Intel XE#7283]) +1 other test skip
   [39]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-6/igt@kms_plane@pixel-format-yf-tiled-ccs-modifier.html

  * igt@kms_plane_multiple@tiling-yf:
    - shard-bmg:          NOTRUN -> [SKIP][40] ([Intel XE#5020] / [Intel XE#7348])
   [40]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-2/igt@kms_plane_multiple@tiling-yf.html

  * igt@kms_pm_backlight@basic-brightness:
    - shard-bmg:          NOTRUN -> [SKIP][41] ([Intel XE#7376] / [Intel XE#7760] / [Intel XE#870])
   [41]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-4/igt@kms_pm_backlight@basic-brightness.html

  * igt@kms_pm_dc@dc6-psr:
    - shard-bmg:          NOTRUN -> [SKIP][42] ([Intel XE#7794])
   [42]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-9/igt@kms_pm_dc@dc6-psr.html

  * igt@kms_pm_rpm@package-g7:
    - shard-bmg:          NOTRUN -> [SKIP][43] ([Intel XE#6814] / [Intel XE#7428])
   [43]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@kms_pm_rpm@package-g7.html

  * igt@kms_psr2_sf@psr2-primary-plane-update-sf-dmg-area-big-fb:
    - shard-bmg:          NOTRUN -> [SKIP][44] ([Intel XE#1489]) +6 other tests skip
   [44]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-2/igt@kms_psr2_sf@psr2-primary-plane-update-sf-dmg-area-big-fb.html

  * igt@kms_psr@psr-cursor-plane-onoff:
    - shard-bmg:          NOTRUN -> [SKIP][45] ([Intel XE#2234] / [Intel XE#2850]) +7 other tests skip
   [45]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-4/igt@kms_psr@psr-cursor-plane-onoff.html

  * igt@xe_ccs@suspend-resume:
    - shard-bmg:          [PASS][46] -> [ABORT][47] ([Intel XE#9362] / [Intel XE#9425] / [Intel XE#9581])
   [46]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-3/igt@xe_ccs@suspend-resume.html
   [47]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-9/igt@xe_ccs@suspend-resume.html

  * igt@xe_ccs@suspend-resume@xmajor-compressed-compfmt0-vram01-vram01:
    - shard-bmg:          [PASS][48] -> [ABORT][49] ([Intel XE#9362] / [Intel XE#9425])
   [48]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-3/igt@xe_ccs@suspend-resume@xmajor-compressed-compfmt0-vram01-vram01.html
   [49]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-9/igt@xe_ccs@suspend-resume@xmajor-compressed-compfmt0-vram01-vram01.html

  * igt@xe_evict@evict-mixed-many-threads-small:
    - shard-bmg:          [PASS][50] -> [INCOMPLETE][51] ([Intel XE#6321] / [Intel XE#8355])
   [50]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-10/igt@xe_evict@evict-mixed-many-threads-small.html
   [51]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-6/igt@xe_evict@evict-mixed-many-threads-small.html

  * igt@xe_evict@evict-small-external-multi-queue-cm:
    - shard-bmg:          NOTRUN -> [SKIP][52] ([Intel XE#8370])
   [52]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-1/igt@xe_evict@evict-small-external-multi-queue-cm.html

  * igt@xe_exec_basic@multigpu-many-execqueues-many-vm-bindexecqueue-userptr-invalidate-race:
    - shard-bmg:          NOTRUN -> [SKIP][53] ([Intel XE#2322] / [Intel XE#7372]) +4 other tests skip
   [53]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-10/igt@xe_exec_basic@multigpu-many-execqueues-many-vm-bindexecqueue-userptr-invalidate-race.html

  * igt@xe_exec_fault_mode@many-multi-queue-invalid-fault:
    - shard-bmg:          NOTRUN -> [SKIP][54] ([Intel XE#8374]) +5 other tests skip
   [54]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-1/igt@xe_exec_fault_mode@many-multi-queue-invalid-fault.html

  * igt@xe_exec_multi_queue@few-execs-preempt-mode-fault-priority:
    - shard-bmg:          NOTRUN -> [SKIP][55] ([Intel XE#8364]) +16 other tests skip
   [55]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@xe_exec_multi_queue@few-execs-preempt-mode-fault-priority.html

  * igt@xe_exec_threads@threads-multi-queue-userptr:
    - shard-bmg:          NOTRUN -> [SKIP][56] ([Intel XE#8378]) +2 other tests skip
   [56]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@xe_exec_threads@threads-multi-queue-userptr.html

  * igt@xe_multigpu_svm@mgpu-coherency-fail-basic:
    - shard-bmg:          NOTRUN -> [SKIP][57] ([Intel XE#6964])
   [57]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@xe_multigpu_svm@mgpu-coherency-fail-basic.html

  * igt@xe_page_reclaim@basic-mixed:
    - shard-bmg:          NOTRUN -> [SKIP][58] ([Intel XE#7793])
   [58]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@xe_page_reclaim@basic-mixed.html

  * igt@xe_pm@d3cold-mmap-system:
    - shard-bmg:          NOTRUN -> [SKIP][59] ([Intel XE#2284] / [Intel XE#7370]) +1 other test skip
   [59]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@xe_pm@d3cold-mmap-system.html

  * igt@xe_prefetch_fault@prefetch-fault-svm:
    - shard-bmg:          NOTRUN -> [SKIP][60] ([Intel XE#7599])
   [60]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@xe_prefetch_fault@prefetch-fault-svm.html

  * igt@xe_pxp@pxp-termination-key-update-post-rpm:
    - shard-bmg:          NOTRUN -> [SKIP][61] ([Intel XE#4733] / [Intel XE#7417])
   [61]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-8/igt@xe_pxp@pxp-termination-key-update-post-rpm.html

  * igt@xe_query@multigpu-query-uc-fw-version-guc:
    - shard-bmg:          NOTRUN -> [SKIP][62] ([Intel XE#944])
   [62]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-2/igt@xe_query@multigpu-query-uc-fw-version-guc.html

  
#### Possible fixes ####

  * igt@intel_hwmon@hwmon-write:
    - shard-bmg:          [FAIL][63] ([Intel XE#8583]) -> [PASS][64]
   [63]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-9/igt@intel_hwmon@hwmon-write.html
   [64]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@intel_hwmon@hwmon-write.html

  * igt@kms_async_flips@alternate-sync-async-flip-atomic:
    - shard-bmg:          [FAIL][65] ([Intel XE#3718] / [Intel XE#6078]) -> [PASS][66]
   [65]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-7/igt@kms_async_flips@alternate-sync-async-flip-atomic.html
   [66]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-5/igt@kms_async_flips@alternate-sync-async-flip-atomic.html

  * igt@kms_atomic_transition@plane-all-modeset-transition@pipe-a-dp-2:
    - shard-bmg:          [FAIL][67] ([Intel XE#8098] / [Intel XE#9561]) -> [PASS][68] +1 other test pass
   [67]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-5/igt@kms_atomic_transition@plane-all-modeset-transition@pipe-a-dp-2.html
   [68]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-2/igt@kms_atomic_transition@plane-all-modeset-transition@pipe-a-dp-2.html

  * igt@kms_cursor_legacy@flip-vs-cursor-legacy:
    - shard-bmg:          [FAIL][69] ([Intel XE#7809]) -> [PASS][70]
   [69]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-1/igt@kms_cursor_legacy@flip-vs-cursor-legacy.html
   [70]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-8/igt@kms_cursor_legacy@flip-vs-cursor-legacy.html

  * igt@kms_hdmi_inject@inject-audio:
    - shard-bmg:          [SKIP][71] ([Intel XE#7308]) -> [PASS][72]
   [71]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-5/igt@kms_hdmi_inject@inject-audio.html
   [72]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-4/igt@kms_hdmi_inject@inject-audio.html

  * igt@xe_evict@evict-beng-mixed-many-threads-small:
    - shard-bmg:          [INCOMPLETE][73] ([Intel XE#6321] / [Intel XE#8355]) -> [PASS][74]
   [73]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-10/igt@xe_evict@evict-beng-mixed-many-threads-small.html
   [74]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-3/igt@xe_evict@evict-beng-mixed-many-threads-small.html

  * igt@xe_exec_reset@gt-reset-fault-injection:
    - shard-bmg:          [ABORT][75] ([Intel XE#9145] / [Intel XE#9463]) -> [PASS][76]
   [75]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-2/igt@xe_exec_reset@gt-reset-fault-injection.html
   [76]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-8/igt@xe_exec_reset@gt-reset-fault-injection.html

  * igt@xe_fault_injection@probe-fail-guc-xe_guc_ct_send_recv:
    - shard-bmg:          [ABORT][77] ([Intel XE#9470]) -> [PASS][78]
   [77]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-8/igt@xe_fault_injection@probe-fail-guc-xe_guc_ct_send_recv.html
   [78]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-9/igt@xe_fault_injection@probe-fail-guc-xe_guc_ct_send_recv.html

  * igt@xe_sriov_flr@flr-vf1-clear:
    - shard-bmg:          [FAIL][79] ([Intel XE#6569]) -> [PASS][80]
   [79]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-4/igt@xe_sriov_flr@flr-vf1-clear.html
   [80]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-7/igt@xe_sriov_flr@flr-vf1-clear.html

  
#### Warnings ####

  * igt@kms_tiled_display@basic-test-pattern-with-chamelium:
    - shard-bmg:          [SKIP][81] ([Intel XE#2426] / [Intel XE#5848]) -> [SKIP][82] ([Intel XE#2509] / [Intel XE#7437])
   [81]: https://intel-gfx-ci.01.org/tree/intel-xe/IGT_9156/shard-bmg-5/igt@kms_tiled_display@basic-test-pattern-with-chamelium.html
   [82]: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/shard-bmg-10/igt@kms_tiled_display@basic-test-pattern-with-chamelium.html

  
  [Intel XE#1124]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1124
  [Intel XE#1489]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1489
  [Intel XE#1503]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/1503
  [Intel XE#2234]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2234
  [Intel XE#2252]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2252
  [Intel XE#2284]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2284
  [Intel XE#2311]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2311
  [Intel XE#2313]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2313
  [Intel XE#2320]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2320
  [Intel XE#2321]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2321
  [Intel XE#2322]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2322
  [Intel XE#2327]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2327
  [Intel XE#2375]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2375
  [Intel XE#2426]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2426
  [Intel XE#2509]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2509
  [Intel XE#2850]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2850
  [Intel XE#2887]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/2887
  [Intel XE#3304]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3304
  [Intel XE#367]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/367
  [Intel XE#3718]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/3718
  [Intel XE#4141]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4141
  [Intel XE#4422]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4422
  [Intel XE#4733]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/4733
  [Intel XE#5020]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5020
  [Intel XE#5848]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/5848
  [Intel XE#607]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/607
  [Intel XE#6078]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6078
  [Intel XE#6321]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6321
  [Intel XE#6569]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6569
  [Intel XE#6814]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6814
  [Intel XE#6912]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6912
  [Intel XE#6964]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/6964
  [Intel XE#7061]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7061
  [Intel XE#7178]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7178
  [Intel XE#7179]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7179
  [Intel XE#7283]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7283
  [Intel XE#7308]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7308
  [Intel XE#7348]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7348
  [Intel XE#7351]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7351
  [Intel XE#7355]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7355
  [Intel XE#7358]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7358
  [Intel XE#7361]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7361
  [Intel XE#7370]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7370
  [Intel XE#7372]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7372
  [Intel XE#7374]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7374
  [Intel XE#7375]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7375
  [Intel XE#7376]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7376
  [Intel XE#7417]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7417
  [Intel XE#7428]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7428
  [Intel XE#7437]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7437
  [Intel XE#7442]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7442
  [Intel XE#7599]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7599
  [Intel XE#7642]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7642
  [Intel XE#7679]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7679
  [Intel XE#7760]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7760
  [Intel XE#7793]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7793
  [Intel XE#7794]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7794
  [Intel XE#7809]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/7809
  [Intel XE#8098]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8098
  [Intel XE#8265]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8265
  [Intel XE#8355]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8355
  [Intel XE#8364]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8364
  [Intel XE#8370]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8370
  [Intel XE#8374]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8374
  [Intel XE#8378]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8378
  [Intel XE#8583]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8583
  [Intel XE#8680]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/8680
  [Intel XE#870]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/870
  [Intel XE#9145]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9145
  [Intel XE#9311]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9311
  [Intel XE#9362]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9362
  [Intel XE#9365]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9365
  [Intel XE#9393]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9393
  [Intel XE#9406]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9406
  [Intel XE#9422]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9422
  [Intel XE#9425]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9425
  [Intel XE#944]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/944
  [Intel XE#9463]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9463
  [Intel XE#9470]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9470
  [Intel XE#9533]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9533
  [Intel XE#9539]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9539
  [Intel XE#9561]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9561
  [Intel XE#9581]: https://gitlab.freedesktop.org/drm/xe/kernel/issues/9581


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

  * IGT: IGT_9156 -> IGTPW_16022
  * Linux: xe-5980-24d867f5e671c78760ab39087a57c25ad98e1f42 -> xe-5988-59808d4b3a8e9cb4db43b9162aa08f35956bb447

  IGTPW_16022: 16022
  IGT_9156: 9156
  xe-5980-24d867f5e671c78760ab39087a57c25ad98e1f42: 24d867f5e671c78760ab39087a57c25ad98e1f42
  xe-5988-59808d4b3a8e9cb4db43b9162aa08f35956bb447: 59808d4b3a8e9cb4db43b9162aa08f35956bb447

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/intel-xe/IGTPW_16022/index.html

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

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

* Re: [PATCH i-g-t] tests/intel/xe_bo_shrink: Add a user-space shrinker test
  2026-10-21 12:33 [PATCH i-g-t] tests/intel/xe_bo_shrink: Add a user-space shrinker test Thomas Hellström
  2026-10-21 15:03 ` ✗ Xe.CI.FULL: failure for " Patchwork
@ 2026-10-21 19:09 ` Matthew Brost
  2026-10-22 11:22 ` Matthew Auld
  2 siblings, 0 replies; 4+ messages in thread
From: Matthew Brost @ 2026-10-21 19:09 UTC (permalink / raw)
  To: Thomas Hellström; +Cc: igt-dev, Kamil Konieczny, Matthew Auld

On Wed, Oct 21, 2026 at 02:33:11PM +0200, Thomas Hellström wrote:
> Add a user-space counterpart of the xe_bo_shrink kunit test, now that
> user-space can mark buffer objects purgeable using the madvise IOCTL.
> 
> The test creates 64 MiB system buffer objects corresponding to twice
> the amount of free system memory, fills them with pseudo-random data
> through CPU mappings that are kept alive until readback, and verifies
> the contents after the overcommit has forced the shrinker to back up
> or purge them. As in the kunit test, the share of the memory that
> doesn't fit in free RAM and swap is marked purgeable (DONTNEED) and
> allocated first. Purgeable objects are only verified if found retained
> when marked WILLNEED again; purged objects are never accessed.
> 
> Subtests:
> - shrink: The kunit test equivalent.
> - purge: Ignore swap space when sizing the purgeable share, so that
>   the shrinker needs to purge rather than swap.
> - shrink-fault-inject: Enable TTM backup / restore fault injection
>   through debugfs, if available, making the shrinker back up only part
>   of the objects and making backup and restore of individual pages
>   fail. The number of injected faults is checked to be non-zero.
> - *-blit: Rather than restoring objects by CPU faults, restore them
>   through a GPU bind and read them back by a MEM_COPY blit to a dummy
>   object in a separate VM. On discrete devices, objects are created
>   with system and VRAM placements, prefetched to system memory on
>   creation and prefetched to VRAM before the copy, so that they are
>   restored by the migration to VRAM.
> - *-private: Create the objects private to the test VM rather than as
>   external objects.
> - *-fast: Allocate at most the free system memory, half of it
>   purgeable, capped to 8 GiB purgeable and 8 GiB non-purgeable, and
>   shrink using drop_caches rather than memory overcommit.
> 
> The non-fast subtests are slow and require a substantial amount of
> swap space for meaningful coverage, so block them in CI and run only
> the fast subtests.
> 
> Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
> Cc: Matthew Auld <matthew.auld@intel.com>
> Cc: Matthew Brost <matthew.brost@intel.com>

I don't have the bandwidth for a full review at the moment, but based on
the commit message, the test cases look good to me. I actually have a
somewhat similar local shrinker test that was generated with Copilot.

One suggestion would be to add a section where a non-GPU thread also
triggers memory pressure. For example, it could either mmap() a large
amount of memory or create files in a loop. This would better simulate
other parts of the OS consuming memory. An example of this can be found
in frag_thread_fn() in [1].

Not blocker, so for test as is:
Acked-by: Matthew Brost <matthew.brost@intel.com>

Matt

[1] https://patchwork.freedesktop.org/patch/739244/?series=169723&rev=2

> Assisted-by: GitHub_Copilot:claude-opus-5.5
> ---
>  tests/intel-ci/xe.blocklist.txt |   3 +-
>  tests/intel/xe_bo_shrink.c      | 610 ++++++++++++++++++++++++++++++++
>  tests/meson.build               |   1 +
>  3 files changed, 613 insertions(+), 1 deletion(-)
>  create mode 100644 tests/intel/xe_bo_shrink.c
> 
> diff --git a/tests/intel-ci/xe.blocklist.txt b/tests/intel-ci/xe.blocklist.txt
> index c1dd3c7a8..ba589aac2 100644
> --- a/tests/intel-ci/xe.blocklist.txt
> +++ b/tests/intel-ci/xe.blocklist.txt
> @@ -35,9 +35,10 @@ igt@gpu_buddy
>  igt@drm_mm
>  igt@kms_selftest.*
>  ##################################################################
> -# Exclude slow KUnit test which should run as manual test
> +# Exclude slow shrinker tests which should run as manual tests
>  ##################################################################
>  igt@xe_live_ktest@xe_bo_shrink
> +igt@xe_bo_shrink@(?!.*-fast$).*
>  ##################################################################
>  # Exclude all other non-Xe tests
>  ##################################################################
> diff --git a/tests/intel/xe_bo_shrink.c b/tests/intel/xe_bo_shrink.c
> new file mode 100644
> index 000000000..6210923af
> --- /dev/null
> +++ b/tests/intel/xe_bo_shrink.c
> @@ -0,0 +1,610 @@
> +// SPDX-License-Identifier: MIT
> +/*
> + * Copyright © 2026 Intel Corporation
> + */
> +
> +/**
> + * TEST: Exercise the xe buffer object shrinker from user-space
> + * Category: Core
> + * Mega feature: General Core features
> + * Sub-category: Memory management tests
> + * Functionality: shrinker, swap, purgeable
> + *
> + * This is a user-space counterpart of the xe_bo_shrink kunit test.
> + * It creates system memory buffer objects corresponding to twice the
> + * amount of free system memory. All objects are filled with pseudo-random
> + * data through a CPU mapping that is kept alive until the data is verified
> + * after the overcommit. Purgeable objects are additionally marked DONTNEED
> + * using the madvise IOCTL so that the shrinker may discard their contents.
> + * Those are only verified if still retained when marked WILLNEED again.
> + *
> + * The blit variants never read the bos using the CPU. Instead each bo is
> + * bound to a separate VM and copied to a dummy bo using the MEM_COPY
> + * blitter command, so that bos are restored by the GPU paths rather than
> + * by CPU faults, and the content of the dummy bo is verified. On discrete
> + * devices, the blit variants create the bos with both system and VRAM
> + * placements and immediately prefetch them to system memory. Before the
> + * copy, each bo is prefetched to VRAM, so that it is restored by the
> + * migration to VRAM.
> + *
> + * The private variants create the bos private to the test VM, sharing
> + * the VM's reservation object, rather than as external bos.
> + *
> + * The fast variants instead create bos corresponding to the amount of
> + * free system memory, half of them purgeable, capped to
> + * XE_BO_SHRINK_FAST_MAX purgeable and non-purgeable each, and shrink
> + * them by writing to /proc/sys/vm/drop_caches rather than relying on
> + * reclaim caused by memory overcommit.
> + */
> +
> +#include <sys/random.h>
> +#include <sys/sysinfo.h>
> +
> +#include "igt.h"
> +#include "igt_debugfs.h"
> +#include "igt_rand.h"
> +#include "igt_sysfs.h"
> +#include "intel_blt.h"
> +#include "intel_mocs.h"
> +#include "xe_drm.h"
> +
> +#include "intel_reg.h"
> +#include "xe/xe_ioctl.h"
> +#include "xe/xe_query.h"
> +
> +#define XE_BO_SHRINK_SIZE	(64ull << 20)
> +#define XE_BO_SHRINK_VA_BASE	(1ull << 32)
> +/* Max purgeable and max non-purgeable memory, each, for fast variants. */
> +#define XE_BO_SHRINK_FAST_MAX	(8ull << 30)
> +
> +#define BLIT_BATCH_ADDR		(1ull << 20)
> +#define BLIT_DST_ADDR		(1ull << 32)
> +#define BLIT_SRC_ADDR		(2ull << 32)
> +
> +#define SHRINK_PURGE		(0x1 << 0)
> +#define SHRINK_FAULT_INJECT	(0x1 << 1)
> +#define SHRINK_BLIT		(0x1 << 2)
> +#define SHRINK_FAST		(0x1 << 3)
> +#define SHRINK_PRIVATE		(0x1 << 4)
> +
> +/**
> + * struct shrink_bo - A shrinker test bo
> + * @map: Persistent CPU mapping of the bo, kept from fill until readback.
> + * @handle: GEM handle of the bo.
> + * @addr: GPU virtual address of the bo in the test VM, if @bound.
> + * @val: The first pseudo-random value written, used to detect a PRNG
> + * that is out of sync on readback.
> + * @purgeable: Whether the bo is marked DONTNEED and thus may be purged.
> + * @bound: Whether the bo is bound at @addr in the test VM.
> + */
> +struct shrink_bo {
> +	uint32_t *map;
> +	uint32_t handle;
> +	uint64_t addr;
> +	uint32_t val;
> +	bool purgeable;
> +	bool bound;
> +};
> +
> +/**
> + * struct shrink_blit - State for blitter readback of bos
> + * @vm: A separate VM used for the copies.
> + * @exec_queue: Copy engine exec queue in @vm.
> + * @batch: Batch bo holding the MEM_COPY command.
> + * @dst: Dummy destination bo, in system memory.
> + * @dst_map: CPU mapping of @dst, used to verify the copied content.
> + */
> +struct shrink_blit {
> +	uint32_t vm;
> +	uint32_t exec_queue;
> +	uint32_t batch;
> +	uint32_t dst;
> +	uint32_t *dst_map;
> +};
> +
> +/**
> + * struct ttm_fault_inject - TTM backup / restore fault injection state
> + * @dir: Debugfs directory fd of the fault attributes, or -1 if not opened.
> + * @probability: Original probability, restored after the test.
> + * @interval: Original interval, restored after the test.
> + * @times: Original times, restored after the test.
> + * @verbose: Original verbosity, restored after the test.
> + * @task_filter: Original task-filter setting, restored after the test.
> + */
> +static struct ttm_fault_inject {
> +	int dir;
> +	uint32_t probability;
> +	uint32_t interval;
> +	int32_t times;
> +	uint32_t verbose;
> +	bool task_filter;
> +} ttm_fi = { .dir = -1 };
> +
> +static void ttm_fault_inject_restore(int sig)
> +{
> +	if (ttm_fi.dir < 0)
> +		return;
> +
> +	__igt_sysfs_set_u32(ttm_fi.dir, "probability", ttm_fi.probability);
> +	__igt_sysfs_set_u32(ttm_fi.dir, "interval", ttm_fi.interval);
> +	__igt_sysfs_set_s32(ttm_fi.dir, "times", ttm_fi.times);
> +	__igt_sysfs_set_u32(ttm_fi.dir, "verbose", ttm_fi.verbose);
> +	__igt_sysfs_set_boolean(ttm_fi.dir, "task-filter", ttm_fi.task_filter);
> +	close(ttm_fi.dir);
> +	ttm_fi.dir = -1;
> +}
> +
> +/*
> + * Enable the TTM backup_fault_inject attribute, which makes the shrinker
> + * back up only part of a bo, fails backup of individual folios and makes
> + * interruptible restores fail with -EINTR. Requires CONFIG_FAULT_INJECTION
> + * and CONFIG_FAULT_INJECTION_DEBUG_FS.
> + */
> +static void ttm_fault_inject_enable(void)
> +{
> +	const char *debugfs_root = igt_debugfs_mount();
> +	char path[PATH_MAX];
> +
> +	igt_require_f(debugfs_root, "debugfs not available\n");
> +	snprintf(path, sizeof(path), "%s/ttm/backup_fault_inject", debugfs_root);
> +	ttm_fi.dir = open(path, O_RDONLY | O_DIRECTORY);
> +	igt_require_f(ttm_fi.dir >= 0,
> +		      "TTM backup fault injection not available (%s)\n", path);
> +
> +	ttm_fi.probability = igt_sysfs_get_u32(ttm_fi.dir, "probability");
> +	ttm_fi.interval = igt_sysfs_get_u32(ttm_fi.dir, "interval");
> +	ttm_fi.times = igt_sysfs_get_s32(ttm_fi.dir, "times");
> +	ttm_fi.verbose = igt_sysfs_get_u32(ttm_fi.dir, "verbose");
> +	ttm_fi.task_filter = igt_sysfs_get_boolean(ttm_fi.dir, "task-filter");
> +	igt_install_exit_handler(ttm_fault_inject_restore);
> +
> +	igt_sysfs_set_boolean(ttm_fi.dir, "task-filter", false);
> +	igt_sysfs_set_u32(ttm_fi.dir, "verbose", 0);
> +	igt_sysfs_set_u32(ttm_fi.dir, "interval", 1);
> +	/* The kernel decrements times on each injection. */
> +	igt_sysfs_set_s32(ttm_fi.dir, "times", INT32_MAX);
> +	igt_sysfs_set_u32(ttm_fi.dir, "probability", 10);
> +}
> +
> +static int32_t ttm_fault_inject_count(void)
> +{
> +	return INT32_MAX - igt_sysfs_get_s32(ttm_fi.dir, "times");
> +}
> +
> +static bool xe_has_purgeable_support(int fd)
> +{
> +	struct drm_xe_query_config *config = xe_config(fd);
> +
> +	return config->info[DRM_XE_QUERY_CONFIG_FLAGS] &
> +		DRM_XE_QUERY_CONFIG_FLAG_HAS_PURGING_SUPPORT;
> +}
> +
> +/*
> + * The CPU mapping is kept until shrink_verify(), so that the shrinker
> + * needs to zap the PTEs of a live mapping and readback restores the
> + * bo through that same mapping.
> + */
> +static void shrink_fill_random(int fd, struct shrink_bo *bo, uint32_t *prng)
> +{
> +	uint32_t *map = xe_bo_map(fd, bo->handle, XE_BO_SHRINK_SIZE);
> +	size_t i;
> +
> +	for (i = 0; i < XE_BO_SHRINK_SIZE / sizeof(*map); i++)
> +		map[i] = hars_petruska_f54_1_random(prng);
> +
> +	bo->val = map[0];
> +	bo->map = map;
> +}
> +
> +static void shrink_verify(const uint32_t *map, uint32_t first_val,
> +			  unsigned int bo_nr, uint32_t *prng)
> +{
> +	size_t i;
> +
> +	for (i = 0; i < XE_BO_SHRINK_SIZE / sizeof(*map); i++) {
> +		uint32_t val = hars_petruska_f54_1_random(prng);
> +
> +		igt_assert_f(map[i] == val,
> +			     "Content not preserved, bo %u offset 0x%016zx. "
> +			     "Failed value is 0x%08x, recorded 0x%08x.%s\n",
> +			     bo_nr, i * sizeof(*map), map[i], val,
> +			     (i == 0 && val != first_val) ?
> +			     " Looks like PRNG is out of sync." : "");
> +	}
> +}
> +
> +/*
> + * The bo was purged. Never touch its mapping, but advance the
> + * pseudo-random sequence to keep it in sync for the following bos.
> + */
> +static void shrink_skip(struct shrink_bo *bo, uint32_t *prng)
> +{
> +	size_t i;
> +
> +	for (i = 0; i < XE_BO_SHRINK_SIZE / sizeof(*bo->map); i++)
> +		hars_petruska_f54_1_random(prng);
> +
> +	munmap(bo->map, XE_BO_SHRINK_SIZE);
> +}
> +
> +/*
> + * Set up a separate VM with a dummy destination bo and a batch copying
> + * a bo bound at BLIT_SRC_ADDR to the dummy bo. A separate VM is used so
> + * that exec doesn't need to revalidate any other shrinker test bos.
> + */
> +static void shrink_blit_init(int fd, struct shrink_blit *blit)
> +{
> +	uint32_t width = XE_BO_SHRINK_SIZE / 256;
> +	uint32_t devid = intel_get_drm_devid(fd);
> +	uint32_t mocs = intel_get_uc_mocs_index(fd);
> +	uint64_t bb_size = xe_bb_size(fd, SZ_4K);
> +	uint32_t *cmd;
> +	int i = 0;
> +
> +	blit->vm = xe_vm_create(fd, 0, 0);
> +	blit->exec_queue = xe_exec_queue_create_class(fd, blit->vm,
> +						      DRM_XE_ENGINE_CLASS_COPY);
> +
> +	blit->dst = xe_bo_create_caching(fd, 0, XE_BO_SHRINK_SIZE,
> +					 system_memory(fd), 0,
> +					 DRM_XE_GEM_CPU_CACHING_WB);
> +	blit->dst_map = xe_bo_map(fd, blit->dst, XE_BO_SHRINK_SIZE);
> +	xe_vm_bind_sync(fd, blit->vm, blit->dst, 0, BLIT_DST_ADDR,
> +			XE_BO_SHRINK_SIZE);
> +
> +	blit->batch = xe_bo_create(fd, 0, bb_size, system_memory(fd), 0);
> +	cmd = xe_bo_map(fd, blit->batch, bb_size);
> +	/* Linear page mode copy, 256 byte units. */
> +	cmd[i++] = MEM_COPY_CMD | (1 << 19);
> +	cmd[i++] = width - 1;
> +	cmd[i++] = 0;
> +	cmd[i++] = width - 1;
> +	cmd[i++] = width - 1;
> +	cmd[i++] = lower_32_bits(BLIT_SRC_ADDR);
> +	cmd[i++] = upper_32_bits(BLIT_SRC_ADDR);
> +	cmd[i++] = lower_32_bits(BLIT_DST_ADDR);
> +	cmd[i++] = upper_32_bits(BLIT_DST_ADDR);
> +	if (intel_graphics_ver(devid) >= IP_VER(20, 0))
> +		cmd[i++] = mocs << XE2_MEM_COPY_SRC_MOCS_SHIFT | mocs;
> +	else
> +		cmd[i++] = mocs << GEN12_MEM_COPY_MOCS_SHIFT | mocs;
> +	cmd[i++] = MI_BATCH_BUFFER_END;
> +	munmap(cmd, bb_size);
> +	xe_vm_bind_sync(fd, blit->vm, blit->batch, 0, BLIT_BATCH_ADDR, bb_size);
> +}
> +
> +static void shrink_blit_fini(int fd, struct shrink_blit *blit)
> +{
> +	munmap(blit->dst_map, XE_BO_SHRINK_SIZE);
> +	xe_exec_queue_destroy(fd, blit->exec_queue);
> +	xe_vm_destroy(fd, blit->vm);
> +	gem_close(fd, blit->batch);
> +	gem_close(fd, blit->dst);
> +}
> +
> +/* Restore @bo through a GPU bind and copy, and return the copy. */
> +static const uint32_t *shrink_blit_copy(int fd, struct shrink_blit *blit,
> +					struct shrink_bo *bo)
> +{
> +	xe_vm_bind_sync(fd, blit->vm, bo->handle, 0, BLIT_SRC_ADDR,
> +			XE_BO_SHRINK_SIZE);
> +	xe_exec_wait(fd, blit->exec_queue, BLIT_BATCH_ADDR);
> +	xe_vm_unbind_sync(fd, blit->vm, 0, BLIT_SRC_ADDR, XE_BO_SHRINK_SIZE);
> +
> +	return blit->dst_map;
> +}
> +
> +/**
> + * SUBTEST: shrink
> + * Description:
> + *	Create system bos corresponding to twice the amount of free system
> + *	memory to test shrinker functionality. If no swap space is available
> + *	to accommodate the memory overcommit, mark bos purgeable.
> + * Test category: functionality test
> + *
> + * SUBTEST: purge
> + * Description:
> + *	Create system bos corresponding to twice the amount of free system
> + *	memory and mark the bos needed to accommodate the memory overcommit
> + *	purgeable regardless of available swap space, to make sure the
> + *	shrinker purges rather than swaps.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-fault-inject
> + * Description:
> + *	Same as shrink, but with TTM backup and restore fault injection
> + *	enabled, making the shrinker back up only part of the bos and
> + *	making backup and restore of individual pages fail.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-blit
> + * Description:
> + *	Same as shrink, but restore and read back bos using a blitter copy
> + *	to a dummy bo instead of CPU access. On discrete devices, bos are
> + *	restored by a prefetch to VRAM.
> + * Test category: functionality test
> + *
> + * SUBTEST: purge-blit
> + * Description:
> + *	Same as purge, but restore and read back bos using a blitter copy
> + *	to a dummy bo instead of CPU access. On discrete devices, bos are
> + *	restored by a prefetch to VRAM.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-fault-inject-blit
> + * Description:
> + *	Same as shrink-fault-inject, but restore and read back bos using a
> + *	blitter copy to a dummy bo instead of CPU access. On discrete
> + *	devices, bos are restored by a prefetch to VRAM.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-fast
> + * Description:
> + *	Create system bos corresponding to the amount of free system memory,
> + *	half of them purgeable, and shrink them using drop_caches rather
> + *	than memory overcommit.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-blit-fast
> + * Description:
> + *	Same as shrink-fast, but restore and read back bos using a blitter
> + *	copy to a dummy bo instead of CPU access. On discrete devices, bos
> + *	are restored by a prefetch to VRAM.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-fault-inject-fast
> + * Description:
> + *	Same as shrink-fast, but with TTM backup and restore fault injection
> + *	enabled.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-fault-inject-blit-fast
> + * Description:
> + *	Same as shrink-blit-fast, but with TTM backup and restore fault
> + *	injection enabled.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-private-fast
> + * Description:
> + *	Same as shrink-fast, but with bos private to the test VM.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-fault-inject-private-fast
> + * Description:
> + *	Same as shrink-fault-inject-fast, but with bos private to the test VM.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-private
> + * Description:
> + *	Same as shrink, but with bos private to the test VM.
> + * Test category: functionality test
> + *
> + * SUBTEST: purge-private
> + * Description:
> + *	Same as purge, but with bos private to the test VM.
> + * Test category: functionality test
> + *
> + * SUBTEST: shrink-fault-inject-private
> + * Description:
> + *	Same as shrink-fault-inject, but with bos private to the test VM.
> + * Test category: functionality test
> + */
> +static void shrink_test_run_device(int fd, unsigned int flags)
> +{
> +	uint64_t ram, ram_and_swap, purgeable = 0, alloced, to_alloc, limit;
> +	unsigned int count = 0, nr_bos = 0, purged = 0, retained = 0;
> +	struct shrink_bo *bos;
> +	struct sysinfo si;
> +	struct shrink_blit blit;
> +	uint64_t placement = system_memory(fd);
> +	uint16_t cpu_caching = DRM_XE_GEM_CPU_CACHING_WB;
> +	uint32_t seed, prng, vram_region = 0;
> +	bool prefetch = false;
> +	uint32_t vm;
> +	int ret;
> +
> +	if (flags & SHRINK_BLIT) {
> +		igt_require_f(blt_has_mem_copy(fd), "MEM_COPY not supported\n");
> +		prefetch = xe_has_vram(fd);
> +	}
> +
> +	if (prefetch) {
> +		placement |= vram_memory(fd, 0);
> +		cpu_caching = DRM_XE_GEM_CPU_CACHING_WC;
> +		vram_region = xe_mem_region(fd, vram_memory(fd, 0))->instance;
> +	}
> +
> +	igt_assert_eq(getrandom(&seed, sizeof(seed), 0), sizeof(seed));
> +	igt_info("Random seed is 0x%08x.\n", seed);
> +
> +	/* Skip if execution time is expected to be too long. */
> +	limit = 32ull << 30;
> +	/* IGFX with flat CCS needs to copy when swapping / shrinking */
> +	if (!xe_has_vram(fd) && blt_platform_has_flat_ccs_enabled(fd))
> +		limit = 16ull << 30;
> +
> +	igt_assert_eq(sysinfo(&si), 0);
> +	ram = (uint64_t)si.freeram * si.mem_unit;
> +
> +	if (flags & SHRINK_FAST) {
> +		/* No overcommit. Shrinking is triggered using drop_caches. */
> +		purgeable = min_t(uint64_t, ram / 2, XE_BO_SHRINK_FAST_MAX);
> +		to_alloc = purgeable + min_t(uint64_t, ram - purgeable,
> +					   XE_BO_SHRINK_FAST_MAX);
> +	} else {
> +		igt_require_f(ram <= limit, "Too long expected execution time.\n");
> +		to_alloc = ram * 2;
> +
> +		ram_and_swap = (flags & SHRINK_PURGE) ? ram :
> +			ram + (uint64_t)si.freeswap * si.mem_unit;
> +		if (to_alloc > ram_and_swap)
> +			purgeable = to_alloc - ram_and_swap;
> +		purgeable += purgeable / 5;
> +	}
> +
> +	igt_info("Free ram is %" PRIu64 " bytes. Will allocate %" PRIu64
> +		 " bytes, %" PRIu64 " bytes purgeable.\n",
> +		 ram, to_alloc, purgeable);
> +	igt_require_f(!purgeable || xe_has_purgeable_support(fd),
> +		      "Kernel does not support purgeable buffer objects\n");
> +
> +	if (flags & SHRINK_FAULT_INJECT)
> +		ttm_fault_inject_enable();
> +
> +	bos = calloc(DIV_ROUND_UP(to_alloc, XE_BO_SHRINK_SIZE), sizeof(*bos));
> +	igt_assert(bos);
> +
> +	if (flags & SHRINK_BLIT)
> +		shrink_blit_init(fd, &blit);
> +
> +	vm = xe_vm_create(fd, 0, 0);
> +	prng = seed;
> +	for (alloced = 0; alloced < to_alloc; alloced += XE_BO_SHRINK_SIZE) {
> +		struct shrink_bo *bo = &bos[nr_bos];
> +
> +		/* The uAPI requires WC with VRAM placement. */
> +		ret = __xe_bo_create_caching(fd,
> +					     (flags & SHRINK_PRIVATE) ? vm : 0,
> +					     XE_BO_SHRINK_SIZE,
> +					     placement, 0, cpu_caching,
> +					     &bo->handle);
> +		if (ret) {
> +			igt_assert_f(ret == -ENOMEM || ret == -ENOSPC ||
> +				     ret == -EINTR,
> +				     "Error creating bo: %d\n", ret);
> +			igt_info("Bo creation failed with %d after %" PRIu64
> +				 " bytes.\n", ret, alloced);
> +			break;
> +		}
> +		nr_bos++;
> +
> +		/*
> +		 * Allocate purgeable bos first, because if we do it the
> +		 * other way around, they may not be subject to swapping...
> +		 * Purgeable state and prefetch are set per VMA, so bind
> +		 * the bo first.
> +		 */
> +		bo->purgeable = alloced < purgeable;
> +		bo->bound = bo->purgeable || prefetch;
> +		bo->addr = XE_BO_SHRINK_VA_BASE + alloced;
> +		if (bo->bound)
> +			xe_vm_bind_sync(fd, vm, bo->handle, 0, bo->addr,
> +					XE_BO_SHRINK_SIZE);
> +		/* CPU faults wait for the migration to complete. */
> +		if (prefetch)
> +			xe_vm_prefetch_async(fd, vm, 0, 0, bo->addr,
> +					     XE_BO_SHRINK_SIZE, NULL, 0, 0);
> +
> +		/* mmap() is blocked in DONTNEED state, so fill first. */
> +		shrink_fill_random(fd, bo, &prng);
> +
> +		/*
> +		 * The CPU mapping is kept, but must not be accessed until
> +		 * the bo is marked WILLNEED and found retained.
> +		 */
> +		if (bo->purgeable)
> +			xe_vm_madvise_purgeable(fd, vm, bo->addr,
> +						XE_BO_SHRINK_SIZE,
> +						DRM_XE_VMA_PURGEABLE_STATE_DONTNEED);
> +	}
> +
> +	if (flags & SHRINK_FAST)
> +		igt_purge_vm_caches(fd);
> +
> +	/*
> +	 * Read back and destroy bos. Reset the pseudo-random seed to get an
> +	 * identical pseudo-random number sequence for readback.
> +	 */
> +	prng = seed;
> +	for (count = 0; count < nr_bos; count++) {
> +		struct shrink_bo *bo = &bos[count];
> +
> +		if (bo->purgeable &&
> +		    !xe_vm_madvise_purgeable(fd, vm, bo->addr,
> +					     XE_BO_SHRINK_SIZE,
> +					     DRM_XE_VMA_PURGEABLE_STATE_WILLNEED)) {
> +			purged++;
> +			shrink_skip(bo, &prng);
> +		} else {
> +			const uint32_t *map = bo->map;
> +
> +			retained += bo->purgeable;
> +			/* The blit bind and exec wait for the migration. */
> +			if (prefetch)
> +				xe_vm_prefetch_async(fd, vm, 0, 0, bo->addr,
> +						     XE_BO_SHRINK_SIZE, NULL, 0,
> +						     vram_region);
> +			if (flags & SHRINK_BLIT)
> +				map = shrink_blit_copy(fd, &blit, bo);
> +			shrink_verify(map, bo->val, count + 1, &prng);
> +			munmap(bo->map, XE_BO_SHRINK_SIZE);
> +		}
> +
> +		if (bo->bound)
> +			xe_vm_unbind_sync(fd, vm, 0, bo->addr, XE_BO_SHRINK_SIZE);
> +		gem_close(fd, bo->handle);
> +	}
> +
> +	igt_info("Readbacks successful: %u (%u purgeable retained), purgeable bos purged: %u\n",
> +		 nr_bos - purged, retained, purged);
> +
> +	if (flags & SHRINK_BLIT)
> +		shrink_blit_fini(fd, &blit);
> +	xe_vm_destroy(fd, vm);
> +	free(bos);
> +
> +	if (flags & SHRINK_FAST)
> +		igt_assert_f(purged > 0, "No purgeable bos were purged\n");
> +
> +	if (flags & SHRINK_FAULT_INJECT) {
> +		int32_t injected = ttm_fault_inject_count();
> +
> +		ttm_fault_inject_restore(0);
> +		igt_info("TTM backup / restore faults injected: %d\n", injected);
> +		igt_assert_f(injected > 0,
> +			     "No TTM backup / restore faults were injected\n");
> +	}
> +}
> +
> +int igt_main()
> +{
> +	const struct section {
> +		const char *name;
> +		unsigned int flags;
> +	} sections[] = {
> +		{ "shrink-fast", SHRINK_FAST },
> +		{ "shrink-blit-fast", SHRINK_FAST | SHRINK_BLIT },
> +		{ "shrink-fault-inject-fast", SHRINK_FAST | SHRINK_FAULT_INJECT },
> +		{ "shrink-fault-inject-blit-fast",
> +		  SHRINK_FAST | SHRINK_FAULT_INJECT | SHRINK_BLIT },
> +		{ "shrink-private-fast", SHRINK_FAST | SHRINK_PRIVATE },
> +		{ "shrink-fault-inject-private-fast",
> +		  SHRINK_FAST | SHRINK_FAULT_INJECT | SHRINK_PRIVATE },
> +		{ "shrink", 0 },
> +		{ "shrink-blit", SHRINK_BLIT },
> +		{ "purge", SHRINK_PURGE },
> +		{ "purge-blit", SHRINK_PURGE | SHRINK_BLIT },
> +		{ "shrink-fault-inject", SHRINK_FAULT_INJECT },
> +		{ "shrink-fault-inject-blit", SHRINK_FAULT_INJECT | SHRINK_BLIT },
> +		{ "shrink-private", SHRINK_PRIVATE },
> +		{ "purge-private", SHRINK_PURGE | SHRINK_PRIVATE },
> +		{ "shrink-fault-inject-private", SHRINK_FAULT_INJECT | SHRINK_PRIVATE },
> +		{ }
> +	};
> +	int fd;
> +
> +	igt_fixture() {
> +		fd = drm_open_driver(DRIVER_XE);
> +		xe_device_get(fd);
> +	}
> +
> +	for (const struct section *s = sections; s->name; s++)
> +		igt_subtest(s->name)
> +			shrink_test_run_device(fd, s->flags);
> +
> +	igt_fixture() {
> +		ttm_fault_inject_restore(0);
> +		xe_device_put(fd);
> +		drm_close_driver(fd);
> +	}
> +}
> diff --git a/tests/meson.build b/tests/meson.build
> index 519a9e727..2f50f000d 100644
> --- a/tests/meson.build
> +++ b/tests/meson.build
> @@ -284,6 +284,7 @@ intel_kms_progs = [
>  
>  intel_xe_progs = [
>  	'xe_wedged',
> +	'xe_bo_shrink',
>  	'xe_ccs',
>  	'xe_create',
>  	'xe_compute',
> -- 
> 2.56.0
> 

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

* Re: [PATCH i-g-t] tests/intel/xe_bo_shrink: Add a user-space shrinker test
  2026-10-21 12:33 [PATCH i-g-t] tests/intel/xe_bo_shrink: Add a user-space shrinker test Thomas Hellström
  2026-10-21 15:03 ` ✗ Xe.CI.FULL: failure for " Patchwork
  2026-10-21 19:09 ` [PATCH i-g-t] " Matthew Brost
@ 2026-10-22 11:22 ` Matthew Auld
  2 siblings, 0 replies; 4+ messages in thread
From: Matthew Auld @ 2026-10-22 11:22 UTC (permalink / raw)
  To: Thomas Hellström, igt-dev; +Cc: Kamil Konieczny, Matthew Brost

On 21/10/2026 13:33, Thomas Hellström wrote:
> Add a user-space counterpart of the xe_bo_shrink kunit test, now that
> user-space can mark buffer objects purgeable using the madvise IOCTL.
> 
> The test creates 64 MiB system buffer objects corresponding to twice
> the amount of free system memory, fills them with pseudo-random data
> through CPU mappings that are kept alive until readback, and verifies
> the contents after the overcommit has forced the shrinker to back up
> or purge them. As in the kunit test, the share of the memory that
> doesn't fit in free RAM and swap is marked purgeable (DONTNEED) and
> allocated first. Purgeable objects are only verified if found retained
> when marked WILLNEED again; purged objects are never accessed.
> 
> Subtests:
> - shrink: The kunit test equivalent.
> - purge: Ignore swap space when sizing the purgeable share, so that
>    the shrinker needs to purge rather than swap.
> - shrink-fault-inject: Enable TTM backup / restore fault injection
>    through debugfs, if available, making the shrinker back up only part
>    of the objects and making backup and restore of individual pages
>    fail. The number of injected faults is checked to be non-zero.
> - *-blit: Rather than restoring objects by CPU faults, restore them
>    through a GPU bind and read them back by a MEM_COPY blit to a dummy
>    object in a separate VM. On discrete devices, objects are created
>    with system and VRAM placements, prefetched to system memory on
>    creation and prefetched to VRAM before the copy, so that they are
>    restored by the migration to VRAM.

Do we use any compression here on igpu? IIRC that is still a pretty big 
test gap. We have the equivalent for VRAM via the CCS evict test, but I 
don't think we have anything for igpu + CCS via shrinker. Maybe the 
kunit does it, but IIUC that is never run in CI?

> - *-private: Create the objects private to the test VM rather than as
>    external objects.
> - *-fast: Allocate at most the free system memory, half of it
>    purgeable, capped to 8 GiB purgeable and 8 GiB non-purgeable, and
>    shrink using drop_caches rather than memory overcommit.
> 
> The non-fast subtests are slow and require a substantial amount of
> swap space for meaningful coverage, so block them in CI and run only
> the fast subtests.

Were there any issues with the test itself getting killed? I seem to 
vaguely remember something like that from the i915 shrinker test. Or is 
that not a concern here?


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

end of thread, other threads:[~2026-10-22 11:26 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-21 12:33 [PATCH i-g-t] tests/intel/xe_bo_shrink: Add a user-space shrinker test Thomas Hellström
2026-10-21 15:03 ` ✗ Xe.CI.FULL: failure for " Patchwork
2026-10-21 19:09 ` [PATCH i-g-t] " Matthew Brost
2026-10-22 11:22 ` Matthew Auld

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox