summaryrefslogtreecommitdiff
authorEric Anholt <eric@anholt.net>2009-07-10 00:49:46 (GMT)
committer Eric Anholt <eric@anholt.net>2009-07-10 03:17:53 (GMT)
commit3f3c5be6f908272199ccf53f108b1124bfe0a00e (patch) (side-by-side diff)
tree757799c548970a7b263c2113f27723c4e671b61c
parent80179df5f85a2fd39b2544f1b7aae61102800f0f (diff)
downloaddrm-3f3c5be6f908272199ccf53f108b1124bfe0a00e.zip
drm-3f3c5be6f908272199ccf53f108b1124bfe0a00e.tar.gz
intel: Free buffers in the BO cache that haven't been reused in a while.
The goal of the BO cache is to keep buffers on hand for fast continuous use, as in every frame of a game or every batchbuffer of the X Server. Keeping older buffers on hand not only doesn't serve this purpose, it may hurt performance by resulting in disk cache getting kicked out, or even driving the system to swap. Bug #20766.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--libdrm/intel/intel_bufmgr_gem.c34
1 files changed, 33 insertions, 1 deletions
diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c
index 70d0c85..737ceae 100644
--- a/libdrm/intel/intel_bufmgr_gem.c
+++ b/libdrm/intel/intel_bufmgr_gem.c
@@ -139,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 */
@@ -220,7 +222,6 @@ drm_intel_gem_bo_bucket_for_size(drm_intel_bufmgr_gem *bufmgr_gem,
return NULL;
}
-
static void drm_intel_gem_dump_validation_list(drm_intel_bufmgr_gem *bufmgr_gem)
{
int i, j;
@@ -533,6 +534,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)
{
@@ -567,6 +592,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;
@@ -575,6 +605,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);
}