[PATCH v6 6/8] drm/xe: Limit purge shrinker pass to the lowest TTM priority band
Matthew Brost <[email protected]> Thu, 30 Jul 2026 19:24:37 -0700
| Newsgroups | org.freedesktop.lists.intel-xe |
|---|---|
| Message-ID | <[email protected]> |
The shrinker's purge pass (xe_shrinker_scan() with shrink_flags.purge set) walks each memory type's whole TTM LRU list looking for BOs that are purgeable (bo->ttm.purgeable, set for DONTNEED BOs, see xe_bo_set_purgeable_shrinker()). Two problems with the current walk: 1. It scans the full LRU across all priority bands, even though a DONTNEED BO is now always kept at XE_BO_PRIORITY_LOW: unbind (xe_vma_destroy()) and the DONTNEED madvise transition (xe_bo_set_purgeable_state()) both drop a BO's priority to XE_BO_PRIORITY_LOW as they mark or become eligible for purging. Since ttm_bo_lru_cursor_first()/_next() walk each priority level in ascending order, nothing beyond XE_BO_PRIORITY_LOW can possibly be purgeable, so continuing past it just wastes time trylocking BOs that can never be purged in this pass. 2. __xe_shrinker_walk() aborts the entire walk (returning early out of the mem_type loop) the moment xe_bo_shrink() returns -EBUSY for a non-purgeable BO reached during the purge pass. Since most BOs sharing the XE_BO_PRIORITY_LOW band are simply unmapped (not DONTNEED), this means the purge pass typically stops after the very first candidate that isn't actually purgeable, skipping any purgeable BOs later in the list instead of continuing to look for them. Fix both: break out of the LRU walk for a given mem_type once a BO's priority rises above XE_BO_PRIORITY_LOW during the purge pass, and treat a -EBUSY from xe_bo_shrink() during the purge pass as "this BO isn't purgeable, try the next one" rather than aborting the walk. Behavior of the non-purge (regular shrink) pass is unchanged. Cc: Carlos Santa <[email protected]> Cc: Ryan Neph <[email protected]> Assisted-by: GitHub_Copilot:claude-sonnet-5 Signed-off-by: Matthew Brost <[email protected]> --- drivers/gpu/drm/xe/xe_shrinker.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_shrinker.c b/drivers/gpu/drm/xe/xe_shrinker.c index 83374cd57660..81895b587b56 100644 --- a/drivers/gpu/drm/xe/xe_shrinker.c +++ b/drivers/gpu/drm/xe/xe_shrinker.c @@ -75,10 +75,24 @@ static s64 __xe_shrinker_walk(struct xe_device *xe, continue; ttm_bo_lru_for_each_reserved_guarded(&curs, man, &arg, ttm_bo) { + /* + * The LRU is walked in ascending priority order. + * Purgeable BOs are clustered at XE_BO_PRIORITY_LOW + * (see xe_bo_set_purgeable_state()), so once we've + * moved past it during the purge pass, nothing + * further down the LRU can be purged; stop early + * rather than walking (and trylocking) BOs that can + * never satisfy this pass. + */ + if (flags.purge && ttm_bo->priority > XE_BO_PRIORITY_LOW) + break; + if (!ttm_bo_shrink_suitable(ttm_bo, ctx)) continue; lret = xe_bo_shrink(ctx, ttm_bo, flags, scanned); + if (flags.purge && lret == -EBUSY) + continue; if (lret < 0) return lret; -- 2.34.1