LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkResourceCache.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 313 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 54 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2013 Google Inc.
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkDiscardableMemory.h"
       9             : #include "SkMessageBus.h"
      10             : #include "SkMipMap.h"
      11             : #include "SkMutex.h"
      12             : #include "SkOpts.h"
      13             : #include "SkResourceCache.h"
      14             : #include "SkTraceMemoryDump.h"
      15             : 
      16             : #include <stddef.h>
      17             : #include <stdlib.h>
      18             : 
      19           0 : DECLARE_SKMESSAGEBUS_MESSAGE(SkResourceCache::PurgeSharedIDMessage)
      20             : 
      21             : // This can be defined by the caller's build system
      22             : //#define SK_USE_DISCARDABLE_SCALEDIMAGECACHE
      23             : 
      24             : #ifndef SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT
      25             : #   define SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT   1024
      26             : #endif
      27             : 
      28             : #ifndef SK_DEFAULT_IMAGE_CACHE_LIMIT
      29             :     #define SK_DEFAULT_IMAGE_CACHE_LIMIT     (32 * 1024 * 1024)
      30             : #endif
      31             : 
      32           0 : void SkResourceCache::Key::init(void* nameSpace, uint64_t sharedID, size_t dataSize) {
      33           0 :     SkASSERT(SkAlign4(dataSize) == dataSize);
      34             : 
      35             :     // fCount32 and fHash are not hashed
      36             :     static const int kUnhashedLocal32s = 2; // fCache32 + fHash
      37             :     static const int kSharedIDLocal32s = 2; // fSharedID_lo + fSharedID_hi
      38             :     static const int kHashedLocal32s = kSharedIDLocal32s + (sizeof(fNamespace) >> 2);
      39             :     static const int kLocal32s = kUnhashedLocal32s + kHashedLocal32s;
      40             : 
      41             :     static_assert(sizeof(Key) == (kLocal32s << 2), "unaccounted_key_locals");
      42             :     static_assert(sizeof(Key) == offsetof(Key, fNamespace) + sizeof(fNamespace),
      43             :                  "namespace_field_must_be_last");
      44             : 
      45           0 :     fCount32 = SkToS32(kLocal32s + (dataSize >> 2));
      46           0 :     fSharedID_lo = (uint32_t)sharedID;
      47           0 :     fSharedID_hi = (uint32_t)(sharedID >> 32);
      48           0 :     fNamespace = nameSpace;
      49             :     // skip unhashed fields when computing the hash
      50           0 :     fHash = SkOpts::hash(this->as32() + kUnhashedLocal32s,
      51           0 :                          (fCount32 - kUnhashedLocal32s) << 2);
      52           0 : }
      53             : 
      54             : #include "SkTHash.h"
      55             : 
      56             : namespace {
      57             :     struct HashTraits {
      58           0 :         static uint32_t Hash(const SkResourceCache::Key& key) { return key.hash(); }
      59           0 :         static const SkResourceCache::Key& GetKey(const SkResourceCache::Rec* rec) {
      60           0 :             return rec->getKey();
      61             :         }
      62             :     };
      63             : }
      64             : 
      65           0 : class SkResourceCache::Hash :
      66             :     public SkTHashTable<SkResourceCache::Rec*, SkResourceCache::Key, HashTraits> {};
      67             : 
      68             : 
      69             : ///////////////////////////////////////////////////////////////////////////////
      70             : 
      71           0 : void SkResourceCache::init() {
      72           0 :     fHead = nullptr;
      73           0 :     fTail = nullptr;
      74           0 :     fHash = new Hash;
      75           0 :     fTotalBytesUsed = 0;
      76           0 :     fCount = 0;
      77           0 :     fSingleAllocationByteLimit = 0;
      78             : 
      79             :     // One of these should be explicit set by the caller after we return.
      80           0 :     fTotalByteLimit = 0;
      81           0 :     fDiscardableFactory = nullptr;
      82           0 : }
      83             : 
      84           0 : SkResourceCache::SkResourceCache(DiscardableFactory factory) {
      85           0 :     this->init();
      86           0 :     fDiscardableFactory = factory;
      87           0 : }
      88             : 
      89           0 : SkResourceCache::SkResourceCache(size_t byteLimit) {
      90           0 :     this->init();
      91           0 :     fTotalByteLimit = byteLimit;
      92           0 : }
      93             : 
      94           0 : SkResourceCache::~SkResourceCache() {
      95           0 :     Rec* rec = fHead;
      96           0 :     while (rec) {
      97           0 :         Rec* next = rec->fNext;
      98           0 :         delete rec;
      99           0 :         rec = next;
     100             :     }
     101           0 :     delete fHash;
     102           0 : }
     103             : 
     104             : ////////////////////////////////////////////////////////////////////////////////
     105             : 
     106           0 : bool SkResourceCache::find(const Key& key, FindVisitor visitor, void* context) {
     107           0 :     this->checkMessages();
     108             : 
     109           0 :     if (auto found = fHash->find(key)) {
     110           0 :         Rec* rec = *found;
     111           0 :         if (visitor(*rec, context)) {
     112           0 :             this->moveToHead(rec);  // for our LRU
     113           0 :             return true;
     114             :         } else {
     115           0 :             this->remove(rec);  // stale
     116           0 :             return false;
     117             :         }
     118             :     }
     119           0 :     return false;
     120             : }
     121             : 
     122           0 : static void make_size_str(size_t size, SkString* str) {
     123           0 :     const char suffix[] = { 'b', 'k', 'm', 'g', 't', 0 };
     124           0 :     int i = 0;
     125           0 :     while (suffix[i] && (size > 1024)) {
     126           0 :         i += 1;
     127           0 :         size >>= 10;
     128             :     }
     129           0 :     str->printf("%zu%c", size, suffix[i]);
     130           0 : }
     131             : 
     132             : static bool gDumpCacheTransactions;
     133             : 
     134           0 : void SkResourceCache::add(Rec* rec, void* payload) {
     135           0 :     this->checkMessages();
     136             : 
     137           0 :     SkASSERT(rec);
     138             :     // See if we already have this key (racy inserts, etc.)
     139           0 :     if (Rec** preexisting = fHash->find(rec->getKey())) {
     140           0 :         Rec* prev = *preexisting;
     141           0 :         if (prev->canBePurged()) {
     142             :             // if it can be purged, the install may fail, so we have to remove it
     143           0 :             this->remove(prev);
     144             :         } else {
     145             :             // if it cannot be purged, we reuse it and delete the new one
     146           0 :             prev->postAddInstall(payload);
     147           0 :             delete rec;
     148           0 :             return;
     149             :         }
     150             :     }
     151             : 
     152           0 :     this->addToHead(rec);
     153           0 :     fHash->set(rec);
     154           0 :     rec->postAddInstall(payload);
     155             : 
     156           0 :     if (gDumpCacheTransactions) {
     157           0 :         SkString bytesStr, totalStr;
     158           0 :         make_size_str(rec->bytesUsed(), &bytesStr);
     159           0 :         make_size_str(fTotalBytesUsed, &totalStr);
     160           0 :         SkDebugf("RC:    add %5s %12p key %08x -- total %5s, count %d\n",
     161           0 :                  bytesStr.c_str(), rec, rec->getHash(), totalStr.c_str(), fCount);
     162             :     }
     163             : 
     164             :     // since the new rec may push us over-budget, we perform a purge check now
     165           0 :     this->purgeAsNeeded();
     166             : }
     167             : 
     168           0 : void SkResourceCache::remove(Rec* rec) {
     169           0 :     SkASSERT(rec->canBePurged());
     170           0 :     size_t used = rec->bytesUsed();
     171           0 :     SkASSERT(used <= fTotalBytesUsed);
     172             : 
     173           0 :     this->release(rec);
     174           0 :     fHash->remove(rec->getKey());
     175             : 
     176           0 :     fTotalBytesUsed -= used;
     177           0 :     fCount -= 1;
     178             : 
     179             :     //SkDebugf("-RC count [%3d] bytes %d\n", fCount, fTotalBytesUsed);
     180             : 
     181           0 :     if (gDumpCacheTransactions) {
     182           0 :         SkString bytesStr, totalStr;
     183           0 :         make_size_str(used, &bytesStr);
     184           0 :         make_size_str(fTotalBytesUsed, &totalStr);
     185           0 :         SkDebugf("RC: remove %5s %12p key %08x -- total %5s, count %d\n",
     186           0 :                  bytesStr.c_str(), rec, rec->getHash(), totalStr.c_str(), fCount);
     187             :     }
     188             : 
     189           0 :     delete rec;
     190           0 : }
     191             : 
     192           0 : void SkResourceCache::purgeAsNeeded(bool forcePurge) {
     193             :     size_t byteLimit;
     194             :     int    countLimit;
     195             : 
     196           0 :     if (fDiscardableFactory) {
     197           0 :         countLimit = SK_DISCARDABLEMEMORY_SCALEDIMAGECACHE_COUNT_LIMIT;
     198           0 :         byteLimit = SK_MaxU32;  // no limit based on bytes
     199             :     } else {
     200           0 :         countLimit = SK_MaxS32; // no limit based on count
     201           0 :         byteLimit = fTotalByteLimit;
     202             :     }
     203             : 
     204           0 :     Rec* rec = fTail;
     205           0 :     while (rec) {
     206           0 :         if (!forcePurge && fTotalBytesUsed < byteLimit && fCount < countLimit) {
     207           0 :             break;
     208             :         }
     209             : 
     210           0 :         Rec* prev = rec->fPrev;
     211           0 :         if (rec->canBePurged()) {
     212           0 :             this->remove(rec);
     213             :         }
     214           0 :         rec = prev;
     215             :     }
     216           0 : }
     217             : 
     218             : //#define SK_TRACK_PURGE_SHAREDID_HITRATE
     219             : 
     220             : #ifdef SK_TRACK_PURGE_SHAREDID_HITRATE
     221             : static int gPurgeCallCounter;
     222             : static int gPurgeHitCounter;
     223             : #endif
     224             : 
     225           0 : void SkResourceCache::purgeSharedID(uint64_t sharedID) {
     226           0 :     if (0 == sharedID) {
     227           0 :         return;
     228             :     }
     229             : 
     230             : #ifdef SK_TRACK_PURGE_SHAREDID_HITRATE
     231             :     gPurgeCallCounter += 1;
     232             :     bool found = false;
     233             : #endif
     234             :     // go backwards, just like purgeAsNeeded, just to make the code similar.
     235             :     // could iterate either direction and still be correct.
     236           0 :     Rec* rec = fTail;
     237           0 :     while (rec) {
     238           0 :         Rec* prev = rec->fPrev;
     239           0 :         if (rec->getKey().getSharedID() == sharedID) {
     240             :             // even though the "src" is now dead, caches could still be in-flight, so
     241             :             // we have to check if it can be removed.
     242           0 :             if (rec->canBePurged()) {
     243           0 :                 this->remove(rec);
     244             :             }
     245             : #ifdef SK_TRACK_PURGE_SHAREDID_HITRATE
     246             :             found = true;
     247             : #endif
     248             :         }
     249           0 :         rec = prev;
     250             :     }
     251             : 
     252             : #ifdef SK_TRACK_PURGE_SHAREDID_HITRATE
     253             :     if (found) {
     254             :         gPurgeHitCounter += 1;
     255             :     }
     256             : 
     257             :     SkDebugf("PurgeShared calls=%d hits=%d rate=%g\n", gPurgeCallCounter, gPurgeHitCounter,
     258             :              gPurgeHitCounter * 100.0 / gPurgeCallCounter);
     259             : #endif
     260             : }
     261             : 
     262           0 : void SkResourceCache::visitAll(Visitor visitor, void* context) {
     263             :     // go backwards, just like purgeAsNeeded, just to make the code similar.
     264             :     // could iterate either direction and still be correct.
     265           0 :     Rec* rec = fTail;
     266           0 :     while (rec) {
     267           0 :         visitor(*rec, context);
     268           0 :         rec = rec->fPrev;
     269             :     }
     270           0 : }
     271             : 
     272             : ///////////////////////////////////////////////////////////////////////////////////////////////////
     273             : 
     274           0 : size_t SkResourceCache::setTotalByteLimit(size_t newLimit) {
     275           0 :     size_t prevLimit = fTotalByteLimit;
     276           0 :     fTotalByteLimit = newLimit;
     277           0 :     if (newLimit < prevLimit) {
     278           0 :         this->purgeAsNeeded();
     279             :     }
     280           0 :     return prevLimit;
     281             : }
     282             : 
     283           0 : SkCachedData* SkResourceCache::newCachedData(size_t bytes) {
     284           0 :     this->checkMessages();
     285             : 
     286           0 :     if (fDiscardableFactory) {
     287           0 :         SkDiscardableMemory* dm = fDiscardableFactory(bytes);
     288           0 :         return dm ? new SkCachedData(bytes, dm) : nullptr;
     289             :     } else {
     290           0 :         return new SkCachedData(sk_malloc_throw(bytes), bytes);
     291             :     }
     292             : }
     293             : 
     294             : ///////////////////////////////////////////////////////////////////////////////
     295             : 
     296           0 : void SkResourceCache::release(Rec* rec) {
     297           0 :     Rec* prev = rec->fPrev;
     298           0 :     Rec* next = rec->fNext;
     299             : 
     300           0 :     if (!prev) {
     301           0 :         SkASSERT(fHead == rec);
     302           0 :         fHead = next;
     303             :     } else {
     304           0 :         prev->fNext = next;
     305             :     }
     306             : 
     307           0 :     if (!next) {
     308           0 :         fTail = prev;
     309             :     } else {
     310           0 :         next->fPrev = prev;
     311             :     }
     312             : 
     313           0 :     rec->fNext = rec->fPrev = nullptr;
     314           0 : }
     315             : 
     316           0 : void SkResourceCache::moveToHead(Rec* rec) {
     317           0 :     if (fHead == rec) {
     318           0 :         return;
     319             :     }
     320             : 
     321           0 :     SkASSERT(fHead);
     322           0 :     SkASSERT(fTail);
     323             : 
     324           0 :     this->validate();
     325             : 
     326           0 :     this->release(rec);
     327             : 
     328           0 :     fHead->fPrev = rec;
     329           0 :     rec->fNext = fHead;
     330           0 :     fHead = rec;
     331             : 
     332           0 :     this->validate();
     333             : }
     334             : 
     335           0 : void SkResourceCache::addToHead(Rec* rec) {
     336           0 :     this->validate();
     337             : 
     338           0 :     rec->fPrev = nullptr;
     339           0 :     rec->fNext = fHead;
     340           0 :     if (fHead) {
     341           0 :         fHead->fPrev = rec;
     342             :     }
     343           0 :     fHead = rec;
     344           0 :     if (!fTail) {
     345           0 :         fTail = rec;
     346             :     }
     347           0 :     fTotalBytesUsed += rec->bytesUsed();
     348           0 :     fCount += 1;
     349             : 
     350           0 :     this->validate();
     351           0 : }
     352             : 
     353             : ///////////////////////////////////////////////////////////////////////////////
     354             : 
     355             : #ifdef SK_DEBUG
     356           0 : void SkResourceCache::validate() const {
     357           0 :     if (nullptr == fHead) {
     358           0 :         SkASSERT(nullptr == fTail);
     359           0 :         SkASSERT(0 == fTotalBytesUsed);
     360           0 :         return;
     361             :     }
     362             : 
     363           0 :     if (fHead == fTail) {
     364           0 :         SkASSERT(nullptr == fHead->fPrev);
     365           0 :         SkASSERT(nullptr == fHead->fNext);
     366           0 :         SkASSERT(fHead->bytesUsed() == fTotalBytesUsed);
     367           0 :         return;
     368             :     }
     369             : 
     370           0 :     SkASSERT(nullptr == fHead->fPrev);
     371           0 :     SkASSERT(fHead->fNext);
     372           0 :     SkASSERT(nullptr == fTail->fNext);
     373           0 :     SkASSERT(fTail->fPrev);
     374             : 
     375           0 :     size_t used = 0;
     376           0 :     int count = 0;
     377           0 :     const Rec* rec = fHead;
     378           0 :     while (rec) {
     379           0 :         count += 1;
     380           0 :         used += rec->bytesUsed();
     381           0 :         SkASSERT(used <= fTotalBytesUsed);
     382           0 :         rec = rec->fNext;
     383             :     }
     384           0 :     SkASSERT(fCount == count);
     385             : 
     386           0 :     rec = fTail;
     387           0 :     while (rec) {
     388           0 :         SkASSERT(count > 0);
     389           0 :         count -= 1;
     390           0 :         SkASSERT(used >= rec->bytesUsed());
     391           0 :         used -= rec->bytesUsed();
     392           0 :         rec = rec->fPrev;
     393             :     }
     394             : 
     395           0 :     SkASSERT(0 == count);
     396           0 :     SkASSERT(0 == used);
     397             : }
     398             : #endif
     399             : 
     400           0 : void SkResourceCache::dump() const {
     401           0 :     this->validate();
     402             : 
     403           0 :     SkDebugf("SkResourceCache: count=%d bytes=%d %s\n",
     404           0 :              fCount, fTotalBytesUsed, fDiscardableFactory ? "discardable" : "malloc");
     405           0 : }
     406             : 
     407           0 : size_t SkResourceCache::setSingleAllocationByteLimit(size_t newLimit) {
     408           0 :     size_t oldLimit = fSingleAllocationByteLimit;
     409           0 :     fSingleAllocationByteLimit = newLimit;
     410           0 :     return oldLimit;
     411             : }
     412             : 
     413           0 : size_t SkResourceCache::getSingleAllocationByteLimit() const {
     414           0 :     return fSingleAllocationByteLimit;
     415             : }
     416             : 
     417           0 : size_t SkResourceCache::getEffectiveSingleAllocationByteLimit() const {
     418             :     // fSingleAllocationByteLimit == 0 means the caller is asking for our default
     419           0 :     size_t limit = fSingleAllocationByteLimit;
     420             : 
     421             :     // if we're not discardable (i.e. we are fixed-budget) then cap the single-limit
     422             :     // to our budget.
     423           0 :     if (nullptr == fDiscardableFactory) {
     424           0 :         if (0 == limit) {
     425           0 :             limit = fTotalByteLimit;
     426             :         } else {
     427           0 :             limit = SkTMin(limit, fTotalByteLimit);
     428             :         }
     429             :     }
     430           0 :     return limit;
     431             : }
     432             : 
     433           0 : void SkResourceCache::checkMessages() {
     434           0 :     SkTArray<PurgeSharedIDMessage> msgs;
     435           0 :     fPurgeSharedIDInbox.poll(&msgs);
     436           0 :     for (int i = 0; i < msgs.count(); ++i) {
     437           0 :         this->purgeSharedID(msgs[i].fSharedID);
     438             :     }
     439           0 : }
     440             : 
     441             : ///////////////////////////////////////////////////////////////////////////////
     442             : 
     443             : SK_DECLARE_STATIC_MUTEX(gMutex);
     444             : static SkResourceCache* gResourceCache = nullptr;
     445             : 
     446             : /** Must hold gMutex when calling. */
     447           0 : static SkResourceCache* get_cache() {
     448             :     // gMutex is always held when this is called, so we don't need to be fancy in here.
     449           0 :     gMutex.assertHeld();
     450           0 :     if (nullptr == gResourceCache) {
     451             : #ifdef SK_USE_DISCARDABLE_SCALEDIMAGECACHE
     452             :         gResourceCache = new SkResourceCache(SkDiscardableMemory::Create);
     453             : #else
     454           0 :         gResourceCache = new SkResourceCache(SK_DEFAULT_IMAGE_CACHE_LIMIT);
     455             : #endif
     456             :     }
     457           0 :     return gResourceCache;
     458             : }
     459             : 
     460           0 : size_t SkResourceCache::GetTotalBytesUsed() {
     461           0 :     SkAutoMutexAcquire am(gMutex);
     462           0 :     return get_cache()->getTotalBytesUsed();
     463             : }
     464             : 
     465           0 : size_t SkResourceCache::GetTotalByteLimit() {
     466           0 :     SkAutoMutexAcquire am(gMutex);
     467           0 :     return get_cache()->getTotalByteLimit();
     468             : }
     469             : 
     470           0 : size_t SkResourceCache::SetTotalByteLimit(size_t newLimit) {
     471           0 :     SkAutoMutexAcquire am(gMutex);
     472           0 :     return get_cache()->setTotalByteLimit(newLimit);
     473             : }
     474             : 
     475           0 : SkResourceCache::DiscardableFactory SkResourceCache::GetDiscardableFactory() {
     476           0 :     SkAutoMutexAcquire am(gMutex);
     477           0 :     return get_cache()->discardableFactory();
     478             : }
     479             : 
     480           0 : SkCachedData* SkResourceCache::NewCachedData(size_t bytes) {
     481           0 :     SkAutoMutexAcquire am(gMutex);
     482           0 :     return get_cache()->newCachedData(bytes);
     483             : }
     484             : 
     485           0 : void SkResourceCache::Dump() {
     486           0 :     SkAutoMutexAcquire am(gMutex);
     487           0 :     get_cache()->dump();
     488           0 : }
     489             : 
     490           0 : size_t SkResourceCache::SetSingleAllocationByteLimit(size_t size) {
     491           0 :     SkAutoMutexAcquire am(gMutex);
     492           0 :     return get_cache()->setSingleAllocationByteLimit(size);
     493             : }
     494             : 
     495           0 : size_t SkResourceCache::GetSingleAllocationByteLimit() {
     496           0 :     SkAutoMutexAcquire am(gMutex);
     497           0 :     return get_cache()->getSingleAllocationByteLimit();
     498             : }
     499             : 
     500           0 : size_t SkResourceCache::GetEffectiveSingleAllocationByteLimit() {
     501           0 :     SkAutoMutexAcquire am(gMutex);
     502           0 :     return get_cache()->getEffectiveSingleAllocationByteLimit();
     503             : }
     504             : 
     505           0 : void SkResourceCache::PurgeAll() {
     506           0 :     SkAutoMutexAcquire am(gMutex);
     507           0 :     return get_cache()->purgeAll();
     508             : }
     509             : 
     510           0 : bool SkResourceCache::Find(const Key& key, FindVisitor visitor, void* context) {
     511           0 :     SkAutoMutexAcquire am(gMutex);
     512           0 :     return get_cache()->find(key, visitor, context);
     513             : }
     514             : 
     515           0 : void SkResourceCache::Add(Rec* rec, void* payload) {
     516           0 :     SkAutoMutexAcquire am(gMutex);
     517           0 :     get_cache()->add(rec, payload);
     518           0 : }
     519             : 
     520           0 : void SkResourceCache::VisitAll(Visitor visitor, void* context) {
     521           0 :     SkAutoMutexAcquire am(gMutex);
     522           0 :     get_cache()->visitAll(visitor, context);
     523           0 : }
     524             : 
     525           0 : void SkResourceCache::PostPurgeSharedID(uint64_t sharedID) {
     526           0 :     if (sharedID) {
     527           0 :         SkMessageBus<PurgeSharedIDMessage>::Post(PurgeSharedIDMessage(sharedID));
     528             :     }
     529           0 : }
     530             : 
     531             : ///////////////////////////////////////////////////////////////////////////////
     532             : 
     533             : #include "SkGraphics.h"
     534             : #include "SkImageFilter.h"
     535             : 
     536           0 : size_t SkGraphics::GetResourceCacheTotalBytesUsed() {
     537           0 :     return SkResourceCache::GetTotalBytesUsed();
     538             : }
     539             : 
     540           0 : size_t SkGraphics::GetResourceCacheTotalByteLimit() {
     541           0 :     return SkResourceCache::GetTotalByteLimit();
     542             : }
     543             : 
     544           0 : size_t SkGraphics::SetResourceCacheTotalByteLimit(size_t newLimit) {
     545           0 :     return SkResourceCache::SetTotalByteLimit(newLimit);
     546             : }
     547             : 
     548           0 : size_t SkGraphics::GetResourceCacheSingleAllocationByteLimit() {
     549           0 :     return SkResourceCache::GetSingleAllocationByteLimit();
     550             : }
     551             : 
     552           0 : size_t SkGraphics::SetResourceCacheSingleAllocationByteLimit(size_t newLimit) {
     553           0 :     return SkResourceCache::SetSingleAllocationByteLimit(newLimit);
     554             : }
     555             : 
     556           0 : void SkGraphics::PurgeResourceCache() {
     557           0 :     SkImageFilter::PurgeCache();
     558           0 :     return SkResourceCache::PurgeAll();
     559             : }
     560             : 
     561             : /////////////
     562             : 
     563           0 : static void dump_visitor(const SkResourceCache::Rec& rec, void*) {
     564           0 :     SkDebugf("RC: %12s bytes %9lu  discardable %p\n",
     565           0 :              rec.getCategory(), rec.bytesUsed(), rec.diagnostic_only_getDiscardable());
     566           0 : }
     567             : 
     568           0 : void SkResourceCache::TestDumpMemoryStatistics() {
     569           0 :     VisitAll(dump_visitor, nullptr);
     570           0 : }
     571             : 
     572           0 : static void sk_trace_dump_visitor(const SkResourceCache::Rec& rec, void* context) {
     573           0 :     SkTraceMemoryDump* dump = static_cast<SkTraceMemoryDump*>(context);
     574           0 :     SkString dumpName = SkStringPrintf("skia/sk_resource_cache/%s_%p", rec.getCategory(), &rec);
     575           0 :     SkDiscardableMemory* discardable = rec.diagnostic_only_getDiscardable();
     576           0 :     if (discardable) {
     577           0 :         dump->setDiscardableMemoryBacking(dumpName.c_str(), *discardable);
     578             : 
     579             :         // The discardable memory size will be calculated by dumper, but we also dump what we think
     580             :         // the size of object in memory is irrespective of whether object is live or dead.
     581           0 :         dump->dumpNumericValue(dumpName.c_str(), "discardable_size", "bytes", rec.bytesUsed());
     582             :     } else {
     583           0 :         dump->dumpNumericValue(dumpName.c_str(), "size", "bytes", rec.bytesUsed());
     584           0 :         dump->setMemoryBacking(dumpName.c_str(), "malloc", nullptr);
     585             :     }
     586           0 : }
     587             : 
     588           0 : void SkResourceCache::DumpMemoryStatistics(SkTraceMemoryDump* dump) {
     589             :     // Since resource could be backed by malloc or discardable, the cache always dumps detailed
     590             :     // stats to be accurate.
     591           0 :     VisitAll(sk_trace_dump_visitor, dump);
     592           0 : }

Generated by: LCOV version 1.13