SkDiscardableMemoryPool to abstract class
Motivation - we want to keep our public headers small.
R=scroggo@google.com, reed@google.com
Author: halcanary@google.com
Review URL: https://codereview.chromium.org/223403012
git-svn-id: http://skia.googlecode.com/svn/trunk@14063 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gm/factory.cpp b/gm/factory.cpp
index efd817d..29cf7ea 100644
--- a/gm/factory.cpp
+++ b/gm/factory.cpp
@@ -35,7 +35,7 @@
// Create a cache which will boot the pixels out anytime the
// bitmap is unlocked.
SkAutoTUnref<SkDiscardableMemoryPool> pool(
- SkNEW_ARGS(SkDiscardableMemoryPool, (1)));
+ SkDiscardableMemoryPool::Create(1));
SkAssertResult(SkInstallDiscardablePixelRef(
SkDecodingImageGenerator::Create(
data, SkDecodingImageGenerator::Options()),
diff --git a/src/lazy/SkDiscardableMemoryPool.cpp b/src/lazy/SkDiscardableMemoryPool.cpp
index 4709709..9612169 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 @@
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 @@
}
}
-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 @@
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 @@
}
}
-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;
}
diff --git a/src/lazy/SkDiscardableMemoryPool.h b/src/lazy/SkDiscardableMemoryPool.h
index 61bad70..d141507 100644
--- a/src/lazy/SkDiscardableMemoryPool.h
+++ b/src/lazy/SkDiscardableMemoryPool.h
@@ -9,60 +9,50 @@
#define SkDiscardableMemoryPool_DEFINED
#include "SkDiscardableMemory.h"
-#include "SkTInternalLList.h"
-#include "SkThread.h"
-class SkPoolDiscardableMemory;
-
-#ifdef SK_DEBUG
- #define LAZY_CACHE_STATS 1
-#elif !defined(LAZY_CACHE_STATS)
- #define LAZY_CACHE_STATS 0
+#ifndef SK_LAZY_CACHE_STATS
+ #ifdef SK_DEBUG
+ #define SK_LAZY_CACHE_STATS 1
+ #else
+ #define SK_LAZY_CACHE_STATS 0
+ #endif
#endif
/**
- * This non-global pool can be used for unit tests to verify that the
- * pool works.
+ * An implementation of Discardable Memory that manages a fixed-size
+ * budget of memory. When the allocated memory exceeds this size,
+ * unlocked blocks of memory are purged. If all memory is locked, it
+ * can exceed the memory-use budget.
*/
class SkDiscardableMemoryPool : public SkDiscardableMemory::Factory {
public:
- /**
- * Without mutex, will be not be thread safe.
- */
- SkDiscardableMemoryPool(size_t budget, SkBaseMutex* mutex = NULL);
- virtual ~SkDiscardableMemoryPool();
+ virtual ~SkDiscardableMemoryPool() { }
- virtual SkDiscardableMemory* create(size_t bytes) SK_OVERRIDE;
-
- size_t getRAMUsed();
- void setRAMBudget(size_t budget);
+ virtual size_t getRAMUsed() = 0;
+ virtual void setRAMBudget(size_t budget) = 0;
+ virtual size_t getRAMBudget() = 0;
/** purges all unlocked DMs */
- void dumpPool();
+ virtual void dumpPool() = 0;
- #if LAZY_CACHE_STATS
- int fCacheHits;
- int fCacheMisses;
- #endif // LAZY_CACHE_STATS
+ #if SK_LAZY_CACHE_STATS
+ /**
+ * These two values are a count of the number of successful and
+ * failed calls to SkDiscardableMemory::lock() for all DMs managed
+ * by this pool.
+ */
+ virtual int getCacheHits() = 0;
+ virtual int getCacheMisses() = 0;
+ virtual void resetCacheHitsAndMisses() = 0;
+ #endif
-private:
- SkBaseMutex* fMutex;
- size_t fBudget;
- size_t fUsed;
- SkTInternalLList<SkPoolDiscardableMemory> fList;
-
- /** Function called to free memory if needed */
- void dumpDownTo(size_t budget);
- /** called by SkDiscardableMemoryPool upon destruction */
- void free(SkPoolDiscardableMemory* dm);
- /** called by SkDiscardableMemoryPool::lock() */
- bool lock(SkPoolDiscardableMemory* dm);
- /** called by SkDiscardableMemoryPool::unlock() */
- void unlock(SkPoolDiscardableMemory* dm);
-
- friend class SkPoolDiscardableMemory;
-
- typedef SkDiscardableMemory::Factory INHERITED;
+ /**
+ * This non-global pool can be used for unit tests to verify that
+ * the pool works.
+ * Without mutex, will be not be thread safe.
+ */
+ static SkDiscardableMemoryPool* Create(
+ size_t size, SkBaseMutex* mutex = NULL);
};
/**
diff --git a/tests/CachedDecodingPixelRefTest.cpp b/tests/CachedDecodingPixelRefTest.cpp
index f9841239..b2ecb0f 100644
--- a/tests/CachedDecodingPixelRefTest.cpp
+++ b/tests/CachedDecodingPixelRefTest.cpp
@@ -303,7 +303,7 @@
reporter, kSkDiscardable_PixelRefType, NULL);
SkAutoTUnref<SkDiscardableMemoryPool> pool(
- SkNEW_ARGS(SkDiscardableMemoryPool, (1, NULL)));
+ SkDiscardableMemoryPool::Create(1, NULL));
REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
check_pixelref(TestImageGenerator::kFailGetPixels_TestType,
reporter, kSkDiscardable_PixelRefType, pool);
diff --git a/tests/DiscardableMemoryPoolTest.cpp b/tests/DiscardableMemoryPoolTest.cpp
index dc927bd..e0145bc 100644
--- a/tests/DiscardableMemoryPoolTest.cpp
+++ b/tests/DiscardableMemoryPoolTest.cpp
@@ -10,7 +10,7 @@
DEF_TEST(DiscardableMemoryPool, reporter) {
SkAutoTUnref<SkDiscardableMemoryPool> pool(
- SkNEW_ARGS(SkDiscardableMemoryPool, (1, NULL)));
+ SkDiscardableMemoryPool::Create(1, NULL));
pool->setRAMBudget(3);
REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
diff --git a/tests/DrawBitmapRectTest.cpp b/tests/DrawBitmapRectTest.cpp
index f51bf53..f778480 100644
--- a/tests/DrawBitmapRectTest.cpp
+++ b/tests/DrawBitmapRectTest.cpp
@@ -43,8 +43,8 @@
//
static void test_faulty_pixelref(skiatest::Reporter* reporter) {
// need a cache, but don't expect to use it, so the budget is not critical
- SkAutoTUnref<SkDiscardableMemoryPool> pool(SkNEW_ARGS(SkDiscardableMemoryPool,
- (10 * 1000, NULL)));
+ SkAutoTUnref<SkDiscardableMemoryPool> pool(
+ SkDiscardableMemoryPool::Create(10 * 1000, NULL));
SkBitmap bm;
bool installSuccess = SkInstallDiscardablePixelRef(SkNEW(FailureImageGenerator), &bm, pool);
REPORTER_ASSERT(reporter, installSuccess);
diff --git a/tests/ImageCacheTest.cpp b/tests/ImageCacheTest.cpp
index 43a5e70..92d0b51 100644
--- a/tests/ImageCacheTest.cpp
+++ b/tests/ImageCacheTest.cpp
@@ -81,6 +81,7 @@
static SkDiscardableMemoryPool* gPool;
static SkDiscardableMemory* pool_factory(size_t bytes) {
+ SkASSERT(gPool);
return gPool->create(bytes);
}
@@ -92,8 +93,9 @@
test_cache(reporter, cache, true);
}
{
- SkDiscardableMemoryPool pool(defLimit);
- gPool = &pool;
+ SkAutoTUnref<SkDiscardableMemoryPool> pool(
+ SkDiscardableMemoryPool::Create(defLimit, NULL));
+ gPool = pool.get();
SkScaledImageCache cache(pool_factory);
test_cache(reporter, cache, true);
}
diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp
index 5829e18..4952571 100644
--- a/tools/bench_pictures_main.cpp
+++ b/tools/bench_pictures_main.cpp
@@ -46,8 +46,8 @@
DEFINE_string(timers, "c", "[wcgWC]*: Display wall, cpu, gpu, truncated wall or truncated cpu time"
" for each picture.");
DEFINE_bool(trackDeferredCaching, false, "Only meaningful with --deferImageDecoding and "
- "LAZY_CACHE_STATS set to true. Report percentage of cache hits when using deferred "
- "image decoding.");
+ "SK_LAZY_CACHE_STATS set to true. Report percentage of cache hits when using "
+ "deferred image decoding.");
static char const * const gFilterTypes[] = {
"paint",
@@ -142,7 +142,7 @@
return result;
}
-#if LAZY_CACHE_STATS
+#if SK_LAZY_CACHE_STATS
static int32_t gTotalCacheHits;
static int32_t gTotalCacheMisses;
#endif
@@ -192,11 +192,11 @@
benchmark.run(picture);
-#if LAZY_CACHE_STATS
+#if SK_LAZY_CACHE_STATS
if (FLAGS_trackDeferredCaching) {
- int32_t cacheHits = pool->fCacheHits;
- int32_t cacheMisses = pool->fCacheMisses;
- pool->fCacheHits = pool->fCacheMisses = 0;
+ int cacheHits = pool->getCacheHits();
+ int cacheMisses = pool->getCacheMisses();
+ pool->resetCacheHitsAndMisses();
SkString hitString;
hitString.printf("Cache hit rate: %f\n", (double) cacheHits / (cacheHits + cacheMisses));
gLogger.logProgress(hitString);
@@ -435,7 +435,7 @@
gLogger.logError(err);
return 1;
}
-#if LAZY_CACHE_STATS
+#if SK_LAZY_CACHE_STATS
if (FLAGS_trackDeferredCaching) {
SkDebugf("Total cache hit rate: %f\n",
(double) gTotalCacheHits / (gTotalCacheHits + gTotalCacheMisses));