drm/i915: Batch copy_from_user for relocation processing
authorChris Wilson <chris@chris-wilson.co.uk>
Sat, 24 Mar 2012 20:12:53 +0000 (20:12 +0000)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Mon, 26 Mar 2012 07:59:05 +0000 (09:59 +0200)
Originally the code tried to allocate a large enough array to perform
the copy using vmalloc, performance wasn't great and throughput was
improved by processing each individual relocation entry separately.
This too is not as efficient as one would desire. A compromise would be
to allocate a single page, or to allocate a few entries on the stack,
and process the copy in batches. The latter gives simpler code and more
consistent performance due to a lack of heuristic.

x11perf -copywinwin10: n450/pnv i3-330m i5-2520m (cpu)
               before:    249000  785000  1280000 (80%)
                 page:   264000  896000  1280000 (65%)
             on-stack:   264000  902000  1280000 (67%)

v2: Use 512-bytes of stack for batching rather than allocate a page.
v3: Tidy the code slightly with more descriptive variable names

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_gem_execbuffer.c

index 0e051eca36395bbff50c987c491c3aa199fc16a7..1fa01313d89ff06be7cabc137c5d392179b9bc2f 100644 (file)
@@ -405,30 +405,46 @@ static int
 i915_gem_execbuffer_relocate_object(struct drm_i915_gem_object *obj,
                                    struct eb_objects *eb)
 {
+#define N_RELOC(x) ((x) / sizeof(struct drm_i915_gem_relocation_entry))
+       struct drm_i915_gem_relocation_entry stack_reloc[N_RELOC(512)];
        struct drm_i915_gem_relocation_entry __user *user_relocs;
        struct drm_i915_gem_exec_object2 *entry = obj->exec_entry;
-       int i, ret;
+       int remain, ret;
 
        user_relocs = (void __user *)(uintptr_t)entry->relocs_ptr;
-       for (i = 0; i < entry->relocation_count; i++) {
-               struct drm_i915_gem_relocation_entry reloc;
 
-               if (__copy_from_user_inatomic(&reloc,
-                                             user_relocs+i,
-                                             sizeof(reloc)))
+       remain = entry->relocation_count;
+       while (remain) {
+               struct drm_i915_gem_relocation_entry *r = stack_reloc;
+               int count = remain;
+               if (count > ARRAY_SIZE(stack_reloc))
+                       count = ARRAY_SIZE(stack_reloc);
+               remain -= count;
+
+               if (__copy_from_user_inatomic(r, user_relocs, count*sizeof(r[0])))
                        return -EFAULT;
 
-               ret = i915_gem_execbuffer_relocate_entry(obj, eb, &reloc);
-               if (ret)
-                       return ret;
+               do {
+                       u64 offset = r->presumed_offset;
 
-               if (__copy_to_user_inatomic(&user_relocs[i].presumed_offset,
-                                           &reloc.presumed_offset,
-                                           sizeof(reloc.presumed_offset)))
-                       return -EFAULT;
+                       ret = i915_gem_execbuffer_relocate_entry(obj, eb, r);
+                       if (ret)
+                               return ret;
+
+                       if (r->presumed_offset != offset &&
+                           __copy_to_user_inatomic(&user_relocs->presumed_offset,
+                                                   &r->presumed_offset,
+                                                   sizeof(r->presumed_offset))) {
+                               return -EFAULT;
+                       }
+
+                       user_relocs++;
+                       r++;
+               } while (--count);
        }
 
        return 0;
+#undef N_RELOC
 }
 
 static int