Unverified Commit 2dd7a476 authored by Thomas Hellström's avatar Thomas Hellström Committed by Rodrigo Vivi
Browse files

drm/xe: Defer buffer object shrinker write-backs and GPU waits



When the xe buffer-object shrinker allows GPU waits and write-back,
(typically from kswapd), perform multiple passes, skipping
subsequent passes if the shrinker number of scanned objects target
is reached.

1) Without GPU waits and write-back
2) Without write-back
3) With both GPU-waits and write-back

This is to avoid stalls and costly write- and readbacks unless they
are really necessary.

v2:
- Don't test for scan completion twice. (Stuart Summers)
- Update tags.

Reported-by: default avatarmelvyn <melvyn2@dnsense.pub>
Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/5557


Cc: Summers Stuart <stuart.summers@intel.com>
Fixes: 00c8efc3 ("drm/xe: Add a shrinker for xe bos")
Cc: <stable@vger.kernel.org> # v6.15+
Signed-off-by: default avatarThomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: default avatarStuart Summers <stuart.summers@intel.com>
Link: https://lore.kernel.org/r/20250805074842.11359-1-thomas.hellstrom@linux.intel.com


(cherry picked from commit 80944d33)
Signed-off-by: default avatarRodrigo Vivi <rodrigo.vivi@intel.com>
parent 145832fb
Loading
Loading
Loading
Loading
+47 −4
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@ xe_shrinker_mod_pages(struct xe_shrinker *shrinker, long shrinkable, long purgea
	write_unlock(&shrinker->lock);
}

static s64 xe_shrinker_walk(struct xe_device *xe,
static s64 __xe_shrinker_walk(struct xe_device *xe,
			      struct ttm_operation_ctx *ctx,
			      const struct xe_bo_shrink_flags flags,
			      unsigned long to_scan, unsigned long *scanned)
@@ -93,6 +93,48 @@ static s64 xe_shrinker_walk(struct xe_device *xe,
	return freed;
}

/*
 * Try shrinking idle objects without writeback first, then if not sufficient,
 * try also non-idle objects and finally if that's not sufficient either,
 * add writeback. This avoids stalls and explicit writebacks with light or
 * moderate memory pressure.
 */
static s64 xe_shrinker_walk(struct xe_device *xe,
			    struct ttm_operation_ctx *ctx,
			    const struct xe_bo_shrink_flags flags,
			    unsigned long to_scan, unsigned long *scanned)
{
	bool no_wait_gpu = true;
	struct xe_bo_shrink_flags save_flags = flags;
	s64 lret, freed;

	swap(no_wait_gpu, ctx->no_wait_gpu);
	save_flags.writeback = false;
	lret = __xe_shrinker_walk(xe, ctx, save_flags, to_scan, scanned);
	swap(no_wait_gpu, ctx->no_wait_gpu);
	if (lret < 0 || *scanned >= to_scan)
		return lret;

	freed = lret;
	if (!ctx->no_wait_gpu) {
		lret = __xe_shrinker_walk(xe, ctx, save_flags, to_scan, scanned);
		if (lret < 0)
			return lret;
		freed += lret;
		if (*scanned >= to_scan)
			return freed;
	}

	if (flags.writeback) {
		lret = __xe_shrinker_walk(xe, ctx, flags, to_scan, scanned);
		if (lret < 0)
			return lret;
		freed += lret;
	}

	return freed;
}

static unsigned long
xe_shrinker_count(struct shrinker *shrink, struct shrink_control *sc)
{
@@ -199,6 +241,7 @@ static unsigned long xe_shrinker_scan(struct shrinker *shrink, struct shrink_con
		runtime_pm = xe_shrinker_runtime_pm_get(shrinker, true, 0, can_backup);

	shrink_flags.purge = false;

	lret = xe_shrinker_walk(shrinker->xe, &ctx, shrink_flags,
				nr_to_scan, &nr_scanned);
	if (lret >= 0)