diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2012-09-12 16:22:49 +0100 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2012-09-12 16:24:25 +0100 |
commit | 6069e78238ca57e3433d528680fe04766a1e5307 (patch) | |
tree | cb5f62a54eed680785124241fa4c60a030e4c64a | |
parent | 1e2a03ad19664e846ece4110e53d26babb5a2159 (diff) |
sna: Keep a very small, short-lived cache of large buffers
As we now regularly retire and so discard the temporary large buffers,
we find them in short supply and ourselves wasting lots of time creating
and destroying the transient buffers.
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
-rw-r--r-- | src/sna/kgem.c | 73 | ||||
-rw-r--r-- | src/sna/kgem.h | 1 |
2 files changed, 64 insertions, 10 deletions
diff --git a/src/sna/kgem.c b/src/sna/kgem.c index d675ebb8..f68b0546 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -858,6 +858,7 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, int gen) list_init(&kgem->active_buffers); list_init(&kgem->flushing); list_init(&kgem->large); + list_init(&kgem->large_inactive); list_init(&kgem->snoop); for (i = 0; i < ARRAY_SIZE(kgem->inactive); i++) list_init(&kgem->inactive[i]); @@ -1287,8 +1288,10 @@ inline static void kgem_bo_move_to_inactive(struct kgem *kgem, assert(!bo->needs_flush); assert(list_is_empty(&bo->vma)); + kgem->need_expire = true; + if (bucket(bo) >= NUM_CACHE_BUCKETS) { - kgem_bo_free(kgem, bo); + list_move(&bo->list, &kgem->large_inactive); return; } @@ -1306,8 +1309,6 @@ inline static void kgem_bo_move_to_inactive(struct kgem *kgem, kgem->vma[type].count++; } } - - kgem->need_expire = true; } inline static void kgem_bo_remove_from_inactive(struct kgem *kgem, @@ -2411,6 +2412,13 @@ bool kgem_expire_cache(struct kgem *kgem) free(rq); } + while (!list_is_empty(&kgem->large_inactive)) { + kgem_bo_free(kgem, + list_first_entry(&kgem->large_inactive, + struct kgem_bo, list)); + + } + expire = 0; list_for_each_entry(bo, &kgem->snoop, list) { if (bo->delta) { @@ -3095,9 +3103,9 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, __FUNCTION__, size, bucket)); if (flags & CREATE_INACTIVE) - goto create; + goto large_inactive; - tiled_height = kgem_aligned_height(kgem, height, I915_TILING_Y); + tiled_height = kgem_aligned_height(kgem, height, tiling); untiled_pitch = kgem_untiled_pitch(kgem, width, bpp, flags); list_for_each_entry(bo, &kgem->large, list) { @@ -3105,18 +3113,28 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, assert(bo->refcnt == 0); assert(bo->reusable); - if (bo->tiling) { + if (kgem->gen < 40) { if (bo->pitch < pitch) { DBG(("tiled and pitch too small: tiling=%d, (want %d), pitch=%d, need %d\n", bo->tiling, tiling, bo->pitch, pitch)); continue; } - } else - bo->pitch = untiled_pitch; - if (bo->pitch * tiled_height > bytes(bo)) - continue; + if (bo->pitch * tiled_height > bytes(bo)) + continue; + } else { + if (num_pages(bo) < size) + continue; + + if (bo->pitch != pitch || bo->tiling != tiling) { + if (gem_set_tiling(kgem->fd, bo->handle, + tiling, pitch) != tiling) + continue; + + bo->pitch = pitch; + } + } kgem_bo_remove_from_active(kgem, bo); @@ -3129,6 +3147,39 @@ struct kgem_bo *kgem_create_2d(struct kgem *kgem, return bo; } +large_inactive: + list_for_each_entry(bo, &kgem->large_inactive, list) { + assert(bo->refcnt == 0); + assert(bo->reusable); + + if (size > num_pages(bo)) + continue; + + if (bo->tiling != tiling || + (tiling != I915_TILING_NONE && bo->pitch != pitch)) { + if (tiling != gem_set_tiling(kgem->fd, + bo->handle, + tiling, pitch)) + continue; + } + + if (bo->purged && !kgem_bo_clear_purgeable(kgem, bo)) { + kgem_bo_free(kgem, bo); + break; + } + + list_del(&bo->list); + + bo->unique_id = kgem_get_unique_id(kgem); + bo->pitch = pitch; + bo->delta = 0; + DBG((" 1:from large inactive: pitch=%d, tiling=%d, handle=%d, id=%d\n", + bo->pitch, bo->tiling, bo->handle, bo->unique_id)); + assert(bo->pitch*kgem_aligned_height(kgem, height, bo->tiling) <= kgem_bo_size(bo)); + bo->refcnt = 1; + return bo; + } + goto create; } @@ -3407,6 +3458,8 @@ search_inactive: } create: + if (bucket >= NUM_CACHE_BUCKETS) + size = ALIGN(size, 1024); handle = gem_create(kgem->fd, size); if (handle == 0) return NULL; diff --git a/src/sna/kgem.h b/src/sna/kgem.h index fb8be3d0..073635f9 100644 --- a/src/sna/kgem.h +++ b/src/sna/kgem.h @@ -123,6 +123,7 @@ struct kgem { struct list flushing; struct list large; + struct list large_inactive; struct list active[NUM_CACHE_BUCKETS][3]; struct list inactive[NUM_CACHE_BUCKETS]; struct list snoop; |