Home | History | Annotate | Download | only in lazy
      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 "SkDiscardableMemoryPool.h"
      9 #include "SkOnce.h"
     10 
     11 // Note:
     12 // A PoolDiscardableMemory is memory that is counted in a pool.
     13 // A DiscardableMemoryPool is a pool of PoolDiscardableMemorys.
     14 
     15 /**
     16  *  A SkPoolDiscardableMemory is a SkDiscardableMemory that relies on
     17  *  a SkDiscardableMemoryPool object to manage the memory.
     18  */
     19 class SkPoolDiscardableMemory : public SkDiscardableMemory {
     20 public:
     21     SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool,
     22                             void* pointer, size_t bytes);
     23     virtual ~SkPoolDiscardableMemory();
     24     virtual bool lock() SK_OVERRIDE;
     25     virtual void* data() SK_OVERRIDE;
     26     virtual void unlock() SK_OVERRIDE;
     27     friend class SkDiscardableMemoryPool;
     28 private:
     29     SK_DECLARE_INTERNAL_LLIST_INTERFACE(SkPoolDiscardableMemory);
     30     SkDiscardableMemoryPool* const fPool;
     31     bool                           fLocked;
     32     void*                          fPointer;
     33     const size_t                   fBytes;
     34 };
     35 
     36 SkPoolDiscardableMemory::SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool,
     37                                                  void* pointer,
     38                                                  size_t bytes)
     39     : fPool(pool)
     40     , fLocked(true)
     41     , fPointer(pointer)
     42     , fBytes(bytes) {
     43     SkASSERT(fPool != NULL);
     44     SkASSERT(fPointer != NULL);
     45     SkASSERT(fBytes > 0);
     46     fPool->ref();
     47 }
     48 
     49 SkPoolDiscardableMemory::~SkPoolDiscardableMemory() {
     50     SkASSERT(!fLocked); // contract for SkDiscardableMemory
     51     fPool->free(this);
     52     fPool->unref();
     53 }
     54 
     55 bool SkPoolDiscardableMemory::lock() {
     56     SkASSERT(!fLocked); // contract for SkDiscardableMemory
     57     return fPool->lock(this);
     58 }
     59 
     60 void* SkPoolDiscardableMemory::data() {
     61     SkASSERT(fLocked); // contract for SkDiscardableMemory
     62     return fPointer;
     63 }
     64 
     65 void SkPoolDiscardableMemory::unlock() {
     66     SkASSERT(fLocked); // contract for SkDiscardableMemory
     67     fPool->unlock(this);
     68 }
     69 
     70 ////////////////////////////////////////////////////////////////////////////////
     71 
     72 SkDiscardableMemoryPool::SkDiscardableMemoryPool(size_t budget,
     73                                                  SkBaseMutex* mutex)
     74     : fMutex(mutex)
     75     , fBudget(budget)
     76     , fUsed(0) {
     77     #if LAZY_CACHE_STATS
     78     fCacheHits = 0;
     79     fCacheMisses = 0;
     80     #endif  // LAZY_CACHE_STATS
     81 }
     82 SkDiscardableMemoryPool::~SkDiscardableMemoryPool() {
     83     // SkPoolDiscardableMemory objects that belong to this pool are
     84     // always deleted before deleting this pool since each one has a
     85     // ref to the pool.
     86     SkASSERT(fList.isEmpty());
     87 }
     88 
     89 void SkDiscardableMemoryPool::dumpDownTo(size_t budget) {
     90     // assert((NULL = fMutex) || fMutex->isLocked());
     91     // TODO(halcanary) implement bool fMutex::isLocked().
     92     // WARNING: only call this function after aquiring lock.
     93     if (fUsed <= budget) {
     94         return;
     95     }
     96     typedef SkTInternalLList<SkPoolDiscardableMemory>::Iter Iter;
     97     Iter iter;
     98     SkPoolDiscardableMemory* cur = iter.init(fList, Iter::kTail_IterStart);
     99     while ((fUsed > budget) && (NULL != cur)) {
    100         if (!cur->fLocked) {
    101             SkPoolDiscardableMemory* dm = cur;
    102             SkASSERT(dm->fPointer != NULL);
    103             sk_free(dm->fPointer);
    104             dm->fPointer = NULL;
    105             SkASSERT(fUsed >= dm->fBytes);
    106             fUsed -= dm->fBytes;
    107             cur = iter.prev();
    108             // Purged DMs are taken out of the list.  This saves times
    109             // looking them up.  Purged DMs are NOT deleted.
    110             fList.remove(dm);
    111         } else {
    112             cur = iter.prev();
    113         }
    114     }
    115 }
    116 
    117 SkDiscardableMemory* SkDiscardableMemoryPool::create(size_t bytes) {
    118     void* addr = sk_malloc_flags(bytes, 0);
    119     if (NULL == addr) {
    120         return NULL;
    121     }
    122     SkPoolDiscardableMemory* dm = SkNEW_ARGS(SkPoolDiscardableMemory,
    123                                              (this, addr, bytes));
    124     SkAutoMutexAcquire autoMutexAcquire(fMutex);
    125     fList.addToHead(dm);
    126     fUsed += bytes;
    127     this->dumpDownTo(fBudget);
    128     return dm;
    129 }
    130 
    131 void SkDiscardableMemoryPool::free(SkPoolDiscardableMemory* dm) {
    132     // This is called by dm's destructor.
    133     if (dm->fPointer != NULL) {
    134         SkAutoMutexAcquire autoMutexAcquire(fMutex);
    135         sk_free(dm->fPointer);
    136         dm->fPointer = NULL;
    137         SkASSERT(fUsed >= dm->fBytes);
    138         fUsed -= dm->fBytes;
    139         fList.remove(dm);
    140     } else {
    141         SkASSERT(!fList.isInList(dm));
    142     }
    143 }
    144 
    145 bool SkDiscardableMemoryPool::lock(SkPoolDiscardableMemory* dm) {
    146     SkASSERT(dm != NULL);
    147     if (NULL == dm->fPointer) {
    148         #if LAZY_CACHE_STATS
    149         SkAutoMutexAcquire autoMutexAcquire(fMutex);
    150         ++fCacheMisses;
    151         #endif  // LAZY_CACHE_STATS
    152         return false;
    153     }
    154     SkAutoMutexAcquire autoMutexAcquire(fMutex);
    155     if (NULL == dm->fPointer) {
    156         // May have been purged while waiting for lock.
    157         #if LAZY_CACHE_STATS
    158         ++fCacheMisses;
    159         #endif  // LAZY_CACHE_STATS
    160         return false;
    161     }
    162     dm->fLocked = true;
    163     fList.remove(dm);
    164     fList.addToHead(dm);
    165     #if LAZY_CACHE_STATS
    166     ++fCacheHits;
    167     #endif  // LAZY_CACHE_STATS
    168     return true;
    169 }
    170 
    171 void SkDiscardableMemoryPool::unlock(SkPoolDiscardableMemory* dm) {
    172     SkASSERT(dm != NULL);
    173     SkAutoMutexAcquire autoMutexAcquire(fMutex);
    174     dm->fLocked = false;
    175     this->dumpDownTo(fBudget);
    176 }
    177 
    178 size_t SkDiscardableMemoryPool::getRAMUsed() {
    179     return fUsed;
    180 }
    181 void SkDiscardableMemoryPool::setRAMBudget(size_t budget) {
    182     SkAutoMutexAcquire autoMutexAcquire(fMutex);
    183     fBudget = budget;
    184     this->dumpDownTo(fBudget);
    185 }
    186 void SkDiscardableMemoryPool::dumpPool() {
    187     SkAutoMutexAcquire autoMutexAcquire(fMutex);
    188     this->dumpDownTo(0);
    189 }
    190 
    191 ////////////////////////////////////////////////////////////////////////////////
    192 SK_DECLARE_STATIC_MUTEX(gMutex);
    193 static void create_pool(SkDiscardableMemoryPool** pool) {
    194     SkASSERT(NULL == *pool);
    195     *pool = SkNEW_ARGS(SkDiscardableMemoryPool,
    196                        (SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE,
    197                         &gMutex));
    198 }
    199 SkDiscardableMemoryPool* SkGetGlobalDiscardableMemoryPool() {
    200     static SkDiscardableMemoryPool* gPool(NULL);
    201     SK_DECLARE_STATIC_ONCE(create_pool_once);
    202     SkOnce(&create_pool_once, create_pool, &gPool);
    203     SkASSERT(NULL != gPool);
    204     return gPool;
    205 }
    206 
    207 ////////////////////////////////////////////////////////////////////////////////
    208