* [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim [not found] <20260728065512.59911-1-neil.zhong@ugreen.com> @ 2026-07-28 6:55 ` Neil Zhong 2026-07-31 1:36 ` Matthew Brost 0 siblings, 1 reply; 9+ messages in thread From: Neil Zhong @ 2026-07-28 6:55 UTC (permalink / raw) To: intel-xe Cc: matthew.brost, thomas.hellstrom, rodrigo.vivi, airlied, simona, dri-devel, linux-kernel On x86, restoring a backed-up write-combined (WC) buffer object can be expensive. The restore path allocates WB pages and converts them with set_pages_array_wc(), which performs synchronous cache and TLB flushes. Xe currently allows its shrinker to back up the pages of a WC BO while the BO still has GPUVA mappings created by VM_BIND. A later validation restores the pages while holding the BO's dma-resv. The cache-attribute conversion then serializes EXEC, VM_BIND and dma-buf users on that reservation object. This was observed as intermittent HDR 4K60 playback stalls on two Panther Lake systems with 8 GiB of memory. In a pre-change reproducer, the maximum ioctl latencies were 549 ms for XE_EXEC, 291 ms for XE_VM_BIND and 343 ms for DMA-BUF IMPORT. ttm_tt_restore reached 80.6 ms. Keep a non-purgeable WC BO resident while it has at least one GPUVA mapping. Purgeable BOs are still discarded, and after the last VM_UNBIND the BO becomes reclaimable again. Add an A/B module parameter which can restore the old behavior. With the change, a 21-minute capture had no XE_EXEC, XE_VM_BIND or DMA-BUF ioctl over the 16.7 ms frame interval. Their respective maxima were 348 us, 136 us and 20 us. The ttm_tt_restore maximum was 8.33 ms, and the set_pages_array_wc call rate fell from 14.64/s to 0.179/s. The change intentionally trades reclaimable memory for latency while a WC BO remains mapped. It does not take an additional BO reference or change teardown: VM destruction and process exit remove the GPUVA mappings and drop their existing references. During testing, MemAvailable remained near 3 GiB and the dma-buf working set released five 24 MiB surfaces while playback continued. Signed-off-by: Neil Zhong <neil.zhong@ugreen.com> --- Changes in v2: - Call ttm_bo_shrink_suitable() before the Xe-specific WC predicate, so ttm_bo->ttm is known to be non-NULL before checking its cache mode. drivers/gpu/drm/xe/xe_defaults.h | 1 + drivers/gpu/drm/xe/xe_module.c | 6 ++++++ drivers/gpu/drm/xe/xe_module.h | 2 +- drivers/gpu/drm/xe/xe_shrinker.c | 28 ++++++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_defaults.h b/drivers/gpu/drm/xe/xe_defaults.h index c8ae1d5f..645e289f 100644 --- a/drivers/gpu/drm/xe/xe_defaults.h +++ b/drivers/gpu/drm/xe/xe_defaults.h @@ -22,5 +22,6 @@ #define XE_DEFAULT_WEDGED_MODE XE_WEDGED_MODE_UPON_CRITICAL_ERROR #define XE_DEFAULT_WEDGED_MODE_STR "upon-critical-error" #define XE_DEFAULT_SVM_NOTIFIER_SIZE 512 +#define XE_DEFAULT_ALLOW_BOUND_WC_SHRINK false #endif diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c index 848d6526..67bcaf54 100644 --- a/drivers/gpu/drm/xe/xe_module.c +++ b/drivers/gpu/drm/xe/xe_module.c @@ -22,6 +22,7 @@ #include "xe_sched_job.h" struct xe_modparam xe_modparam = { + .allow_bound_wc_shrink = XE_DEFAULT_ALLOW_BOUND_WC_SHRINK, .probe_display = XE_DEFAULT_PROBE_DISPLAY, .guc_log_level = XE_DEFAULT_GUC_LOG_LEVEL, .force_probe = XE_DEFAULT_FORCE_PROBE, @@ -33,6 +34,11 @@ struct xe_modparam xe_modparam = { /* the rest are 0 by default */ }; +module_param_named(allow_bound_wc_shrink, xe_modparam.allow_bound_wc_shrink, + bool, 0600); +MODULE_PARM_DESC(allow_bound_wc_shrink, + "Permit reclaim of VM-bound write-combined BOs"); + module_param_named(svm_notifier_size, xe_modparam.svm_notifier_size, uint, 0600); MODULE_PARM_DESC(svm_notifier_size, "Set the svm notifier size in MiB, must be power of 2 " "[default=" __stringify(XE_DEFAULT_SVM_NOTIFIER_SIZE) "]"); diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h index a0eb7db0..bf2c49ce 100644 --- a/drivers/gpu/drm/xe/xe_module.h +++ b/drivers/gpu/drm/xe/xe_module.h @@ -12,6 +12,7 @@ struct work_struct; /* Module modprobe variables */ struct xe_modparam { + bool allow_bound_wc_shrink; bool probe_display; int force_vram_bar_size; int guc_log_level; @@ -32,4 +33,3 @@ bool xe_destroy_wq_queue(struct work_struct *work); void xe_destroy_wq_flush(void); #endif - diff --git a/drivers/gpu/drm/xe/xe_shrinker.c b/drivers/gpu/drm/xe/xe_shrinker.c index 83374cd5..edbc22b2 100644 --- a/drivers/gpu/drm/xe/xe_shrinker.c +++ b/drivers/gpu/drm/xe/xe_shrinker.c @@ -11,6 +11,7 @@ #include <drm/ttm/ttm_tt.h> #include "xe_bo.h" +#include "xe_module.h" #include "xe_pm.h" #include "xe_shrinker.h" @@ -54,6 +55,30 @@ xe_shrinker_mod_pages(struct xe_shrinker *shrinker, long shrinkable, long purgea write_unlock(&shrinker->lock); } +static bool xe_shrinker_skip_bound_wc(struct ttm_buffer_object *ttm_bo, + const struct xe_bo_shrink_flags flags) +{ + struct xe_bo *bo; + + if (flags.purge || xe_modparam.allow_bound_wc_shrink || + !xe_bo_is_xe_bo(ttm_bo)) + return false; + + bo = ttm_to_xe_bo(ttm_bo); + + /* + * Restoring a backed-up WC BO changes freshly allocated WB pages to WC. + * On x86 that runs CPA cache/TLB flushes synchronously while validation + * holds this BO's dma-resv. A VM-bound BO is also likely to be reused by + * a following EXEC, so reclaiming it can turn moderate memory pressure + * into a multi-client reservation-lock stall. Keep that working set + * resident; purgeable objects and objects after VM_UNBIND remain + * reclaimable. + */ + return ttm_bo->ttm->caching == ttm_write_combined && + xe_bo_is_vm_bound(bo); +} + static s64 __xe_shrinker_walk(struct xe_device *xe, struct ttm_operation_ctx *ctx, const struct xe_bo_shrink_flags flags, @@ -78,6 +103,9 @@ static s64 __xe_shrinker_walk(struct xe_device *xe, if (!ttm_bo_shrink_suitable(ttm_bo, ctx)) continue; + if (xe_shrinker_skip_bound_wc(ttm_bo, flags)) + continue; + lret = xe_bo_shrink(ctx, ttm_bo, flags, scanned); if (lret < 0) return lret; -- 2.50.1 (Apple Git-155) ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim 2026-07-28 6:55 ` [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim Neil Zhong @ 2026-07-31 1:36 ` Matthew Brost 2026-07-31 2:44 ` Matthew Brost 0 siblings, 1 reply; 9+ messages in thread From: Matthew Brost @ 2026-07-31 1:36 UTC (permalink / raw) To: Neil Zhong Cc: intel-xe, thomas.hellstrom, rodrigo.vivi, airlied, simona, dri-devel, linux-kernel On Tue, Jul 28, 2026 at 02:55:12PM +0800, Neil Zhong wrote: > On x86, restoring a backed-up write-combined (WC) buffer object can be > expensive. The restore path allocates WB pages and converts them with > set_pages_array_wc(), which performs synchronous cache and TLB flushes. > > Xe currently allows its shrinker to back up the pages of a WC BO while > the BO still has GPUVA mappings created by VM_BIND. A later validation > restores the pages while holding the BO's dma-resv. The cache-attribute > conversion then serializes EXEC, VM_BIND and dma-buf users on that > reservation object. > > This was observed as intermittent HDR 4K60 playback stalls on two > Panther Lake systems with 8 GiB of memory. In a pre-change reproducer, > the maximum ioctl latencies were 549 ms for XE_EXEC, 291 ms for > XE_VM_BIND and 343 ms for DMA-BUF IMPORT. ttm_tt_restore reached 80.6 ms. > > Keep a non-purgeable WC BO resident while it has at least one GPUVA > mapping. Purgeable BOs are still discarded, and after the last > VM_UNBIND the BO becomes reclaimable again. Add an A/B module parameter > which can restore the old behavior. > > With the change, a 21-minute capture had no XE_EXEC, XE_VM_BIND or > DMA-BUF ioctl over the 16.7 ms frame interval. Their respective maxima > were 348 us, 136 us and 20 us. The ttm_tt_restore maximum was 8.33 ms, > and the set_pages_array_wc call rate fell from 14.64/s to 0.179/s. > > The change intentionally trades reclaimable memory for latency while a > WC BO remains mapped. It does not take an additional BO reference or > change teardown: VM destruction and process exit remove the GPUVA > mappings and drop their existing references. During testing, > MemAvailable remained near 3 GiB and the dma-buf working set released > five 24 MiB surfaces while playback continued. > I think integrating WC into the TTM priority scheme for LRU-based eviction is probably the right approach rather than blocking WC from shrinking. I have a series on the list that implements TTM priorities for Xe [1], but WC isn't currently taken into account. It probably should be, although I think we'd need more than four TTM priority levels to do it properly. If I respin that series with some WC awareness, would you be willing to give it a try? Also btw, we are aware of bunch shrinker / memory pressure / fragmentation issues with Xe on iGPU devices and are actively working on this, here are a couple more examples of in flight work [2] [3], here some which have been merged [4] [5] [6]. Matt [1] https://patchwork.freedesktop.org/series/170454/ [2] https://patchwork.freedesktop.org/series/170216/ [3] https://patchwork.freedesktop.org/series/168651/ [4] https://patchwork.freedesktop.org/series/165878/ [5] https://patchwork.freedesktop.org/series/168649/ [6] https://patchwork.freedesktop.org/series/168466/ > Signed-off-by: Neil Zhong <neil.zhong@ugreen.com> > --- > Changes in v2: > - Call ttm_bo_shrink_suitable() before the Xe-specific WC predicate, so > ttm_bo->ttm is known to be non-NULL before checking its cache mode. > > drivers/gpu/drm/xe/xe_defaults.h | 1 + > drivers/gpu/drm/xe/xe_module.c | 6 ++++++ > drivers/gpu/drm/xe/xe_module.h | 2 +- > drivers/gpu/drm/xe/xe_shrinker.c | 28 ++++++++++++++++++++++++++++ > 4 files changed, 36 insertions(+), 1 deletion(-) > > diff --git a/drivers/gpu/drm/xe/xe_defaults.h b/drivers/gpu/drm/xe/xe_defaults.h > index c8ae1d5f..645e289f 100644 > --- a/drivers/gpu/drm/xe/xe_defaults.h > +++ b/drivers/gpu/drm/xe/xe_defaults.h > @@ -22,5 +22,6 @@ > #define XE_DEFAULT_WEDGED_MODE XE_WEDGED_MODE_UPON_CRITICAL_ERROR > #define XE_DEFAULT_WEDGED_MODE_STR "upon-critical-error" > #define XE_DEFAULT_SVM_NOTIFIER_SIZE 512 > +#define XE_DEFAULT_ALLOW_BOUND_WC_SHRINK false > > #endif > diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c > index 848d6526..67bcaf54 100644 > --- a/drivers/gpu/drm/xe/xe_module.c > +++ b/drivers/gpu/drm/xe/xe_module.c > @@ -22,6 +22,7 @@ > #include "xe_sched_job.h" > > struct xe_modparam xe_modparam = { > + .allow_bound_wc_shrink = XE_DEFAULT_ALLOW_BOUND_WC_SHRINK, > .probe_display = XE_DEFAULT_PROBE_DISPLAY, > .guc_log_level = XE_DEFAULT_GUC_LOG_LEVEL, > .force_probe = XE_DEFAULT_FORCE_PROBE, > @@ -33,6 +34,11 @@ struct xe_modparam xe_modparam = { > /* the rest are 0 by default */ > }; > > +module_param_named(allow_bound_wc_shrink, xe_modparam.allow_bound_wc_shrink, > + bool, 0600); > +MODULE_PARM_DESC(allow_bound_wc_shrink, > + "Permit reclaim of VM-bound write-combined BOs"); > + > module_param_named(svm_notifier_size, xe_modparam.svm_notifier_size, uint, 0600); > MODULE_PARM_DESC(svm_notifier_size, "Set the svm notifier size in MiB, must be power of 2 " > "[default=" __stringify(XE_DEFAULT_SVM_NOTIFIER_SIZE) "]"); > diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h > index a0eb7db0..bf2c49ce 100644 > --- a/drivers/gpu/drm/xe/xe_module.h > +++ b/drivers/gpu/drm/xe/xe_module.h > @@ -12,6 +12,7 @@ struct work_struct; > > /* Module modprobe variables */ > struct xe_modparam { > + bool allow_bound_wc_shrink; > bool probe_display; > int force_vram_bar_size; > int guc_log_level; > @@ -32,4 +33,3 @@ bool xe_destroy_wq_queue(struct work_struct *work); > void xe_destroy_wq_flush(void); > > #endif > - > diff --git a/drivers/gpu/drm/xe/xe_shrinker.c b/drivers/gpu/drm/xe/xe_shrinker.c > index 83374cd5..edbc22b2 100644 > --- a/drivers/gpu/drm/xe/xe_shrinker.c > +++ b/drivers/gpu/drm/xe/xe_shrinker.c > @@ -11,6 +11,7 @@ > #include <drm/ttm/ttm_tt.h> > > #include "xe_bo.h" > +#include "xe_module.h" > #include "xe_pm.h" > #include "xe_shrinker.h" > > @@ -54,6 +55,30 @@ xe_shrinker_mod_pages(struct xe_shrinker *shrinker, long shrinkable, long purgea > write_unlock(&shrinker->lock); > } > > +static bool xe_shrinker_skip_bound_wc(struct ttm_buffer_object *ttm_bo, > + const struct xe_bo_shrink_flags flags) > +{ > + struct xe_bo *bo; > + > + if (flags.purge || xe_modparam.allow_bound_wc_shrink || > + !xe_bo_is_xe_bo(ttm_bo)) > + return false; > + > + bo = ttm_to_xe_bo(ttm_bo); > + > + /* > + * Restoring a backed-up WC BO changes freshly allocated WB pages to WC. > + * On x86 that runs CPA cache/TLB flushes synchronously while validation > + * holds this BO's dma-resv. A VM-bound BO is also likely to be reused by > + * a following EXEC, so reclaiming it can turn moderate memory pressure > + * into a multi-client reservation-lock stall. Keep that working set > + * resident; purgeable objects and objects after VM_UNBIND remain > + * reclaimable. > + */ > + return ttm_bo->ttm->caching == ttm_write_combined && > + xe_bo_is_vm_bound(bo); > +} > + > static s64 __xe_shrinker_walk(struct xe_device *xe, > struct ttm_operation_ctx *ctx, > const struct xe_bo_shrink_flags flags, > @@ -78,6 +103,9 @@ static s64 __xe_shrinker_walk(struct xe_device *xe, > if (!ttm_bo_shrink_suitable(ttm_bo, ctx)) > continue; > > + if (xe_shrinker_skip_bound_wc(ttm_bo, flags)) > + continue; > + > lret = xe_bo_shrink(ctx, ttm_bo, flags, scanned); > if (lret < 0) > return lret; > -- > 2.50.1 (Apple Git-155) ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim 2026-07-31 1:36 ` Matthew Brost @ 2026-07-31 2:44 ` Matthew Brost 2026-08-01 5:39 ` Neil Zhong 0 siblings, 1 reply; 9+ messages in thread From: Matthew Brost @ 2026-07-31 2:44 UTC (permalink / raw) To: Neil Zhong Cc: intel-xe, thomas.hellstrom, rodrigo.vivi, airlied, simona, dri-devel, linux-kernel On Thu, Jul 30, 2026 at 06:36:46PM -0700, Matthew Brost wrote: > On Tue, Jul 28, 2026 at 02:55:12PM +0800, Neil Zhong wrote: > > On x86, restoring a backed-up write-combined (WC) buffer object can be > > expensive. The restore path allocates WB pages and converts them with > > set_pages_array_wc(), which performs synchronous cache and TLB flushes. > > > > Xe currently allows its shrinker to back up the pages of a WC BO while > > the BO still has GPUVA mappings created by VM_BIND. A later validation > > restores the pages while holding the BO's dma-resv. The cache-attribute > > conversion then serializes EXEC, VM_BIND and dma-buf users on that > > reservation object. > > > > This was observed as intermittent HDR 4K60 playback stalls on two > > Panther Lake systems with 8 GiB of memory. In a pre-change reproducer, > > the maximum ioctl latencies were 549 ms for XE_EXEC, 291 ms for > > XE_VM_BIND and 343 ms for DMA-BUF IMPORT. ttm_tt_restore reached 80.6 ms. > > > > Keep a non-purgeable WC BO resident while it has at least one GPUVA > > mapping. Purgeable BOs are still discarded, and after the last > > VM_UNBIND the BO becomes reclaimable again. Add an A/B module parameter > > which can restore the old behavior. > > > > With the change, a 21-minute capture had no XE_EXEC, XE_VM_BIND or > > DMA-BUF ioctl over the 16.7 ms frame interval. Their respective maxima > > were 348 us, 136 us and 20 us. The ttm_tt_restore maximum was 8.33 ms, > > and the set_pages_array_wc call rate fell from 14.64/s to 0.179/s. > > > > The change intentionally trades reclaimable memory for latency while a > > WC BO remains mapped. It does not take an additional BO reference or > > change teardown: VM destruction and process exit remove the GPUVA > > mappings and drop their existing references. During testing, > > MemAvailable remained near 3 GiB and the dma-buf working set released > > five 24 MiB surfaces while playback continued. > > > > I think integrating WC into the TTM priority scheme for LRU-based > eviction is probably the right approach rather than blocking WC from > shrinking. I have a series on the list that implements TTM priorities > for Xe [1], but WC isn't currently taken into account. It probably > should be, although I think we'd need more than four TTM priority levels > to do it properly. > > If I respin that series with some WC awareness, would you be willing to > give it a try? > So I posted another rev priority changes to account WB vs WB/UC: [7] https://patchwork.freedesktop.org/series/170454/ gitlab branch: https://gitlab.freedesktop.org/mbrost/xe-kernel-driver-svn-perf-6-15-2025/-/commits/priority_fixes.v4 But after reading this a bit more carefully, I suspect the real issue is that fragmentation is driving shrinker activity. Your changes more or less prevent Xe from shrinking its working set, since nearly every buffer is WC. In my opinion, that behavior is reasonable for fragmentation-driven reclaim, but it is much less appropriate in genuine low-memory situations. This is also a known issue for us. We most recently attempted to address it here [8], but the fix was blocked by the shrinker maintainer - the same has happened to other proposed solutions as well. We have several downstream customers carrying non-upstream fixes to work around this problem too... [8] https://patchwork.freedesktop.org/series/168651/ I guess if it isn't too much trouble could you test: 1. Priority changes [7] 2. Avoid shrinking working sets on fragmentation [8] 3. Both [7], [8] Matt > Also btw, we are aware of bunch shrinker / memory pressure / > fragmentation issues with Xe on iGPU devices and are actively working on > this, here are a couple more examples of in flight work [2] [3], here > some which have been merged [4] [5] [6]. > > Matt > > [1] https://patchwork.freedesktop.org/series/170454/ > [2] https://patchwork.freedesktop.org/series/170216/ > [3] https://patchwork.freedesktop.org/series/168651/ > [4] https://patchwork.freedesktop.org/series/165878/ > [5] https://patchwork.freedesktop.org/series/168649/ > [6] https://patchwork.freedesktop.org/series/168466/ > > > Signed-off-by: Neil Zhong <neil.zhong@ugreen.com> > > --- > > Changes in v2: > > - Call ttm_bo_shrink_suitable() before the Xe-specific WC predicate, so > > ttm_bo->ttm is known to be non-NULL before checking its cache mode. > > > > drivers/gpu/drm/xe/xe_defaults.h | 1 + > > drivers/gpu/drm/xe/xe_module.c | 6 ++++++ > > drivers/gpu/drm/xe/xe_module.h | 2 +- > > drivers/gpu/drm/xe/xe_shrinker.c | 28 ++++++++++++++++++++++++++++ > > 4 files changed, 36 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/gpu/drm/xe/xe_defaults.h b/drivers/gpu/drm/xe/xe_defaults.h > > index c8ae1d5f..645e289f 100644 > > --- a/drivers/gpu/drm/xe/xe_defaults.h > > +++ b/drivers/gpu/drm/xe/xe_defaults.h > > @@ -22,5 +22,6 @@ > > #define XE_DEFAULT_WEDGED_MODE XE_WEDGED_MODE_UPON_CRITICAL_ERROR > > #define XE_DEFAULT_WEDGED_MODE_STR "upon-critical-error" > > #define XE_DEFAULT_SVM_NOTIFIER_SIZE 512 > > +#define XE_DEFAULT_ALLOW_BOUND_WC_SHRINK false > > > > #endif > > diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c > > index 848d6526..67bcaf54 100644 > > --- a/drivers/gpu/drm/xe/xe_module.c > > +++ b/drivers/gpu/drm/xe/xe_module.c > > @@ -22,6 +22,7 @@ > > #include "xe_sched_job.h" > > > > struct xe_modparam xe_modparam = { > > + .allow_bound_wc_shrink = XE_DEFAULT_ALLOW_BOUND_WC_SHRINK, > > .probe_display = XE_DEFAULT_PROBE_DISPLAY, > > .guc_log_level = XE_DEFAULT_GUC_LOG_LEVEL, > > .force_probe = XE_DEFAULT_FORCE_PROBE, > > @@ -33,6 +34,11 @@ struct xe_modparam xe_modparam = { > > /* the rest are 0 by default */ > > }; > > > > +module_param_named(allow_bound_wc_shrink, xe_modparam.allow_bound_wc_shrink, > > + bool, 0600); > > +MODULE_PARM_DESC(allow_bound_wc_shrink, > > + "Permit reclaim of VM-bound write-combined BOs"); > > + > > module_param_named(svm_notifier_size, xe_modparam.svm_notifier_size, uint, 0600); > > MODULE_PARM_DESC(svm_notifier_size, "Set the svm notifier size in MiB, must be power of 2 " > > "[default=" __stringify(XE_DEFAULT_SVM_NOTIFIER_SIZE) "]"); > > diff --git a/drivers/gpu/drm/xe/xe_module.h b/drivers/gpu/drm/xe/xe_module.h > > index a0eb7db0..bf2c49ce 100644 > > --- a/drivers/gpu/drm/xe/xe_module.h > > +++ b/drivers/gpu/drm/xe/xe_module.h > > @@ -12,6 +12,7 @@ struct work_struct; > > > > /* Module modprobe variables */ > > struct xe_modparam { > > + bool allow_bound_wc_shrink; > > bool probe_display; > > int force_vram_bar_size; > > int guc_log_level; > > @@ -32,4 +33,3 @@ bool xe_destroy_wq_queue(struct work_struct *work); > > void xe_destroy_wq_flush(void); > > > > #endif > > - > > diff --git a/drivers/gpu/drm/xe/xe_shrinker.c b/drivers/gpu/drm/xe/xe_shrinker.c > > index 83374cd5..edbc22b2 100644 > > --- a/drivers/gpu/drm/xe/xe_shrinker.c > > +++ b/drivers/gpu/drm/xe/xe_shrinker.c > > @@ -11,6 +11,7 @@ > > #include <drm/ttm/ttm_tt.h> > > > > #include "xe_bo.h" > > +#include "xe_module.h" > > #include "xe_pm.h" > > #include "xe_shrinker.h" > > > > @@ -54,6 +55,30 @@ xe_shrinker_mod_pages(struct xe_shrinker *shrinker, long shrinkable, long purgea > > write_unlock(&shrinker->lock); > > } > > > > +static bool xe_shrinker_skip_bound_wc(struct ttm_buffer_object *ttm_bo, > > + const struct xe_bo_shrink_flags flags) > > +{ > > + struct xe_bo *bo; > > + > > + if (flags.purge || xe_modparam.allow_bound_wc_shrink || > > + !xe_bo_is_xe_bo(ttm_bo)) > > + return false; > > + > > + bo = ttm_to_xe_bo(ttm_bo); > > + > > + /* > > + * Restoring a backed-up WC BO changes freshly allocated WB pages to WC. > > + * On x86 that runs CPA cache/TLB flushes synchronously while validation > > + * holds this BO's dma-resv. A VM-bound BO is also likely to be reused by > > + * a following EXEC, so reclaiming it can turn moderate memory pressure > > + * into a multi-client reservation-lock stall. Keep that working set > > + * resident; purgeable objects and objects after VM_UNBIND remain > > + * reclaimable. > > + */ > > + return ttm_bo->ttm->caching == ttm_write_combined && > > + xe_bo_is_vm_bound(bo); > > +} > > + > > static s64 __xe_shrinker_walk(struct xe_device *xe, > > struct ttm_operation_ctx *ctx, > > const struct xe_bo_shrink_flags flags, > > @@ -78,6 +103,9 @@ static s64 __xe_shrinker_walk(struct xe_device *xe, > > if (!ttm_bo_shrink_suitable(ttm_bo, ctx)) > > continue; > > > > + if (xe_shrinker_skip_bound_wc(ttm_bo, flags)) > > + continue; > > + > > lret = xe_bo_shrink(ctx, ttm_bo, flags, scanned); > > if (lret < 0) > > return lret; > > -- > > 2.50.1 (Apple Git-155) ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim 2026-07-31 2:44 ` Matthew Brost @ 2026-08-01 5:39 ` Neil Zhong 2026-08-01 6:00 ` Matthew Brost 0 siblings, 1 reply; 9+ messages in thread From: Neil Zhong @ 2026-08-01 5:39 UTC (permalink / raw) To: Matthew Brost Cc: intel-xe, thomas.hellstrom, rodrigo.vivi, airlied, simona, dri-devel, linux-kernel On Thu, Jul 30, 2026 at 07:44:02PM -0700, Matthew Brost wrote: > So I posted another rev priority changes to account WB vs WB/UC: > > [7] https://patchwork.freedesktop.org/series/170454/ > gitlab branch: https://gitlab.freedesktop.org/mbrost/xe-kernel-driver-svn-perf-6-15-2025/-/commits/priority_fixes.v4 > > But after reading this a bit more carefully, I suspect the real issue is > that fragmentation is driving shrinker activity. Your changes more or > less prevent Xe from shrinking its working set, since nearly every > buffer is WC. In my opinion, that behavior is reasonable for > fragmentation-driven reclaim, but it is much less appropriate in genuine > low-memory situations. > > This is also a known issue for us. We most recently attempted to address > it here [8], but the fix was blocked by the shrinker maintainer - the > same has happened to other proposed solutions as well. We have several > downstream customers carrying non-upstream fixes to work around this > problem too... > > [8] https://patchwork.freedesktop.org/series/168651/ > > I guess if it isn't too much trouble could you test: > > 1. Priority changes [7] > 2. Avoid shrinking working sets on fragmentation [8] > 3. Both [7], [8] > > Matt Hi Matt, Thanks again for the priority series. I have now done a longer test of [7], including a system-wide Xe/TTM trace that records the exact BO backup and restore traffic. Test setup ---------- The test machine has a Panther Lake iGPU and 8 GiB of system memory. It is running Linux 6.18.15 with the applicable parts of the current v6 priority series backported. Since 6.18 does not have the newer Xe purgeable madvise state machine, I backported patches 1-4 and 7-8. Patches 5-6 depend on the newer xe_bo_set_purgeable_state() infrastructure. The active VM-bound WC path in this reproducer does not use those purgeable states. The workload is continuous 4K60 HDR playback. Decoded video frames are passed through a libplacebo/OpenGL rendering path, with every HDR frame going through GPU HDR rendering/tone mapping before display. glFlush() submits the rendering work for each frame. The working set is mostly DMA-BUF-backed video/render surfaces and other VM-bound WC BOs. Results with [7] ---------------- The priority changes alone did not fix the stalls. They appear to delay the first visible failure after playback starts, but once reclaim and fragmentation activity builds up, the same failure mechanism and hundreds-of-milliseconds Flush stalls return. In a 599.545-second trace, the player recorded: Flush samples: 16,462 Flush > 16.667 ms: 157 Flush > 100 ms: 67 Maximum Flush: 494.434 ms Every one of the 157 Flush calls over the frame interval contained both ttm_tt_restore() and set_pages_array_wc(). The maximum Flush contained 73 BO restores and 65 WC conversions. For the memory trace I used temporary entry/return probes to record the ttm_tt pointer, num_pages, and the actual page count returned by ttm_tt_backup(). This allowed a later restore to be matched to the exact same ttm_tt rather than only comparing aggregate counters. The ten-minute working-set traffic was: successful ttm_tt_backup: 6,743 (11.247 objects/s) pages actually backed up: 6,717,364 (26,239.703 MiB total) ttm_tt_restore: 6,693 (11.163 objects/s) restore matched to same ttm_tt: 6,673 / 6,693 matched restore volume: 25,993.043 MiB This is at least 52,232.746 MiB of backup-plus-restore copy traffic in ten minutes, or 87.121 MiB/s on average. It is cumulative migration traffic, not resident memory growth. Of 639 unique ttm_tt objects that were backed up, 491 were backed up at least twice. One object went through 125 backup cycles during the capture. The delay from completion of a backup to restoration of the same ttm_tt was: median: 47.932 ms p95: 189.083 ms p99: 360.138 ms within 100 ms: 5,190 / 6,673 (77.8%) within 1 s: 6,653 / 6,673 (99.7%) This looks like working-set thrashing rather than reclaim of cold BOs. The caller distribution makes the cycle particularly clear: kswapd0 performed 6,460 of the 6,743 backups (95.8%), while the restores were mostly performed by the player's rendering and decode threads. The activity was bursty. Backup occurred in only 42 of the 600 trace seconds, grouped into 14 reclaim/restore storms, with up to 397 BO restores in one second. Backup and restore page volume had a same-second correlation of 0.997. Per-second maximum Flush had correlations of 0.904 with backup pages and 0.917 with restore-request pages. The trigger also looks fragmentation driven: kswapd wake order-10: 577 / 590 (97.8%) wakeup_kswapd order-10: 560 / 576 (97.2%) direct reclaim order-10: 512 / 518 (98.8%) MemAvailable during the trace: 2.89 - 3.15 GiB compact_stall/success/fail: 1,073 / 132 / 941 Thus the system still had about 3 GiB available while nearly all of the reclaim wakeups were for order-10 allocations. This is consistent with high-order fragmentation repeatedly invoking shrinkers, rather than sustained order-0 memory shortage. There is also normal small-object allocation activity, but it is not the main problem. ttm_pool_alloc/free ran at about 41.6/41.5 calls per second, but 97.6% of allocations were only one or two pages and are normally reused through the TTM pool. In contrast, the same active working set was copied back and forth for more than 52 GiB during the test. For comparison, with my earlier workaround that skipped non-purge shrinking of VM-bound WC BOs, set_pages_array_wc() ran at 0.179/s, versus 9.859/s in this test. The current trace restored backed-up content at about 11,099 pages/s, while the earlier capture recorded ttm_backup_copy_page() at 26.74/s. The earlier 21-minute capture also had no Flush, XE_EXEC, VM_BIND, or DMA-BUF ioctl over 16.7 ms. The current trace is system-wide whereas that older function graph was player-TID filtered, so these are not fully identical A/B collection scopes. However, the difference in WC restore activity and the user-visible result is large and consistent. Interpretation of [7] --------------------- The priority changes seem to be doing what they are intended to do: they change which object is considered first. However, most of the active working set in this workload is VM-bound WC. Once the lower-priority and WB candidates are absent or insufficient, the shrinker still reaches the WC half of the bands and then the higher-priority WC BOs. Therefore [7] has no clear steady-state benefit for this reproducer. It mostly postpones the point at which the active WC working set becomes the remaining reclaim target. Once that point is reached, the backup/restore and CPA cost is essentially the original problem. Possible Xe-local alternative to [8] ------------------------------------ I agree that [8] may help this workload, and the order-10 trace data is consistent with the condition that [8] is trying to identify. I have not yet completed the [8]-only and [7]+[8] tests. I also understand the MM feedback that this is a wider compaction versus shrinker-working-set problem, not something unique to Xe. Nevertheless, for Xe there may be a narrower implementation that does not require a new hint to be propagated through MM. My idea is to make the Xe shrinker distinguish base-page shortage from fragmentation before entering its destructive, non-purge backup pass: 1. Always keep the purgeable-object pass available. 2. Check order-0 free pages against the relevant node/zone watermarks, using sc->nid and the zones allowed by sc->gfp_mask. This should be a watermark check, not a global MemAvailable threshold. 3. If the relevant order-0 supply is healthy, for example above the high watermark, treat the shrink request as fragmentation-only for Xe and skip backing up the active VM-bound working set. Reclaiming arbitrary BO-sized objects is unlikely to produce the contiguous order-10 extent and is very likely to destroy the GPU working set. 4. If the order-0 watermark is below low, treat it as genuine memory pressure and retain the normal Xe shrinker behavior, including WC reclaim if cheaper candidates are insufficient. Between low and high the existing priority policy could remain the conservative fallback. In pseudocode, the special case would be placed between the purgeable pass and the non-purge backup pass in xe_shrinker_scan(): run_purgeable_pass(); if (order0_watermarks_healthy(sc)) skip_non_purge_working_set_backup; run_normal_priority_based_backup_pass(); This differs from my original workaround because it would not make VM-bound WC BOs unconditionally unreclaimable. They remain reclaimable under real base-page pressure, so the system can still recover memory in a genuine low-memory situation. It only avoids the expensive backup and immediate restore cycle while base-page watermarks say that the problem is fragmentation rather than capacity. This Xe-local policy would not solve the broader problem for inode, dentry, or other shrinker-managed working sets, so I do not see it as a replacement for a general MM solution. It may, however, be a small and testable Xe-side safeguard while the general compaction/shrinker policy is being worked out. Would this be a reasonable Xe-specific experiment, or do you think Xe should rely exclusively on an MM-provided indication such as [8]? I have retained the raw trace, the per-second timeline, and the probe script and can provide them if useful. Thanks, Neil ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim 2026-08-01 5:39 ` Neil Zhong @ 2026-08-01 6:00 ` Matthew Brost 2026-08-08 9:34 ` Neil Zhong 0 siblings, 1 reply; 9+ messages in thread From: Matthew Brost @ 2026-08-01 6:00 UTC (permalink / raw) To: Neil Zhong Cc: intel-xe, thomas.hellstrom, rodrigo.vivi, airlied, simona, dri-devel, linux-kernel On Sat, Aug 01, 2026 at 01:39:13PM +0800, Neil Zhong wrote: > On Thu, Jul 30, 2026 at 07:44:02PM -0700, Matthew Brost wrote: > > So I posted another rev priority changes to account WB vs WB/UC: > > > > [7] https://patchwork.freedesktop.org/series/170454/ > > gitlab branch: https://gitlab.freedesktop.org/mbrost/xe-kernel-driver-svn-perf-6-15-2025/-/commits/priority_fixes.v4 > > > > But after reading this a bit more carefully, I suspect the real issue is > > that fragmentation is driving shrinker activity. Your changes more or > > less prevent Xe from shrinking its working set, since nearly every > > buffer is WC. In my opinion, that behavior is reasonable for > > fragmentation-driven reclaim, but it is much less appropriate in genuine > > low-memory situations. > > > > This is also a known issue for us. We most recently attempted to address > > it here [8], but the fix was blocked by the shrinker maintainer - the > > same has happened to other proposed solutions as well. We have several > > downstream customers carrying non-upstream fixes to work around this > > problem too... > > > > [8] https://patchwork.freedesktop.org/series/168651/ > > > > I guess if it isn't too much trouble could you test: > > > > 1. Priority changes [7] > > 2. Avoid shrinking working sets on fragmentation [8] > > 3. Both [7], [8] > > > > Matt > > Hi Matt, > > Thanks again for the priority series. I have now done a longer test of > [7], including a system-wide Xe/TTM trace that records the exact BO > backup and restore traffic. > > Test setup > ---------- > > The test machine has a Panther Lake iGPU and 8 GiB of system memory. It > is running Linux 6.18.15 with the applicable parts of the current v6 > priority series backported. > > Since 6.18 does not have the newer Xe purgeable madvise state machine, I > backported patches 1-4 and 7-8. Patches 5-6 depend on the newer > xe_bo_set_purgeable_state() infrastructure. The active VM-bound WC path > in this reproducer does not use those purgeable states. > > The workload is continuous 4K60 HDR playback. Decoded video frames are > passed through a libplacebo/OpenGL rendering path, with every HDR frame > going through GPU HDR rendering/tone mapping before display. glFlush() > submits the rendering work for each frame. The working set is mostly > DMA-BUF-backed video/render surfaces and other VM-bound WC BOs. > > Results with [7] > ---------------- > > The priority changes alone did not fix the stalls. They appear to delay > the first visible failure after playback starts, but once reclaim and > fragmentation activity builds up, the same failure mechanism and > hundreds-of-milliseconds Flush stalls return. > > In a 599.545-second trace, the player recorded: > > Flush samples: 16,462 > Flush > 16.667 ms: 157 > Flush > 100 ms: 67 > Maximum Flush: 494.434 ms > > Every one of the 157 Flush calls over the frame interval contained both > ttm_tt_restore() and set_pages_array_wc(). The maximum Flush contained > 73 BO restores and 65 WC conversions. > > For the memory trace I used temporary entry/return probes to record the > ttm_tt pointer, num_pages, and the actual page count returned by > ttm_tt_backup(). This allowed a later restore to be matched to the exact > same ttm_tt rather than only comparing aggregate counters. > > The ten-minute working-set traffic was: > > successful ttm_tt_backup: 6,743 (11.247 objects/s) > pages actually backed up: 6,717,364 (26,239.703 MiB total) > ttm_tt_restore: 6,693 (11.163 objects/s) > restore matched to same ttm_tt: 6,673 / 6,693 > matched restore volume: 25,993.043 MiB > > This is at least 52,232.746 MiB of backup-plus-restore copy traffic in > ten minutes, or 87.121 MiB/s on average. It is cumulative migration > traffic, not resident memory growth. > > Of 639 unique ttm_tt objects that were backed up, 491 were backed up at > least twice. One object went through 125 backup cycles during the > capture. The delay from completion of a backup to restoration of the > same ttm_tt was: > > median: 47.932 ms > p95: 189.083 ms > p99: 360.138 ms > within 100 ms: 5,190 / 6,673 (77.8%) > within 1 s: 6,653 / 6,673 (99.7%) > > This looks like working-set thrashing rather than reclaim of cold BOs. > The caller distribution makes the cycle particularly clear: kswapd0 > performed 6,460 of the 6,743 backups (95.8%), while the restores were > mostly performed by the player's rendering and decode threads. > > The activity was bursty. Backup occurred in only 42 of the 600 trace > seconds, grouped into 14 reclaim/restore storms, with up to 397 BO > restores in one second. Backup and restore page volume had a same-second > correlation of 0.997. Per-second maximum Flush had correlations of 0.904 > with backup pages and 0.917 with restore-request pages. > > The trigger also looks fragmentation driven: > > kswapd wake order-10: 577 / 590 (97.8%) > wakeup_kswapd order-10: 560 / 576 (97.2%) > direct reclaim order-10: 512 / 518 (98.8%) > MemAvailable during the trace: 2.89 - 3.15 GiB > compact_stall/success/fail: 1,073 / 132 / 941 > > Thus the system still had about 3 GiB available while nearly all of the > reclaim wakeups were for order-10 allocations. This is consistent with > high-order fragmentation repeatedly invoking shrinkers, rather than > sustained order-0 memory shortage. > > There is also normal small-object allocation activity, but it is not the > main problem. ttm_pool_alloc/free ran at about 41.6/41.5 calls per second, > but 97.6% of allocations were only one or two pages and are normally > reused through the TTM pool. In contrast, the same active working set was > copied back and forth for more than 52 GiB during the test. > > For comparison, with my earlier workaround that skipped non-purge > shrinking of VM-bound WC BOs, set_pages_array_wc() ran at 0.179/s, > versus 9.859/s in this test. The current trace restored backed-up content > at about 11,099 pages/s, while the earlier capture recorded > ttm_backup_copy_page() at 26.74/s. The earlier 21-minute capture also had > no Flush, XE_EXEC, VM_BIND, or DMA-BUF ioctl over 16.7 ms. > > The current trace is system-wide whereas that older function graph was > player-TID filtered, so these are not fully identical A/B collection > scopes. However, the difference in WC restore activity and the > user-visible result is large and consistent. > > Interpretation of [7] > --------------------- > > The priority changes seem to be doing what they are intended to do: they > change which object is considered first. However, most of the active > working set in this workload is VM-bound WC. Once the lower-priority and > WB candidates are absent or insufficient, the shrinker still reaches the > WC half of the bands and then the higher-priority WC BOs. > > Therefore [7] has no clear steady-state benefit for this reproducer. It > mostly postpones the point at which the active WC working set becomes the > remaining reclaim target. Once that point is reached, the backup/restore > and CPA cost is essentially the original problem. > > Possible Xe-local alternative to [8] > ------------------------------------ > > I agree that [8] may help this workload, and the order-10 trace data is > consistent with the condition that [8] is trying to identify. I have not > yet completed the [8]-only and [7]+[8] tests. > > I also understand the MM feedback that this is a wider compaction versus > shrinker-working-set problem, not something unique to Xe. Nevertheless, > for Xe there may be a narrower implementation that does not require a new > hint to be propagated through MM. > > My idea is to make the Xe shrinker distinguish base-page shortage from > fragmentation before entering its destructive, non-purge backup pass: > > 1. Always keep the purgeable-object pass available. > > 2. Check order-0 free pages against the relevant node/zone watermarks, > using sc->nid and the zones allowed by sc->gfp_mask. This should be a > watermark check, not a global MemAvailable threshold. > > 3. If the relevant order-0 supply is healthy, for example above the > high watermark, treat the shrink request as fragmentation-only for > Xe and skip backing up the active VM-bound working set. Reclaiming > arbitrary BO-sized objects is unlikely to produce the contiguous > order-10 extent and is very likely to destroy the GPU working set. > > 4. If the order-0 watermark is below low, treat it as genuine memory > pressure and retain the normal Xe shrinker behavior, including WC > reclaim if cheaper candidates are insufficient. Between low and high > the existing priority policy could remain the conservative fallback. > > In pseudocode, the special case would be placed between the purgeable pass > and the non-purge backup pass in xe_shrinker_scan(): > > run_purgeable_pass(); > > if (order0_watermarks_healthy(sc)) > skip_non_purge_working_set_backup; This actually roughly what downstream customers are carrying :). It is basically these 3 patches [9] [10] [11] implemented directly in the Xe shrinker code to avoid touching the MM or TTM... [9] https://patchwork.freedesktop.org/patch/720030/?series=165329&rev=1 [10] https://patchwork.freedesktop.org/patch/720036/?series=165329&rev=1 [11] https://patchwork.freedesktop.org/patch/720031/?series=165329&rev=1 Alas I got nack'd by someone outside my subsystem on this approach. > > run_normal_priority_based_backup_pass(); > > This differs from my original workaround because it would not make > VM-bound WC BOs unconditionally unreclaimable. They remain reclaimable > under real base-page pressure, so the system can still recover memory in > a genuine low-memory situation. It only avoids the expensive backup and > immediate restore cycle while base-page watermarks say that the problem is > fragmentation rather than capacity. > > This Xe-local policy would not solve the broader problem for inode, dentry, > or other shrinker-managed working sets, so I do not see it as a replacement > for a general MM solution. It may, however, be a small and testable Xe-side > safeguard while the general compaction/shrinker policy is being worked out. > > Would this be a reasonable Xe-specific experiment, or do you think Xe > should rely exclusively on an MM-provided indication such as [8]? > I think if you use the reference patches above to implement a heuristic in Xe, or come up with a similar one, it will likely solve this issue. Since you're on 6.18, you may also be missing some Xe/TTM changes related to this problem that have already been merged into drm-tip. There are a couple of one-line fixes that should help somewhat, but the heuristic is what I think will actually address the root cause. As heads up, I've started looking at this again and pushing to get something upstream as this at least 5th time someone or org has flagged this as a problem. Any data you can provide will help us push towards a solution. Matt [12] https://patchwork.freedesktop.org/patch/732698/?series=168466&rev=1 [13] https://patchwork.freedesktop.org/patch/732420/?series=168389&rev=1 > I have retained the raw trace, the per-second timeline, and the probe > script and can provide them if useful. > > Thanks, > Neil ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim 2026-08-01 6:00 ` Matthew Brost @ 2026-08-08 9:34 ` Neil Zhong 2026-08-12 2:09 ` Matthew Brost 0 siblings, 1 reply; 9+ messages in thread From: Neil Zhong @ 2026-08-08 9:34 UTC (permalink / raw) To: Matthew Brost Cc: intel-xe, thomas.hellstrom, rodrigo.vivi, airlied, simona, dri-devel, linux-kernel On Fri, Jul 31, 2026 at 11:00:49PM -0700, Matthew Brost wrote: > This actually roughly what downstream customers are carrying :). > > It is basically these 3 patches [9] [10] [11] implemented directly in > the Xe shrinker code to avoid touching the MM or TTM... > > Alas I got nack'd by someone outside my subsystem on this approach. > > I think if you use the reference patches above to implement a heuristic > in Xe, or come up with a similar one, it will likely solve this issue. > > Since you're on 6.18, you may also be missing some Xe/TTM changes > related to this problem that have already been merged into drm-tip. > There are a couple of one-line fixes that should help somewhat, but the > heuristic is what I think will actually address the root cause. > > As heads up, I've started looking at this again and pushing to get > something upstream as this at least 5th time someone or org has flagged > this as a problem. Any data you can provide will help us push towards a > solution. Hi Matt, Thanks. I tested [9]-[13] on the same machine and the fragmentation heuristic does reduce the frequency of the problem. However, after these tests I would like to clarify my actual requirement, since my previous watermark-based proposal did not express it correctly. For BOs that belong to a latency-critical visual processing working set, I think userspace should be able to mark them as non-shrinkable, and Xe should not back them up under any memory-reclaim condition while that mark is held. This would be a hard residency contract, not another reclaim priority or a fragmentation hint. Why a hard contract is useful for visual workloads -------------------------------------------------- The reproducer is continuous 4K60 HDR playback. Every decoded frame is imported through DMA-BUF and processed by libplacebo/OpenGL for HDR tone mapping before presentation. The active BO set contains decoded video surfaces, intermediate render targets and presentation-related surfaces. At 60 Hz the complete frame interval is 16.667 ms. If glFlush() is blocked for longer than this, the application misses at least one presentation deadline. Repeated missed deadlines are perceived directly as dropped frames or visible stutter. A 100-500 ms reclaim/restore storm is an obvious freeze, even if the system eventually recovers and its average throughput looks normal. Fence-idle is not equivalent to cold for this workload. A video surface can have no active fence in the small gap between two frames and still be part of the application's current visual working set. The next frame can need the same BO immediately. The trace demonstrates exactly this case. In one sequence, kswapd completed backup of an 8,208-page BO and the rendering thread started restoring the exact same ttm_tt about 33 microseconds later. The kernel copied about 32 MiB to shmem, dropped the WC pages, then immediately had to allocate pages, copy the data back and reapply WC. In the ten-minute default-watermark capture: successful ttm_tt_backup: 4,853 ttm_tt_restore: 4,810 minimum backup+restore copy traffic: 50,436.105 MiB Flush > 16.667 ms: 209 Flush > 100 ms: 65 maximum trace-aligned Flush: 223.195 ms Of 4,791 restores matched to the same preceding backup, 4,279 happened within 100 ms and 4,753 within one second. kswapd0 performed 4,839 of the 4,853 backups, while the player's rendering thread performed most of the restores. Of the 209 Flush calls over one frame interval, 205 contained ttm_tt_restore() and all 209 contained set_pages_array_wc(). This is not useful recovery of cold memory. It is destruction and immediate reconstruction of the visible working set. What the heuristic test showed ------------------------------ I backported [9]-[13], extended the fragmentation check to direct reclaim, and tested a `high + min` watermark threshold. In a follow-up run with the same kernel, video and playback configuration, I set vm.min_free_kbytes to 50000. This lowered the Normal-zone `high + min` threshold from about 379.8 MiB to 255.1 MiB. With the lower threshold, the fragmentation helper returned true more often and Xe working-set churn fell by about 90%: successful ttm_tt_backup: 4,853 -> 443 ttm_tt_restore: 4,810 -> 435 Flush > 16.667 ms: 209 -> 19 Flush > 100 ms: 65 -> 3 This confirms that preventing working-set backup prevents the visual stalls. It does not make the individual restore path cheaper. When the heuristic still allowed a storm, the maximum Flush was 191.655 ms and contained 25 restores and 23 WC conversions. I do not think tuning global watermarks is the right solution. More importantly, I no longer think that protection for explicitly identified visual BOs should depend on whether reclaim was caused by fragmentation or genuine low memory. Once userspace has declared a bounded set as presentation-critical, violating that residency guarantee produces an immediate and user-visible failure. Possible explicit marking mechanism ----------------------------------- Could Xe provide an opt-in, mlock-like mechanism for this purpose? One possible interface would be a new DRM_IOCTL_XE_MADVISE VMA attribute, for example DRM_XE_VMA_ATTR_RECLAIM_POLICY, with states similar to: DRM_XE_VMA_RECLAIM_DEFAULT DRM_XE_VMA_RECLAIM_NO_SHRINK NO_SHRINK would mean that the backing BO is excluded from the Xe shrinker while at least one protected VMA holds the attribute. Userspace would set it when a video/render surface enters the active visual pipeline and clear it after the surface leaves that working set. Unbind, VM destruction or file close would also release the holder automatically. For a BO shared by multiple VMAs, Xe could maintain a BO-level no_shrink_count, similar to the holder accounting already used for purgeable state. The shrinker would skip a BO with a non-zero count. I would prefer a separate shrinker-specific count rather than exposing TTM pin_count, because pinning also affects placement and migration, which is broader than the requested guarantee. The existing WILLNEED state does not provide this contract: it prevents purging of the contents, but the non-purge shrinker may still back up and unpopulate the BO. It also cannot simply be redefined because WILLNEED is the default state for all VMAs. SCANOUT is not sufficient either, since many HDR intermediate and imported video surfaces are not scanout BOs. I understand that an unprivileged client must not be allowed to make an unbounded amount of memory unreclaimable. Like mlock, this could be controlled by an explicit per-file, per-client or cgroup byte limit, and possibly by a privilege check. If the requested protected set exceeds the configured limit, the madvise should fail rather than silently accepting the mark and later violating it under pressure. The application or system service would then decide which visual surfaces to protect or release. Within that bounded contract, however, I think NO_SHRINK should remain a hard guarantee even in genuine low-memory reclaim. Under pressure the kernel may reclaim unmarked BOs and other memory, reject additional NO_SHRINK requests, or require the application/service to release part of its protected set. Backing up an already accepted presentation-critical BO and stalling a frame by hundreds of milliseconds defeats the purpose of the interface. For comparison, my original workaround approximated such a hard contract by excluding VM-bound WC BOs from non-purge shrinking. In a 21-minute capture, no XE_EXEC, VM_BIND or DMA-BUF ioctl exceeded the 16.7 ms frame interval; their maxima were 348 us, 136 us and 20 us. The call rate of set_pages_array_wc fell to 0.179/s. That automatic VM-bound WC rule is too broad, but an explicit and bounded userspace mark could provide the same latency guarantee only for the BOs that actually need it. Would an explicit, bounded NO_SHRINK/latency-critical VMA attribute be a reasonable Xe UAPI direction? If so, I can prototype the BO holder accounting and shrinker exclusion, then modify the video/Mesa path to mark only the active visual working set and collect another strict A/B trace. [9] https://patchwork.freedesktop.org/patch/720030/?series=165329&rev=1 [10] https://patchwork.freedesktop.org/patch/720036/?series=165329&rev=1 [11] https://patchwork.freedesktop.org/patch/720031/?series=165329&rev=1 [12] https://patchwork.freedesktop.org/patch/732698/?series=168466&rev=1 [13] https://patchwork.freedesktop.org/patch/732420/?series=168389&rev=1 Thanks, Neil ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim 2026-08-08 9:34 ` Neil Zhong @ 2026-08-12 2:09 ` Matthew Brost 2026-08-12 8:28 ` Neil Zhong 2026-08-12 22:25 ` Matthew Brost 0 siblings, 2 replies; 9+ messages in thread From: Matthew Brost @ 2026-08-12 2:09 UTC (permalink / raw) To: Neil Zhong Cc: intel-xe, thomas.hellstrom, rodrigo.vivi, airlied, simona, dri-devel, linux-kernel On Sat, Aug 08, 2026 at 05:34:04PM +0800, Neil Zhong wrote: > On Fri, Jul 31, 2026 at 11:00:49PM -0700, Matthew Brost wrote: > > This actually roughly what downstream customers are carrying :). > > > > It is basically these 3 patches [9] [10] [11] implemented directly in > > the Xe shrinker code to avoid touching the MM or TTM... > > > > Alas I got nack'd by someone outside my subsystem on this approach. > > > > I think if you use the reference patches above to implement a heuristic > > in Xe, or come up with a similar one, it will likely solve this issue. > > > > Since you're on 6.18, you may also be missing some Xe/TTM changes > > related to this problem that have already been merged into drm-tip. > > There are a couple of one-line fixes that should help somewhat, but the > > heuristic is what I think will actually address the root cause. > > > > As heads up, I've started looking at this again and pushing to get > > something upstream as this at least 5th time someone or org has flagged > > this as a problem. Any data you can provide will help us push towards a > > solution. > > Hi Matt, > Thanks for all the details here, very helpful. > Thanks. I tested [9]-[13] on the same machine and the fragmentation > heuristic does reduce the frequency of the problem. However, after these > tests I would like to clarify my actual requirement, since my previous > watermark-based proposal did not express it correctly. > > For BOs that belong to a latency-critical visual processing working set, > I think userspace should be able to mark them as non-shrinkable, and Xe > should not back them up under any memory-reclaim condition while that mark > is held. This would be a hard residency contract, not another reclaim > priority or a fragmentation hint. This is roughly what customers have indicated to us for laptop-type products: anything displayed on the screen should avoid eviction or shrinking at all costs. This series came out of that discussion: https://patchwork.freedesktop.org/series/170454/ This customer, in particular, utilizes priority bands to express this heuristic (e.g., the compositor is the highest priority, any non-privileged UI-related content is normal priority, and everything else is low priority). I'm not sure if stock distros do anything like this. Pinning would take this even further, allowing the compositor (or anyone really) to effectively say, "Don't shrink this". > > Why a hard contract is useful for visual workloads > -------------------------------------------------- > > The reproducer is continuous 4K60 HDR playback. Every decoded frame is Can you give me instructions on how to recreate this on our end and your machine, memory details? I have a bunch of various reproducers which I have been using for shrinker work and the more the better. > imported through DMA-BUF and processed by libplacebo/OpenGL for HDR tone > mapping before presentation. The active BO set contains decoded video > surfaces, intermediate render targets and presentation-related surfaces. > DMA-BUF in priority series moves to the prior band that is least likely to be shrunk. > At 60 Hz the complete frame interval is 16.667 ms. If glFlush() is blocked > for longer than this, the application misses at least one presentation > deadline. Repeated missed deadlines are perceived directly as dropped > frames or visible stutter. A 100-500 ms reclaim/restore storm is an > obvious freeze, even if the system eventually recovers and its average > throughput looks normal. > > Fence-idle is not equivalent to cold for this workload. A video surface > can have no active fence in the small gap between two frames and still be > part of the application's current visual working set. The next frame can > need the same BO immediately. > Ok, I think I see a potential problem here with priorities. If, for example, a buffer is assigned a priority indicating that it is unlikely to be evicted but has no active fences, it could be chosen for shrinking before buffers whose priorities indicate "shrink this first" if those buffers have active fences. > The trace demonstrates exactly this case. In one sequence, kswapd > completed backup of an 8,208-page BO and the rendering thread started > restoring the exact same ttm_tt about 33 microseconds later. The kernel > copied about 32 MiB to shmem, dropped the WC pages, then immediately had > to allocate pages, copy the data back and reapply WC. > > In the ten-minute default-watermark capture: > > successful ttm_tt_backup: 4,853 > ttm_tt_restore: 4,810 > minimum backup+restore copy traffic: 50,436.105 MiB > Flush > 16.667 ms: 209 > Flush > 100 ms: 65 > maximum trace-aligned Flush: 223.195 ms Also a quick write up how you extracted these numbers from reproducer so I can recreate on my end. > > Of 4,791 restores matched to the same preceding backup, 4,279 happened > within 100 ms and 4,753 within one second. kswapd0 performed 4,839 of the > 4,853 backups, while the player's rendering thread performed most of the > restores. Of the 209 Flush calls over one frame interval, 205 contained > ttm_tt_restore() and all 209 contained set_pages_array_wc(). > > This is not useful recovery of cold memory. It is destruction and > immediate reconstruction of the visible working set. > Yes, indeed. We really don't want to destroy a working set unless the core system genuinely needs memory and doing so is the only option. Even then, there may be parts of the working set that simply cannot be shrunk, as you are suggesting. > What the heuristic test showed > ------------------------------ > > I backported [9]-[13], extended the fragmentation check to direct reclaim, > and tested a `high + min` watermark threshold. In a follow-up run with the > same kernel, video and playback configuration, I set vm.min_free_kbytes to > 50000. This lowered the Normal-zone `high + min` threshold from about > 379.8 MiB to 255.1 MiB. > > With the lower threshold, the fragmentation helper returned true more > often and Xe working-set churn fell by about 90%: > > successful ttm_tt_backup: 4,853 -> 443 > ttm_tt_restore: 4,810 -> 435 > Flush > 16.667 ms: 209 -> 19 > Flush > 100 ms: 65 -> 3 > > This confirms that preventing working-set backup prevents the visual > stalls. It does not make the individual restore path cheaper. When the > heuristic still allowed a storm, the maximum Flush was 191.655 ms and > contained 25 restores and 23 WC conversions. > > I do not think tuning global watermarks is the right solution. More Nor do I. [9]-[13] were Xe replacement for what is IMO a proper solution in the core MM: https://patchwork.freedesktop.org/series/168651/ I'm pushing on this patch a bit more with the core MM maintainers and have another shrinker locally that is semi-related to this as well. I guess I'd like numbers with the patch above + priority bands to see if that is enough prevent working set shrinking of valuable buffers + spikes in flush times. > importantly, I no longer think that protection for explicitly identified > visual BOs should depend on whether reclaim was caused by fragmentation > or genuine low memory. Once userspace has declared a bounded set as > presentation-critical, violating that residency guarantee produces an > immediate and user-visible failure. > To be clear - this would be an addition to fixes discussed above, right? > Possible explicit marking mechanism > ----------------------------------- > > Could Xe provide an opt-in, mlock-like mechanism for this purpose? > Yes, we could implement something like this, but we'd need buy-in across the entire stack (i.e., from user space as well). I'll run this by the internal team too to see if anyone can immediately poke holes in it, because I don't currently see any obvious issues. > One possible interface would be a new DRM_IOCTL_XE_MADVISE VMA attribute, > for example DRM_XE_VMA_ATTR_RECLAIM_POLICY, with states similar to: > > DRM_XE_VMA_RECLAIM_DEFAULT > DRM_XE_VMA_RECLAIM_NO_SHRINK This seems like a reasonable API. > > NO_SHRINK would mean that the backing BO is excluded from the Xe shrinker > while at least one protected VMA holds the attribute. Userspace would set > it when a video/render surface enters the active visual pipeline and clear > it after the surface leaves that working set. Unbind, VM destruction or > file close would also release the holder automatically. > > For a BO shared by multiple VMAs, Xe could maintain a BO-level > no_shrink_count, similar to the holder accounting already used for > purgeable state. The shrinker would skip a BO with a non-zero count. I > would prefer a separate shrinker-specific count rather than exposing TTM > pin_count, because pinning also affects placement and migration, which is > broader than the requested guarantee. > > The existing WILLNEED state does not provide this contract: it prevents > purging of the contents, but the non-purge shrinker may still back up and > unpopulate the BO. It also cannot simply be redefined because WILLNEED is > the default state for all VMAs. SCANOUT is not sufficient either, since > many HDR intermediate and imported video surfaces are not scanout BOs. > > I understand that an unprivileged client must not be allowed to make an > unbounded amount of memory unreclaimable. Like mlock, this could be > controlled by an explicit per-file, per-client or cgroup byte limit, and I think we could just hook into mlock accounting. There is an exported function for exactly this purpose: https://elixir.bootlin.com/linux/v7.1.7/source/mm/util.c#L549 You'd have to deal with multiple VMAs (from the same or different MMs in a dma-buf) aliasing the same BO and ensure that accounting remains consistent everywhere, but it shouldn't be too difficult. We already have this problem WILLNEED/WONTNEED and solved it. Ofc, this only works for system memory buffers so we'd some VRAM type accounting too. iirc Thomas was working on cgroups for that part in a slightly different context though. > possibly by a privilege check. If the requested protected set exceeds the > configured limit, the madvise should fail rather than silently accepting > the mark and later violating it under pressure. The application or system > service would then decide which visual surfaces to protect or release. > > Within that bounded contract, however, I think NO_SHRINK should remain a > hard guarantee even in genuine low-memory reclaim. Under pressure the > kernel may reclaim unmarked BOs and other memory, reject additional > NO_SHRINK requests, or require the application/service to release part of > its protected set. Backing up an already accepted presentation-critical > BO and stalling a frame by hundreds of milliseconds defeats the purpose > of the interface. > > For comparison, my original workaround approximated such a hard contract > by excluding VM-bound WC BOs from non-purge shrinking. In a 21-minute > capture, no XE_EXEC, VM_BIND or DMA-BUF ioctl exceeded the 16.7 ms frame > interval; their maxima were 348 us, 136 us and 20 us. The call rate of > set_pages_array_wc fell to 0.179/s. That automatic VM-bound WC rule is too > broad, but an explicit and bounded userspace mark could provide the same > latency guarantee only for the BOs that actually need it. > > Would an explicit, bounded NO_SHRINK/latency-critical VMA attribute be a > reasonable Xe UAPI direction? If so, I can prototype the BO holder > accounting and shrinker exclusion, then modify the video/Mesa path to mark > only the active visual working set and collect another strict A/B trace. No issue if you want to prototype this, but as mentioned above, this would require buy-in from user space (which is not under my control) and at least one other person on the KMD team (most likely Thomas). So I can't guarantee that it won't be rejected by someone. Matt > [9] https://patchwork.freedesktop.org/patch/720030/?series=165329&rev=1 > [10] https://patchwork.freedesktop.org/patch/720036/?series=165329&rev=1 > [11] https://patchwork.freedesktop.org/patch/720031/?series=165329&rev=1 > [12] https://patchwork.freedesktop.org/patch/732698/?series=168466&rev=1 > [13] https://patchwork.freedesktop.org/patch/732420/?series=168389&rev=1 > > Thanks, > Neil ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim 2026-08-12 2:09 ` Matthew Brost @ 2026-08-12 8:28 ` Neil Zhong 2026-08-12 22:25 ` Matthew Brost 1 sibling, 0 replies; 9+ messages in thread From: Neil Zhong @ 2026-08-12 8:28 UTC (permalink / raw) To: Matthew Brost Cc: intel-xe, thomas.hellstrom, rodrigo.vivi, airlied, simona, dri-devel, linux-kernel Hi Matt, > Can you give me instructions on how to recreate this on our end and your > machine, memory details? I have a bunch of various reproducers which I > have been using for shrinker work and the more the better. Yes. The test system and workload are as follows. - Panther Lake iGPU using shared system memory - 8 GiB installed memory; /proc/meminfo reports 7,723,392 KiB - 4 KiB base pages - four zram swap devices, 3,858,416 KiB in total - Linux 6.18.15, x86_64, PREEMPT_DYNAMIC - X11 fullscreen output at 3840x2160 and 60 Hz - a 3840x2160, 60 fps, HEVC HDR video played continuously in a loop The player uses hardware decoding. Each decoded frame is imported through DMA-BUF and processed by libplacebo/OpenGL for HDR tone mapping before presentation. It calls glFlush() for every rendered frame. During steady playback, the player accounts for about 1.85 GiB of logical Xe BO allocation, including about 672 MiB reported as shared. The player is not currently public. However, an equivalent pipeline should reproduce the condition if it keeps the decoded surfaces, HDR intermediate render targets and presentation surfaces alive, rather than creating a small synthetic BO set. No additional memory-pressure tool was used for the first reproduction. I start the video, let its working set reach steady state, and then capture ten minutes while playback continues. On the 8 GiB system, the priority-only run had MemAvailable between 2.89 and 3.15 GiB, while 97.8% of kswapd wakeups were for order-10 allocations. Thus this reproduces without forcing an order-0 shortage. I collected the trace with: sudo ./capture_xe_memory_churn.sh \ -t 600 \ -s 0.2 \ -o ./xe-memory-churn `-t 600` records ten minutes. `-t 0` can instead be used to record until Ctrl-C. The 0.2 second option is only the /proc and TTM-pool sampling interval; ftrace events are recorded continuously. The player also logs one line after each frame submission in this form: gl_sw_submit_frame timing: ... Flush=123.456 ms The log prefix contains the wall-clock timestamp. An equivalent reproducer can record the time immediately after glFlush() returns and the measured duration. The trace script inserts a wall-clock epoch marker into a mono_raw ftrace stream so that the two timelines can be aligned. The figures in my previous email came from the 6.18.15 kernel with [9]-[13] backported, the fragmentation check applied to direct reclaim as well, and the high-plus-min watermark experiment described there. The default-device watermark capture used vm.min_free_kbytes=131072. The follow-up used 50000; the workload and trace procedure were otherwise unchanged. > Also a quick write up how you extracted these numbers from reproducer so > I can recreate on my end. The capture script creates temporary entry and return kprobes for: ttm_tt_backup() ttm_tt_restore() ttm_pool_alloc() ttm_pool_free() ttm_pool_shrink() It also traces the Xe shrinker, TTM restore and cache-attribute functions, kswapd and direct-reclaim events, compaction, and allocation fragmentation. At ttm_tt_backup() entry, the probe records the ttm_tt pointer and num_pages. At return, it records the positive return value, which is the number of pages actually backed up. I sum those successful return values, not the requested page count, when reporting backup volume. A later ttm_tt_restore() is matched to the most recent successful backup using the same ttm_tt pointer. That provides per-object backup-to-restore latency and repeated-cycle counts. The byte-volume calculation is: backup bytes = sum(successful backup return pages) * PAGE_SIZE restore bytes = sum(num_pages for matched restores) * PAGE_SIZE The reported backup-plus-restore volume is the sum of those two values. It is cumulative migration/copy traffic, not resident memory and not net memory freed. A shmem backup remains resident system memory unless those shmem pages are subsequently swapped out. > This customer, in particular, utilizes priority bands to express this > heuristic (e.g., the compositor is the highest priority, any > non-privileged UI-related content is normal priority, and everything > else is low priority). I think priority bands are useful for relative reclaim ordering, but they do not by themselves express the guarantee needed here. Consider a system with one large GPU workload. If nearly all reclaimable BOs belong to that client and are placed in the high-priority band, the low bands will contain few or no candidates. When enough memory is requested, the shrinker must eventually enter the high band. In that case, high priority delays reclaim but does not prevent it. The priority-only test showed exactly this limitation: over ten minutes there were 6,743 successful backups and 6,693 restores, with 157 Flush calls over 16.667 ms and a maximum Flush of 494.434 ms. I am not suggesting that every BO of a high-priority client should be unreclaimable. Whether reclaim is acceptable depends on the workload, and the kernel cannot infer that semantic from WC, VM-bound state, client count or BO size alone. For example, the driver-visible behavior of these two workloads can look very similar: 1. Foreground 4K60 HDR playback. Its active decoded surfaces, HDR render targets and presentation surfaces have a 16.667 ms deadline. Backing them up and restoring them causes an immediate and clearly visible product failure. These BOs should avoid eviction and shrinking while they are part of the active visual pipeline. 2. Background image recognition or classification. Its BOs have no presentation deadline. Reclaiming them under system memory pressure is reasonable, even if the job later has to reconstruct its working set. Priority bands cannot distinguish those cases if both clients assign their current working set a high relative priority. This is why I think the business semantic has to come from userspace. Priority bands can remain the general ordering mechanism, while a separate, explicit and bounded NO_SHRINK or latency-critical mark protects only the BOs in an active visual pipeline. The mark should be removed as soon as a surface leaves that working set. > To be clear - this would be an addition to fixes discussed above, right? Yes. I see explicit workload-semantic protection as an addition to the core MM fragmentation/shrinker fixes and the Xe/TTM priority bands, not a replacement for either. I agree that testing series 168651 together with the priority bands is still useful for general working-set preservation. It can reduce accidental reclaim, while an accounted NO_SHRINK contract handles the smaller set for which a missed presentation deadline is not an acceptable reclaim tradeoff. Thanks, Neil ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim 2026-08-12 2:09 ` Matthew Brost 2026-08-12 8:28 ` Neil Zhong @ 2026-08-12 22:25 ` Matthew Brost 1 sibling, 0 replies; 9+ messages in thread From: Matthew Brost @ 2026-08-12 22:25 UTC (permalink / raw) To: Neil Zhong Cc: intel-xe, thomas.hellstrom, rodrigo.vivi, airlied, simona, dri-devel, linux-kernel On Tue, Aug 11, 2026 at 07:09:33PM -0700, Matthew Brost wrote: > On Sat, Aug 08, 2026 at 05:34:04PM +0800, Neil Zhong wrote: > > On Fri, Jul 31, 2026 at 11:00:49PM -0700, Matthew Brost wrote: > > > This actually roughly what downstream customers are carrying :). > > > > > > It is basically these 3 patches [9] [10] [11] implemented directly in > > > the Xe shrinker code to avoid touching the MM or TTM... > > > > > > Alas I got nack'd by someone outside my subsystem on this approach. > > > > > > I think if you use the reference patches above to implement a heuristic > > > in Xe, or come up with a similar one, it will likely solve this issue. > > > > > > Since you're on 6.18, you may also be missing some Xe/TTM changes > > > related to this problem that have already been merged into drm-tip. > > > There are a couple of one-line fixes that should help somewhat, but the > > > heuristic is what I think will actually address the root cause. > > > > > > As heads up, I've started looking at this again and pushing to get > > > something upstream as this at least 5th time someone or org has flagged > > > this as a problem. Any data you can provide will help us push towards a > > > solution. > > > > Hi Matt, > > > > Thanks for all the details here, very helpful. > > > Thanks. I tested [9]-[13] on the same machine and the fragmentation > > heuristic does reduce the frequency of the problem. However, after these > > tests I would like to clarify my actual requirement, since my previous > > watermark-based proposal did not express it correctly. > > > > For BOs that belong to a latency-critical visual processing working set, > > I think userspace should be able to mark them as non-shrinkable, and Xe > > should not back them up under any memory-reclaim condition while that mark > > is held. This would be a hard residency contract, not another reclaim > > priority or a fragmentation hint. > > This is roughly what customers have indicated to us for laptop-type > products: anything displayed on the screen should avoid eviction or > shrinking at all costs. This series came out of that discussion: > > https://patchwork.freedesktop.org/series/170454/ > > This customer, in particular, utilizes priority bands to express this > heuristic (e.g., the compositor is the highest priority, any > non-privileged UI-related content is normal priority, and everything > else is low priority). I'm not sure if stock distros do anything like > this. > > Pinning would take this even further, allowing the compositor (or anyone > really) to effectively say, "Don't shrink this". > > > > > Why a hard contract is useful for visual workloads > > -------------------------------------------------- > > > > The reproducer is continuous 4K60 HDR playback. Every decoded frame is > > Can you give me instructions on how to recreate this on our end and your > machine, memory details? I have a bunch of various reproducers which I > have been using for shrinker work and the more the better. > > > imported through DMA-BUF and processed by libplacebo/OpenGL for HDR tone > > mapping before presentation. The active BO set contains decoded video > > surfaces, intermediate render targets and presentation-related surfaces. > > > > DMA-BUF in priority series moves to the prior band that is least likely > to be shrunk. > > > At 60 Hz the complete frame interval is 16.667 ms. If glFlush() is blocked > > for longer than this, the application misses at least one presentation > > deadline. Repeated missed deadlines are perceived directly as dropped > > frames or visible stutter. A 100-500 ms reclaim/restore storm is an > > obvious freeze, even if the system eventually recovers and its average > > throughput looks normal. > > > > Fence-idle is not equivalent to cold for this workload. A video surface > > can have no active fence in the small gap between two frames and still be > > part of the application's current visual working set. The next frame can > > need the same BO immediately. > > > > Ok, I think I see a potential problem here with priorities. If, for > example, a buffer is assigned a priority indicating that it is unlikely > to be evicted but has no active fences, it could be chosen for shrinking > before buffers whose priorities indicate "shrink this first" if those > buffers have active fences. > > > The trace demonstrates exactly this case. In one sequence, kswapd > > completed backup of an 8,208-page BO and the rendering thread started > > restoring the exact same ttm_tt about 33 microseconds later. The kernel > > copied about 32 MiB to shmem, dropped the WC pages, then immediately had > > to allocate pages, copy the data back and reapply WC. > > > > In the ten-minute default-watermark capture: > > > > successful ttm_tt_backup: 4,853 > > ttm_tt_restore: 4,810 > > minimum backup+restore copy traffic: 50,436.105 MiB > > Flush > 16.667 ms: 209 > > Flush > 100 ms: 65 > > maximum trace-aligned Flush: 223.195 ms > > Also a quick write up how you extracted these numbers from reproducer so > I can recreate on my end. > > > > > Of 4,791 restores matched to the same preceding backup, 4,279 happened > > within 100 ms and 4,753 within one second. kswapd0 performed 4,839 of the > > 4,853 backups, while the player's rendering thread performed most of the > > restores. Of the 209 Flush calls over one frame interval, 205 contained > > ttm_tt_restore() and all 209 contained set_pages_array_wc(). > > > > This is not useful recovery of cold memory. It is destruction and > > immediate reconstruction of the visible working set. > > > > Yes, indeed. We really don't want to destroy a working set unless the > core system genuinely needs memory and doing so is the only option. > Even then, there may be parts of the working set that simply cannot be > shrunk, as you are suggesting. > > > What the heuristic test showed > > ------------------------------ > > > > I backported [9]-[13], extended the fragmentation check to direct reclaim, > > and tested a `high + min` watermark threshold. In a follow-up run with the > > same kernel, video and playback configuration, I set vm.min_free_kbytes to > > 50000. This lowered the Normal-zone `high + min` threshold from about > > 379.8 MiB to 255.1 MiB. > > > > With the lower threshold, the fragmentation helper returned true more > > often and Xe working-set churn fell by about 90%: > > > > successful ttm_tt_backup: 4,853 -> 443 > > ttm_tt_restore: 4,810 -> 435 > > Flush > 16.667 ms: 209 -> 19 > > Flush > 100 ms: 65 -> 3 > > > > This confirms that preventing working-set backup prevents the visual > > stalls. It does not make the individual restore path cheaper. When the > > heuristic still allowed a storm, the maximum Flush was 191.655 ms and > > contained 25 restores and 23 WC conversions. > > > > I do not think tuning global watermarks is the right solution. More > > Nor do I. [9]-[13] were Xe replacement for what is IMO a proper solution > in the core MM: https://patchwork.freedesktop.org/series/168651/ I'm > pushing on this patch a bit more with the core MM maintainers and have > another shrinker locally that is semi-related to this as well. > > I guess I'd like numbers with the patch above + priority bands to see if > that is enough prevent working set shrinking of valuable buffers + > spikes in flush times. > > > importantly, I no longer think that protection for explicitly identified > > visual BOs should depend on whether reclaim was caused by fragmentation > > or genuine low memory. Once userspace has declared a bounded set as > > presentation-critical, violating that residency guarantee produces an > > immediate and user-visible failure. > > > > To be clear - this would be an addition to fixes discussed above, right? > > > Possible explicit marking mechanism > > ----------------------------------- > > > > Could Xe provide an opt-in, mlock-like mechanism for this purpose? > > > > Yes, we could implement something like this, but we'd need buy-in across > the entire stack (i.e., from user space as well). I'll run this by the > internal team too to see if anyone can immediately poke holes in it, > because I don't currently see any obvious issues. > > > One possible interface would be a new DRM_IOCTL_XE_MADVISE VMA attribute, > > for example DRM_XE_VMA_ATTR_RECLAIM_POLICY, with states similar to: > > > > DRM_XE_VMA_RECLAIM_DEFAULT > > DRM_XE_VMA_RECLAIM_NO_SHRINK > > This seems like a reasonable API. > > > > > NO_SHRINK would mean that the backing BO is excluded from the Xe shrinker > > while at least one protected VMA holds the attribute. Userspace would set > > it when a video/render surface enters the active visual pipeline and clear > > it after the surface leaves that working set. Unbind, VM destruction or > > file close would also release the holder automatically. > > > > For a BO shared by multiple VMAs, Xe could maintain a BO-level > > no_shrink_count, similar to the holder accounting already used for > > purgeable state. The shrinker would skip a BO with a non-zero count. I > > would prefer a separate shrinker-specific count rather than exposing TTM > > pin_count, because pinning also affects placement and migration, which is > > broader than the requested guarantee. > > > > The existing WILLNEED state does not provide this contract: it prevents > > purging of the contents, but the non-purge shrinker may still back up and > > unpopulate the BO. It also cannot simply be redefined because WILLNEED is > > the default state for all VMAs. SCANOUT is not sufficient either, since > > many HDR intermediate and imported video surfaces are not scanout BOs. > > > > I understand that an unprivileged client must not be allowed to make an > > unbounded amount of memory unreclaimable. Like mlock, this could be > > controlled by an explicit per-file, per-client or cgroup byte limit, and > > I think we could just hook into mlock accounting. There is an exported > function for exactly this purpose: > > https://elixir.bootlin.com/linux/v7.1.7/source/mm/util.c#L549 > I guess using mlock accounting for pinning has been discussed in the past and was ultimately rejected because it is susceptible to fork-bomb attacks, which can result in all SRAM being pinned. Thomas has a write-up with more details that he can perhaps share, but I think the community direction of a pinning uAPI is reasonable. However, we likely need cgroup-based pinning limits. Dave has a series implementing cgroups for SRAM here [1], and we'd likely need to extend this to support pinning limits as well. Likewise, the VRAM controller would also need pinning limits. Matt [1] https://patchwork.freedesktop.org/series/169824/ > You'd have to deal with multiple VMAs (from the same or different MMs in > a dma-buf) aliasing the same BO and ensure that accounting remains > consistent everywhere, but it shouldn't be too difficult. We already > have this problem WILLNEED/WONTNEED and solved it. > > Ofc, this only works for system memory buffers so we'd some VRAM type > accounting too. iirc Thomas was working on cgroups for that part in a > slightly different context though. > > > possibly by a privilege check. If the requested protected set exceeds the > > configured limit, the madvise should fail rather than silently accepting > > the mark and later violating it under pressure. The application or system > > service would then decide which visual surfaces to protect or release. > > > > Within that bounded contract, however, I think NO_SHRINK should remain a > > hard guarantee even in genuine low-memory reclaim. Under pressure the > > kernel may reclaim unmarked BOs and other memory, reject additional > > NO_SHRINK requests, or require the application/service to release part of > > its protected set. Backing up an already accepted presentation-critical > > BO and stalling a frame by hundreds of milliseconds defeats the purpose > > of the interface. > > > > For comparison, my original workaround approximated such a hard contract > > by excluding VM-bound WC BOs from non-purge shrinking. In a 21-minute > > capture, no XE_EXEC, VM_BIND or DMA-BUF ioctl exceeded the 16.7 ms frame > > interval; their maxima were 348 us, 136 us and 20 us. The call rate of > > set_pages_array_wc fell to 0.179/s. That automatic VM-bound WC rule is too > > broad, but an explicit and bounded userspace mark could provide the same > > latency guarantee only for the BOs that actually need it. > > > > Would an explicit, bounded NO_SHRINK/latency-critical VMA attribute be a > > reasonable Xe UAPI direction? If so, I can prototype the BO holder > > accounting and shrinker exclusion, then modify the video/Mesa path to mark > > only the active visual working set and collect another strict A/B trace. > > No issue if you want to prototype this, but as mentioned above, this > would require buy-in from user space (which is not under my control) and > at least one other person on the KMD team (most likely Thomas). So I > can't guarantee that it won't be rejected by someone. > > Matt > > > [9] https://patchwork.freedesktop.org/patch/720030/?series=165329&rev=1 > > [10] https://patchwork.freedesktop.org/patch/720036/?series=165329&rev=1 > > [11] https://patchwork.freedesktop.org/patch/720031/?series=165329&rev=1 > > [12] https://patchwork.freedesktop.org/patch/732698/?series=168466&rev=1 > > [13] https://patchwork.freedesktop.org/patch/732420/?series=168389&rev=1 > > > > Thanks, > > Neil ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-08-12 22:25 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <20260728065512.59911-1-neil.zhong@ugreen.com>
2026-07-28 6:55 ` [RFC PATCH v2 1/1] drm/xe: keep VM-bound WC BOs resident during reclaim Neil Zhong
2026-07-31 1:36 ` Matthew Brost
2026-07-31 2:44 ` Matthew Brost
2026-08-01 5:39 ` Neil Zhong
2026-08-01 6:00 ` Matthew Brost
2026-08-08 9:34 ` Neil Zhong
2026-08-12 2:09 ` Matthew Brost
2026-08-12 8:28 ` Neil Zhong
2026-08-12 22:25 ` Matthew Brost
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®