On Tue, 2015-09-15 at 16:14 +0100, Tvrtko Ursulin wrote:
> On 09/15/2015 09:33 AM, ankitprasad.r.sha...@intel.com wrote:
> > From: Chris Wilson <chris at chris-wilson.co.uk>
> >
> > If we run out of stolen memory when trying to allocate an object, see if
> > we can reap enough purgeable objects to free up enough contiguous free
> > space for the allocation. This is in principle very much like evicting
> > objects to free up enough contiguous space in the vma when binding
> > a new object - and you will be forgiven for thinking that the code looks
> > very similar.
> >
> > At the moment, we do not allow userspace to allocate objects in stolen,
> > so there is neither the memory pressure to trigger stolen eviction nor
> > any purgeable objects inside the stolen arena. However, this will change
> > in the near future, and so better management and defragmentation of
> > stolen memory will become a real issue.
> >
> > v2: Remember to remove the drm_mm_node.
> >
> > v3: Rebased to the latest drm-intel-nightly (Ankit)
> >
> > v4: corrected if-else braces format (Tvrtko/kerneldoc)
> >
> > v5: Rebased to the latest drm-intel-nightly (Ankit)
> > Added a seperate list to maintain purgable objects from stolen memory
> > region (Chris/Daniel)
> >
> > Testcase: igt/gem_stolen
> >
> > Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
> > Signed-off-by: Ankitprasad Sharma <ankitprasad.r.sha...@intel.com>
> > ---
> >   drivers/gpu/drm/i915/i915_debugfs.c    |   4 +-
> >   drivers/gpu/drm/i915/i915_drv.h        |  17 +++-
> >   drivers/gpu/drm/i915/i915_gem.c        |  16 +++
> >   drivers/gpu/drm/i915/i915_gem_stolen.c | 176 
> > ++++++++++++++++++++++++++++-----
> >   drivers/gpu/drm/i915/intel_pm.c        |   4 +-
> >   5 files changed, 187 insertions(+), 30 deletions(-)
> >
> > diff --git a/drivers/gpu/drm/i915/i915_debugfs.c 
> > b/drivers/gpu/drm/i915/i915_debugfs.c
> > index 7a28de5..0db8c47 100644
> > --- a/drivers/gpu/drm/i915/i915_debugfs.c
> > +++ b/drivers/gpu/drm/i915/i915_debugfs.c
> > @@ -179,7 +179,7 @@ describe_obj(struct seq_file *m, struct 
> > drm_i915_gem_object *obj)
> >                     seq_puts(m, ")");
> >     }
> >     if (obj->stolen)
> > -           seq_printf(m, " (stolen: %08llx)", obj->stolen->start);
> > +           seq_printf(m, " (stolen: %08llx)", obj->stolen->base.start);
> >     if (obj->pin_display || obj->fault_mappable) {
> >             char s[3], *t = s;
> >             if (obj->pin_display)
> > @@ -258,7 +258,7 @@ static int obj_rank_by_stolen(void *priv,
> >     struct drm_i915_gem_object *b =
> >             container_of(B, struct drm_i915_gem_object, obj_exec_link);
> >
> > -   return a->stolen->start - b->stolen->start;
> > +   return a->stolen->base.start - b->stolen->base.start;
> >   }
> >
> >   static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
> > diff --git a/drivers/gpu/drm/i915/i915_drv.h 
> > b/drivers/gpu/drm/i915/i915_drv.h
> > index e6ef083..37ee32d 100644
> > --- a/drivers/gpu/drm/i915/i915_drv.h
> > +++ b/drivers/gpu/drm/i915/i915_drv.h
> > @@ -841,6 +841,12 @@ struct i915_ctx_hang_stats {
> >     bool banned;
> >   };
> >
> > +struct i915_stolen_node {
> > +   struct drm_mm_node base;
> > +   struct list_head mm_link;
> > +   struct drm_i915_gem_object *obj;
> > +};
> > +
> >   /* This must match up with the value previously used for execbuf2.rsvd1. 
> > */
> >   #define DEFAULT_CONTEXT_HANDLE 0
> >
> > @@ -1268,6 +1274,13 @@ struct i915_gem_mm {
> >      */
> >     struct list_head unbound_list;
> >
> > +   /**
> > +    * List of stolen objects that have been marked as purgeable and
> > +    * thus available for reaping if we need more space for a new
> > +    * allocation. Ordered by time of marking purgeable.
> > +    */
> > +   struct list_head stolen_list;
> > +
> >     /** Usable portion of the GTT for GEM */
> >     unsigned long stolen_base; /* limited to low memory (32-bit) */
> >
> > @@ -2026,7 +2039,7 @@ struct drm_i915_gem_object {
> >     struct list_head vma_list;
> >
> >     /** Stolen memory for this object, instead of being backed by shmem. */
> > -   struct drm_mm_node *stolen;
> > +   struct i915_stolen_node *stolen;
> >     struct list_head global_list;
> >
> >     struct list_head ring_list[I915_NUM_RINGS];
> > @@ -2034,6 +2047,7 @@ struct drm_i915_gem_object {
> >     struct list_head obj_exec_link;
> >
> >     struct list_head batch_pool_link;
> > +   struct list_head tmp_link;
> >
> >     /**
> >      * This is set if the object is on the active lists (has pending
> > @@ -2150,6 +2164,7 @@ struct drm_i915_gem_object {
> >     };
> >   };
> >   #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
> > +#define I915_BO_IS_ACTIVE(__obj) (__obj->active)
> >
> >   void i915_gem_track_fb(struct drm_i915_gem_object *old,
> >                    struct drm_i915_gem_object *new,
> > diff --git a/drivers/gpu/drm/i915/i915_gem.c 
> > b/drivers/gpu/drm/i915/i915_gem.c
> > index 6568a7f..85025b1 100644
> > --- a/drivers/gpu/drm/i915/i915_gem.c
> > +++ b/drivers/gpu/drm/i915/i915_gem.c
> > @@ -4228,6 +4228,20 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void 
> > *data,
> >     if (obj->madv == I915_MADV_DONTNEED && obj->pages == NULL)
> >             i915_gem_object_truncate(obj);
> >
> > +   if (obj->stolen) {
> > +           switch (obj->madv) {
> > +           case I915_MADV_WILLNEED:
> > +                   list_del_init(&obj->stolen->mm_link);
> > +                   break;
> > +           case I915_MADV_DONTNEED:
> > +                   list_move(&obj->stolen->mm_link,
> > +                             &dev_priv->mm.stolen_list);
> > +                   break;
> > +           default:
> > +                   break;
> > +           }
> > +   }
> > +
> >     args->retained = obj->madv != __I915_MADV_PURGED;
> >
> >   out:
> > @@ -4248,6 +4262,7 @@ void i915_gem_object_init(struct drm_i915_gem_object 
> > *obj,
> >     INIT_LIST_HEAD(&obj->obj_exec_link);
> >     INIT_LIST_HEAD(&obj->vma_list);
> >     INIT_LIST_HEAD(&obj->batch_pool_link);
> > +   INIT_LIST_HEAD(&obj->tmp_link);
> >
> >     obj->ops = ops;
> >
> > @@ -4898,6 +4913,7 @@ i915_gem_load(struct drm_device *dev)
> >     INIT_LIST_HEAD(&dev_priv->context_list);
> >     INIT_LIST_HEAD(&dev_priv->mm.unbound_list);
> >     INIT_LIST_HEAD(&dev_priv->mm.bound_list);
> > +   INIT_LIST_HEAD(&dev_priv->mm.stolen_list);
> >     INIT_LIST_HEAD(&dev_priv->mm.fence_list);
> >     for (i = 0; i < I915_NUM_RINGS; i++)
> >             init_ring_lists(&dev_priv->ring[i]);
> > diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c 
> > b/drivers/gpu/drm/i915/i915_gem_stolen.c
> > index 99f2bce..430e0b0 100644
> > --- a/drivers/gpu/drm/i915/i915_gem_stolen.c
> > +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
> > @@ -52,8 +52,8 @@ int i915_gem_stolen_insert_node(struct drm_i915_private 
> > *dev_priv,
> >             return -ENODEV;
> >
> >     mutex_lock(&dev_priv->mm.stolen_lock);
> > -   ret = drm_mm_insert_node(&dev_priv->mm.stolen, node, size, alignment,
> > -                            DRM_MM_SEARCH_DEFAULT);
> > +   ret = drm_mm_insert_node(&dev_priv->mm.stolen, node,
> > +                            size, alignment, DRM_MM_SEARCH_DEFAULT);
> 
> There is no change here.
> 
> >     mutex_unlock(&dev_priv->mm.stolen_lock);
> >
> >     return ret;
> > @@ -407,18 +407,19 @@ static void i915_gem_object_put_pages_stolen(struct 
> > drm_i915_gem_object *obj)
> >     kfree(obj->pages);
> >   }
> >
> > -
>  >
> >   static void
> >   i915_gem_object_release_stolen(struct drm_i915_gem_object *obj)
> >   {
> >     struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
> >
> >     if (obj->stolen) {
> > -           i915_gem_stolen_remove_node(dev_priv, obj->stolen);
> > +           list_del(&obj->stolen->mm_link);
> > +           i915_gem_stolen_remove_node(dev_priv, &obj->stolen->base);
> >             kfree(obj->stolen);
> >             obj->stolen = NULL;
> >     }
> >   }
> > +
> >   static const struct drm_i915_gem_object_ops i915_gem_object_stolen_ops = {
> >     .get_pages = i915_gem_object_get_pages_stolen,
> >     .put_pages = i915_gem_object_put_pages_stolen,
> > @@ -427,7 +428,7 @@ static const struct drm_i915_gem_object_ops 
> > i915_gem_object_stolen_ops = {
> >
> >   static struct drm_i915_gem_object *
> >   _i915_gem_object_create_stolen(struct drm_device *dev,
> > -                          struct drm_mm_node *stolen)
> > +                          struct i915_stolen_node *stolen)
> >   {
> >     struct drm_i915_gem_object *obj;
> >
> > @@ -435,17 +436,21 @@ _i915_gem_object_create_stolen(struct drm_device *dev,
> >     if (obj == NULL)
> >             return NULL;
> >
> > -   drm_gem_private_object_init(dev, &obj->base, stolen->size);
> > +   drm_gem_private_object_init(dev, &obj->base, stolen->base.size);
> >     i915_gem_object_init(obj, &i915_gem_object_stolen_ops);
> >
> >     obj->pages = i915_pages_create_for_stolen(dev,
> > -                                             stolen->start, stolen->size);
> > +                                             stolen->base.start,
> > +                                             stolen->base.size);
> >     if (obj->pages == NULL)
> >             goto cleanup;
> >
> >     i915_gem_object_pin_pages(obj);
> >     obj->stolen = stolen;
> >
> > +   stolen->obj = obj;
> > +   INIT_LIST_HEAD(&stolen->mm_link);
> > +
> >     obj->base.read_domains = I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT;
> >     obj->cache_level = HAS_LLC(dev) ? I915_CACHE_LLC : I915_CACHE_NONE;
> >
> > @@ -456,36 +461,157 @@ cleanup:
> >     return NULL;
> >   }
> >
> > -struct drm_i915_gem_object *
> > -i915_gem_object_create_stolen(struct drm_device *dev, u64 size)
> > +static bool mark_free(struct drm_i915_gem_object *obj, struct list_head 
> > *unwind)
> > +{
> > +   if (obj->stolen == NULL)
> > +           return false;
> 
> As Chris said, just WARN_ON instead of BUG_ON please.
> 
> > +   if (obj->madv != I915_MADV_DONTNEED)
> > +           return false;
> > +
> > +   if (obj->pin_display)
> > +           return false;
> > +
> > +   if (I915_BO_IS_ACTIVE(obj))
> > +           return false;
> 
> Chris already spotted this will prevent callers from working as they expect.
> 
> > +   list_add(&obj->tmp_link, unwind);
> > +   return drm_mm_scan_add_block(&obj->stolen->base);
> > +}
> > +
> > +static int
> > +stolen_evict(struct drm_i915_private *dev_priv, u64 size)
> >   {
> > -   struct drm_i915_private *dev_priv = dev->dev_private;
> >     struct drm_i915_gem_object *obj;
> > -   struct drm_mm_node *stolen;
> > +   struct list_head unwind, evict;
> > +   struct i915_stolen_node *iter;
> >     int ret;
> >
> > -   if (!drm_mm_initialized(&dev_priv->mm.stolen))
> > -           return NULL;
> > +   drm_mm_init_scan(&dev_priv->mm.stolen, size, 0, 0);
> > +   INIT_LIST_HEAD(&unwind);
> > +
> > +   list_for_each_entry(iter, &dev_priv->mm.stolen_list, mm_link) {
> > +           if (I915_BO_IS_ACTIVE(iter->obj))
> > +                   continue;
> > +
> > +           if (mark_free(iter->obj, &unwind))
> > +                   goto found;
> > +   }
> > +
> > +   list_for_each_entry(iter, &dev_priv->mm.stolen_list, mm_link) {
> > +           if (!I915_BO_IS_ACTIVE(iter->obj))
> > +                   continue;
> > +
> > +           if (mark_free(iter->obj, &unwind))
> > +                   goto found;
> > +   }
>  > +
> > +found:
> > +   INIT_LIST_HEAD(&evict);
> > +   while (!list_empty(&unwind)) {
> > +           obj = list_first_entry(&unwind,
> > +                                  struct drm_i915_gem_object,
> > +                                  tmp_link);
> > +           list_del_init(&obj->tmp_link);
> > +
> > +           if (drm_mm_scan_remove_block(&obj->stolen->base)) {
> > +                   list_add(&obj->tmp_link, &evict);
> > +                   drm_gem_object_reference(&obj->base);
> > +           }
> 
> In what circumstances can drm_mm_scan_remove_block fail?
It works some thing like this:
If there are 10 purgable nodes in the unwind list and 4 of them are
positioned in a way to reap enough contiguous space for the new object
(not necessarily purging all nodes will give us the amount of space we
need), then for the remaining 6 nodes drm_mm_scan_remove_block will
fail, while the rest will be removed to make space for the new object.

Thanks,
Ankit

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/intel-gfx

Reply via email to