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