Add debug helper for finding leaks in GrMemoryPool.h
authorBrian Salomon <bsalomon@google.com>
Tue, 28 Mar 2017 20:51:02 +0000 (16:51 -0400)
committerSkia Commit-Bot <skia-commit-bot@chromium.org>
Tue, 28 Mar 2017 22:51:34 +0000 (22:51 +0000)
Change-Id: I1d11769f9e99606af5e7752b3a6d055a5bf6a48d
Reviewed-on: https://skia-review.googlesource.com/10289
Commit-Queue: Brian Salomon <bsalomon@google.com>
Reviewed-by: Robert Phillips <robertphillips@google.com>
src/gpu/GrMemoryPool.cpp
src/gpu/GrMemoryPool.h

index 91cecbd4c2b5fda718ee6f53d3e36d51912142ec..32a361297223546117d91988e6a2c42b610b95b8 100644 (file)
@@ -6,8 +6,10 @@
  */
 
 #include "GrMemoryPool.h"
-
 #include "SkMalloc.h"
+#ifdef SK_DEBUG
+#include "SkAtomics.h"
+#endif
 
 #ifdef SK_DEBUG
     #define VALIDATE this->validate()
@@ -36,6 +38,19 @@ GrMemoryPool::GrMemoryPool(size_t preallocSize, size_t minAllocSize) {
 
 GrMemoryPool::~GrMemoryPool() {
     VALIDATE;
+#ifdef SK_DEBUG
+    int i = 0;
+    int n = fAllocatedIDs.count();
+    fAllocatedIDs.foreach([&i, n] (int32_t id) {
+        if (++i == 1) {
+            SkDebugf("Leaked IDs (in no particular order): %d", id);
+        } else if (i < 11) {
+            SkDebugf(", %d%s", id, (n == i ? "\n" : ""));
+        } else if (i == 11) {
+            SkDebugf(", ...\n");
+        }
+    });
+#endif
     SkASSERT(0 == fAllocationCnt);
     SkASSERT(fHead == fTail);
     SkASSERT(0 == fHead->fLiveCount);
@@ -66,13 +81,15 @@ void* GrMemoryPool::allocate(size_t size) {
     // so that we can decrement the live count on delete in constant time.
     AllocHeader* allocData = reinterpret_cast<AllocHeader*>(ptr);
     SkDEBUGCODE(allocData->fSentinal = kAssignedMarker);
+    SkDEBUGCODE(allocData->fID = []{static int32_t gID; return sk_atomic_inc(&gID) + 1;}());
+    // You can set a breakpoint here when a leaked ID is allocated to see the stack frame.
+    SkDEBUGCODE(fAllocatedIDs.add(allocData->fID));
     allocData->fHeader = fTail;
     ptr += kPerAllocPad;
     fTail->fPrevPtr = fTail->fCurrPtr;
     fTail->fCurrPtr += size;
     fTail->fFreeSize -= size;
     fTail->fLiveCount += 1;
-
     SkDEBUGCODE(++fAllocationCnt);
     VALIDATE;
     return reinterpret_cast<void*>(ptr);
@@ -84,6 +101,7 @@ void GrMemoryPool::release(void* p) {
     AllocHeader* allocData = reinterpret_cast<AllocHeader*>(ptr);
     SkASSERT(kAssignedMarker == allocData->fSentinal);
     SkDEBUGCODE(allocData->fSentinal = kFreedMarker);
+    SkDEBUGCODE(fAllocatedIDs.remove(allocData->fID));
     BlockHeader* block = allocData->fHeader;
     SkASSERT(kAssignedMarker == block->fBlockSentinal);
     if (1 == block->fLiveCount) {
@@ -181,6 +199,7 @@ void GrMemoryPool::validate() {
         prev = block;
     } while ((block = block->fNext));
     SkASSERT(allocCount == fAllocationCnt);
+    SkASSERT(fAllocationCnt == fAllocatedIDs.count());
     SkASSERT(prev == fTail);
     SkASSERT(fAllocBlockCnt != 0 || fSize == 0);
 #endif
index e483aab6f2177ce333e7ad41c25de788e095bb75..26a763430ff013becafd30c49009630f46690d23 100644 (file)
@@ -9,6 +9,9 @@
 #define GrMemoryPool_DEFINED
 
 #include "GrTypes.h"
+#ifdef SK_DEBUG
+#include "SkTHash.h"
+#endif
 
 /**
  * Allocates memory in blocks and parcels out space in the blocks for allocation
@@ -94,6 +97,7 @@ private:
     struct AllocHeader {
 #ifdef SK_DEBUG
         uint32_t fSentinal;      ///< known value to check for memory stomping (e.g., (CD)*)
+        int32_t fID;             ///< ID that can be used to track down leaks by clients.
 #endif
         BlockHeader* fHeader;    ///< pointer back to the block header in which an alloc resides
     };
@@ -105,6 +109,7 @@ private:
 #ifdef SK_DEBUG
     int                               fAllocationCnt;
     int                               fAllocBlockCnt;
+    SkTHashSet<int32_t>               fAllocatedIDs;
 #endif
 
 protected: