intel: Only call clock_gettime once per unreference_final.
authorEric Anholt <eric@anholt.net>
Tue, 20 Oct 2009 21:19:38 +0000 (14:19 -0700)
committerEric Anholt <eric@anholt.net>
Tue, 20 Oct 2009 21:24:44 +0000 (14:24 -0700)
Notably when freeing a batchbuffer, we often end up freeing many of the
buffers it points at as well.  Avoiding repeated calls brings us a 9% CPU
win for cairo-gl.

[ # ]  backend                         test   min(s) median(s) stddev. count
before:
[  0]       gl            firefox-talos-gfx   58.941   58.966   0.75%    3/3
after:
[  0]       gl            firefox-talos-gfx   54.186   54.195   0.49%    3/3

libdrm/intel/intel_bufmgr_gem.c

index 739c99b..87795f3 100644 (file)
@@ -188,6 +188,8 @@ drm_intel_gem_bo_set_tiling(drm_intel_bo *bo, uint32_t * tiling_mode,
                            uint32_t stride);
 
 static void drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo);
+static void drm_intel_gem_bo_unreference_locked_timed(drm_intel_bo *bo,
+                                                     time_t time);
 
 static void drm_intel_gem_bo_unreference(drm_intel_bo *bo);
 
@@ -708,20 +710,20 @@ drm_intel_gem_cleanup_bo_cache(drm_intel_bufmgr_gem *bufmgr_gem, time_t time)
        }
 }
 
-static void drm_intel_gem_bo_unreference_final(drm_intel_bo *bo)
+static void
+drm_intel_gem_bo_unreference_final(drm_intel_bo *bo, time_t time)
 {
        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_intel_gem_bo_bucket *bucket;
        uint32_t tiling_mode;
+       int i;
 
-       if (bo_gem->relocs != NULL) {
-               int i;
-
-               /* Unreference all the target buffers */
-               for (i = 0; i < bo_gem->reloc_count; i++)
-                       drm_intel_gem_bo_unreference_locked(bo_gem->
-                                                           reloc_target_bo[i]);
+       /* Unreference all the target buffers */
+       for (i = 0; i < bo_gem->reloc_count; i++) {
+               drm_intel_gem_bo_unreference_locked_timed(bo_gem->
+                                                         reloc_target_bo[i],
+                                                         time);
        }
 
        DBG("bo_unreference final: %d (%s)\n",
@@ -732,10 +734,7 @@ static void drm_intel_gem_bo_unreference_final(drm_intel_bo *bo)
        tiling_mode = I915_TILING_NONE;
        if (bufmgr_gem->bo_reuse && bo_gem->reusable && bucket != NULL &&
            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->free_time = time;
 
                bo_gem->name = NULL;
                bo_gem->validate_index = -1;
@@ -745,7 +744,7 @@ static void drm_intel_gem_bo_unreference_final(drm_intel_bo *bo)
 
                drm_intel_gem_bo_madvise(bufmgr_gem, bo_gem,
                                         I915_MADV_DONTNEED);
-               drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time.tv_sec);
+               drm_intel_gem_cleanup_bo_cache(bufmgr_gem, time);
        } else {
                drm_intel_gem_bo_free(bo);
        }
@@ -756,8 +755,22 @@ static void drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo)
        drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
 
        assert(atomic_read(&bo_gem->refcount) > 0);
+       if (atomic_dec_and_test(&bo_gem->refcount)) {
+               struct timespec time;
+
+               clock_gettime(CLOCK_MONOTONIC, &time);
+               drm_intel_gem_bo_unreference_final(bo, time.tv_sec);
+       }
+}
+
+static void drm_intel_gem_bo_unreference_locked_timed(drm_intel_bo *bo,
+                                                     time_t time)
+{
+       drm_intel_bo_gem *bo_gem = (drm_intel_bo_gem *) bo;
+
+       assert(atomic_read(&bo_gem->refcount) > 0);
        if (atomic_dec_and_test(&bo_gem->refcount))
-               drm_intel_gem_bo_unreference_final(bo);
+               drm_intel_gem_bo_unreference_final(bo, time);
 }
 
 static void drm_intel_gem_bo_unreference(drm_intel_bo *bo)
@@ -768,8 +781,12 @@ static void drm_intel_gem_bo_unreference(drm_intel_bo *bo)
        if (atomic_dec_and_test(&bo_gem->refcount)) {
                drm_intel_bufmgr_gem *bufmgr_gem =
                    (drm_intel_bufmgr_gem *) bo->bufmgr;
+               struct timespec time;
+
+               clock_gettime(CLOCK_MONOTONIC, &time);
+
                pthread_mutex_lock(&bufmgr_gem->lock);
-               drm_intel_gem_bo_unreference_final(bo);
+               drm_intel_gem_bo_unreference_final(bo, time.tv_sec);
                pthread_mutex_unlock(&bufmgr_gem->lock);
        }
 }