Message ID | 20180517060738.19193-29-chris@chris-wilson.co.uk (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On 17 May 2018 at 07:03, Chris Wilson <chris@chris-wilson.co.uk> wrote: > Currently the purgeable objects, I915_MADV_DONTNEED, as mixed in the > normal bound/unbound lists. Every shrinker pass starts with an attempt > to purge from this set of unneeded objects, which entails us doing a > walk over both lists looking for any candidates. If there are none, and > since we are shrinking we can reasonably assume that the lists are > full!, this becomes a very slow futile walk. > > If we separate out the purgeable objects into own list, this search then > becomes its own phase that is preferentially handled during shrinking. > Instead the cost becomes that we then need to filter the purgeable list > if we want to distinguish between bound and unbound objects. > > Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> > Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> > --- > drivers/gpu/drm/i915/i915_drv.h | 13 ++++--- > drivers/gpu/drm/i915/i915_gem.c | 49 ++++++++++++++++++------ > drivers/gpu/drm/i915/i915_gem_shrinker.c | 28 +++++++------- > drivers/gpu/drm/i915/i915_vma.c | 2 +- > 4 files changed, 60 insertions(+), 32 deletions(-) > > diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h > index 56ffdd523893..1eeee043e164 100644 > --- a/drivers/gpu/drm/i915/i915_drv.h > +++ b/drivers/gpu/drm/i915/i915_drv.h > @@ -926,6 +926,10 @@ struct i915_gem_mm { > * not actually have any pages attached. > */ > struct list_head unbound_list; > + /** > + * List of objects which are purgeable. May be active. > + */ > + struct list_head purge_list; > > /** List of all objects in gtt_space, currently mmaped by userspace. > * All objects within this list must also be on bound_list. > @@ -3310,11 +3314,10 @@ unsigned long i915_gem_shrink(struct drm_i915_private *i915, > unsigned long target, > unsigned long *nr_scanned, > unsigned flags); > -#define I915_SHRINK_PURGEABLE 0x1 > -#define I915_SHRINK_UNBOUND 0x2 > -#define I915_SHRINK_BOUND 0x4 > -#define I915_SHRINK_ACTIVE 0x8 > -#define I915_SHRINK_VMAPS 0x10 > +#define I915_SHRINK_UNBOUND BIT(0) > +#define I915_SHRINK_BOUND BIT(1) > +#define I915_SHRINK_ACTIVE BIT(2) > +#define I915_SHRINK_VMAPS BIT(3) > unsigned long i915_gem_shrink_all(struct drm_i915_private *i915); > void i915_gem_shrinker_register(struct drm_i915_private *i915); > void i915_gem_shrinker_unregister(struct drm_i915_private *i915); > diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c > index 42d95f6490f8..be3092a03722 100644 > --- a/drivers/gpu/drm/i915/i915_gem.c > +++ b/drivers/gpu/drm/i915/i915_gem.c > @@ -1672,8 +1672,6 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, > > static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj) > { > - struct drm_i915_private *i915; > - struct list_head *list; > struct i915_vma *vma; > > GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj)); > @@ -1688,11 +1686,16 @@ static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj) > list_move_tail(&vma->vm_link, &vma->vm->inactive_list); > } > > - i915 = to_i915(obj->base.dev); > - spin_lock(&i915->mm.obj_lock); > - list = obj->bind_count ? &i915->mm.bound_list : &i915->mm.unbound_list; > - list_move_tail(&obj->mm.link, list); > - spin_unlock(&i915->mm.obj_lock); > + if (obj->mm.madv == I915_MADV_WILLNEED) { > + struct drm_i915_private *i915 = to_i915(obj->base.dev); > + struct list_head *list; > + > + spin_lock(&i915->mm.obj_lock); > + list = obj->bind_count ? > + &i915->mm.bound_list : &i915->mm.unbound_list; > + list_move_tail(&obj->mm.link, list); > + spin_unlock(&i915->mm.obj_lock); > + } > } > > /** > @@ -2531,7 +2534,7 @@ static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) > sg_page_sizes = 0; > for (i = 0; i < page_count; i++) { > const unsigned int shrink[] = { > - I915_SHRINK_BOUND | I915_SHRINK_UNBOUND | I915_SHRINK_PURGEABLE, > + I915_SHRINK_BOUND | I915_SHRINK_UNBOUND, > 0, > }, *s = shrink; > gfp_t gfp = noreclaim; > @@ -4519,7 +4522,7 @@ int > i915_gem_madvise_ioctl(struct drm_device *dev, void *data, > struct drm_file *file_priv) > { > - struct drm_i915_private *dev_priv = to_i915(dev); > + struct drm_i915_private *i915 = to_i915(dev); > struct drm_i915_gem_madvise *args = data; > struct drm_i915_gem_object *obj; > int err; > @@ -4542,7 +4545,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, > > if (i915_gem_object_has_pages(obj) && > i915_gem_object_is_tiled(obj) && > - dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES) { > + i915->quirks & QUIRK_PIN_SWIZZLED_PAGES) { > if (obj->mm.madv == I915_MADV_WILLNEED) { > GEM_BUG_ON(!obj->mm.quirked); > __i915_gem_object_unpin_pages(obj); > @@ -4558,6 +4561,20 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, > if (obj->mm.madv != __I915_MADV_PURGED) > obj->mm.madv = args->madv; > > + if (i915_gem_object_has_pages(obj)) { > + struct list_head *list; > + > + spin_lock(&i915->mm.obj_lock); > + if (obj->mm.madv != I915_MADV_WILLNEED) > + list = &i915->mm.purge_list; > + else if (obj->bind_count) > + list = &i915->mm.bound_list; > + else > + list = &i915->mm.unbound_list; > + list_move_tail(&obj->mm.link, list); > + spin_unlock(&i915->mm.obj_lock); > + } > + > /* if the object is no longer attached, discard its backing storage */ > if (obj->mm.madv == I915_MADV_DONTNEED && > !i915_gem_object_has_pages(obj)) > @@ -4876,9 +4893,18 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) > if (obj->mm.quirked) > __i915_gem_object_unpin_pages(obj); > > - if (discard_backing_storage(obj)) > + if (discard_backing_storage(obj)) { > + struct drm_i915_private *i915 = to_i915(obj->base.dev); > + > obj->mm.madv = I915_MADV_DONTNEED; > > + if (i915_gem_object_has_pages(obj)) { > + spin_lock(&i915->mm.obj_lock); > + list_move_tail(&obj->mm.link, &i915->mm.purge_list); > + spin_unlock(&i915->mm.obj_lock); > + } > + } > + > /* > * Before we free the object, make sure any pure RCU-only > * read-side critical sections are complete, e.g. > @@ -5527,6 +5553,7 @@ static void i915_gem_init__mm(struct drm_i915_private *i915) > > init_llist_head(&i915->mm.free_list); > > + INIT_LIST_HEAD(&i915->mm.purge_list); > INIT_LIST_HEAD(&i915->mm.unbound_list); > INIT_LIST_HEAD(&i915->mm.bound_list); > INIT_LIST_HEAD(&i915->mm.fence_list); > diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c > index 5757fb7c4b5a..ea5a6e2d62d2 100644 > --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c > +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c > @@ -151,6 +151,7 @@ i915_gem_shrink(struct drm_i915_private *i915, > struct list_head *list; > unsigned int bit; > } phases[] = { > + { &i915->mm.purge_list, 0 }, > { &i915->mm.unbound_list, I915_SHRINK_UNBOUND }, > { &i915->mm.bound_list, I915_SHRINK_BOUND }, > { NULL, 0 }, > @@ -182,8 +183,7 @@ i915_gem_shrink(struct drm_i915_private *i915, > * device just to recover a little memory. If absolutely necessary, > * we will force the wake during oom-notifier. > */ > - if ((flags & I915_SHRINK_BOUND) && > - !intel_runtime_pm_get_if_in_use(i915)) > + if (flags & I915_SHRINK_BOUND && !intel_runtime_pm_get_if_in_use(i915)) > flags &= ~I915_SHRINK_BOUND; > > /* > @@ -209,7 +209,7 @@ i915_gem_shrink(struct drm_i915_private *i915, > struct list_head still_in_list; > struct drm_i915_gem_object *obj; > > - if ((flags & phase->bit) == 0) > + if (phase->bit && (flags & phase->bit) == 0) > continue; > > INIT_LIST_HEAD(&still_in_list); > @@ -228,10 +228,6 @@ i915_gem_shrink(struct drm_i915_private *i915, > mm.link))) { > list_move_tail(&obj->mm.link, &still_in_list); > > - if (flags & I915_SHRINK_PURGEABLE && > - obj->mm.madv != I915_MADV_DONTNEED) > - continue; > - > if (flags & I915_SHRINK_VMAPS && > !is_vmalloc_addr(obj->mm.mapping)) > continue; > @@ -241,6 +237,10 @@ i915_gem_shrink(struct drm_i915_private *i915, > i915_gem_object_is_framebuffer(obj))) > continue; > > + if (!(flags & I915_SHRINK_BOUND) && > + READ_ONCE(obj->bind_count)) > + continue; > + > if (!can_release_pages(obj)) > continue; > > @@ -325,6 +325,11 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) > count += obj->base.size >> PAGE_SHIFT; > num_objects++; > } > + list_for_each_entry(obj, &i915->mm.purge_list, mm.link) > + if (!i915_gem_object_is_active(obj) && can_release_pages(obj)) { > + count += obj->base.size >> PAGE_SHIFT; > + num_objects++; > + } > spin_unlock(&i915->mm.obj_lock); > > /* Update our preferred vmscan batch size for the next pass. > @@ -361,14 +366,7 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) > sc->nr_to_scan, > &sc->nr_scanned, > I915_SHRINK_BOUND | > - I915_SHRINK_UNBOUND | > - I915_SHRINK_PURGEABLE); > - if (sc->nr_scanned < sc->nr_to_scan) > - freed += i915_gem_shrink(i915, > - sc->nr_to_scan - sc->nr_scanned, > - &sc->nr_scanned, > - I915_SHRINK_BOUND | > - I915_SHRINK_UNBOUND); > + I915_SHRINK_UNBOUND); > if (sc->nr_scanned < sc->nr_to_scan && current_is_kswapd()) { > intel_runtime_pm_get(i915); > freed += i915_gem_shrink(i915, > diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c > index 9324d476e0a7..96039c4ef434 100644 > --- a/drivers/gpu/drm/i915/i915_vma.c > +++ b/drivers/gpu/drm/i915/i915_vma.c > @@ -624,7 +624,7 @@ i915_vma_remove(struct i915_vma *vma) > * no more VMAs exist. > */ > spin_lock(&i915->mm.obj_lock); > - if (--obj->bind_count == 0) > + if (--obj->bind_count == 0 && obj->mm.madv == I915_MADV_WILLNEED) How does this play with volatile objects, like gem object internal, since they are DONTNEED while pinned? > list_move_tail(&obj->mm.link, &i915->mm.unbound_list); > spin_unlock(&i915->mm.obj_lock); > > -- > 2.17.0 > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Quoting Matthew Auld (2018-05-18 12:36:30) > On 17 May 2018 at 07:03, Chris Wilson <chris@chris-wilson.co.uk> wrote: > > diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c > > index 9324d476e0a7..96039c4ef434 100644 > > --- a/drivers/gpu/drm/i915/i915_vma.c > > +++ b/drivers/gpu/drm/i915/i915_vma.c > > @@ -624,7 +624,7 @@ i915_vma_remove(struct i915_vma *vma) > > * no more VMAs exist. > > */ > > spin_lock(&i915->mm.obj_lock); > > - if (--obj->bind_count == 0) > > + if (--obj->bind_count == 0 && obj->mm.madv == I915_MADV_WILLNEED) > > How does this play with volatile objects, like gem object internal, > since they are DONTNEED while pinned? Not brilliant as they are left on the unbound_list rather than promoted to the purge_lit. They will still be reaped eventually, but I don't expect it to make any difference in practice (since they are either short lived shadow batches, or longer lived and quite-oft pinned ringbuffers). It really just means stop poking at mm.madv directly, and probably just make the decision to mark as purgeable from the start and play fewer games. -Chris
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 56ffdd523893..1eeee043e164 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -926,6 +926,10 @@ struct i915_gem_mm { * not actually have any pages attached. */ struct list_head unbound_list; + /** + * List of objects which are purgeable. May be active. + */ + struct list_head purge_list; /** List of all objects in gtt_space, currently mmaped by userspace. * All objects within this list must also be on bound_list. @@ -3310,11 +3314,10 @@ unsigned long i915_gem_shrink(struct drm_i915_private *i915, unsigned long target, unsigned long *nr_scanned, unsigned flags); -#define I915_SHRINK_PURGEABLE 0x1 -#define I915_SHRINK_UNBOUND 0x2 -#define I915_SHRINK_BOUND 0x4 -#define I915_SHRINK_ACTIVE 0x8 -#define I915_SHRINK_VMAPS 0x10 +#define I915_SHRINK_UNBOUND BIT(0) +#define I915_SHRINK_BOUND BIT(1) +#define I915_SHRINK_ACTIVE BIT(2) +#define I915_SHRINK_VMAPS BIT(3) unsigned long i915_gem_shrink_all(struct drm_i915_private *i915); void i915_gem_shrinker_register(struct drm_i915_private *i915); void i915_gem_shrinker_unregister(struct drm_i915_private *i915); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 42d95f6490f8..be3092a03722 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1672,8 +1672,6 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data, static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj) { - struct drm_i915_private *i915; - struct list_head *list; struct i915_vma *vma; GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj)); @@ -1688,11 +1686,16 @@ static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj) list_move_tail(&vma->vm_link, &vma->vm->inactive_list); } - i915 = to_i915(obj->base.dev); - spin_lock(&i915->mm.obj_lock); - list = obj->bind_count ? &i915->mm.bound_list : &i915->mm.unbound_list; - list_move_tail(&obj->mm.link, list); - spin_unlock(&i915->mm.obj_lock); + if (obj->mm.madv == I915_MADV_WILLNEED) { + struct drm_i915_private *i915 = to_i915(obj->base.dev); + struct list_head *list; + + spin_lock(&i915->mm.obj_lock); + list = obj->bind_count ? + &i915->mm.bound_list : &i915->mm.unbound_list; + list_move_tail(&obj->mm.link, list); + spin_unlock(&i915->mm.obj_lock); + } } /** @@ -2531,7 +2534,7 @@ static int i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) sg_page_sizes = 0; for (i = 0; i < page_count; i++) { const unsigned int shrink[] = { - I915_SHRINK_BOUND | I915_SHRINK_UNBOUND | I915_SHRINK_PURGEABLE, + I915_SHRINK_BOUND | I915_SHRINK_UNBOUND, 0, }, *s = shrink; gfp_t gfp = noreclaim; @@ -4519,7 +4522,7 @@ int i915_gem_madvise_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv) { - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_i915_private *i915 = to_i915(dev); struct drm_i915_gem_madvise *args = data; struct drm_i915_gem_object *obj; int err; @@ -4542,7 +4545,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, if (i915_gem_object_has_pages(obj) && i915_gem_object_is_tiled(obj) && - dev_priv->quirks & QUIRK_PIN_SWIZZLED_PAGES) { + i915->quirks & QUIRK_PIN_SWIZZLED_PAGES) { if (obj->mm.madv == I915_MADV_WILLNEED) { GEM_BUG_ON(!obj->mm.quirked); __i915_gem_object_unpin_pages(obj); @@ -4558,6 +4561,20 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data, if (obj->mm.madv != __I915_MADV_PURGED) obj->mm.madv = args->madv; + if (i915_gem_object_has_pages(obj)) { + struct list_head *list; + + spin_lock(&i915->mm.obj_lock); + if (obj->mm.madv != I915_MADV_WILLNEED) + list = &i915->mm.purge_list; + else if (obj->bind_count) + list = &i915->mm.bound_list; + else + list = &i915->mm.unbound_list; + list_move_tail(&obj->mm.link, list); + spin_unlock(&i915->mm.obj_lock); + } + /* if the object is no longer attached, discard its backing storage */ if (obj->mm.madv == I915_MADV_DONTNEED && !i915_gem_object_has_pages(obj)) @@ -4876,9 +4893,18 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj) if (obj->mm.quirked) __i915_gem_object_unpin_pages(obj); - if (discard_backing_storage(obj)) + if (discard_backing_storage(obj)) { + struct drm_i915_private *i915 = to_i915(obj->base.dev); + obj->mm.madv = I915_MADV_DONTNEED; + if (i915_gem_object_has_pages(obj)) { + spin_lock(&i915->mm.obj_lock); + list_move_tail(&obj->mm.link, &i915->mm.purge_list); + spin_unlock(&i915->mm.obj_lock); + } + } + /* * Before we free the object, make sure any pure RCU-only * read-side critical sections are complete, e.g. @@ -5527,6 +5553,7 @@ static void i915_gem_init__mm(struct drm_i915_private *i915) init_llist_head(&i915->mm.free_list); + INIT_LIST_HEAD(&i915->mm.purge_list); INIT_LIST_HEAD(&i915->mm.unbound_list); INIT_LIST_HEAD(&i915->mm.bound_list); INIT_LIST_HEAD(&i915->mm.fence_list); diff --git a/drivers/gpu/drm/i915/i915_gem_shrinker.c b/drivers/gpu/drm/i915/i915_gem_shrinker.c index 5757fb7c4b5a..ea5a6e2d62d2 100644 --- a/drivers/gpu/drm/i915/i915_gem_shrinker.c +++ b/drivers/gpu/drm/i915/i915_gem_shrinker.c @@ -151,6 +151,7 @@ i915_gem_shrink(struct drm_i915_private *i915, struct list_head *list; unsigned int bit; } phases[] = { + { &i915->mm.purge_list, 0 }, { &i915->mm.unbound_list, I915_SHRINK_UNBOUND }, { &i915->mm.bound_list, I915_SHRINK_BOUND }, { NULL, 0 }, @@ -182,8 +183,7 @@ i915_gem_shrink(struct drm_i915_private *i915, * device just to recover a little memory. If absolutely necessary, * we will force the wake during oom-notifier. */ - if ((flags & I915_SHRINK_BOUND) && - !intel_runtime_pm_get_if_in_use(i915)) + if (flags & I915_SHRINK_BOUND && !intel_runtime_pm_get_if_in_use(i915)) flags &= ~I915_SHRINK_BOUND; /* @@ -209,7 +209,7 @@ i915_gem_shrink(struct drm_i915_private *i915, struct list_head still_in_list; struct drm_i915_gem_object *obj; - if ((flags & phase->bit) == 0) + if (phase->bit && (flags & phase->bit) == 0) continue; INIT_LIST_HEAD(&still_in_list); @@ -228,10 +228,6 @@ i915_gem_shrink(struct drm_i915_private *i915, mm.link))) { list_move_tail(&obj->mm.link, &still_in_list); - if (flags & I915_SHRINK_PURGEABLE && - obj->mm.madv != I915_MADV_DONTNEED) - continue; - if (flags & I915_SHRINK_VMAPS && !is_vmalloc_addr(obj->mm.mapping)) continue; @@ -241,6 +237,10 @@ i915_gem_shrink(struct drm_i915_private *i915, i915_gem_object_is_framebuffer(obj))) continue; + if (!(flags & I915_SHRINK_BOUND) && + READ_ONCE(obj->bind_count)) + continue; + if (!can_release_pages(obj)) continue; @@ -325,6 +325,11 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc) count += obj->base.size >> PAGE_SHIFT; num_objects++; } + list_for_each_entry(obj, &i915->mm.purge_list, mm.link) + if (!i915_gem_object_is_active(obj) && can_release_pages(obj)) { + count += obj->base.size >> PAGE_SHIFT; + num_objects++; + } spin_unlock(&i915->mm.obj_lock); /* Update our preferred vmscan batch size for the next pass. @@ -361,14 +366,7 @@ i915_gem_shrinker_scan(struct shrinker *shrinker, struct shrink_control *sc) sc->nr_to_scan, &sc->nr_scanned, I915_SHRINK_BOUND | - I915_SHRINK_UNBOUND | - I915_SHRINK_PURGEABLE); - if (sc->nr_scanned < sc->nr_to_scan) - freed += i915_gem_shrink(i915, - sc->nr_to_scan - sc->nr_scanned, - &sc->nr_scanned, - I915_SHRINK_BOUND | - I915_SHRINK_UNBOUND); + I915_SHRINK_UNBOUND); if (sc->nr_scanned < sc->nr_to_scan && current_is_kswapd()) { intel_runtime_pm_get(i915); freed += i915_gem_shrink(i915, diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c index 9324d476e0a7..96039c4ef434 100644 --- a/drivers/gpu/drm/i915/i915_vma.c +++ b/drivers/gpu/drm/i915/i915_vma.c @@ -624,7 +624,7 @@ i915_vma_remove(struct i915_vma *vma) * no more VMAs exist. */ spin_lock(&i915->mm.obj_lock); - if (--obj->bind_count == 0) + if (--obj->bind_count == 0 && obj->mm.madv == I915_MADV_WILLNEED) list_move_tail(&obj->mm.link, &i915->mm.unbound_list); spin_unlock(&i915->mm.obj_lock);
Currently the purgeable objects, I915_MADV_DONTNEED, as mixed in the normal bound/unbound lists. Every shrinker pass starts with an attempt to purge from this set of unneeded objects, which entails us doing a walk over both lists looking for any candidates. If there are none, and since we are shrinking we can reasonably assume that the lists are full!, this becomes a very slow futile walk. If we separate out the purgeable objects into own list, this search then becomes its own phase that is preferentially handled during shrinking. Instead the cost becomes that we then need to filter the purgeable list if we want to distinguish between bound and unbound objects. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> --- drivers/gpu/drm/i915/i915_drv.h | 13 ++++--- drivers/gpu/drm/i915/i915_gem.c | 49 ++++++++++++++++++------ drivers/gpu/drm/i915/i915_gem_shrinker.c | 28 +++++++------- drivers/gpu/drm/i915/i915_vma.c | 2 +- 4 files changed, 60 insertions(+), 32 deletions(-)