[Intel-gfx] [PATCH 2/2] drm/i915: Report all objects with allocated pages to the shrinker
Matthew Auld
matthew.william.auld at gmail.com
Thu May 30 16:10:16 UTC 2019
On Tue, 28 May 2019 at 20:50, 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.
>
> 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 | 22 --------
> 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 ++++--
> 8 files changed, 41 insertions(+), 119 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 f064876f1214..1fccb1de5851 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);
> }
>
> /**
> @@ -240,7 +219,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_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);
> obj->bind_count++;
> spin_unlock(&dev_priv->mm.obj_lock);
>
> diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
> index e415d7ef90f2..214dbd698d8e 100644
> --- a/drivers/gpu/drm/i915/i915_debugfs.c
> +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> @@ -271,7 +271,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
> unsigned long total, count, n;
> int ret;
>
> - total = READ_ONCE(dev_priv->mm.object_count);
> + total = READ_ONCE(dev_priv->mm.shrink_count);
> objects = kvmalloc_array(total, sizeof(*objects), GFP_KERNEL);
> if (!objects)
> return -ENOMEM;
> @@ -460,9 +460,9 @@ static int i915_gem_object_info(struct seq_file *m, void *data)
> char buf[80];
> int ret;
>
> - seq_printf(m, "%u objects, %llu bytes\n",
> - dev_priv->mm.object_count,
> - dev_priv->mm.object_memory);
> + seq_printf(m, "%u shrinkable objects, %llu bytes\n",
> + dev_priv->mm.shrink_count,
> + dev_priv->mm.shrink_memory);
>
> size = count = 0;
> mapped_size = mapped_count = 0;
> @@ -552,55 +552,6 @@ static int i915_gem_object_info(struct seq_file *m, void *data)
> return 0;
> }
>
> -static int i915_gem_gtt_info(struct seq_file *m, void *data)
> -{
> - struct drm_info_node *node = m->private;
> - struct drm_i915_private *dev_priv = node_to_i915(node);
> - struct drm_device *dev = &dev_priv->drm;
> - struct drm_i915_gem_object **objects;
> - struct drm_i915_gem_object *obj;
> - u64 total_obj_size, total_gtt_size;
> - unsigned long nobject, n;
> - int count, ret;
> -
> - nobject = READ_ONCE(dev_priv->mm.object_count);
> - objects = kvmalloc_array(nobject, sizeof(*objects), GFP_KERNEL);
> - if (!objects)
> - return -ENOMEM;
> -
> - ret = mutex_lock_interruptible(&dev->struct_mutex);
> - if (ret)
> - return ret;
> -
> - count = 0;
> - spin_lock(&dev_priv->mm.obj_lock);
> - list_for_each_entry(obj, &dev_priv->mm.bound_list, mm.link) {
> - objects[count++] = obj;
> - if (count == nobject)
> - break;
> - }
> - spin_unlock(&dev_priv->mm.obj_lock);
> -
> - total_obj_size = total_gtt_size = 0;
> - for (n = 0; n < count; n++) {
> - obj = objects[n];
> -
> - seq_puts(m, " ");
> - describe_obj(m, obj);
> - seq_putc(m, '\n');
> - total_obj_size += obj->base.size;
> - total_gtt_size += i915_gem_obj_total_ggtt_size(obj);
> - }
> -
> - mutex_unlock(&dev->struct_mutex);
> -
> - seq_printf(m, "Total %d objects, %llu bytes, %llu GTT size\n",
> - count, total_obj_size, total_gtt_size);
> - kvfree(objects);
> -
> - return 0;
> -}
> -
> static int i915_gem_batch_pool_info(struct seq_file *m, void *data)
> {
> struct drm_i915_private *dev_priv = node_to_i915(m->private);
> @@ -4584,7 +4535,6 @@ static const struct file_operations i915_fifo_underrun_reset_ops = {
> static const struct drm_info_list i915_debugfs_list[] = {
> {"i915_capabilities", i915_capabilities, 0},
> {"i915_gem_objects", i915_gem_object_info, 0},
> - {"i915_gem_gtt", i915_gem_gtt_info, 0},
> {"i915_gem_stolen", i915_gem_stolen_list_info },
> {"i915_gem_fence_regs", i915_gem_fence_regs_info, 0},
> {"i915_gem_interrupt", i915_interrupt_info, 0},
> diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
> index fb2e89133e78..770c54b87de6 100644
> --- a/drivers/gpu/drm/i915/i915_drv.h
> +++ b/drivers/gpu/drm/i915/i915_drv.h
> @@ -926,10 +926,9 @@ struct i915_gem_mm {
> /** Bit 6 swizzling required for Y tiling */
> u32 bit_6_swizzle_y;
>
> - /* accounting, useful for userland debugging */
> - spinlock_t object_stat_lock;
> - u64 object_memory;
> - u32 object_count;
> + /* shrinker accounting, also useful for userland debugging */
> + u64 shrink_memory;
> + u32 shrink_count;
Colour me confused. I can't see where we set these? Or is my brain fried?
> };
>
> #define I915_IDLE_ENGINES_TIMEOUT (200) /* in ms */
> diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
> index d98ccbbde53c..0a5049aec144 100644
> --- a/drivers/gpu/drm/i915/i915_gem.c
> +++ b/drivers/gpu/drm/i915/i915_gem.c
> @@ -1137,15 +1137,17 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
> 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 (i915_gem_object_is_shrinkable(obj)) {
> + 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 */
> @@ -1750,7 +1752,6 @@ i915_gem_load_init_fences(struct drm_i915_private *dev_priv)
>
> static void i915_gem_init__mm(struct drm_i915_private *i915)
> {
> - spin_lock_init(&i915->mm.object_stat_lock);
> spin_lock_init(&i915->mm.obj_lock);
> spin_lock_init(&i915->mm.free_lock);
>
> @@ -1800,7 +1801,7 @@ void i915_gem_cleanup_early(struct drm_i915_private *dev_priv)
> i915_gem_drain_freed_objects(dev_priv);
> GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list));
> GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count));
> - WARN_ON(dev_priv->mm.object_count);
> + WARN_ON(dev_priv->mm.shrink_count);
>
> cleanup_srcu_struct(&dev_priv->gpu_error.reset_backoff_srcu);
>
> diff --git a/drivers/gpu/drm/i915/i915_vma.c b/drivers/gpu/drm/i915/i915_vma.c
> index f640caec4bae..b7fb7d216f77 100644
> --- a/drivers/gpu/drm/i915/i915_vma.c
> +++ b/drivers/gpu/drm/i915/i915_vma.c
> @@ -110,7 +110,8 @@ static void __i915_vma_retire(struct i915_active *ref)
> * so that we don't steal from recently used but inactive objects
> * (unless we are forced to ofc!)
> */
> - obj_bump_mru(obj);
> + if (i915_gem_object_is_shrinkable(obj))
> + obj_bump_mru(obj);
>
> i915_gem_object_put(obj); /* and drop the active reference */
> }
> @@ -677,11 +678,14 @@ i915_vma_insert(struct i915_vma *vma, u64 size, u64 alignment, u64 flags)
> struct drm_i915_gem_object *obj = vma->obj;
>
> spin_lock(&dev_priv->mm.obj_lock);
> - list_move_tail(&obj->mm.link, &dev_priv->mm.bound_list);
> - obj->bind_count++;
> - spin_unlock(&dev_priv->mm.obj_lock);
>
> + if (i915_gem_object_is_shrinkable(obj))
> + list_move_tail(&obj->mm.link, &dev_priv->mm.bound_list);
> +
> + obj->bind_count++;
> assert_bind_count(obj);
> +
> + spin_unlock(&dev_priv->mm.obj_lock);
> }
>
> return 0;
> @@ -717,9 +721,13 @@ i915_vma_remove(struct i915_vma *vma)
> struct drm_i915_gem_object *obj = vma->obj;
>
> spin_lock(&i915->mm.obj_lock);
> +
> + GEM_BUG_ON(obj->bind_count == 0);
> if (--obj->bind_count == 0 &&
> + i915_gem_object_is_shrinkable(obj) &&
> obj->mm.madv == I915_MADV_WILLNEED)
> list_move_tail(&obj->mm.link, &i915->mm.unbound_list);
> +
> spin_unlock(&i915->mm.obj_lock);
>
> /*
> --
> 2.20.1
>
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
More information about the Intel-gfx
mailing list