1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/lazy/SkDiscardableMemoryPool.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,207 @@ 1.4 +/* 1.5 + * Copyright 2013 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkDiscardableMemoryPool.h" 1.12 +#include "SkOnce.h" 1.13 + 1.14 +// Note: 1.15 +// A PoolDiscardableMemory is memory that is counted in a pool. 1.16 +// A DiscardableMemoryPool is a pool of PoolDiscardableMemorys. 1.17 + 1.18 +/** 1.19 + * A SkPoolDiscardableMemory is a SkDiscardableMemory that relies on 1.20 + * a SkDiscardableMemoryPool object to manage the memory. 1.21 + */ 1.22 +class SkPoolDiscardableMemory : public SkDiscardableMemory { 1.23 +public: 1.24 + SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool, 1.25 + void* pointer, size_t bytes); 1.26 + virtual ~SkPoolDiscardableMemory(); 1.27 + virtual bool lock() SK_OVERRIDE; 1.28 + virtual void* data() SK_OVERRIDE; 1.29 + virtual void unlock() SK_OVERRIDE; 1.30 + friend class SkDiscardableMemoryPool; 1.31 +private: 1.32 + SK_DECLARE_INTERNAL_LLIST_INTERFACE(SkPoolDiscardableMemory); 1.33 + SkDiscardableMemoryPool* const fPool; 1.34 + bool fLocked; 1.35 + void* fPointer; 1.36 + const size_t fBytes; 1.37 +}; 1.38 + 1.39 +SkPoolDiscardableMemory::SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool, 1.40 + void* pointer, 1.41 + size_t bytes) 1.42 + : fPool(pool) 1.43 + , fLocked(true) 1.44 + , fPointer(pointer) 1.45 + , fBytes(bytes) { 1.46 + SkASSERT(fPool != NULL); 1.47 + SkASSERT(fPointer != NULL); 1.48 + SkASSERT(fBytes > 0); 1.49 + fPool->ref(); 1.50 +} 1.51 + 1.52 +SkPoolDiscardableMemory::~SkPoolDiscardableMemory() { 1.53 + SkASSERT(!fLocked); // contract for SkDiscardableMemory 1.54 + fPool->free(this); 1.55 + fPool->unref(); 1.56 +} 1.57 + 1.58 +bool SkPoolDiscardableMemory::lock() { 1.59 + SkASSERT(!fLocked); // contract for SkDiscardableMemory 1.60 + return fPool->lock(this); 1.61 +} 1.62 + 1.63 +void* SkPoolDiscardableMemory::data() { 1.64 + SkASSERT(fLocked); // contract for SkDiscardableMemory 1.65 + return fPointer; 1.66 +} 1.67 + 1.68 +void SkPoolDiscardableMemory::unlock() { 1.69 + SkASSERT(fLocked); // contract for SkDiscardableMemory 1.70 + fPool->unlock(this); 1.71 +} 1.72 + 1.73 +//////////////////////////////////////////////////////////////////////////////// 1.74 + 1.75 +SkDiscardableMemoryPool::SkDiscardableMemoryPool(size_t budget, 1.76 + SkBaseMutex* mutex) 1.77 + : fMutex(mutex) 1.78 + , fBudget(budget) 1.79 + , fUsed(0) { 1.80 + #if LAZY_CACHE_STATS 1.81 + fCacheHits = 0; 1.82 + fCacheMisses = 0; 1.83 + #endif // LAZY_CACHE_STATS 1.84 +} 1.85 +SkDiscardableMemoryPool::~SkDiscardableMemoryPool() { 1.86 + // SkPoolDiscardableMemory objects that belong to this pool are 1.87 + // always deleted before deleting this pool since each one has a 1.88 + // ref to the pool. 1.89 + SkASSERT(fList.isEmpty()); 1.90 +} 1.91 + 1.92 +void SkDiscardableMemoryPool::dumpDownTo(size_t budget) { 1.93 + // assert((NULL = fMutex) || fMutex->isLocked()); 1.94 + // TODO(halcanary) implement bool fMutex::isLocked(). 1.95 + // WARNING: only call this function after aquiring lock. 1.96 + if (fUsed <= budget) { 1.97 + return; 1.98 + } 1.99 + typedef SkTInternalLList<SkPoolDiscardableMemory>::Iter Iter; 1.100 + Iter iter; 1.101 + SkPoolDiscardableMemory* cur = iter.init(fList, Iter::kTail_IterStart); 1.102 + while ((fUsed > budget) && (NULL != cur)) { 1.103 + if (!cur->fLocked) { 1.104 + SkPoolDiscardableMemory* dm = cur; 1.105 + SkASSERT(dm->fPointer != NULL); 1.106 + sk_free(dm->fPointer); 1.107 + dm->fPointer = NULL; 1.108 + SkASSERT(fUsed >= dm->fBytes); 1.109 + fUsed -= dm->fBytes; 1.110 + cur = iter.prev(); 1.111 + // Purged DMs are taken out of the list. This saves times 1.112 + // looking them up. Purged DMs are NOT deleted. 1.113 + fList.remove(dm); 1.114 + } else { 1.115 + cur = iter.prev(); 1.116 + } 1.117 + } 1.118 +} 1.119 + 1.120 +SkDiscardableMemory* SkDiscardableMemoryPool::create(size_t bytes) { 1.121 + void* addr = sk_malloc_flags(bytes, 0); 1.122 + if (NULL == addr) { 1.123 + return NULL; 1.124 + } 1.125 + SkPoolDiscardableMemory* dm = SkNEW_ARGS(SkPoolDiscardableMemory, 1.126 + (this, addr, bytes)); 1.127 + SkAutoMutexAcquire autoMutexAcquire(fMutex); 1.128 + fList.addToHead(dm); 1.129 + fUsed += bytes; 1.130 + this->dumpDownTo(fBudget); 1.131 + return dm; 1.132 +} 1.133 + 1.134 +void SkDiscardableMemoryPool::free(SkPoolDiscardableMemory* dm) { 1.135 + // This is called by dm's destructor. 1.136 + if (dm->fPointer != NULL) { 1.137 + SkAutoMutexAcquire autoMutexAcquire(fMutex); 1.138 + sk_free(dm->fPointer); 1.139 + dm->fPointer = NULL; 1.140 + SkASSERT(fUsed >= dm->fBytes); 1.141 + fUsed -= dm->fBytes; 1.142 + fList.remove(dm); 1.143 + } else { 1.144 + SkASSERT(!fList.isInList(dm)); 1.145 + } 1.146 +} 1.147 + 1.148 +bool SkDiscardableMemoryPool::lock(SkPoolDiscardableMemory* dm) { 1.149 + SkASSERT(dm != NULL); 1.150 + if (NULL == dm->fPointer) { 1.151 + #if LAZY_CACHE_STATS 1.152 + SkAutoMutexAcquire autoMutexAcquire(fMutex); 1.153 + ++fCacheMisses; 1.154 + #endif // LAZY_CACHE_STATS 1.155 + return false; 1.156 + } 1.157 + SkAutoMutexAcquire autoMutexAcquire(fMutex); 1.158 + if (NULL == dm->fPointer) { 1.159 + // May have been purged while waiting for lock. 1.160 + #if LAZY_CACHE_STATS 1.161 + ++fCacheMisses; 1.162 + #endif // LAZY_CACHE_STATS 1.163 + return false; 1.164 + } 1.165 + dm->fLocked = true; 1.166 + fList.remove(dm); 1.167 + fList.addToHead(dm); 1.168 + #if LAZY_CACHE_STATS 1.169 + ++fCacheHits; 1.170 + #endif // LAZY_CACHE_STATS 1.171 + return true; 1.172 +} 1.173 + 1.174 +void SkDiscardableMemoryPool::unlock(SkPoolDiscardableMemory* dm) { 1.175 + SkASSERT(dm != NULL); 1.176 + SkAutoMutexAcquire autoMutexAcquire(fMutex); 1.177 + dm->fLocked = false; 1.178 + this->dumpDownTo(fBudget); 1.179 +} 1.180 + 1.181 +size_t SkDiscardableMemoryPool::getRAMUsed() { 1.182 + return fUsed; 1.183 +} 1.184 +void SkDiscardableMemoryPool::setRAMBudget(size_t budget) { 1.185 + SkAutoMutexAcquire autoMutexAcquire(fMutex); 1.186 + fBudget = budget; 1.187 + this->dumpDownTo(fBudget); 1.188 +} 1.189 +void SkDiscardableMemoryPool::dumpPool() { 1.190 + SkAutoMutexAcquire autoMutexAcquire(fMutex); 1.191 + this->dumpDownTo(0); 1.192 +} 1.193 + 1.194 +//////////////////////////////////////////////////////////////////////////////// 1.195 +SK_DECLARE_STATIC_MUTEX(gMutex); 1.196 +static void create_pool(SkDiscardableMemoryPool** pool) { 1.197 + SkASSERT(NULL == *pool); 1.198 + *pool = SkNEW_ARGS(SkDiscardableMemoryPool, 1.199 + (SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE, 1.200 + &gMutex)); 1.201 +} 1.202 +SkDiscardableMemoryPool* SkGetGlobalDiscardableMemoryPool() { 1.203 + static SkDiscardableMemoryPool* gPool(NULL); 1.204 + SK_DECLARE_STATIC_ONCE(create_pool_once); 1.205 + SkOnce(&create_pool_once, create_pool, &gPool); 1.206 + SkASSERT(NULL != gPool); 1.207 + return gPool; 1.208 +} 1.209 + 1.210 +////////////////////////////////////////////////////////////////////////////////