[Intel-gfx] [RFC 1/2]drm i915: provide ioctl and API to shrink gem object size

Shaohua Li shaohua.li at intel.com
Thu Jun 11 08:45:23 CEST 2009


Most GEM object pages are dirty, because userspace always write something to
an object and then execute GPU ins. This makes i915_gem_object_unbind not able
to free memory, as shmem dirty pages can only be swapped out and then free.
Userspace is caching GEM object, but userspace can tell kernel which object's
content is useless, and kernel can free gem's memory even it's dirty.
The patch provide a new ioctl for this.

In this RFC patch, I just free all clean objects which are in in_active list.
Maybe we could add a new list just and hook the shirk to slab shrinker just
like Chris's patch does.

For the RFC patch, I just use the module paramter interface for easy test
To test, echo 1 > /sys/modules/i915/parameters/do_test
---
 drivers/gpu/drm/i915/i915_dma.c |    1 
 drivers/gpu/drm/i915/i915_drv.h |    6 ++
 drivers/gpu/drm/i915/i915_gem.c |   87 ++++++++++++++++++++++++++++++++++++++--
 include/drm/i915_drm.h          |    5 ++
 4 files changed, 96 insertions(+), 3 deletions(-)

Index: linux/drivers/gpu/drm/i915/i915_dma.c
===================================================================
--- linux.orig/drivers/gpu/drm/i915/i915_dma.c	2009-06-11 14:09:25.000000000 +0800
+++ linux/drivers/gpu/drm/i915/i915_dma.c	2009-06-11 14:09:32.000000000 +0800
@@ -1351,6 +1351,7 @@ struct drm_ioctl_desc i915_ioctls[] = {
 	DRM_IOCTL_DEF(DRM_I915_GEM_GET_TILING, i915_gem_get_tiling, 0),
 	DRM_IOCTL_DEF(DRM_I915_GEM_GET_APERTURE, i915_gem_get_aperture_ioctl, 0),
 	DRM_IOCTL_DEF(DRM_I915_GET_PIPE_FROM_CRTC_ID, intel_get_pipe_from_crtc_id, 0),
+	DRM_IOCTL_DEF(DRM_I915_GEM_OBJ_CLEAN, i915_gem_obj_clean, 0),
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
Index: linux/drivers/gpu/drm/i915/i915_drv.h
===================================================================
--- linux.orig/drivers/gpu/drm/i915/i915_drv.h	2009-06-11 14:09:25.000000000 +0800
+++ linux/drivers/gpu/drm/i915/i915_drv.h	2009-06-11 14:09:32.000000000 +0800
@@ -407,6 +407,9 @@ struct drm_i915_gem_object {
 	 */
 	int dirty;
 
+	/* This is set when userspace is caching the obj, but thought the obj ic clean */
+	int clean;
+
 	/** AGP memory structure for our GTT binding. */
 	DRM_AGP_MEM *agp_mem;
 
@@ -643,6 +646,9 @@ void i915_gem_free_all_phys_object(struc
 int i915_gem_object_get_pages(struct drm_gem_object *obj);
 void i915_gem_object_put_pages(struct drm_gem_object *obj);
 
+int i915_gem_obj_clean(struct drm_device *dev, void *data,
+	struct drm_file *file_priv);
+
 /* i915_gem_tiling.c */
 void i915_gem_detect_bit_6_swizzle(struct drm_device *dev);
 void i915_gem_object_do_bit_17_swizzle(struct drm_gem_object *obj);
Index: linux/drivers/gpu/drm/i915/i915_gem.c
===================================================================
--- linux.orig/drivers/gpu/drm/i915/i915_gem.c	2009-06-11 14:08:55.000000000 +0800
+++ linux/drivers/gpu/drm/i915/i915_gem.c	2009-06-11 14:12:38.000000000 +0800
@@ -966,6 +966,7 @@ i915_gem_pwrite_ioctl(struct drm_device 
 		DRM_INFO("pwrite failed %d\n", ret);
 #endif
 
+	obj_priv->clean = 0;
 	drm_gem_object_unreference(obj);
 
 	return ret;
@@ -1102,6 +1103,7 @@ i915_gem_mmap_ioctl(struct drm_device *d
 		return addr;
 
 	args->addr_ptr = (uint64_t) addr;
+	((struct drm_i915_gem_object *)(obj->driver_private))->clean = 0;
 
 	return 0;
 }
@@ -1164,7 +1166,7 @@ int i915_gem_fault(struct vm_area_struct
 			return VM_FAULT_SIGBUS;
 		}
 	}
-
+	obj_priv->clean = 0;
 	pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
 		page_offset;
 
@@ -1405,15 +1407,30 @@ i915_gem_object_put_pages(struct drm_gem
 
 	if (obj_priv->tiling_mode != I915_TILING_NONE)
 		i915_gem_object_save_bit_17_swizzle(obj);
-
+	if (obj_priv->clean)
+		obj_priv->dirty = 0;
 	for (i = 0; i < page_count; i++)
 		if (obj_priv->pages[i] != NULL) {
 			if (obj_priv->dirty)
 				set_page_dirty(obj_priv->pages[i]);
-			mark_page_accessed(obj_priv->pages[i]);
+			if (!obj_priv->clean)
+				mark_page_accessed(obj_priv->pages[i]);
 			page_cache_release(obj_priv->pages[i]);
 		}
 	obj_priv->dirty = 0;
+	if (obj_priv->clean) {
+		int pages;
+		struct inode *inode;
+		obj_priv->clean = 0;
+		inode = obj->filp->f_path.dentry->d_inode;
+		pages = inode->i_mapping->nrpages;
+		printk("Truncate one mapping before %d pages", pages);
+		mutex_lock(&inode->i_mutex);
+		truncate_inode_pages(obj->filp->f_path.dentry->d_inode->i_mapping, 0);
+		mutex_unlock(&inode->i_mutex);
+		pages = inode->i_mapping->nrpages;
+		printk("after %d pages\n", pages);
+	}
 
 	drm_free_large(obj_priv->pages);
 	obj_priv->pages = NULL;
@@ -1430,6 +1447,7 @@ i915_gem_object_move_to_active(struct dr
 	if (!obj_priv->active) {
 		drm_gem_object_reference(obj);
 		obj_priv->active = 1;
+		obj_priv->clean = 0;
 	}
 	/* Move from whatever list we were on to the tail of execution. */
 	spin_lock(&dev_priv->mm.active_list_lock);
@@ -2405,6 +2423,8 @@ i915_gem_object_bind_to_gtt(struct drm_g
 	atomic_inc(&dev->gtt_count);
 	atomic_add(obj->size, &dev->gtt_memory);
 
+	obj_priv->clean = 0;
+
 	/* Assert that the object is not currently in any GPU domain. As it
 	 * wasn't in the GTT, there shouldn't be any way it could have been in
 	 * a GPU cache
@@ -4352,3 +4372,63 @@ i915_gem_phys_pwrite(struct drm_device *
 	drm_agp_chipset_flush(dev);
 	return 0;
 }
+
+static struct drm_device *saved_device;
+int i915_gem_obj_clean(struct drm_device *dev, void *data,
+		struct drm_file *file_priv)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_gem_obj_clean *args = data;
+	struct drm_gem_object *obj;
+	struct drm_i915_gem_object *obj_priv;
+
+	if (!saved_device)
+		saved_device = dev;
+
+	obj = drm_gem_object_lookup(dev, file_priv, args->handle);
+	if (obj == NULL) {
+		DRM_ERROR("Bad handle in i915_gem_madvise_ioctl(): %d\n",
+			  args->handle);
+		return -EBADF;
+	}
+
+	mutex_lock(&dev->struct_mutex);
+	obj_priv = obj->driver_private;
+	if (obj_priv->pin_count) {
+		drm_gem_object_unreference(obj);
+		mutex_unlock(&dev->struct_mutex);
+
+		DRM_ERROR("Attempted i915_gem_madvise_ioctl() on a pinned object\n");
+		return -EINVAL;
+	}
+
+	obj_priv->clean = 1;
+
+	drm_gem_object_unreference(obj);
+	mutex_unlock(&dev->struct_mutex);
+
+	return 0;
+}
+
+static int i915_gem_shrink_objects(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+	struct drm_i915_gem_object *obj_priv, *next;
+
+	mutex_lock(&dev->struct_mutex);
+	list_for_each_entry_safe(obj_priv, next, &dev_priv->mm.inactive_list, list) {
+		if (obj_priv->pin_count == 0)
+			i915_gem_object_unbind(obj_priv->obj);
+	}
+	mutex_unlock(&dev->struct_mutex);
+	return 0;
+}
+
+static int do_test_call(const char *val, struct kernel_param *kp)
+{
+	printk("Invoke shrinker\n");
+	if (saved_device)
+		i915_gem_shrink_objects(saved_device);
+	return 0;
+}
+module_param_call(do_test, do_test_call, NULL, NULL,0200);
Index: linux/include/drm/i915_drm.h
===================================================================
--- linux.orig/include/drm/i915_drm.h	2009-06-11 14:09:25.000000000 +0800
+++ linux/include/drm/i915_drm.h	2009-06-11 14:09:32.000000000 +0800
@@ -185,6 +185,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_GEM_GET_APERTURE 0x23
 #define DRM_I915_GEM_MMAP_GTT	0x24
 #define DRM_I915_GET_PIPE_FROM_CRTC_ID	0x25
+#define DRM_I915_GEM_OBJ_CLEAN	0x26
 
 #define DRM_IOCTL_I915_INIT		DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH		DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -221,6 +222,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_GET_TILING	DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_GET_TILING, struct drm_i915_gem_get_tiling)
 #define DRM_IOCTL_I915_GEM_GET_APERTURE	DRM_IOR  (DRM_COMMAND_BASE + DRM_I915_GEM_GET_APERTURE, struct drm_i915_gem_get_aperture)
 #define DRM_IOCTL_I915_GET_PIPE_FROM_CRTC_ID DRM_IOWR(DRM_COMMAND_BASE + DRM_I915_GET_PIPE_FROM_CRTC_ID, struct drm_intel_get_pipe_from_crtc_id)
+#define DRM_IOCTL_I915_GEM_MADVISE DRM_IOW(DRM_COMMAND_BASE + DRM_I915_GEM_OBJ_CLEAN, struct drm_i915_gem_obj_clean)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -667,4 +669,7 @@ struct drm_i915_get_pipe_from_crtc_id {
 	__u32 pipe;
 };
 
+struct drm_i915_gem_obj_clean {
+	__u32 handle;
+};
 #endif				/* _I915_DRM_H_ */



More information about the Intel-gfx mailing list