diff options
author | Owain Ainsworth <oga@cvs.openbsd.org> | 2009-11-22 20:16:04 +0000 |
---|---|---|
committer | Owain Ainsworth <oga@cvs.openbsd.org> | 2009-11-22 20:16:04 +0000 |
commit | 5295c289d0d5329bd13d77a4353c23233d5a08a2 (patch) | |
tree | 688acb907bd3782a45fb19aed4a3567f98c0be7f | |
parent | db3a2889a6637209cf620a4f6bf3383520264520 (diff) |
Some improvements from upstream for the GEM buffer object cache to stop the
cache growing stupidly big (like it used to).
ok matthieu@ ages ago.
-rw-r--r-- | lib/libdrm/intel/intel_bufmgr_gem.c | 116 |
1 files changed, 75 insertions, 41 deletions
diff --git a/lib/libdrm/intel/intel_bufmgr_gem.c b/lib/libdrm/intel/intel_bufmgr_gem.c index 7d66f7788..ea8f21c44 100644 --- a/lib/libdrm/intel/intel_bufmgr_gem.c +++ b/lib/libdrm/intel/intel_bufmgr_gem.c @@ -78,12 +78,13 @@ struct drm_intel_gem_bo_bucket { */ int max_entries; int num_entries; + unsigned long size; }; -/* Arbitrarily chosen, 16 means that the maximum size we'll cache for reuse - * is 1 << 16 pages, or 256MB. +/* Only cache objects up to 64MB. Bigger than that, and the rounding of the + * size makes many operation fail that wouldn't otherwise. */ -#define DRM_INTEL_GEM_BO_BUCKETS 16 +#define DRM_INTEL_GEM_BO_BUCKETS 14 typedef struct _drm_intel_bufmgr_gem { drm_intel_bufmgr bufmgr; @@ -138,6 +139,8 @@ struct _drm_intel_bo_gem { uint32_t tiling_mode; uint32_t swizzle_mode; + time_t free_time; + /** Array passed to the DRM containing relocation information. */ struct drm_i915_gem_relocation_entry *relocs; /** Array of bos corresponding to relocs[i].target_handle */ @@ -173,6 +176,10 @@ struct _drm_intel_bo_gem { * relocations. */ int reloc_tree_fences; + +#ifndef INTEL_ALWAYS_UNMAP + void *saved_virtual; +#endif }; static void drm_intel_gem_bo_reference_locked(drm_intel_bo *bo); @@ -194,42 +201,22 @@ drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t *tiling_mode, static void drm_intel_gem_bo_unreference(drm_intel_bo *bo); -static int -logbase2(int n) -{ - int i = 1; - int log2 = 0; - - while (n > i) { - i *= 2; - log2++; - } - - return log2; -} - static struct drm_intel_gem_bo_bucket * drm_intel_gem_bo_bucket_for_size(drm_intel_bufmgr_gem *bufmgr_gem, unsigned long size) { int i; - /* We only do buckets in power of two increments */ - if ((size & (size - 1)) != 0) - return NULL; - - /* We should only see sizes rounded to pages. */ - assert((size % 4096) == 0); - - /* We always allocate in units of pages */ - i = ffs(size / 4096) - 1; - if (i >= DRM_INTEL_GEM_BO_BUCKETS) - return NULL; + for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) { + struct drm_intel_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i]; + if (bucket->size >= size) { + return bucket; + } + } - return &bufmgr_gem->cache_bucket[i]; + return NULL; } - static void drm_intel_gem_dump_validation_list(drm_intel_bufmgr_gem *bufmgr_gem) { int i, j; @@ -336,10 +323,7 @@ drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr, const char *name, unsigned long bo_size; /* Round the allocated size up to a power of two number of pages. */ - bo_size = 1 << logbase2(size); - if (bo_size < page_size) - bo_size = page_size; - bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, bo_size); + bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, size); /* If we don't have caching at this size, don't actually round the * allocation up. @@ -348,6 +332,8 @@ drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr, const char *name, bo_size = size; if (bo_size < page_size) bo_size = page_size; + } else { + bo_size = bucket->size; } pthread_mutex_lock(&bufmgr_gem->lock); @@ -526,6 +512,10 @@ drm_intel_gem_bo_free(drm_intel_bo *bo) if (bo->virtual) munmap (bo->virtual, bo_gem->bo.size); +#ifndef INTEL_ALWAYS_UNMAP + else if (bo_gem->saved_virtual) + munmap(bo_gem->saved_virtual, bo->size); +#endif /* Close this object */ memset(&close, 0, sizeof(close)); @@ -539,6 +529,30 @@ drm_intel_gem_bo_free(drm_intel_bo *bo) free(bo); } +/** Frees all cached buffers significantly older than @time. */ +static void +drm_intel_gem_cleanup_bo_cache(drm_intel_bufmgr_gem *bufmgr_gem, time_t time) +{ + int i; + + for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) { + struct drm_intel_gem_bo_bucket *bucket = &bufmgr_gem->cache_bucket[i]; + + while (!DRMLISTEMPTY(&bucket->head)) { + drm_intel_bo_gem *bo_gem; + + bo_gem = DRMLISTENTRY(drm_intel_bo_gem, bucket->head.next, head); + if (time - bo_gem->free_time <= 1) + break; + + DRMLISTDEL(&bo_gem->head); + bucket->num_entries--; + + drm_intel_gem_bo_free(&bo_gem->bo); + } + } +} + static void drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo) { @@ -573,6 +587,11 @@ drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo) bucket->num_entries < bucket->max_entries)) && drm_intel_gem_bo_set_tiling(bo, &tiling_mode, 0) == 0) { + struct timespec time; + + clock_gettime(CLOCK_MONOTONIC, &time); + bo_gem->free_time = time.tv_sec; + bo_gem->name = NULL; bo_gem->validate_index = -1; bo_gem->relocs = NULL; @@ -581,6 +600,8 @@ drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo) DRMLISTADDTAIL(&bo_gem->head, &bucket->head); bucket->num_entries++; + + drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time.tv_sec); } else { drm_intel_gem_bo_free(bo); } @@ -612,7 +633,9 @@ drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) int ret; pthread_mutex_lock(&bufmgr_gem->lock); - +#ifndef INTEL_ALWAYS_UNMAP + if (bo_gem->saved_virtual == NULL) { +#endif assert(bo->virtual == NULL); struct drm_i915_gem_mmap mmap_arg; @@ -635,6 +658,11 @@ drm_intel_gem_bo_map_gtt(drm_intel_bo *bo) DBG("bo_map: %d (%s) -> %p\n", bo_gem->gem_handle, bo_gem->name, bo->virtual); +#ifndef INTEL_ALWAYS_UNMAP + bo_gem->saved_virtual = bo->virtual; + } else + bo->virtual = bo_gem->saved_virtual; +#endif pthread_mutex_unlock(&bufmgr_gem->lock); @@ -646,19 +674,22 @@ drm_intel_gem_bo_unmap_gtt(drm_intel_bo *bo) { drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bo->bufmgr; drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *)bo; - struct drm_i915_gem_sw_finish sw_finish; - int ret = 0; if (bo == NULL) return 0; assert(bo->virtual != NULL); pthread_mutex_lock(&bufmgr_gem->lock); - munmap(bo->virtual, bo_gem->bo.size); +#ifdef INTEL_ALWAYS_UNMAP + munmap(bo->virtual, bo->size); +#else + assert(bo_gem->saved_virtual != NULL && + bo_gem->saved_virtual == bo->virtual); +#endif bo->virtual = NULL; pthread_mutex_unlock(&bufmgr_gem->lock); - return ret; + return 0; } static int @@ -723,7 +754,7 @@ drm_intel_gem_bo_get_subdata (drm_intel_bo *bo, unsigned long offset, static void drm_intel_gem_bo_wait_rendering(drm_intel_bo *bo) { - return drm_intel_gem_bo_start_gtt_access(bo, 0); + drm_intel_gem_bo_start_gtt_access(bo, 0); } /** @@ -1254,6 +1285,7 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size) struct drm_i915_gem_get_aperture aperture; drm_i915_getparam_t gp; int ret, i; + unsigned long size; bufmgr_gem = calloc(1, sizeof(*bufmgr_gem)); bufmgr_gem->fd = fd; @@ -1323,8 +1355,10 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size) bufmgr_gem->bufmgr.debug = 0; bufmgr_gem->bufmgr.check_aperture_space = drm_intel_gem_check_aperture_space; /* Initialize the linked lists for BO reuse cache. */ - for (i = 0; i < DRM_INTEL_GEM_BO_BUCKETS; i++) + for (i = 0, size = 4096; i < DRM_INTEL_GEM_BO_BUCKETS; i++, size *= 2) { DRMINITLISTHEAD(&bufmgr_gem->cache_bucket[i].head); + bufmgr_gem->cache_bucket[i].size = size; + } return &bufmgr_gem->bufmgr; } |