drm/i915: Use the reloc.handle as an index into the execbuffer array

Using copywinwin10 as an example that is dependent upon emitting a lot
of relocations (2 per operation), we see improvements of:

c2d/gm45: 618000.0/sec to 623000.0/sec.
i3-330m: 748000.0/sec to 789000.0/sec.

(measured relative to a baseline with neither optimisations applied).

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Imre Deak <imre.deak@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
This commit is contained in:
Chris Wilson 2013-01-08 10:53:17 +00:00 committed by Daniel Vetter
parent ed5982e6ce
commit eef90ccb8a
3 changed files with 70 additions and 39 deletions

View file

@ -995,6 +995,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_HAS_EXEC_NO_RELOC: case I915_PARAM_HAS_EXEC_NO_RELOC:
value = 1; value = 1;
break; break;
case I915_PARAM_HAS_EXEC_HANDLE_LUT:
value = 1;
break;
default: default:
DRM_DEBUG_DRIVER("Unknown parameter %d\n", DRM_DEBUG_DRIVER("Unknown parameter %d\n",
param->param); param->param);

View file

@ -36,24 +36,40 @@
struct eb_objects { struct eb_objects {
struct list_head objects; struct list_head objects;
int and; int and;
union {
struct drm_i915_gem_object *lut[0];
struct hlist_head buckets[0]; struct hlist_head buckets[0];
}; };
};
static struct eb_objects * static struct eb_objects *
eb_create(int size) eb_create(struct drm_i915_gem_execbuffer2 *args)
{ {
struct eb_objects *eb; struct eb_objects *eb = NULL;
if (args->flags & I915_EXEC_HANDLE_LUT) {
int size = args->buffer_count;
size *= sizeof(struct drm_i915_gem_object *);
size += sizeof(struct eb_objects);
eb = kmalloc(size, GFP_TEMPORARY | __GFP_NOWARN | __GFP_NORETRY);
}
if (eb == NULL) {
int size = args->buffer_count;
int count = PAGE_SIZE / sizeof(struct hlist_head) / 2; int count = PAGE_SIZE / sizeof(struct hlist_head) / 2;
BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head))); BUILD_BUG_ON(!is_power_of_2(PAGE_SIZE / sizeof(struct hlist_head)));
while (count > size) while (count > 2*size)
count >>= 1; count >>= 1;
eb = kzalloc(count*sizeof(struct hlist_head) + eb = kzalloc(count*sizeof(struct hlist_head) +
sizeof(struct eb_objects), sizeof(struct eb_objects),
GFP_KERNEL); GFP_TEMPORARY);
if (eb == NULL) if (eb == NULL)
return eb; return eb;
eb->and = count - 1; eb->and = count - 1;
} else
eb->and = -args->buffer_count;
INIT_LIST_HEAD(&eb->objects); INIT_LIST_HEAD(&eb->objects);
return eb; return eb;
} }
@ -61,26 +77,20 @@ eb_create(int size)
static void static void
eb_reset(struct eb_objects *eb) eb_reset(struct eb_objects *eb)
{ {
if (eb->and >= 0)
memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head)); memset(eb->buckets, 0, (eb->and+1)*sizeof(struct hlist_head));
} }
static void
eb_add_object(struct eb_objects *eb, struct drm_i915_gem_object *obj)
{
hlist_add_head(&obj->exec_node,
&eb->buckets[obj->exec_handle & eb->and]);
}
static int static int
eb_lookup_objects(struct eb_objects *eb, eb_lookup_objects(struct eb_objects *eb,
struct drm_i915_gem_exec_object2 *exec, struct drm_i915_gem_exec_object2 *exec,
int count, const struct drm_i915_gem_execbuffer2 *args,
struct drm_file *file) struct drm_file *file)
{ {
int i; int i;
spin_lock(&file->table_lock); spin_lock(&file->table_lock);
for (i = 0; i < count; i++) { for (i = 0; i < args->buffer_count; i++) {
struct drm_i915_gem_object *obj; struct drm_i915_gem_object *obj;
obj = to_intel_bo(idr_find(&file->object_idr, exec[i].handle)); obj = to_intel_bo(idr_find(&file->object_idr, exec[i].handle));
@ -101,9 +111,15 @@ eb_lookup_objects(struct eb_objects *eb,
drm_gem_object_reference(&obj->base); drm_gem_object_reference(&obj->base);
list_add_tail(&obj->exec_list, &eb->objects); list_add_tail(&obj->exec_list, &eb->objects);
obj->exec_handle = exec[i].handle;
obj->exec_entry = &exec[i]; obj->exec_entry = &exec[i];
eb_add_object(eb, obj); if (eb->and < 0) {
eb->lut[i] = obj;
} else {
uint32_t handle = args->flags & I915_EXEC_HANDLE_LUT ? i : exec[i].handle;
obj->exec_handle = handle;
hlist_add_head(&obj->exec_node,
&eb->buckets[handle & eb->and]);
}
} }
spin_unlock(&file->table_lock); spin_unlock(&file->table_lock);
@ -113,19 +129,25 @@ eb_lookup_objects(struct eb_objects *eb,
static struct drm_i915_gem_object * static struct drm_i915_gem_object *
eb_get_object(struct eb_objects *eb, unsigned long handle) eb_get_object(struct eb_objects *eb, unsigned long handle)
{ {
if (eb->and < 0) {
if (handle >= -eb->and)
return NULL;
return eb->lut[handle];
} else {
struct hlist_head *head; struct hlist_head *head;
struct hlist_node *node; struct hlist_node *node;
struct drm_i915_gem_object *obj;
head = &eb->buckets[handle & eb->and]; head = &eb->buckets[handle & eb->and];
hlist_for_each(node, head) { hlist_for_each(node, head) {
struct drm_i915_gem_object *obj;
obj = hlist_entry(node, struct drm_i915_gem_object, exec_node); obj = hlist_entry(node, struct drm_i915_gem_object, exec_node);
if (obj->exec_handle == handle) if (obj->exec_handle == handle)
return obj; return obj;
} }
return NULL; return NULL;
} }
}
static void static void
eb_destroy(struct eb_objects *eb) eb_destroy(struct eb_objects *eb)
@ -615,7 +637,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
/* reacquire the objects */ /* reacquire the objects */
eb_reset(eb); eb_reset(eb);
ret = eb_lookup_objects(eb, exec, count, file); ret = eb_lookup_objects(eb, exec, args, file);
if (ret) if (ret)
goto err; goto err;
@ -919,7 +941,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
goto pre_mutex_err; goto pre_mutex_err;
} }
eb = eb_create(args->buffer_count); eb = eb_create(args);
if (eb == NULL) { if (eb == NULL) {
mutex_unlock(&dev->struct_mutex); mutex_unlock(&dev->struct_mutex);
ret = -ENOMEM; ret = -ENOMEM;
@ -927,7 +949,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
} }
/* Look up object handles */ /* Look up object handles */
ret = eb_lookup_objects(eb, exec, args->buffer_count, file); ret = eb_lookup_objects(eb, exec, args, file);
if (ret) if (ret)
goto err; goto err;

View file

@ -309,6 +309,7 @@ typedef struct drm_i915_irq_wait {
#define I915_PARAM_HAS_SECURE_BATCHES 23 #define I915_PARAM_HAS_SECURE_BATCHES 23
#define I915_PARAM_HAS_PINNED_BATCHES 24 #define I915_PARAM_HAS_PINNED_BATCHES 24
#define I915_PARAM_HAS_EXEC_NO_RELOC 25 #define I915_PARAM_HAS_EXEC_NO_RELOC 25
#define I915_PARAM_HAS_EXEC_HANDLE_LUT 26
typedef struct drm_i915_getparam { typedef struct drm_i915_getparam {
int param; int param;
@ -699,7 +700,12 @@ struct drm_i915_gem_execbuffer2 {
*/ */
#define I915_EXEC_NO_RELOC (1<<11) #define I915_EXEC_NO_RELOC (1<<11)
#define __I915_EXEC_UNKNOWN_FLAGS -(I915_EXEC_NO_RELOC<<1) /** Use the reloc.handle as an index into the exec object array rather
* than as the per-file handle.
*/
#define I915_EXEC_HANDLE_LUT (1<<12)
#define __I915_EXEC_UNKNOWN_FLAGS -(I915_EXEC_HANDLE_LUT<<1)
#define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff)
#define i915_execbuffer2_set_context_id(eb2, context) \ #define i915_execbuffer2_set_context_id(eb2, context) \