Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Tvrtko Ursulin <tvrtko.ursulin@igalia.com>
To: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>,
	igt-dev@lists.freedesktop.org
Cc: siqueira@igalia.com, dri-devel@lists.freedesktop.org,
	amd-gfx@lists.freedesktop.org, intel-xe@lists.freedesktop.org,
	"Christian Koenig" <christian.koenig@amd.com>,
	maarten.lankhorst@linux.intel.com,
	"Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
	"Kamil Konieczny" <kamil.konieczny@linux.intel.com>,
	"Janusz Krzysztofik" <janusz.krzysztofik@linux.intel.com>,
	"Vitaly Prosyak" <vitaly.prosyak@amd.com>,
	"Natalie Vock" <natalie.vock@gmx.de>,
	kernel-dev@igalia.com
Subject: Re: [PATCH i-g-t v6 8/9] tests/cgroup_dmem: add dmem cgroup eviction test
Date: Fri, 4 Sep 2026 15:48:46 +0100	[thread overview]
Message-ID: <715172ab-e2c1-495b-a1a1-d95ef2563ee6@igalia.com> (raw)
In-Reply-To: <20260903-dmem_max-v6-8-61dc62970fae@igalia.com>


On 03/09/2026 23:00, Thadeu Lima de Souza Cascardo wrote:
> From: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> 
> The write_eviction subtest:
>   - Creates a sub-cgroup and moves the test process into it.
>   - Sets a dmem.max limit on the first VRAM region (up to 4 GiB, or
>     the full capacity if smaller).
> - Fills VRAM by repeatedly creating BOs placed in VRAM, depending on card
>    support.
>   - Verifies that cgroup current usage is within the expected range when
>     the limit is hit.
>   - Lowers dmem.max in 128 MiB steps, waiting for usage to follow each
>     reduction.
> 
> The write_eviction_interruptible subtest runs the same test with
> SIGCONT signals injected via igt_fork_signal_helper() and reports the
> number of signals received.  When a signal interrupts kernel-side
> eviction, a small BO allocation is used to re-trigger it.
> 
> Assisted-by: GitHub Copilot:claude-sonnet-4.6
> Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
> Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@igalia.com>
> ---
>   tests/cgroup_dmem.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>   1 file changed, 149 insertions(+)
> 
> diff --git a/tests/cgroup_dmem.c b/tests/cgroup_dmem.c
> index ba5e6a2e3deb..0d3b415acd54 100644
> --- a/tests/cgroup_dmem.c
> +++ b/tests/cgroup_dmem.c
> @@ -36,9 +36,12 @@
>   
>   #define BO_SIZE			SZ_64M
>   #define MAX_LIMIT		((uint64_t)4 * SZ_1G)
> +#define EVICT_STEP		SZ_128M
>   #define USAGE_POLL_MS		10
>   #define USAGE_DROP_TIMEOUT_MS	1000
>   
> +#define TEST_INTERRUPTIBLE	(1 << 0)
> +
>   /**
>    * SUBTEST: simple
>    * DESCRIPTION:
> @@ -61,6 +64,62 @@
>    * REQUIREMENTS: xe or amdgpu device with at least one VRAM region
>    */
>   
> +/**
> + * SUBTEST: write_eviction
> + * DESCRIPTION:
> + *   Create a dmem cgroup, move the current process into it and set the max
> + *   device memory limit for the first VRAM region to 4 GiB.  Then fill VRAM
> + *   by creating BOs with %DRM_XE_GEM_CREATE_FLAG_DEFER_BACKING (so that the
> + *   physical allocation is deferred until VM_BIND) and binding them into an
> + *   LR VM until the cgroup limit is hit.  Verify that the reported cgroup
> + *   current usage is within the expected range when the error occurs.
> + *   Finally lower the max limit in 256 MiB steps and verify that the cgroup
> + *   usage follows.
> + * REQUIREMENTS: must run as root; xe device with at least one VRAM region

It feels that adding an explicit igt_require(DRIVER_XE) to the test 
would be a good move.

> + */
> +
> +/**
> + * SUBTEST: write_eviction_interruptible
> + * DESCRIPTION:
> + *   Same as write_eviction but with SIGCONT signals injected throughout via
> + *   igt_fork_signal_helper() to verify that the dmem.max write path handles
> + *   signal interruption correctly.  A signal handler counts received signals
> + *   and the count is reported as debug output at the end of the test.
> + *   A signal interrupts the set-time eviction, and further eviction can be
> + *   triggered by an explicit allocation.
> + * REQUIREMENTS: must run as root; xe device with at least one VRAM region
> + */
> +
> +static atomic_int signal_count;
> +static struct sigaction sigcont_oldact;
> +
> +static void sigcont_handler(int sig)
> +{
> +	atomic_fetch_add(&signal_count, 1);
> +
> +	/* Chain to the previous handler (IGT's dummy sig_handler) */
> +	if (sigcont_oldact.sa_handler &&
> +	    sigcont_oldact.sa_handler != SIG_IGN &&
> +	    sigcont_oldact.sa_handler != SIG_DFL)
> +		sigcont_oldact.sa_handler(sig);
> +}
> +
> +static void install_sigcont_counter(void)
> +{
> +	struct sigaction sa;
> +
> +	atomic_store(&signal_count, 0);
> +	igt_fork_signal_helper();
> +	/*
> +	 * Install the counter after igt_fork_signal_helper() so our handler
> +	 * is not overwritten.  Save the old handler so we can chain to it.
> +	 */
> +	memset(&sa, 0, sizeof(sa));
> +	sa.sa_handler = sigcont_handler;
> +	sigemptyset(&sa.sa_mask);
> +	sigaction(SIGCONT, &sa, &sigcont_oldact);
> +}
> +
>   static uint64_t wait_for_usage_drop(struct igt_cgroup *cg, const char *region,
>   				    uint64_t limit)
>   {
> @@ -213,12 +272,102 @@ static void test_current(int fd, char *cg_region, unsigned int flags, const stru
>   	igt_cgroup_free(cg);
>   }
>   
> +static void test_write_eviction(int fd, char *cg_region, unsigned int flags, const struct igt_dmem_driver *drv, void *ctx)
> +{
> +	struct igt_cgroup *cg;
> +	void **handles;
> +	int max_bo;
> +	uint64_t current, capacity, cg_max, limit, after;
> +	int err;
> +
> +	igt_cgroup_dmem_get_capacity(cg_region, &capacity);
> +	igt_require_f(capacity >= 4 * BO_SIZE,
> +		      "VRAM capacity (%"PRIu64" MiB) too small to test\n",
> +		      capacity / SZ_1M);
> +
> +	/*
> +	 * Use up to 4 GiB, or the full capacity if the device has less.
> +	 * Leave one BO_SIZE worth of headroom so the device isn't completely
> +	 * exhausted before the cgroup limit is hit.
> +	 */
> +	cg_max = min(MAX_LIMIT, capacity - BO_SIZE);
> +	cg_max = ALIGN_DOWN(cg_max, EVICT_STEP);
> +
> +	if (flags & TEST_INTERRUPTIBLE)
> +		install_sigcont_counter();

I stumbled upon IGT docs recommending igt_while_interruptible as a 
gentler alternative. Would that still work here and be simpler?

> +
> +	/* Create cgroup and move into it */
> +	cg = igt_cgroup_new("igt_cgroups_test");
> +	igt_cgroup_move_current(cg);
> +	igt_cgroup_dmem_set_max(cg, cg_region, cg_max, false);
> +
> +	max_bo = (cg_max / BO_SIZE) + 8; /* headroom for overcommit */
> +
> +	handles = calloc(max_bo, sizeof(handles[0]));
> +	igt_assert_f(handles, "failed to allocate handles array");
> +
> +	allocate_vram(handles, drv, ctx, max_bo, BO_SIZE);
> +
> +	igt_cgroup_dmem_get_current(cg, cg_region, &current);
> +	igt_debug("After fill: cgroup current = %"PRIu64" MiB, "
> +		  "max = %"PRIu64" MiB\n",
> +		  current / SZ_1M, cg_max / SZ_1M);
> +
> +	igt_assert_f(current <= cg_max,
> +		     "Usage %"PRIu64" MiB exceeds max %"PRIu64" MiB + slack\n",
> +		     current / SZ_1M, cg_max / SZ_1M);
> +
> +	/* Phase 2: lower max in 256 MiB steps, verify usage follows */
> +	limit = cg_max;
> +	while (limit >= EVICT_STEP) {
> +
> +		limit -= EVICT_STEP;
> +		igt_cgroup_dmem_set_max(cg, cg_region, limit, false);
> +
> +		igt_cgroup_dmem_get_current(cg, cg_region, &after);
> +		igt_debug("Lowered max to %"PRIu64" MiB: usage = %"PRIu64" MiB\n",
> +			  limit / SZ_1M, after / SZ_1M);
> +
> +		if (limit > EVICT_STEP) {
> +			if ((flags & TEST_INTERRUPTIBLE) && after > limit) {
> +				/* Let a new bo creation trigger eviction. */
> +				void *handle;
> +				err = drv->allocate_vram(ctx, BO_SIZE / 8, &handle);
> +				igt_assert_f(err == 0,
> +					"Error trying to allocate more VRAM to trigger eviction.");
> +				drv->free_vram(ctx, handle);
> +
> +				igt_cgroup_dmem_get_current(cg, cg_region, &after);
> +				igt_debug("Forced eviction max is %"PRIu64
> +					  " MiB: usage = %"PRIu64" MiB\n",
> +					  limit / SZ_1M, after / SZ_1M);
> +			}
> +
> +			igt_assert_f(after <= limit,
> +				     "Usage %"PRIu64" MiB did not follow max %"PRIu64" MiB\n",
> +				     after / SZ_1M, limit / SZ_1M);

I was quite confused by what is the interrupt by signal business about. 
My best guess is the point is not to interrupt the write to the sysfs on 
the superficial level, but to interrupt the actual eviction process 
which happens during the write? Is that a cgroup requirement that the 
new limit has to become effective (or attempted at least) during the 
write itself? And once interrupted it will not re-try it until new 
"activity" in the dmem cgroup happens (the dummy allocation above)?

Regards,

Tvrtko

> +		}
> +	}
> +
> +	if (flags & TEST_INTERRUPTIBLE) {
> +		igt_stop_signal_helper();
> +		igt_info("Signals received during test: %d\n",
> +			 atomic_load(&signal_count));
> +	}
> +
> +	/* Cleanup */
> +	igt_cgroup_dmem_set_max(cg, cg_region, IGT_CGROUP_DMEM_MAX, false);
> +	igt_cgroup_free(cg);
> +}
> +
>   static const struct {
>   	const char *name;
>   	void (*test_fn)(int fd, char *cg_region, unsigned int flags, const struct igt_dmem_driver *drv, void *ctx);
>   	unsigned int flags;
>   } subtests[] = {
>   	{ "current", test_current, 0 },
> +	{ "write_eviction", test_write_eviction, 0 },
> +	{ "write_eviction_interruptible", test_write_eviction, TEST_INTERRUPTIBLE },
>   	{ }
>   };
>   
> 


  reply	other threads:[~2026-09-04 14:48 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-03 22:00 [PATCH i-g-t v6 0/9] add cgroup_dmem test Thadeu Lima de Souza Cascardo
2026-09-03 22:00 ` [PATCH i-g-t v6 1/9] lib/igt_cgroup: add cgroup v2 and dmem controller helpers Thadeu Lima de Souza Cascardo
2026-09-03 22:00 ` [PATCH i-g-t v6 2/9] tests/cgroup_dmem: add dmem cgroup controller test Thadeu Lima de Souza Cascardo
2026-09-03 22:00 ` [PATCH i-g-t v6 3/9] lib/xe: add xe_cgroup_region_name() helper Thadeu Lima de Souza Cascardo
2026-09-03 22:00 ` [PATCH i-g-t v6 4/9] lib/xe: Introduce dmem driver and implement Xe support Thadeu Lima de Souza Cascardo
2026-09-04 10:02   ` Tvrtko Ursulin
2026-09-03 22:00 ` [PATCH i-g-t v6 5/9] lib/amdgpu: add amdgpu_cgroup_region_name Thadeu Lima de Souza Cascardo
2026-09-04 10:00   ` Tvrtko Ursulin
2026-09-03 22:00 ` [PATCH i-g-t v6 6/9] lib/amdgpu: add amdgpu support to igt_dmem_driver Thadeu Lima de Souza Cascardo
2026-09-04 10:11   ` Tvrtko Ursulin
2026-09-03 22:00 ` [PATCH i-g-t v6 7/9] tests/cgroup_dmem: add test for dmem.current Thadeu Lima de Souza Cascardo
2026-09-04 12:40   ` Tvrtko Ursulin
2026-09-03 22:00 ` [PATCH i-g-t v6 8/9] tests/cgroup_dmem: add dmem cgroup eviction test Thadeu Lima de Souza Cascardo
2026-09-04 14:48   ` Tvrtko Ursulin [this message]
2026-09-03 22:00 ` [PATCH i-g-t v6 9/9] tests/cgroup_dmem: add write_eviction_nonblock subtest Thadeu Lima de Souza Cascardo
2026-09-04 14:51   ` Tvrtko Ursulin

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=715172ab-e2c1-495b-a1a1-d95ef2563ee6@igalia.com \
    --to=tvrtko.ursulin@igalia.com \
    --cc=amd-gfx@lists.freedesktop.org \
    --cc=cascardo@igalia.com \
    --cc=christian.koenig@amd.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=intel-xe@lists.freedesktop.org \
    --cc=janusz.krzysztofik@linux.intel.com \
    --cc=kamil.konieczny@linux.intel.com \
    --cc=kernel-dev@igalia.com \
    --cc=maarten.lankhorst@linux.intel.com \
    --cc=natalie.vock@gmx.de \
    --cc=siqueira@igalia.com \
    --cc=thomas.hellstrom@linux.intel.com \
    --cc=vitaly.prosyak@amd.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