On Mon, 2014-04-07 at 20:01 +0000, Rodrigo Vivi wrote:
> From: Chris Wilson <ch...@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.
> 
> Signed-off-by: Chris Wilson <ch...@chris-wilson.co.uk>
> Cc: "Gupta, Sourab" <sourab.gu...@intel.com>
> Cc: "Goel, Akash" <akash.g...@intel.com>
> Signed-off-by: Rodrigo Vivi <rodrigo.v...@gmail.com>
> ---
>  drivers/gpu/drm/i915/i915_gem_stolen.c | 119 
> ++++++++++++++++++++++++++++++---
>  1 file changed, 108 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c 
> b/drivers/gpu/drm/i915/i915_gem_stolen.c
> index 62ef55b..1fc1986 100644
> --- a/drivers/gpu/drm/i915/i915_gem_stolen.c
> +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
> @@ -329,18 +329,25 @@ cleanup:
>       return NULL;
>  }
>  
> -struct drm_i915_gem_object *
> -i915_gem_object_create_stolen(struct drm_device *dev, u32 size)
> +static bool mark_free(struct drm_i915_gem_object *obj, struct list_head 
> *unwind)
> +{
> +     if (obj->stolen == NULL)
> +             return false;
> +
> +     if (obj->madv != I915_MADV_DONTNEED)
> +             return false;
> +
> +     list_add(&obj->obj_exec_link, unwind);
> +     return drm_mm_scan_add_block(obj->stolen);
> +}
> +
> +static struct drm_mm_node *stolen_alloc(struct drm_i915_private *dev_priv, 
> u32 size)
>  {
> -     struct drm_i915_private *dev_priv = dev->dev_private;
> -     struct drm_i915_gem_object *obj;
>       struct drm_mm_node *stolen;
> +     struct drm_i915_gem_object *obj;
> +     struct list_head unwind, evict;
>       int ret;
>  
> -     if (!drm_mm_initialized(&dev_priv->mm.stolen))
> -             return NULL;
> -
> -     DRM_DEBUG_KMS("creating stolen object: size=%x\n", size);
>       if (size == 0)
>               return NULL;
>  
> @@ -350,11 +357,101 @@ i915_gem_object_create_stolen(struct drm_device *dev, 
> u32 size)
>  
>       ret = drm_mm_insert_node(&dev_priv->mm.stolen, stolen, size,
>                                4096, DRM_MM_SEARCH_DEFAULT);
> -     if (ret) {
> -             kfree(stolen);
> -             return NULL;
> +     if (ret == 0)
> +             return stolen;
> +
> +     /* No more stolen memory available, or too fragmented.
> +      * Try evicting purgeable objects and search again.
> +      */
> +
> +     drm_mm_init_scan(&dev_priv->mm.stolen, size, 4096, 0);
> +     INIT_LIST_HEAD(&unwind);
> +
> +     list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list)
> +             if (mark_free(obj, &unwind))
> +                     goto found;
> +
> +     list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
> +             if (mark_free(obj, &unwind))
> +                     goto found;
> +
> +found:
> +     INIT_LIST_HEAD(&evict);
> +     while (!list_empty(&unwind)) {
> +             obj = list_first_entry(&unwind,
> +                                    struct drm_i915_gem_object,
> +                                    obj_exec_link);
> +             list_del_init(&obj->obj_exec_link);
> +
> +             if (drm_mm_scan_remove_block(obj->stolen)) {
> +                     list_add(&obj->obj_exec_link, &evict);
> +                     drm_gem_object_reference(&obj->base);
> +             }
>       }
>  
> +     ret = 0;
> +     while (!list_empty(&evict)) {
> +             obj = list_first_entry(&evict,
> +                                    struct drm_i915_gem_object,
> +                                    obj_exec_link);
> +             list_del_init(&obj->obj_exec_link);
> +
> +             if (ret == 0) {
> +                     struct i915_vma *vma, *vma_next;
> +
> +                     list_for_each_entry_safe(vma, vma_next,
> +                                              &obj->vma_list,
> +                                              vma_link)
> +                             if (i915_vma_unbind(vma))
> +                                     break;
> +
> +                     /* Stolen pins its pages to prevent the
> +                      * normal shrinker from processing stolen
> +                      * objects.
> +                      */
> +                     i915_gem_object_unpin_pages(obj);
> +
> +                     ret = i915_gem_object_put_pages(obj);
> +                     if (ret == 0) {
> +                             obj->madv = __I915_MADV_PURGED;
> +
> +                             kfree(obj->stolen);
> +                             obj->stolen = NULL;
> +                     } else
> +                             i915_gem_object_pin_pages(obj);
> +             }
> +
> +             drm_gem_object_unreference(&obj->base);
> +     }
> +
> +     if (ret == 0)
> +             ret = drm_mm_insert_node(&dev_priv->mm.stolen, stolen, size,
> +                                      4096, DRM_MM_SEARCH_DEFAULT);
> +     if (ret == 0)
> +             return stolen;
> +
> +     kfree(stolen);
> +     return NULL;
> +}
> +
> +struct drm_i915_gem_object *
> +i915_gem_object_create_stolen(struct drm_device *dev, u32 size)
> +{
> +     struct drm_i915_private *dev_priv = dev->dev_private;
> +     struct drm_i915_gem_object *obj;
> +     struct drm_mm_node *stolen;
> +
> +     lockdep_assert_held(&dev->struct_mutex);
> +
> +     if (!drm_mm_initialized(&dev_priv->mm.stolen))
> +             return NULL;
> +
> +     DRM_DEBUG_KMS("creating stolen object: size=%x\n", size);
> +
> +     stolen = stolen_alloc(dev_priv, size);
> +     if (stolen == NULL)
> +             return NULL;
> +
>       obj = _i915_gem_object_create_stolen(dev, stolen);
>       if (obj)
>               return obj;

Hi Rodrigo,
In this patch, while freeing the purgeable stolen object, the memory
node also has to be freed, so as to make space for new object. We need
to call drm_mm_remove_node while freeing obj.

The below modification patch was floated earlier for this purpose:
http://lists.freedesktop.org/archives/intel-gfx/2014-March/041282.html

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

Reply via email to