Line data Source code
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 "SkDiscardableMemory.h"
9 : #include "SkDiscardableMemoryPool.h"
10 : #include "SkImageGenerator.h"
11 : #include "SkMalloc.h"
12 : #include "SkMutex.h"
13 : #include "SkOnce.h"
14 : #include "SkTInternalLList.h"
15 :
16 : // Note:
17 : // A PoolDiscardableMemory is memory that is counted in a pool.
18 : // A DiscardableMemoryPool is a pool of PoolDiscardableMemorys.
19 :
20 : namespace {
21 :
22 : class PoolDiscardableMemory;
23 :
24 : /**
25 : * This non-global pool can be used for unit tests to verify that the
26 : * pool works.
27 : */
28 : class DiscardableMemoryPool : public SkDiscardableMemoryPool {
29 : public:
30 : /**
31 : * Without mutex, will be not be thread safe.
32 : */
33 : DiscardableMemoryPool(size_t budget, SkBaseMutex* mutex = nullptr);
34 : ~DiscardableMemoryPool() override;
35 :
36 : SkDiscardableMemory* create(size_t bytes) override;
37 :
38 : size_t getRAMUsed() override;
39 : void setRAMBudget(size_t budget) override;
40 0 : size_t getRAMBudget() override { return fBudget; }
41 :
42 : /** purges all unlocked DMs */
43 : void dumpPool() override;
44 :
45 : #if SK_LAZY_CACHE_STATS // Defined in SkDiscardableMemoryPool.h
46 0 : int getCacheHits() override { return fCacheHits; }
47 0 : int getCacheMisses() override { return fCacheMisses; }
48 0 : void resetCacheHitsAndMisses() override {
49 0 : fCacheHits = fCacheMisses = 0;
50 0 : }
51 : int fCacheHits;
52 : int fCacheMisses;
53 : #endif // SK_LAZY_CACHE_STATS
54 :
55 : private:
56 : SkBaseMutex* fMutex;
57 : size_t fBudget;
58 : size_t fUsed;
59 : SkTInternalLList<PoolDiscardableMemory> fList;
60 :
61 : /** Function called to free memory if needed */
62 : void dumpDownTo(size_t budget);
63 : /** called by DiscardableMemoryPool upon destruction */
64 : void free(PoolDiscardableMemory* dm);
65 : /** called by DiscardableMemoryPool::lock() */
66 : bool lock(PoolDiscardableMemory* dm);
67 : /** called by DiscardableMemoryPool::unlock() */
68 : void unlock(PoolDiscardableMemory* dm);
69 :
70 : friend class PoolDiscardableMemory;
71 :
72 : typedef SkDiscardableMemory::Factory INHERITED;
73 : };
74 :
75 : /**
76 : * A PoolDiscardableMemory is a SkDiscardableMemory that relies on
77 : * a DiscardableMemoryPool object to manage the memory.
78 : */
79 : class PoolDiscardableMemory : public SkDiscardableMemory {
80 : public:
81 : PoolDiscardableMemory(DiscardableMemoryPool* pool,
82 : void* pointer, size_t bytes);
83 : ~PoolDiscardableMemory() override;
84 : bool lock() override;
85 : void* data() override;
86 : void unlock() override;
87 : friend class DiscardableMemoryPool;
88 : private:
89 : SK_DECLARE_INTERNAL_LLIST_INTERFACE(PoolDiscardableMemory);
90 : DiscardableMemoryPool* const fPool;
91 : bool fLocked;
92 : void* fPointer;
93 : const size_t fBytes;
94 : };
95 :
96 0 : PoolDiscardableMemory::PoolDiscardableMemory(DiscardableMemoryPool* pool,
97 : void* pointer,
98 0 : size_t bytes)
99 : : fPool(pool)
100 : , fLocked(true)
101 : , fPointer(pointer)
102 0 : , fBytes(bytes) {
103 0 : SkASSERT(fPool != nullptr);
104 0 : SkASSERT(fPointer != nullptr);
105 0 : SkASSERT(fBytes > 0);
106 0 : fPool->ref();
107 0 : }
108 :
109 0 : PoolDiscardableMemory::~PoolDiscardableMemory() {
110 0 : SkASSERT(!fLocked); // contract for SkDiscardableMemory
111 0 : fPool->free(this);
112 0 : fPool->unref();
113 0 : }
114 :
115 0 : bool PoolDiscardableMemory::lock() {
116 0 : SkASSERT(!fLocked); // contract for SkDiscardableMemory
117 0 : return fPool->lock(this);
118 : }
119 :
120 0 : void* PoolDiscardableMemory::data() {
121 0 : SkASSERT(fLocked); // contract for SkDiscardableMemory
122 0 : return fPointer;
123 : }
124 :
125 0 : void PoolDiscardableMemory::unlock() {
126 0 : SkASSERT(fLocked); // contract for SkDiscardableMemory
127 0 : fPool->unlock(this);
128 0 : }
129 :
130 : ////////////////////////////////////////////////////////////////////////////////
131 :
132 0 : DiscardableMemoryPool::DiscardableMemoryPool(size_t budget,
133 0 : SkBaseMutex* mutex)
134 : : fMutex(mutex)
135 : , fBudget(budget)
136 0 : , fUsed(0) {
137 : #if SK_LAZY_CACHE_STATS
138 0 : fCacheHits = 0;
139 0 : fCacheMisses = 0;
140 : #endif // SK_LAZY_CACHE_STATS
141 0 : }
142 0 : DiscardableMemoryPool::~DiscardableMemoryPool() {
143 : // PoolDiscardableMemory objects that belong to this pool are
144 : // always deleted before deleting this pool since each one has a
145 : // ref to the pool.
146 0 : SkASSERT(fList.isEmpty());
147 0 : }
148 :
149 0 : void DiscardableMemoryPool::dumpDownTo(size_t budget) {
150 0 : if (fMutex != nullptr) {
151 0 : fMutex->assertHeld();
152 : }
153 0 : if (fUsed <= budget) {
154 0 : return;
155 : }
156 : typedef SkTInternalLList<PoolDiscardableMemory>::Iter Iter;
157 0 : Iter iter;
158 0 : PoolDiscardableMemory* cur = iter.init(fList, Iter::kTail_IterStart);
159 0 : while ((fUsed > budget) && (cur)) {
160 0 : if (!cur->fLocked) {
161 0 : PoolDiscardableMemory* dm = cur;
162 0 : SkASSERT(dm->fPointer != nullptr);
163 0 : sk_free(dm->fPointer);
164 0 : dm->fPointer = nullptr;
165 0 : SkASSERT(fUsed >= dm->fBytes);
166 0 : fUsed -= dm->fBytes;
167 0 : cur = iter.prev();
168 : // Purged DMs are taken out of the list. This saves times
169 : // looking them up. Purged DMs are NOT deleted.
170 0 : fList.remove(dm);
171 : } else {
172 0 : cur = iter.prev();
173 : }
174 : }
175 : }
176 :
177 0 : SkDiscardableMemory* DiscardableMemoryPool::create(size_t bytes) {
178 0 : void* addr = sk_malloc_flags(bytes, 0);
179 0 : if (nullptr == addr) {
180 0 : return nullptr;
181 : }
182 0 : PoolDiscardableMemory* dm = new PoolDiscardableMemory(this, addr, bytes);
183 0 : SkAutoMutexAcquire autoMutexAcquire(fMutex);
184 0 : fList.addToHead(dm);
185 0 : fUsed += bytes;
186 0 : this->dumpDownTo(fBudget);
187 0 : return dm;
188 : }
189 :
190 0 : void DiscardableMemoryPool::free(PoolDiscardableMemory* dm) {
191 0 : SkAutoMutexAcquire autoMutexAcquire(fMutex);
192 : // This is called by dm's destructor.
193 0 : if (dm->fPointer != nullptr) {
194 0 : sk_free(dm->fPointer);
195 0 : dm->fPointer = nullptr;
196 0 : SkASSERT(fUsed >= dm->fBytes);
197 0 : fUsed -= dm->fBytes;
198 0 : fList.remove(dm);
199 : } else {
200 0 : SkASSERT(!fList.isInList(dm));
201 : }
202 0 : }
203 :
204 0 : bool DiscardableMemoryPool::lock(PoolDiscardableMemory* dm) {
205 0 : SkASSERT(dm != nullptr);
206 0 : SkAutoMutexAcquire autoMutexAcquire(fMutex);
207 0 : if (nullptr == dm->fPointer) {
208 : // May have been purged while waiting for lock.
209 : #if SK_LAZY_CACHE_STATS
210 0 : ++fCacheMisses;
211 : #endif // SK_LAZY_CACHE_STATS
212 0 : return false;
213 : }
214 0 : dm->fLocked = true;
215 0 : fList.remove(dm);
216 0 : fList.addToHead(dm);
217 : #if SK_LAZY_CACHE_STATS
218 0 : ++fCacheHits;
219 : #endif // SK_LAZY_CACHE_STATS
220 0 : return true;
221 : }
222 :
223 0 : void DiscardableMemoryPool::unlock(PoolDiscardableMemory* dm) {
224 0 : SkASSERT(dm != nullptr);
225 0 : SkAutoMutexAcquire autoMutexAcquire(fMutex);
226 0 : dm->fLocked = false;
227 0 : this->dumpDownTo(fBudget);
228 0 : }
229 :
230 0 : size_t DiscardableMemoryPool::getRAMUsed() {
231 0 : return fUsed;
232 : }
233 0 : void DiscardableMemoryPool::setRAMBudget(size_t budget) {
234 0 : SkAutoMutexAcquire autoMutexAcquire(fMutex);
235 0 : fBudget = budget;
236 0 : this->dumpDownTo(fBudget);
237 0 : }
238 0 : void DiscardableMemoryPool::dumpPool() {
239 0 : SkAutoMutexAcquire autoMutexAcquire(fMutex);
240 0 : this->dumpDownTo(0);
241 0 : }
242 :
243 : } // namespace
244 :
245 0 : SkDiscardableMemoryPool* SkDiscardableMemoryPool::Create(size_t size, SkBaseMutex* mutex) {
246 0 : return new DiscardableMemoryPool(size, mutex);
247 : }
248 :
249 : SK_DECLARE_STATIC_MUTEX(gMutex);
250 :
251 0 : SkDiscardableMemoryPool* SkGetGlobalDiscardableMemoryPool() {
252 : static SkOnce once;
253 : static SkDiscardableMemoryPool* global;
254 0 : once([]{
255 0 : global = SkDiscardableMemoryPool::Create(SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE,
256 : &gMutex);
257 0 : });
258 0 : return global;
259 : }
|