2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "SkDiscardableMemory.h"
9 #include "SkDiscardableMemoryPool.h"
10 #include "SkImageGenerator.h"
11 #include "SkLazyPtr.h"
12 #include "SkTInternalLList.h"
16 // A PoolDiscardableMemory is memory that is counted in a pool.
17 // A DiscardableMemoryPool is a pool of PoolDiscardableMemorys.
21 class PoolDiscardableMemory;
24 * This non-global pool can be used for unit tests to verify that the
27 class DiscardableMemoryPool : public SkDiscardableMemoryPool {
30 * Without mutex, will be not be thread safe.
32 DiscardableMemoryPool(size_t budget, SkBaseMutex* mutex = NULL);
33 virtual ~DiscardableMemoryPool();
35 virtual SkDiscardableMemory* create(size_t bytes) SK_OVERRIDE;
37 virtual size_t getRAMUsed() SK_OVERRIDE;
38 virtual void setRAMBudget(size_t budget) SK_OVERRIDE;
39 virtual size_t getRAMBudget() SK_OVERRIDE { return fBudget; }
41 /** purges all unlocked DMs */
42 virtual void dumpPool() SK_OVERRIDE;
44 #if SK_LAZY_CACHE_STATS // Defined in SkDiscardableMemoryPool.h
45 virtual int getCacheHits() SK_OVERRIDE { return fCacheHits; }
46 virtual int getCacheMisses() SK_OVERRIDE { return fCacheMisses; }
47 virtual void resetCacheHitsAndMisses() SK_OVERRIDE {
48 fCacheHits = fCacheMisses = 0;
52 #endif // SK_LAZY_CACHE_STATS
58 SkTInternalLList<PoolDiscardableMemory> fList;
60 /** Function called to free memory if needed */
61 void dumpDownTo(size_t budget);
62 /** called by DiscardableMemoryPool upon destruction */
63 void free(PoolDiscardableMemory* dm);
64 /** called by DiscardableMemoryPool::lock() */
65 bool lock(PoolDiscardableMemory* dm);
66 /** called by DiscardableMemoryPool::unlock() */
67 void unlock(PoolDiscardableMemory* dm);
69 friend class PoolDiscardableMemory;
71 typedef SkDiscardableMemory::Factory INHERITED;
75 * A PoolDiscardableMemory is a SkDiscardableMemory that relies on
76 * a DiscardableMemoryPool object to manage the memory.
78 class PoolDiscardableMemory : public SkDiscardableMemory {
80 PoolDiscardableMemory(DiscardableMemoryPool* pool,
81 void* pointer, size_t bytes);
82 virtual ~PoolDiscardableMemory();
83 virtual bool lock() SK_OVERRIDE;
84 virtual void* data() SK_OVERRIDE;
85 virtual void unlock() SK_OVERRIDE;
86 friend class DiscardableMemoryPool;
88 SK_DECLARE_INTERNAL_LLIST_INTERFACE(PoolDiscardableMemory);
89 DiscardableMemoryPool* const fPool;
95 PoolDiscardableMemory::PoolDiscardableMemory(DiscardableMemoryPool* pool,
102 SkASSERT(fPool != NULL);
103 SkASSERT(fPointer != NULL);
104 SkASSERT(fBytes > 0);
108 PoolDiscardableMemory::~PoolDiscardableMemory() {
109 SkASSERT(!fLocked); // contract for SkDiscardableMemory
114 bool PoolDiscardableMemory::lock() {
115 SkASSERT(!fLocked); // contract for SkDiscardableMemory
116 return fPool->lock(this);
119 void* PoolDiscardableMemory::data() {
120 SkASSERT(fLocked); // contract for SkDiscardableMemory
124 void PoolDiscardableMemory::unlock() {
125 SkASSERT(fLocked); // contract for SkDiscardableMemory
129 ////////////////////////////////////////////////////////////////////////////////
131 DiscardableMemoryPool::DiscardableMemoryPool(size_t budget,
136 #if SK_LAZY_CACHE_STATS
139 #endif // SK_LAZY_CACHE_STATS
141 DiscardableMemoryPool::~DiscardableMemoryPool() {
142 // PoolDiscardableMemory objects that belong to this pool are
143 // always deleted before deleting this pool since each one has a
145 SkASSERT(fList.isEmpty());
148 void DiscardableMemoryPool::dumpDownTo(size_t budget) {
149 if (fMutex != NULL) {
150 fMutex->assertHeld();
152 if (fUsed <= budget) {
155 typedef SkTInternalLList<PoolDiscardableMemory>::Iter Iter;
157 PoolDiscardableMemory* cur = iter.init(fList, Iter::kTail_IterStart);
158 while ((fUsed > budget) && (NULL != cur)) {
160 PoolDiscardableMemory* dm = cur;
161 SkASSERT(dm->fPointer != NULL);
162 sk_free(dm->fPointer);
164 SkASSERT(fUsed >= dm->fBytes);
167 // Purged DMs are taken out of the list. This saves times
168 // looking them up. Purged DMs are NOT deleted.
176 SkDiscardableMemory* DiscardableMemoryPool::create(size_t bytes) {
177 void* addr = sk_malloc_flags(bytes, 0);
181 PoolDiscardableMemory* dm = SkNEW_ARGS(PoolDiscardableMemory,
182 (this, addr, bytes));
183 SkAutoMutexAcquire autoMutexAcquire(fMutex);
186 this->dumpDownTo(fBudget);
190 void DiscardableMemoryPool::free(PoolDiscardableMemory* dm) {
191 // This is called by dm's destructor.
192 if (dm->fPointer != NULL) {
193 SkAutoMutexAcquire autoMutexAcquire(fMutex);
194 sk_free(dm->fPointer);
196 SkASSERT(fUsed >= dm->fBytes);
200 SkASSERT(!fList.isInList(dm));
204 bool DiscardableMemoryPool::lock(PoolDiscardableMemory* dm) {
205 SkASSERT(dm != NULL);
206 if (NULL == dm->fPointer) {
207 #if SK_LAZY_CACHE_STATS
208 SkAutoMutexAcquire autoMutexAcquire(fMutex);
210 #endif // SK_LAZY_CACHE_STATS
213 SkAutoMutexAcquire autoMutexAcquire(fMutex);
214 if (NULL == dm->fPointer) {
215 // May have been purged while waiting for lock.
216 #if SK_LAZY_CACHE_STATS
218 #endif // SK_LAZY_CACHE_STATS
224 #if SK_LAZY_CACHE_STATS
226 #endif // SK_LAZY_CACHE_STATS
230 void DiscardableMemoryPool::unlock(PoolDiscardableMemory* dm) {
231 SkASSERT(dm != NULL);
232 SkAutoMutexAcquire autoMutexAcquire(fMutex);
234 this->dumpDownTo(fBudget);
237 size_t DiscardableMemoryPool::getRAMUsed() {
240 void DiscardableMemoryPool::setRAMBudget(size_t budget) {
241 SkAutoMutexAcquire autoMutexAcquire(fMutex);
243 this->dumpDownTo(fBudget);
245 void DiscardableMemoryPool::dumpPool() {
246 SkAutoMutexAcquire autoMutexAcquire(fMutex);
250 ////////////////////////////////////////////////////////////////////////////////
251 SK_DECLARE_STATIC_MUTEX(gMutex);
252 SkDiscardableMemoryPool* create_global_pool() {
253 return SkDiscardableMemoryPool::Create(SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE,
259 SkDiscardableMemoryPool* SkDiscardableMemoryPool::Create(size_t size, SkBaseMutex* mutex) {
260 return SkNEW_ARGS(DiscardableMemoryPool, (size, mutex));
263 SkDiscardableMemoryPool* SkGetGlobalDiscardableMemoryPool() {
264 SK_DECLARE_STATIC_LAZY_PTR(SkDiscardableMemoryPool, global, create_global_pool);
268 // defined in SkImageGenerator.h
269 void SkPurgeGlobalDiscardableMemoryPool() {
270 SkGetGlobalDiscardableMemoryPool()->dumpPool();
272 ////////////////////////////////////////////////////////////////////////////////