| Index: src/lazy/SkDiscardableMemoryPool.cpp
|
| diff --git a/src/lazy/SkDiscardableMemoryPool.cpp b/src/lazy/SkDiscardableMemoryPool.cpp
|
| index 4709709861f59abbfe34cdf4cac281adc496e70a..961216963e39951fdce5b866b4617d57340999a9 100644
|
| --- a/src/lazy/SkDiscardableMemoryPool.cpp
|
| +++ b/src/lazy/SkDiscardableMemoryPool.cpp
|
| @@ -5,37 +5,95 @@
|
| * found in the LICENSE file.
|
| */
|
|
|
| +#include "SkDiscardableMemory.h"
|
| #include "SkDiscardableMemoryPool.h"
|
| #include "SkOnce.h"
|
| +#include "SkTInternalLList.h"
|
| +#include "SkThread.h"
|
|
|
| // Note:
|
| // A PoolDiscardableMemory is memory that is counted in a pool.
|
| // A DiscardableMemoryPool is a pool of PoolDiscardableMemorys.
|
|
|
| +namespace {
|
| +
|
| +class PoolDiscardableMemory;
|
| +
|
| /**
|
| - * A SkPoolDiscardableMemory is a SkDiscardableMemory that relies on
|
| - * a SkDiscardableMemoryPool object to manage the memory.
|
| + * This non-global pool can be used for unit tests to verify that the
|
| + * pool works.
|
| */
|
| -class SkPoolDiscardableMemory : public SkDiscardableMemory {
|
| +class DiscardableMemoryPool : public SkDiscardableMemoryPool {
|
| public:
|
| - SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool,
|
| + /**
|
| + * Without mutex, will be not be thread safe.
|
| + */
|
| + DiscardableMemoryPool(size_t budget, SkBaseMutex* mutex = NULL);
|
| + virtual ~DiscardableMemoryPool();
|
| +
|
| + virtual SkDiscardableMemory* create(size_t bytes) SK_OVERRIDE;
|
| +
|
| + virtual size_t getRAMUsed() SK_OVERRIDE;
|
| + virtual void setRAMBudget(size_t budget) SK_OVERRIDE;
|
| + virtual size_t getRAMBudget() SK_OVERRIDE { return fBudget; }
|
| +
|
| + /** purges all unlocked DMs */
|
| + virtual void dumpPool() SK_OVERRIDE;
|
| +
|
| + #if SK_LAZY_CACHE_STATS // Defined in SkDiscardableMemoryPool.h
|
| + virtual int getCacheHits() SK_OVERRIDE { return fCacheHits; }
|
| + virtual int getCacheMisses() SK_OVERRIDE { return fCacheMisses; }
|
| + virtual void resetCacheHitsAndMisses() SK_OVERRIDE {
|
| + fCacheHits = fCacheMisses = 0;
|
| + }
|
| + int fCacheHits;
|
| + int fCacheMisses;
|
| + #endif // SK_LAZY_CACHE_STATS
|
| +
|
| +private:
|
| + SkBaseMutex* fMutex;
|
| + size_t fBudget;
|
| + size_t fUsed;
|
| + SkTInternalLList<PoolDiscardableMemory> fList;
|
| +
|
| + /** Function called to free memory if needed */
|
| + void dumpDownTo(size_t budget);
|
| + /** called by DiscardableMemoryPool upon destruction */
|
| + void free(PoolDiscardableMemory* dm);
|
| + /** called by DiscardableMemoryPool::lock() */
|
| + bool lock(PoolDiscardableMemory* dm);
|
| + /** called by DiscardableMemoryPool::unlock() */
|
| + void unlock(PoolDiscardableMemory* dm);
|
| +
|
| + friend class PoolDiscardableMemory;
|
| +
|
| + typedef SkDiscardableMemory::Factory INHERITED;
|
| +};
|
| +
|
| +/**
|
| + * A PoolDiscardableMemory is a SkDiscardableMemory that relies on
|
| + * a DiscardableMemoryPool object to manage the memory.
|
| + */
|
| +class PoolDiscardableMemory : public SkDiscardableMemory {
|
| +public:
|
| + PoolDiscardableMemory(DiscardableMemoryPool* pool,
|
| void* pointer, size_t bytes);
|
| - virtual ~SkPoolDiscardableMemory();
|
| + virtual ~PoolDiscardableMemory();
|
| virtual bool lock() SK_OVERRIDE;
|
| virtual void* data() SK_OVERRIDE;
|
| virtual void unlock() SK_OVERRIDE;
|
| - friend class SkDiscardableMemoryPool;
|
| + friend class DiscardableMemoryPool;
|
| private:
|
| - SK_DECLARE_INTERNAL_LLIST_INTERFACE(SkPoolDiscardableMemory);
|
| - SkDiscardableMemoryPool* const fPool;
|
| - bool fLocked;
|
| - void* fPointer;
|
| - const size_t fBytes;
|
| + SK_DECLARE_INTERNAL_LLIST_INTERFACE(PoolDiscardableMemory);
|
| + DiscardableMemoryPool* const fPool;
|
| + bool fLocked;
|
| + void* fPointer;
|
| + const size_t fBytes;
|
| };
|
|
|
| -SkPoolDiscardableMemory::SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool,
|
| - void* pointer,
|
| - size_t bytes)
|
| +PoolDiscardableMemory::PoolDiscardableMemory(DiscardableMemoryPool* pool,
|
| + void* pointer,
|
| + size_t bytes)
|
| : fPool(pool)
|
| , fLocked(true)
|
| , fPointer(pointer)
|
| @@ -46,59 +104,59 @@ SkPoolDiscardableMemory::SkPoolDiscardableMemory(SkDiscardableMemoryPool* pool,
|
| fPool->ref();
|
| }
|
|
|
| -SkPoolDiscardableMemory::~SkPoolDiscardableMemory() {
|
| +PoolDiscardableMemory::~PoolDiscardableMemory() {
|
| SkASSERT(!fLocked); // contract for SkDiscardableMemory
|
| fPool->free(this);
|
| fPool->unref();
|
| }
|
|
|
| -bool SkPoolDiscardableMemory::lock() {
|
| +bool PoolDiscardableMemory::lock() {
|
| SkASSERT(!fLocked); // contract for SkDiscardableMemory
|
| return fPool->lock(this);
|
| }
|
|
|
| -void* SkPoolDiscardableMemory::data() {
|
| +void* PoolDiscardableMemory::data() {
|
| SkASSERT(fLocked); // contract for SkDiscardableMemory
|
| return fPointer;
|
| }
|
|
|
| -void SkPoolDiscardableMemory::unlock() {
|
| +void PoolDiscardableMemory::unlock() {
|
| SkASSERT(fLocked); // contract for SkDiscardableMemory
|
| fPool->unlock(this);
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
|
|
| -SkDiscardableMemoryPool::SkDiscardableMemoryPool(size_t budget,
|
| - SkBaseMutex* mutex)
|
| +DiscardableMemoryPool::DiscardableMemoryPool(size_t budget,
|
| + SkBaseMutex* mutex)
|
| : fMutex(mutex)
|
| , fBudget(budget)
|
| , fUsed(0) {
|
| - #if LAZY_CACHE_STATS
|
| + #if SK_LAZY_CACHE_STATS
|
| fCacheHits = 0;
|
| fCacheMisses = 0;
|
| - #endif // LAZY_CACHE_STATS
|
| + #endif // SK_LAZY_CACHE_STATS
|
| }
|
| -SkDiscardableMemoryPool::~SkDiscardableMemoryPool() {
|
| - // SkPoolDiscardableMemory objects that belong to this pool are
|
| +DiscardableMemoryPool::~DiscardableMemoryPool() {
|
| + // PoolDiscardableMemory objects that belong to this pool are
|
| // always deleted before deleting this pool since each one has a
|
| // ref to the pool.
|
| SkASSERT(fList.isEmpty());
|
| }
|
|
|
| -void SkDiscardableMemoryPool::dumpDownTo(size_t budget) {
|
| +void DiscardableMemoryPool::dumpDownTo(size_t budget) {
|
| // assert((NULL = fMutex) || fMutex->isLocked());
|
| // TODO(halcanary) implement bool fMutex::isLocked().
|
| // WARNING: only call this function after aquiring lock.
|
| if (fUsed <= budget) {
|
| return;
|
| }
|
| - typedef SkTInternalLList<SkPoolDiscardableMemory>::Iter Iter;
|
| + typedef SkTInternalLList<PoolDiscardableMemory>::Iter Iter;
|
| Iter iter;
|
| - SkPoolDiscardableMemory* cur = iter.init(fList, Iter::kTail_IterStart);
|
| + PoolDiscardableMemory* cur = iter.init(fList, Iter::kTail_IterStart);
|
| while ((fUsed > budget) && (NULL != cur)) {
|
| if (!cur->fLocked) {
|
| - SkPoolDiscardableMemory* dm = cur;
|
| + PoolDiscardableMemory* dm = cur;
|
| SkASSERT(dm->fPointer != NULL);
|
| sk_free(dm->fPointer);
|
| dm->fPointer = NULL;
|
| @@ -114,12 +172,12 @@ void SkDiscardableMemoryPool::dumpDownTo(size_t budget) {
|
| }
|
| }
|
|
|
| -SkDiscardableMemory* SkDiscardableMemoryPool::create(size_t bytes) {
|
| +SkDiscardableMemory* DiscardableMemoryPool::create(size_t bytes) {
|
| void* addr = sk_malloc_flags(bytes, 0);
|
| if (NULL == addr) {
|
| return NULL;
|
| }
|
| - SkPoolDiscardableMemory* dm = SkNEW_ARGS(SkPoolDiscardableMemory,
|
| + PoolDiscardableMemory* dm = SkNEW_ARGS(PoolDiscardableMemory,
|
| (this, addr, bytes));
|
| SkAutoMutexAcquire autoMutexAcquire(fMutex);
|
| fList.addToHead(dm);
|
| @@ -128,7 +186,7 @@ SkDiscardableMemory* SkDiscardableMemoryPool::create(size_t bytes) {
|
| return dm;
|
| }
|
|
|
| -void SkDiscardableMemoryPool::free(SkPoolDiscardableMemory* dm) {
|
| +void DiscardableMemoryPool::free(PoolDiscardableMemory* dm) {
|
| // This is called by dm's destructor.
|
| if (dm->fPointer != NULL) {
|
| SkAutoMutexAcquire autoMutexAcquire(fMutex);
|
| @@ -142,64 +200,73 @@ void SkDiscardableMemoryPool::free(SkPoolDiscardableMemory* dm) {
|
| }
|
| }
|
|
|
| -bool SkDiscardableMemoryPool::lock(SkPoolDiscardableMemory* dm) {
|
| +bool DiscardableMemoryPool::lock(PoolDiscardableMemory* dm) {
|
| SkASSERT(dm != NULL);
|
| if (NULL == dm->fPointer) {
|
| - #if LAZY_CACHE_STATS
|
| + #if SK_LAZY_CACHE_STATS
|
| SkAutoMutexAcquire autoMutexAcquire(fMutex);
|
| ++fCacheMisses;
|
| - #endif // LAZY_CACHE_STATS
|
| + #endif // SK_LAZY_CACHE_STATS
|
| return false;
|
| }
|
| SkAutoMutexAcquire autoMutexAcquire(fMutex);
|
| if (NULL == dm->fPointer) {
|
| // May have been purged while waiting for lock.
|
| - #if LAZY_CACHE_STATS
|
| + #if SK_LAZY_CACHE_STATS
|
| ++fCacheMisses;
|
| - #endif // LAZY_CACHE_STATS
|
| + #endif // SK_LAZY_CACHE_STATS
|
| return false;
|
| }
|
| dm->fLocked = true;
|
| fList.remove(dm);
|
| fList.addToHead(dm);
|
| - #if LAZY_CACHE_STATS
|
| + #if SK_LAZY_CACHE_STATS
|
| ++fCacheHits;
|
| - #endif // LAZY_CACHE_STATS
|
| + #endif // SK_LAZY_CACHE_STATS
|
| return true;
|
| }
|
|
|
| -void SkDiscardableMemoryPool::unlock(SkPoolDiscardableMemory* dm) {
|
| +void DiscardableMemoryPool::unlock(PoolDiscardableMemory* dm) {
|
| SkASSERT(dm != NULL);
|
| SkAutoMutexAcquire autoMutexAcquire(fMutex);
|
| dm->fLocked = false;
|
| this->dumpDownTo(fBudget);
|
| }
|
|
|
| -size_t SkDiscardableMemoryPool::getRAMUsed() {
|
| +size_t DiscardableMemoryPool::getRAMUsed() {
|
| return fUsed;
|
| }
|
| -void SkDiscardableMemoryPool::setRAMBudget(size_t budget) {
|
| +void DiscardableMemoryPool::setRAMBudget(size_t budget) {
|
| SkAutoMutexAcquire autoMutexAcquire(fMutex);
|
| fBudget = budget;
|
| this->dumpDownTo(fBudget);
|
| }
|
| -void SkDiscardableMemoryPool::dumpPool() {
|
| +void DiscardableMemoryPool::dumpPool() {
|
| SkAutoMutexAcquire autoMutexAcquire(fMutex);
|
| this->dumpDownTo(0);
|
| }
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| SK_DECLARE_STATIC_MUTEX(gMutex);
|
| -static void create_pool(SkDiscardableMemoryPool** pool) {
|
| - SkASSERT(NULL == *pool);
|
| - *pool = SkNEW_ARGS(SkDiscardableMemoryPool,
|
| - (SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE,
|
| - &gMutex));
|
| +SkDiscardableMemoryPool* gPool = NULL;
|
| +void create_global_pool(int) {
|
| + SkASSERT(NULL == gPool);
|
| + gPool = SkDiscardableMemoryPool::Create(
|
| + SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE, &gMutex);
|
| +}
|
| +void cleanup_global_pool() {
|
| + gPool->unref();
|
| }
|
| +} // namespace
|
| +
|
| +SkDiscardableMemoryPool* SkDiscardableMemoryPool::Create(
|
| + size_t size, SkBaseMutex* mutex) {
|
| + return SkNEW_ARGS(DiscardableMemoryPool, (size, mutex));
|
| +}
|
| +
|
| SkDiscardableMemoryPool* SkGetGlobalDiscardableMemoryPool() {
|
| - static SkDiscardableMemoryPool* gPool(NULL);
|
| SK_DECLARE_STATIC_ONCE(create_pool_once);
|
| - SkOnce(&create_pool_once, create_pool, &gPool);
|
| + SkOnce(&create_pool_once, create_global_pool, 0, &cleanup_global_pool);
|
| SkASSERT(NULL != gPool);
|
| return gPool;
|
| }
|
|
|