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:
parent
d8fba39f32
commit
b29bbd29c1
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user