[Intel-gfx] [PATCH 2/2] drm/i915: Report all objects with allocated pages to the shrinker
Matthew Auld
matthew.william.auld at gmail.com
Fri May 31 20:06:46 UTC 2019
On Thu, 30 May 2019 at 21:35, Chris Wilson <chris at chris-wilson.co.uk> wrote:
>
> Currently, we try to report to the shrinker the precise number of
> objects (pages) that are available to be reaped at this moment. This
> requires searching all objects with allocated pages to see if they
> fulfill the search criteria, and this count is performed quite
> frequently. (The shrinker tries to free ~128 pages on each invocation,
> before which we count all the objects; counting takes longer than
> unbinding the objects!) If we take the pragmatic view that with
> sufficient desire, all objects are eventually reapable (they become
> inactive, or no longer used as framebuffer etc), we can simply return
> the count of pinned pages maintained during get_pages/put_pages rather
> than walk the lists every time.
>
> The downside is that we may (slightly) over-report the number of
> objects/pages we could shrink and so penalize ourselves by shrinking
> more than required. This is mitigated by keeping the order in which we
> shrink objects such that we avoid penalizing active and frequently used
> objects, and if memory is so tight that we need to free them we would
> need to anyway.
>
> v2: Only expose shrinkable objects to the shrinker; a small reduction in
> not considering stolen and foreign objects.
> v3: Restore the tracking from a "backup" copy from before the gem/ split
>
> Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: Joonas Lahtinen <joonas.lahtinen at linux.intel.com>
> Cc: Matthew Auld <matthew.auld at intel.com>
> ---
> drivers/gpu/drm/i915/gem/i915_gem_domain.c | 3 +-
> drivers/gpu/drm/i915/gem/i915_gem_object.c | 33 +++--------
> drivers/gpu/drm/i915/gem/i915_gem_pages.c | 20 +++++--
> drivers/gpu/drm/i915/gem/i915_gem_shrinker.c | 28 ++--------
> drivers/gpu/drm/i915/gem/i915_gem_stolen.c | 3 +-
> drivers/gpu/drm/i915/i915_debugfs.c | 58 ++------------------
> drivers/gpu/drm/i915/i915_drv.h | 7 +--
> drivers/gpu/drm/i915/i915_gem.c | 23 ++++----
> drivers/gpu/drm/i915/i915_vma.c | 16 ++++--
> 9 files changed, 63 insertions(+), 128 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_domain.c b/drivers/gpu/drm/i915/gem/i915_gem_domain.c
> index 52b73e90c9f4..e5deae62681f 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_domain.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_domain.c
> @@ -475,7 +475,8 @@ static void i915_gem_object_bump_inactive_ggtt(struct drm_i915_gem_object *obj)
> }
> mutex_unlock(&i915->ggtt.vm.mutex);
>
> - if (obj->mm.madv == I915_MADV_WILLNEED) {
> + if (i915_gem_object_is_shrinkable(obj) &&
> + obj->mm.madv == I915_MADV_WILLNEED) {
> struct list_head *list;
>
> spin_lock(&i915->mm.obj_lock);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_object.c b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> index a42763e4dd5f..49c959c11b2a 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_object.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_object.c
> @@ -44,25 +44,6 @@ void i915_gem_object_free(struct drm_i915_gem_object *obj)
> return kmem_cache_free(global.slab_objects, obj);
> }
>
> -/* some bookkeeping */
> -static void i915_gem_info_add_obj(struct drm_i915_private *i915,
> - u64 size)
> -{
> - spin_lock(&i915->mm.object_stat_lock);
> - i915->mm.object_count++;
> - i915->mm.object_memory += size;
> - spin_unlock(&i915->mm.object_stat_lock);
> -}
> -
> -static void i915_gem_info_remove_obj(struct drm_i915_private *i915,
> - u64 size)
> -{
> - spin_lock(&i915->mm.object_stat_lock);
> - i915->mm.object_count--;
> - i915->mm.object_memory -= size;
> - spin_unlock(&i915->mm.object_stat_lock);
> -}
> -
> static void
> frontbuffer_retire(struct i915_active_request *active,
> struct i915_request *request)
> @@ -98,8 +79,6 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
> obj->mm.madv = I915_MADV_WILLNEED;
> INIT_RADIX_TREE(&obj->mm.get_page.radix, GFP_KERNEL | __GFP_NOWARN);
> mutex_init(&obj->mm.get_page.lock);
> -
> - i915_gem_info_add_obj(to_i915(obj->base.dev), obj->base.size);
> }
>
> /**
> @@ -163,11 +142,14 @@ void i915_gem_close_object(struct drm_gem_object *gem, struct drm_file *file)
>
> static bool discard_backing_storage(struct drm_i915_gem_object *obj)
> {
> - /* If we are the last user of the backing storage (be it shmemfs
> + /*
> + * If we are the last user of the backing storage (be it shmemfs
> * pages or stolen etc), we know that the pages are going to be
> * immediately released. In this case, we can then skip copying
> * back the contents from the GPU.
> */
> + if (!i915_gem_object_is_shrinkable(obj))
> + return false;
>
> if (obj->mm.madv != I915_MADV_WILLNEED)
> return false;
> @@ -208,13 +190,15 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
> GEM_BUG_ON(!list_empty(&obj->vma.list));
> GEM_BUG_ON(!RB_EMPTY_ROOT(&obj->vma.tree));
>
> - /* This serializes freeing with the shrinker. Since the free
> + /*
> + * This serializes freeing with the shrinker. Since the free
> * is delayed, first by RCU then by the workqueue, we want the
> * shrinker to be able to free pages of unreferenced objects,
> * or else we may oom whilst there are plenty of deferred
> * freed objects.
> */
> - if (i915_gem_object_has_pages(obj)) {
> + if (i915_gem_object_has_pages(obj) &&
> + i915_gem_object_is_shrinkable(obj)) {
> spin_lock(&i915->mm.obj_lock);
> list_del_init(&obj->mm.link);
> spin_unlock(&i915->mm.obj_lock);
> @@ -240,7 +224,6 @@ static void __i915_gem_free_objects(struct drm_i915_private *i915,
>
> reservation_object_fini(&obj->__builtin_resv);
> drm_gem_object_release(&obj->base);
> - i915_gem_info_remove_obj(i915, obj->base.size);
>
> bitmap_free(obj->bit_17);
> i915_gem_object_free(obj);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_pages.c b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
> index e53860147f21..7e64fd6bc19b 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_pages.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_pages.c
> @@ -56,9 +56,13 @@ void __i915_gem_object_set_pages(struct drm_i915_gem_object *obj,
> }
> GEM_BUG_ON(!HAS_PAGE_SIZES(i915, obj->mm.page_sizes.sg));
>
> - spin_lock(&i915->mm.obj_lock);
> - list_add(&obj->mm.link, &i915->mm.unbound_list);
> - spin_unlock(&i915->mm.obj_lock);
> + if (i915_gem_object_is_shrinkable(obj)) {
> + spin_lock(&i915->mm.obj_lock);
> + i915->mm.shrink_count++;
> + i915->mm.shrink_memory += obj->base.size;
> + list_add(&obj->mm.link, &i915->mm.unbound_list);
> + spin_unlock(&i915->mm.obj_lock);
> + }
> }
>
> int ____i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
> @@ -146,9 +150,13 @@ __i915_gem_object_unset_pages(struct drm_i915_gem_object *obj)
> if (IS_ERR_OR_NULL(pages))
> return pages;
>
> - spin_lock(&i915->mm.obj_lock);
> - list_del(&obj->mm.link);
> - spin_unlock(&i915->mm.obj_lock);
> + if (i915_gem_object_is_shrinkable(obj)) {
> + spin_lock(&i915->mm.obj_lock);
> + list_del(&obj->mm.link);
> + i915->mm.shrink_count--;
> + i915->mm.shrink_memory -= obj->base.size;
> + spin_unlock(&i915->mm.obj_lock);
> + }
>
> if (obj->mm.mapping) {
> void *ptr;
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
> index 6a93e326abf3..d71e630c6fb8 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_shrinker.c
> @@ -309,30 +309,14 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
> {
> struct drm_i915_private *i915 =
> container_of(shrinker, struct drm_i915_private, mm.shrinker);
> - struct drm_i915_gem_object *obj;
> - unsigned long num_objects = 0;
> - unsigned long count = 0;
> + unsigned long num_objects;
> + unsigned long count;
>
> - spin_lock(&i915->mm.obj_lock);
> - list_for_each_entry(obj, &i915->mm.unbound_list, mm.link)
> - if (can_release_pages(obj)) {
> - count += obj->base.size >> PAGE_SHIFT;
> - num_objects++;
> - }
> + count = READ_ONCE(i915->mm.shrink_memory) >> PAGE_SHIFT;
> + num_objects = READ_ONCE(i915->mm.shrink_count);
>
> - list_for_each_entry(obj, &i915->mm.bound_list, mm.link)
> - if (!i915_gem_object_is_active(obj) && can_release_pages(obj)) {
> - 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.
> + /*
> + * Update our preferred vmscan batch size for the next pass.
> * Our rough guess for an effective batch size is roughly 2
> * available GEM objects worth of pages. That is we don't want
> * the shrinker to fire, until it is worth the cost of freeing an
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
> index 9080a736663a..8b3a23bff7f6 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_stolen.c
> @@ -690,7 +690,8 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_i915_private *dev_priv
> mutex_unlock(&ggtt->vm.mutex);
>
> spin_lock(&dev_priv->mm.obj_lock);
> - list_move_tail(&obj->mm.link, &dev_priv->mm.bound_list);
> + if (i915_gem_object_is_shrinkable(obj))
> + list_move_tail(&obj->mm.link, &dev_priv->mm.bound_list);
Always false, no, or maybe just future thinking?
Anyway,
Reviewed-by: Matthew Auld <matthew.auld at intel.com>
More information about the Intel-gfx
mailing list