vc4: Track the number of BOs allocated and their size.
authorEric Anholt <eric@anholt.net>
Thu, 18 Jun 2015 05:56:15 +0000 (22:56 -0700)
committerEric Anholt <eric@anholt.net>
Thu, 18 Jun 2015 06:53:49 +0000 (23:53 -0700)
This is useful for BO leak debugging.

src/gallium/drivers/vc4/vc4_bufmgr.c
src/gallium/drivers/vc4/vc4_screen.h

index 69a7584e14b6eb6ef74c0a2514a9c7e25e7e1309..eef7e9dc16fcc62ae3e2ab9767ed6119a82d5b39 100644 (file)
 #include "vc4_context.h"
 #include "vc4_screen.h"
 
+static bool dump_stats = false;
+
+static void
+vc4_bo_dump_stats(struct vc4_screen *screen)
+{
+        struct vc4_bo_cache *cache = &screen->bo_cache;
+
+        fprintf(stderr, "  BOs allocated:   %d\n", screen->bo_count);
+        fprintf(stderr, "  BOs size:        %dkb\n", screen->bo_size / 102);
+        fprintf(stderr, "  BOs cached:      %d\n", cache->bo_count);
+        fprintf(stderr, "  BOs cached size: %dkb\n", cache->bo_size / 102);
+
+        if (!list_empty(&cache->time_list)) {
+                struct vc4_bo *first = LIST_ENTRY(struct vc4_bo,
+                                                  cache->time_list.next,
+                                                  time_list);
+                struct vc4_bo *last = LIST_ENTRY(struct vc4_bo,
+                                                  cache->time_list.prev,
+                                                  time_list);
+
+                fprintf(stderr, "  oldest cache time: %ld\n",
+                        (long)first->free_time);
+                fprintf(stderr, "  newest cache time: %ld\n",
+                        (long)last->free_time);
+
+                struct timespec time;
+                clock_gettime(CLOCK_MONOTONIC, &time);
+                fprintf(stderr, "  now:               %ld\n",
+                        time.tv_sec);
+        }
+}
+
+static void
+vc4_bo_remove_from_cache(struct vc4_bo_cache *cache, struct vc4_bo *bo)
+{
+        list_del(&bo->time_list);
+        list_del(&bo->size_list);
+        cache->bo_count--;
+        cache->bo_size -= bo->size;
+}
+
 static struct vc4_bo *
 vc4_bo_from_cache(struct vc4_screen *screen, uint32_t size, const char *name)
 {
@@ -60,8 +101,7 @@ vc4_bo_from_cache(struct vc4_screen *screen, uint32_t size, const char *name)
                 }
 
                 pipe_reference_init(&bo->reference, 1);
-                list_del(&bo->time_list);
-                list_del(&bo->size_list);
+                vc4_bo_remove_from_cache(cache, bo);
 
                 bo->name = name;
         }
@@ -78,8 +118,14 @@ vc4_bo_alloc(struct vc4_screen *screen, uint32_t size, const char *name)
         size = align(size, 4096);
 
         bo = vc4_bo_from_cache(screen, size, name);
-        if (bo)
+        if (bo) {
+                if (dump_stats) {
+                        fprintf(stderr, "Allocated %s %dkb from cache:\n",
+                                name, size / 1024);
+                        vc4_bo_dump_stats(screen);
+                }
                 return bo;
+        }
 
         bo = CALLOC_STRUCT(vc4_bo);
         if (!bo)
@@ -116,6 +162,13 @@ vc4_bo_alloc(struct vc4_screen *screen, uint32_t size, const char *name)
                 abort();
         }
 
+        screen->bo_count++;
+        screen->bo_size += bo->size;
+        if (dump_stats) {
+                fprintf(stderr, "Allocated %s %dkb:\n", name, size / 1024);
+                vc4_bo_dump_stats(screen);
+        }
+
         return bo;
 }
 
@@ -153,6 +206,17 @@ vc4_bo_free(struct vc4_bo *bo)
         if (ret != 0)
                 fprintf(stderr, "close object %d: %s\n", bo->handle, strerror(errno));
 
+        screen->bo_count--;
+        screen->bo_size -= bo->size;
+
+        if (dump_stats) {
+                fprintf(stderr, "Freed %s%s%dkb:\n",
+                        bo->name ? bo->name : "",
+                        bo->name ? " " : "",
+                        bo->size / 1024);
+                vc4_bo_dump_stats(screen);
+        }
+
         free(bo);
 }
 
@@ -160,18 +224,29 @@ static void
 free_stale_bos(struct vc4_screen *screen, time_t time)
 {
         struct vc4_bo_cache *cache = &screen->bo_cache;
+        bool freed_any = false;
 
         list_for_each_entry_safe(struct vc4_bo, bo, &cache->time_list,
                                  time_list) {
+                if (dump_stats && !freed_any) {
+                        fprintf(stderr, "Freeing stale BOs:\n");
+                        vc4_bo_dump_stats(screen);
+                        freed_any = true;
+                }
+
                 /* If it's more than a second old, free it. */
                 if (time - bo->free_time > 2) {
-                        list_del(&bo->time_list);
-                        list_del(&bo->size_list);
+                        vc4_bo_remove_from_cache(cache, bo);
                         vc4_bo_free(bo);
                 } else {
                         break;
                 }
         }
+
+        if (dump_stats && freed_any) {
+                fprintf(stderr, "Freed stale BOs:\n");
+                vc4_bo_dump_stats(screen);
+        }
 }
 
 void
@@ -214,6 +289,14 @@ vc4_bo_last_unreference_locked_timed(struct vc4_bo *bo, time_t time)
         bo->free_time = time;
         list_addtail(&bo->size_list, &cache->size_list[page_index]);
         list_addtail(&bo->time_list, &cache->time_list);
+        cache->bo_count++;
+        cache->bo_size += bo->size;
+        if (dump_stats) {
+                fprintf(stderr, "Freed %s %dkb to cache:\n",
+                        bo->name, bo->size / 1024);
+                vc4_bo_dump_stats(screen);
+        }
+        bo->name = NULL;
 
         free_stale_bos(screen, time);
 }
@@ -450,8 +533,12 @@ vc4_bufmgr_destroy(struct pipe_screen *pscreen)
 
         list_for_each_entry_safe(struct vc4_bo, bo, &cache->time_list,
                                  time_list) {
-                list_del(&bo->time_list);
-                list_del(&bo->size_list);
+                vc4_bo_remove_from_cache(cache, bo);
                 vc4_bo_free(bo);
         }
+
+        if (dump_stats) {
+                fprintf(stderr, "BO stats after screen destroy:\n");
+                vc4_bo_dump_stats(screen);
+        }
 }
index fb08cc1c7a0201b3464ecd714fe98fecad086ea8..5992e37109380e4590ba140c01451fe315ef5498 100644 (file)
@@ -67,7 +67,13 @@ struct vc4_screen {
                 uint32_t size_list_size;
 
                 pipe_mutex lock;
+
+                uint32_t bo_size;
+                uint32_t bo_count;
         } bo_cache;
+
+        uint32_t bo_size;
+        uint32_t bo_count;
 };
 
 static inline struct vc4_screen *