LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/lazy - SkDiscardableMemoryPool.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 111 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 24 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 "SkDiscardableMemoryPool.h"
      10             : #include "SkImageGenerator.h"
      11             : #include "SkMalloc.h"
      12             : #include "SkMutex.h"
      13             : #include "SkOnce.h"
      14             : #include "SkTInternalLList.h"
      15             : 
      16             : // Note:
      17             : // A PoolDiscardableMemory is memory that is counted in a pool.
      18             : // A DiscardableMemoryPool is a pool of PoolDiscardableMemorys.
      19             : 
      20             : namespace {
      21             : 
      22             : class PoolDiscardableMemory;
      23             : 
      24             : /**
      25             :  *  This non-global pool can be used for unit tests to verify that the
      26             :  *  pool works.
      27             :  */
      28             : class DiscardableMemoryPool : public SkDiscardableMemoryPool {
      29             : public:
      30             :     /**
      31             :      *  Without mutex, will be not be thread safe.
      32             :      */
      33             :     DiscardableMemoryPool(size_t budget, SkBaseMutex* mutex = nullptr);
      34             :     ~DiscardableMemoryPool() override;
      35             : 
      36             :     SkDiscardableMemory* create(size_t bytes) override;
      37             : 
      38             :     size_t getRAMUsed() override;
      39             :     void setRAMBudget(size_t budget) override;
      40           0 :     size_t getRAMBudget() override { return fBudget; }
      41             : 
      42             :     /** purges all unlocked DMs */
      43             :     void dumpPool() override;
      44             : 
      45             :     #if SK_LAZY_CACHE_STATS  // Defined in SkDiscardableMemoryPool.h
      46           0 :     int getCacheHits() override { return fCacheHits; }
      47           0 :     int getCacheMisses() override { return fCacheMisses; }
      48           0 :     void resetCacheHitsAndMisses() override {
      49           0 :         fCacheHits = fCacheMisses = 0;
      50           0 :     }
      51             :     int          fCacheHits;
      52             :     int          fCacheMisses;
      53             :     #endif  // SK_LAZY_CACHE_STATS
      54             : 
      55             : private:
      56             :     SkBaseMutex* fMutex;
      57             :     size_t       fBudget;
      58             :     size_t       fUsed;
      59             :     SkTInternalLList<PoolDiscardableMemory> fList;
      60             : 
      61             :     /** Function called to free memory if needed */
      62             :     void dumpDownTo(size_t budget);
      63             :     /** called by DiscardableMemoryPool upon destruction */
      64             :     void free(PoolDiscardableMemory* dm);
      65             :     /** called by DiscardableMemoryPool::lock() */
      66             :     bool lock(PoolDiscardableMemory* dm);
      67             :     /** called by DiscardableMemoryPool::unlock() */
      68             :     void unlock(PoolDiscardableMemory* dm);
      69             : 
      70             :     friend class PoolDiscardableMemory;
      71             : 
      72             :     typedef SkDiscardableMemory::Factory INHERITED;
      73             : };
      74             : 
      75             : /**
      76             :  *  A PoolDiscardableMemory is a SkDiscardableMemory that relies on
      77             :  *  a DiscardableMemoryPool object to manage the memory.
      78             :  */
      79             : class PoolDiscardableMemory : public SkDiscardableMemory {
      80             : public:
      81             :     PoolDiscardableMemory(DiscardableMemoryPool* pool,
      82             :                             void* pointer, size_t bytes);
      83             :     ~PoolDiscardableMemory() override;
      84             :     bool lock() override;
      85             :     void* data() override;
      86             :     void unlock() override;
      87             :     friend class DiscardableMemoryPool;
      88             : private:
      89             :     SK_DECLARE_INTERNAL_LLIST_INTERFACE(PoolDiscardableMemory);
      90             :     DiscardableMemoryPool* const fPool;
      91             :     bool                         fLocked;
      92             :     void*                        fPointer;
      93             :     const size_t                 fBytes;
      94             : };
      95             : 
      96           0 : PoolDiscardableMemory::PoolDiscardableMemory(DiscardableMemoryPool* pool,
      97             :                                              void* pointer,
      98           0 :                                              size_t bytes)
      99             :     : fPool(pool)
     100             :     , fLocked(true)
     101             :     , fPointer(pointer)
     102           0 :     , fBytes(bytes) {
     103           0 :     SkASSERT(fPool != nullptr);
     104           0 :     SkASSERT(fPointer != nullptr);
     105           0 :     SkASSERT(fBytes > 0);
     106           0 :     fPool->ref();
     107           0 : }
     108             : 
     109           0 : PoolDiscardableMemory::~PoolDiscardableMemory() {
     110           0 :     SkASSERT(!fLocked); // contract for SkDiscardableMemory
     111           0 :     fPool->free(this);
     112           0 :     fPool->unref();
     113           0 : }
     114             : 
     115           0 : bool PoolDiscardableMemory::lock() {
     116           0 :     SkASSERT(!fLocked); // contract for SkDiscardableMemory
     117           0 :     return fPool->lock(this);
     118             : }
     119             : 
     120           0 : void* PoolDiscardableMemory::data() {
     121           0 :     SkASSERT(fLocked); // contract for SkDiscardableMemory
     122           0 :     return fPointer;
     123             : }
     124             : 
     125           0 : void PoolDiscardableMemory::unlock() {
     126           0 :     SkASSERT(fLocked); // contract for SkDiscardableMemory
     127           0 :     fPool->unlock(this);
     128           0 : }
     129             : 
     130             : ////////////////////////////////////////////////////////////////////////////////
     131             : 
     132           0 : DiscardableMemoryPool::DiscardableMemoryPool(size_t budget,
     133           0 :                                              SkBaseMutex* mutex)
     134             :     : fMutex(mutex)
     135             :     , fBudget(budget)
     136           0 :     , fUsed(0) {
     137             :     #if SK_LAZY_CACHE_STATS
     138           0 :     fCacheHits = 0;
     139           0 :     fCacheMisses = 0;
     140             :     #endif  // SK_LAZY_CACHE_STATS
     141           0 : }
     142           0 : DiscardableMemoryPool::~DiscardableMemoryPool() {
     143             :     // PoolDiscardableMemory objects that belong to this pool are
     144             :     // always deleted before deleting this pool since each one has a
     145             :     // ref to the pool.
     146           0 :     SkASSERT(fList.isEmpty());
     147           0 : }
     148             : 
     149           0 : void DiscardableMemoryPool::dumpDownTo(size_t budget) {
     150           0 :     if (fMutex != nullptr) {
     151           0 :         fMutex->assertHeld();
     152             :     }
     153           0 :     if (fUsed <= budget) {
     154           0 :         return;
     155             :     }
     156             :     typedef SkTInternalLList<PoolDiscardableMemory>::Iter Iter;
     157           0 :     Iter iter;
     158           0 :     PoolDiscardableMemory* cur = iter.init(fList, Iter::kTail_IterStart);
     159           0 :     while ((fUsed > budget) && (cur)) {
     160           0 :         if (!cur->fLocked) {
     161           0 :             PoolDiscardableMemory* dm = cur;
     162           0 :             SkASSERT(dm->fPointer != nullptr);
     163           0 :             sk_free(dm->fPointer);
     164           0 :             dm->fPointer = nullptr;
     165           0 :             SkASSERT(fUsed >= dm->fBytes);
     166           0 :             fUsed -= dm->fBytes;
     167           0 :             cur = iter.prev();
     168             :             // Purged DMs are taken out of the list.  This saves times
     169             :             // looking them up.  Purged DMs are NOT deleted.
     170           0 :             fList.remove(dm);
     171             :         } else {
     172           0 :             cur = iter.prev();
     173             :         }
     174             :     }
     175             : }
     176             : 
     177           0 : SkDiscardableMemory* DiscardableMemoryPool::create(size_t bytes) {
     178           0 :     void* addr = sk_malloc_flags(bytes, 0);
     179           0 :     if (nullptr == addr) {
     180           0 :         return nullptr;
     181             :     }
     182           0 :     PoolDiscardableMemory* dm = new PoolDiscardableMemory(this, addr, bytes);
     183           0 :     SkAutoMutexAcquire autoMutexAcquire(fMutex);
     184           0 :     fList.addToHead(dm);
     185           0 :     fUsed += bytes;
     186           0 :     this->dumpDownTo(fBudget);
     187           0 :     return dm;
     188             : }
     189             : 
     190           0 : void DiscardableMemoryPool::free(PoolDiscardableMemory* dm) {
     191           0 :     SkAutoMutexAcquire autoMutexAcquire(fMutex);
     192             :     // This is called by dm's destructor.
     193           0 :     if (dm->fPointer != nullptr) {
     194           0 :         sk_free(dm->fPointer);
     195           0 :         dm->fPointer = nullptr;
     196           0 :         SkASSERT(fUsed >= dm->fBytes);
     197           0 :         fUsed -= dm->fBytes;
     198           0 :         fList.remove(dm);
     199             :     } else {
     200           0 :         SkASSERT(!fList.isInList(dm));
     201             :     }
     202           0 : }
     203             : 
     204           0 : bool DiscardableMemoryPool::lock(PoolDiscardableMemory* dm) {
     205           0 :     SkASSERT(dm != nullptr);
     206           0 :     SkAutoMutexAcquire autoMutexAcquire(fMutex);
     207           0 :     if (nullptr == dm->fPointer) {
     208             :         // May have been purged while waiting for lock.
     209             :         #if SK_LAZY_CACHE_STATS
     210           0 :         ++fCacheMisses;
     211             :         #endif  // SK_LAZY_CACHE_STATS
     212           0 :         return false;
     213             :     }
     214           0 :     dm->fLocked = true;
     215           0 :     fList.remove(dm);
     216           0 :     fList.addToHead(dm);
     217             :     #if SK_LAZY_CACHE_STATS
     218           0 :     ++fCacheHits;
     219             :     #endif  // SK_LAZY_CACHE_STATS
     220           0 :     return true;
     221             : }
     222             : 
     223           0 : void DiscardableMemoryPool::unlock(PoolDiscardableMemory* dm) {
     224           0 :     SkASSERT(dm != nullptr);
     225           0 :     SkAutoMutexAcquire autoMutexAcquire(fMutex);
     226           0 :     dm->fLocked = false;
     227           0 :     this->dumpDownTo(fBudget);
     228           0 : }
     229             : 
     230           0 : size_t DiscardableMemoryPool::getRAMUsed() {
     231           0 :     return fUsed;
     232             : }
     233           0 : void DiscardableMemoryPool::setRAMBudget(size_t budget) {
     234           0 :     SkAutoMutexAcquire autoMutexAcquire(fMutex);
     235           0 :     fBudget = budget;
     236           0 :     this->dumpDownTo(fBudget);
     237           0 : }
     238           0 : void DiscardableMemoryPool::dumpPool() {
     239           0 :     SkAutoMutexAcquire autoMutexAcquire(fMutex);
     240           0 :     this->dumpDownTo(0);
     241           0 : }
     242             : 
     243             : }  // namespace
     244             : 
     245           0 : SkDiscardableMemoryPool* SkDiscardableMemoryPool::Create(size_t size, SkBaseMutex* mutex) {
     246           0 :     return new DiscardableMemoryPool(size, mutex);
     247             : }
     248             : 
     249             : SK_DECLARE_STATIC_MUTEX(gMutex);
     250             : 
     251           0 : SkDiscardableMemoryPool* SkGetGlobalDiscardableMemoryPool() {
     252             :     static SkOnce once;
     253             :     static SkDiscardableMemoryPool* global;
     254           0 :     once([]{
     255           0 :         global = SkDiscardableMemoryPool::Create(SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE,
     256             :                                                  &gMutex);
     257           0 :     });
     258           0 :     return global;
     259             : }

Generated by: LCOV version 1.13