summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOwain Ainsworth <oga@cvs.openbsd.org>2009-11-22 20:16:04 +0000
committerOwain Ainsworth <oga@cvs.openbsd.org>2009-11-22 20:16:04 +0000
commit5295c289d0d5329bd13d77a4353c23233d5a08a2 (patch)
tree688acb907bd3782a45fb19aed4a3567f98c0be7f
parentdb3a2889a6637209cf620a4f6bf3383520264520 (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.c116
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;
}