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.
This commit is contained in:
oga 2009-11-22 20:16:03 +00:00
parent d8fba39f32
commit b29bbd29c1

View File

@ -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;
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;
}
}
/* 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;
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;
}