Skip to content

Commit

Permalink
drm/i915: Cache last obj->pages location for i915_gem_object_get_page()
Browse files Browse the repository at this point in the history
The biggest user of i915_gem_object_get_page() is the relocation
processing during execbuffer. Typically userspace passes in a set of
relocations in sorted order. Sadly, we alternate between relocations
increasing from the start of the buffers, and relocations decreasing
from the end. However the majority of consecutive lookups will still be
in the same page. We could cache the start of the last sg chain, however
for most callers, the entire sgl is inside a single chain and so we see
no improve from the extra layer of caching.

v2: Avoid the double increment inside unlikely()

References: https://bugs.freedesktop.org/show_bug.cgi?id=88308
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Cc: John Harrison <John.C.Harrison@Intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
  • Loading branch information
Chris Wilson authored and Daniel Vetter committed Apr 10, 2015
1 parent f9fc42f commit ee28637
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 5 deletions.
31 changes: 26 additions & 5 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -1986,6 +1986,10 @@ struct drm_i915_gem_object {

struct sg_table *pages;
int pages_pin_count;
struct get_page {
struct scatterlist *sg;
int last;
} get_page;

/* prime dma-buf support */
void *dma_buf_vmapping;
Expand Down Expand Up @@ -2656,15 +2660,32 @@ int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
int *needs_clflush);

int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)

static inline int __sg_page_count(struct scatterlist *sg)
{
return sg->length >> PAGE_SHIFT;
}

static inline struct page *
i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
{
struct sg_page_iter sg_iter;
if (WARN_ON(n >= obj->base.size >> PAGE_SHIFT))
return NULL;

for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, n)
return sg_page_iter_page(&sg_iter);
if (n < obj->get_page.last) {
obj->get_page.sg = obj->pages->sgl;
obj->get_page.last = 0;
}

while (obj->get_page.last + __sg_page_count(obj->get_page.sg) <= n) {
obj->get_page.last += __sg_page_count(obj->get_page.sg++);
if (unlikely(sg_is_chain(obj->get_page.sg)))
obj->get_page.sg = sg_chain_ptr(obj->get_page.sg);
}

return NULL;
return nth_page(sg_page(obj->get_page.sg), n - obj->get_page.last);
}

static inline void i915_gem_object_pin_pages(struct drm_i915_gem_object *obj)
{
BUG_ON(obj->pages == NULL);
Expand Down
4 changes: 4 additions & 0 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -2178,6 +2178,10 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
return ret;

list_add_tail(&obj->global_list, &dev_priv->mm.unbound_list);

obj->get_page.sg = obj->pages->sgl;
obj->get_page.last = 0;

return 0;
}

Expand Down

0 comments on commit ee28637

Please sign in to comment.