This adds some debug code to track what kinds of buffer objects are in use
and in the re-use cache.

Signed-off-by: Keith Packard <kei...@keithp.com>
---
 libdrm/intel/intel_bufmgr_gem.c |  175 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 175 insertions(+), 0 deletions(-)

diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c
index 9ba377b..4d1f7d1 100644
--- a/libdrm/intel/intel_bufmgr_gem.c
+++ b/libdrm/intel/intel_bufmgr_gem.c
@@ -101,6 +101,8 @@ typedef struct _drm_intel_bufmgr_gem {
     uint64_t gtt_size;
 } drm_intel_bufmgr_gem;
 
+#define DEBUG_LEAK 1
+
 struct _drm_intel_bo_gem {
     drm_intel_bo bo;
 
@@ -146,6 +148,9 @@ struct _drm_intel_bo_gem {
     /** free list */
     drm_intel_bo_gem *next;
 
+#if DEBUG_LEAK
+    drm_intel_bo_gem *leak_prev, *leak_next;
+#endif
     /**
      * Boolean of whether this BO and its children have been included in
      * the current drm_intel_bufmgr_check_aperture_space() total.
@@ -168,6 +173,167 @@ struct _drm_intel_bo_gem {
     int reloc_tree_size;
 };
 
+#if DEBUG_LEAK
+static drm_intel_bo_gem *leak_head;
+int drm_intel_bo_inuse;
+int drm_intel_bo_alloc_count, drm_intel_bo_free_count;
+static drm_intel_bufmgr_gem *leak_mgr;
+
+static void
+leak_insert(drm_intel_bo_gem *bo)
+{
+    drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bo->bo.bufmgr;
+    assert(bo->leak_prev == NULL);
+    assert(bo->leak_next == NULL);
+    
+    pthread_mutex_lock(&bufmgr_gem->lock);
+    bo->leak_prev = NULL;
+    if (leak_head)
+       leak_head->leak_prev = bo;
+    bo->leak_next = leak_head;
+    leak_head = bo;
+    drm_intel_bo_inuse++;
+    drm_intel_bo_alloc_count++;
+    leak_mgr = bufmgr_gem;
+    pthread_mutex_unlock(&bufmgr_gem->lock);
+}
+
+static void
+leak_remove_locked(drm_intel_bo_gem *bo)
+{
+    drm_intel_bo_gem   **next;
+    
+    if (bo->leak_prev == NULL) {
+       assert(leak_head == bo);
+       next = &leak_head;
+    } else {
+       assert(bo->leak_prev != NULL);
+       assert(bo->leak_prev->leak_next == bo);
+       next = &bo->leak_prev->leak_next;
+    }
+    *next = bo->leak_next;
+
+    if (bo->leak_next != NULL) {
+       assert(bo->leak_next->leak_prev == bo);
+       bo->leak_next->leak_prev = bo->leak_prev;
+    }
+    bo->leak_next = bo->leak_prev = NULL;
+    drm_intel_bo_inuse--;
+    drm_intel_bo_free_count++;
+}
+
+struct bo_count {
+    const char *name;
+    int                count;
+    int                bytes;
+    int                mapped_count;
+    int                mapped_bytes;
+};
+
+#define MAX_COUNTS  1024
+
+static void
+bo_count_add(struct bo_count bo_counts[MAX_COUNTS], 
+            drm_intel_bo_gem *bo)
+{
+    int        i;
+
+    for (i = 0; i < MAX_COUNTS; i++) {
+       if (bo_counts[i].name == NULL) {
+           bo_counts[i].name = bo->name;
+           break;
+       }
+       if (bo_counts[i].name == bo->name ||
+           strcmp(bo_counts[i].name, bo->name) == 0)
+           break;
+    }
+    if (i == MAX_COUNTS)
+       return;
+    bo_counts[i].count++;
+    bo_counts[i].bytes += bo->bo.size;
+    if (bo->mapped) {
+       bo_counts[i].mapped_count++;
+       bo_counts[i].mapped_bytes += bo->bo.size;
+    }
+}
+
+static void
+bo_count_reset(struct bo_count bo_counts[MAX_COUNTS])
+{
+    memset(bo_counts, 0, MAX_COUNTS * sizeof (struct bo_count));
+}
+
+static int bo_count_compar(const void *av, const void *bv)
+{
+    const struct bo_count *a = av;
+    const struct bo_count *b = bv;
+    int        v;
+
+    v = b->count - a->count;
+    if (v == 0)
+       v = b->bytes - a->bytes;
+    return v;
+}
+
+static void
+bo_count_dump(struct bo_count bo_counts[MAX_COUNTS])
+{
+    int        ncount, i;
+
+    for (i = 0; i < MAX_COUNTS; i++)
+       if (bo_counts[i].name == NULL)
+           break;
+    ncount = i;
+    qsort(bo_counts, ncount, sizeof(struct bo_count), bo_count_compar);
+    for (i = 0; i < ncount; i++)
+       fprintf(stderr, "\t%-25.25s %8d (%10d bytes) alloc %8d (%10d bytes) 
map\n",
+               bo_counts[i].name,
+               bo_counts[i].count, bo_counts[i].bytes,
+               bo_counts[i].mapped_count, bo_counts[i].mapped_bytes);
+}
+
+void
+drm_intel_bo_count(void);
+
+void
+drm_intel_bo_count(void)
+{
+    struct bo_count bo_inuse[MAX_COUNTS];
+    struct bo_count bo_idle[MAX_COUNTS];
+    drm_intel_bo_gem *bo;
+    char bucket_name[DRM_INTEL_GEM_BO_BUCKETS][64];
+    int        b;
+    int num_idle = 0;
+    
+    fprintf(stderr, "%s: %10d in use %10d alloc %10d free\n",
+           __func__, drm_intel_bo_inuse, drm_intel_bo_alloc_count, 
drm_intel_bo_free_count);
+    bo_count_reset(bo_inuse);
+    for (bo = leak_head; bo; bo = bo->leak_next)
+       bo_count_add(bo_inuse, bo);
+    bo_count_dump(bo_inuse);
+
+    if (leak_mgr) {
+       bo_count_reset(bo_idle);
+
+       for (b = 0; b < DRM_INTEL_GEM_BO_BUCKETS; b++) {
+           num_idle += leak_mgr->cache_bucket[b].num_entries;
+           sprintf(bucket_name[b], "bucket %d", (1 << b) * 4096);
+           for (bo = leak_mgr->cache_bucket[b].head; bo; bo = bo->next) {
+               assert(bo->name == NULL);
+               bo->name = bucket_name[b];
+               bo_count_add(bo_idle, bo);
+               bo->name = NULL;
+           }
+       }
+       fprintf (stderr, "%s: %d idle\n", __func__, num_idle);
+       bo_count_dump(bo_idle);
+    }
+}
+#else
+#define leak_insert(bo)
+#define leak_remove_locked(bo)
+#endif
+
 static void drm_intel_gem_bo_reference_locked(drm_intel_bo *bo);
 
 static unsigned int
@@ -397,6 +563,9 @@ drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr, const char 
*name,
     DBG("bo_create: buf %d (%s) %ldb\n",
        bo_gem->gem_handle, bo_gem->name, size);
 
+    
+    leak_insert(bo_gem);
+
     return &bo_gem->bo;
 }
 
@@ -504,6 +673,7 @@ drm_intel_gem_bo_unreference_locked(drm_intel_bo *bo)
     if (--bo_gem->refcount == 0) {
        struct drm_intel_gem_bo_bucket *bucket;
 
+       leak_remove_locked(bo_gem);
        if (bo_gem->relocs != NULL) {
            int i;
 
@@ -582,9 +752,14 @@ drm_intel_gem_bo_map(drm_intel_bo *bo, int write_enable)
            mmap_arg.size = bo->size;
            ret = ioctl(bufmgr_gem->fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg);
            if (ret != 0) {
+               static int been_here;
                fprintf(stderr, "%s:%d: Error mapping buffer %d (%s): %s .\n",
                        __FILE__, __LINE__,
                        bo_gem->gem_handle, bo_gem->name, strerror(errno));
+               if (!been_here) {
+                   been_here = 1;
+                   drm_intel_bo_count();
+               }
                pthread_mutex_unlock(&bufmgr_gem->lock);
                return ret;
            }
-- 
1.5.6.5


------------------------------------------------------------------------------
SF.Net email is Sponsored by MIX09, March 18-20, 2009 in Las Vegas, Nevada.
The future of the web can't happen without you.  Join us at MIX09 to help
pave the way to the Next Web now. Learn more and register at
http://ad.doubleclick.net/clk;208669438;13503038;i?http://2009.visitmix.com/
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to