private iterator to visit all resource cache entries

BUG=skia:
TBR=

Review URL: https://codereview.chromium.org/1271033002
diff --git a/bench/ImageCacheBench.cpp b/bench/ImageCacheBench.cpp
index 4a068b0..96c64f8 100644
--- a/bench/ImageCacheBench.cpp
+++ b/bench/ImageCacheBench.cpp
@@ -26,6 +26,8 @@
 
     const Key& getKey() const override { return fKey; }
     size_t bytesUsed() const override { return sizeof(fKey) + sizeof(fValue); }
+    const char* getCategory() const override { return "imagecachebench-test"; }
+    SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return NULL; }
 
     static bool Visitor(const SkResourceCache::Rec&, void*) {
         return true;
diff --git a/include/core/SkPixelRef.h b/include/core/SkPixelRef.h
index 2e3e85a..5d1aef7 100644
--- a/include/core/SkPixelRef.h
+++ b/include/core/SkPixelRef.h
@@ -24,6 +24,7 @@
 struct SkIRect;
 
 class GrTexture;
+class SkDiscardableMemory;
 
 /** \class SkPixelRef
 
@@ -262,6 +263,8 @@
         fAddedToCache.store(true);
     }
 
+    virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return NULL; }
+
 protected:
     /**
      *  On success, returns true and fills out the LockRec for the pixels. On
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 0a89b48..c985b1e 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -1473,9 +1473,18 @@
     return true;
 }
 
+#include "SkResourceCache.h"
+#include "SkGlyphCache.h"
 bool SampleWindow::nextSample() {
     fCurrIndex = (fCurrIndex + 1) % fSamples.count();
     this->loadView((*fSamples[fCurrIndex])());
+
+    if (false) {
+        SkResourceCache::TestDumpMemoryStatistics();
+        SkGlyphCache::Dump();
+        SkDebugf("\n");
+    }
+
     return true;
 }
 
diff --git a/src/core/SkBitmapCache.cpp b/src/core/SkBitmapCache.cpp
index 3f1feac..08e3fdc 100644
--- a/src/core/SkBitmapCache.cpp
+++ b/src/core/SkBitmapCache.cpp
@@ -74,6 +74,11 @@
     const Key& getKey() const override { return fKey; }
     size_t bytesUsed() const override { return sizeof(fKey) + fBitmap.getSize(); }
 
+    const char* getCategory() const override { return "bitmap"; }
+    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
+        return fBitmap.pixelRef()->diagnostic_only_getDiscardable();
+    }
+
     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextBitmap) {
         const BitmapRec& rec = static_cast<const BitmapRec&>(baseRec);
         SkBitmap* result = (SkBitmap*)contextBitmap;
@@ -187,6 +192,10 @@
 
     const Key& getKey() const override { return fKey; }
     size_t bytesUsed() const override { return sizeof(fKey) + fMipMap->size(); }
+    const char* getCategory() const override { return "mipmap"; }
+    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
+        return fMipMap->diagnostic_only_getDiscardable();
+    }
 
     static bool Finder(const SkResourceCache::Rec& baseRec, void* contextMip) {
         const MipMapRec& rec = static_cast<const MipMapRec&>(baseRec);
diff --git a/src/core/SkCachedData.h b/src/core/SkCachedData.h
index a861157..d44fbc5 100644
--- a/src/core/SkCachedData.h
+++ b/src/core/SkCachedData.h
@@ -31,6 +31,10 @@
     bool testing_only_isLocked() const { return fIsLocked; }
     bool testing_only_isInCache() const { return fInCache; }
 
+    SkDiscardableMemory* diagnostic_only_getDiscardable() const {
+        return kDiscardableMemory_StorageType == fStorageType ? fStorage.fDM : nullptr;
+    }
+
 protected:
     // called when fData changes. could be NULL.
     virtual void onDataChange(void* oldData, void* newData) {}
diff --git a/src/core/SkGlyphCache.cpp b/src/core/SkGlyphCache.cpp
index 9b0199f..e719c00 100755
--- a/src/core/SkGlyphCache.cpp
+++ b/src/core/SkGlyphCache.cpp
@@ -104,10 +104,14 @@
     return fScalerContext->glyphIDToChar(glyphID);
 }
 
-unsigned SkGlyphCache::getGlyphCount() {
+unsigned SkGlyphCache::getGlyphCount() const {
     return fScalerContext->getGlyphCount();
 }
 
+int SkGlyphCache::countCachedGlyphs() const {
+    return fGlyphMap.count();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 const SkGlyph& SkGlyphCache::getUnicharAdvance(SkUnichar charCode) {
@@ -402,18 +406,39 @@
     get_globals().attachCacheToHead(cache);
 }
 
+static void dump_visitor(const SkGlyphCache& cache, void* context) {
+    int* counter = (int*)context;
+    int index = *counter;
+    *counter += 1;
+
+    const SkScalerContextRec& rec = cache.getScalerContext()->getRec();
+
+    SkDebugf("[%3d] ID %3d, glyphs %3d, size %g, scale %g, skew %g, [%g %g %g %g]\n",
+             index, rec.fFontID, cache.countCachedGlyphs(),
+             rec.fTextSize, rec.fPreScaleX, rec.fPreSkewX,
+             rec.fPost2x2[0][0], rec.fPost2x2[0][1], rec.fPost2x2[1][0], rec.fPost2x2[1][1]);
+}
+
 void SkGlyphCache::Dump() {
+    SkDebugf("GlyphCache [     used    budget ]\n");
+    SkDebugf("    bytes  [ %8zu  %8zu ]\n",
+             SkGraphics::GetFontCacheUsed(), SkGraphics::GetFontCacheLimit());
+    SkDebugf("    count  [ %8zu  %8zu ]\n",
+             SkGraphics::GetFontCacheCountUsed(), SkGraphics::GetFontCacheCountLimit());
+
+    int counter = 0;
+    SkGlyphCache::VisitAll(dump_visitor, &counter);
+}
+
+void SkGlyphCache::VisitAll(Visitor visitor, void* context) {
     SkGlyphCache_Globals& globals = get_globals();
     AutoAcquire           ac(globals.fLock);
     SkGlyphCache*         cache;
 
     globals.validate();
 
-    SkDebugf("SkGlyphCache strikes:%d memory:%d\n",
-             globals.getCacheCountUsed(), (int)globals.getTotalMemoryUsed());
-
     for (cache = globals.internalGetHead(); cache != NULL; cache = cache->fNext) {
-        cache->dump();
+        visitor(*cache, context);
     }
 }
 
diff --git a/src/core/SkGlyphCache.h b/src/core/SkGlyphCache.h
index 1c985bf..dc2aa57 100644
--- a/src/core/SkGlyphCache.h
+++ b/src/core/SkGlyphCache.h
@@ -66,7 +66,10 @@
 
     /** Returns the number of glyphs for this strike.
     */
-    unsigned getGlyphCount();
+    unsigned getGlyphCount() const;
+
+    /** Return the number of glyphs currently cached. */
+    int countCachedGlyphs() const;
 
     /** Return the image associated with the glyph. If it has not been generated this will
         trigger that.
@@ -138,6 +141,9 @@
 
     static void Dump();
 
+    typedef void (*Visitor)(const SkGlyphCache&, void* context);
+    static void VisitAll(Visitor, void* context);
+
 #ifdef SK_DEBUG
     void validate() const;
 #else
diff --git a/src/core/SkMaskCache.cpp b/src/core/SkMaskCache.cpp
index 31a789f..7dc4e4e 100644
--- a/src/core/SkMaskCache.cpp
+++ b/src/core/SkMaskCache.cpp
@@ -53,6 +53,10 @@
 
     const Key& getKey() const override { return fKey; }
     size_t bytesUsed() const override { return sizeof(*this) + fValue.fData->size(); }
+    const char* getCategory() const override { return "rrect-blur"; }
+    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
+        return fValue.fData->diagnostic_only_getDiscardable();
+    }
 
     static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextData) {
         const RRectBlurRec& rec = static_cast<const RRectBlurRec&>(baseRec);
@@ -144,6 +148,10 @@
 
     const Key& getKey() const override { return fKey; }
     size_t bytesUsed() const override { return sizeof(*this) + fValue.fData->size(); }
+    const char* getCategory() const override { return "rects-blur"; }
+    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
+        return fValue.fData->diagnostic_only_getDiscardable();
+    }
 
     static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextData) {
         const RectsBlurRec& rec = static_cast<const RectsBlurRec&>(baseRec);
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
index f8c2ab0..b843339 100644
--- a/src/core/SkPictureShader.cpp
+++ b/src/core/SkPictureShader.cpp
@@ -75,6 +75,8 @@
     size_t bytesUsed() const override {
         return sizeof(fKey) + sizeof(SkShader) + fBitmapBytes;
     }
+    const char* getCategory() const override { return "bitmap-shader"; }
+    SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return nullptr; }
 
     static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextShader) {
         const BitmapShaderRec& rec = static_cast<const BitmapShaderRec&>(baseRec);
diff --git a/src/core/SkResourceCache.cpp b/src/core/SkResourceCache.cpp
index 6c76d35..6febbd2 100644
--- a/src/core/SkResourceCache.cpp
+++ b/src/core/SkResourceCache.cpp
@@ -347,6 +347,18 @@
 #endif
 }
 
+void SkResourceCache::visitAll(Visitor visitor, void* context) {
+    // go backwards, just like purgeAsNeeded, just to make the code similar.
+    // could iterate either direction and still be correct.
+    Rec* rec = fTail;
+    while (rec) {
+        visitor(*rec, context);
+        rec = rec->fPrev;
+    }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
 size_t SkResourceCache::setTotalByteLimit(size_t newLimit) {
     size_t prevLimit = fTotalByteLimit;
     fTotalByteLimit = newLimit;
@@ -608,6 +620,11 @@
     get_cache()->add(rec);
 }
 
+void SkResourceCache::VisitAll(Visitor visitor, void* context) {
+    SkAutoMutexAcquire am(gMutex);
+    get_cache()->visitAll(visitor, context);
+}
+
 void SkResourceCache::PostPurgeSharedID(uint64_t sharedID) {
     if (sharedID) {
         SkMessageBus<PurgeSharedIDMessage>::Post(PurgeSharedIDMessage(sharedID));
@@ -644,3 +661,13 @@
     return SkResourceCache::PurgeAll();
 }
 
+/////////////
+
+static void dump_visitor(const SkResourceCache::Rec& rec, void*) {
+    SkDebugf("RC: %12s bytes %9lu  discardable %p\n",
+             rec.getCategory(), rec.bytesUsed(), rec.diagnostic_only_getDiscardable());
+}
+
+void SkResourceCache::TestDumpMemoryStatistics() {
+    VisitAll(dump_visitor, nullptr);
+}
diff --git a/src/core/SkResourceCache.h b/src/core/SkResourceCache.h
index b43572f..7267c67 100644
--- a/src/core/SkResourceCache.h
+++ b/src/core/SkResourceCache.h
@@ -14,7 +14,6 @@
 
 class SkCachedData;
 class SkDiscardableMemory;
-class SkMipMap;
 
 /**
  *  Cache object for bitmaps (with possible scale in X Y as part of the key).
@@ -78,6 +77,10 @@
         virtual const Key& getKey() const = 0;
         virtual size_t bytesUsed() const = 0;
 
+        // for memory usage diagnostics
+        virtual const char* getCategory() const = 0;
+        virtual SkDiscardableMemory* diagnostic_only_getDiscardable() const { return NULL; }
+
         // for SkTDynamicHash::Traits
         static uint32_t Hash(const Key& key) { return key.hash(); }
         static const Key& GetKey(const Rec& rec) { return rec.getKey(); }
@@ -133,6 +136,10 @@
     static bool Find(const Key& key, FindVisitor, void* context);
     static void Add(Rec*);
 
+    typedef void (*Visitor)(const Rec&, void* context);
+    // Call the visitor for every Rec in the cache.
+    static void VisitAll(Visitor, void* context);
+
     static size_t GetTotalBytesUsed();
     static size_t GetTotalByteLimit();
     static size_t SetTotalByteLimit(size_t newLimit);
@@ -143,6 +150,8 @@
 
     static void PurgeAll();
 
+    static void TestDumpMemoryStatistics();
+
     /**
      *  Returns the DiscardableFactory used by the global cache, or NULL.
      */
@@ -194,6 +203,7 @@
      */
     bool find(const Key&, FindVisitor, void* context);
     void add(Rec*);
+    void visitAll(Visitor, void* context);
 
     size_t getTotalBytesUsed() const { return fTotalBytesUsed; }
     size_t getTotalByteLimit() const { return fTotalByteLimit; }
diff --git a/src/core/SkYUVPlanesCache.cpp b/src/core/SkYUVPlanesCache.cpp
index 79136db..b113c07 100644
--- a/src/core/SkYUVPlanesCache.cpp
+++ b/src/core/SkYUVPlanesCache.cpp
@@ -48,6 +48,10 @@
 
     const Key& getKey() const override { return fKey; }
     size_t bytesUsed() const override { return sizeof(*this) + fValue.fData->size(); }
+    const char* getCategory() const override { return "yuv-planes"; }
+    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
+        return fValue.fData->diagnostic_only_getDiscardable();
+    }
 
     static bool Visitor(const SkResourceCache::Rec& baseRec, void* contextData) {
         const YUVPlanesRec& rec = static_cast<const YUVPlanesRec&>(baseRec);
diff --git a/src/lazy/SkDiscardablePixelRef.h b/src/lazy/SkDiscardablePixelRef.h
index 6f422e3..e8451ee 100644
--- a/src/lazy/SkDiscardablePixelRef.h
+++ b/src/lazy/SkDiscardablePixelRef.h
@@ -21,6 +21,9 @@
 class SkDiscardablePixelRef : public SkPixelRef {
 public:
     
+    SkDiscardableMemory* diagnostic_only_getDiscardable() const override {
+        return fDiscardableMemory;
+    }
 
 protected:
     ~SkDiscardablePixelRef();
diff --git a/tests/ImageCacheTest.cpp b/tests/ImageCacheTest.cpp
index 2244bb0..e2efe97 100644
--- a/tests/ImageCacheTest.cpp
+++ b/tests/ImageCacheTest.cpp
@@ -26,6 +26,8 @@
 
     const Key& getKey() const override { return fKey; }
     size_t bytesUsed() const override { return sizeof(fKey) + sizeof(fValue); }
+    const char* getCategory() const override { return "test_cache"; }
+    SkDiscardableMemory* diagnostic_only_getDiscardable() const override { return NULL; }
 
     static bool Visitor(const SkResourceCache::Rec& baseRec, void* context) {
         const TestingRec& rec = static_cast<const TestingRec&>(baseRec);