Flutter Engine
The Flutter Engine
SkDiscardableMemoryPool.cpp
Go to the documentation of this file.
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
14
15using namespace skia_private;
16
17// Note:
18// A PoolDiscardableMemory is memory that is counted in a pool.
19// A DiscardableMemoryPool is a pool of PoolDiscardableMemorys.
20
21namespace {
22
23class PoolDiscardableMemory;
24
25/**
26 * This non-global pool can be used for unit tests to verify that the
27 * pool works.
28 */
29class DiscardableMemoryPool : public SkDiscardableMemoryPool {
30public:
31 DiscardableMemoryPool(size_t budget);
32 ~DiscardableMemoryPool() override;
33
34 std::unique_ptr<SkDiscardableMemory> make(size_t bytes);
35 SkDiscardableMemory* create(size_t bytes) override {
36 return this->make(bytes).release(); // TODO: change API
37 }
38
39 size_t getRAMUsed() override;
40 void setRAMBudget(size_t budget) override;
41 size_t getRAMBudget() override { return fBudget; }
42
43 /** purges all unlocked DMs */
44 void dumpPool() override;
45
46 #if SK_LAZY_CACHE_STATS // Defined in SkDiscardableMemoryPool.h
47 int getCacheHits() override { return fCacheHits; }
48 int getCacheMisses() override { return fCacheMisses; }
49 void resetCacheHitsAndMisses() override {
50 fCacheHits = fCacheMisses = 0;
51 }
52 int fCacheHits;
53 int fCacheMisses;
54 #endif // SK_LAZY_CACHE_STATS
55
56private:
57 SkMutex fMutex;
58 size_t fBudget;
59 size_t fUsed;
61
62 /** Function called to free memory if needed */
63 void dumpDownTo(size_t budget);
64 /** called by DiscardableMemoryPool upon destruction */
65 void removeFromPool(PoolDiscardableMemory* dm);
66 /** called by DiscardableMemoryPool::lock() */
67 bool lock(PoolDiscardableMemory* dm);
68 /** called by DiscardableMemoryPool::unlock() */
69 void unlock(PoolDiscardableMemory* dm);
70
71 friend class PoolDiscardableMemory;
72
74};
75
76/**
77 * A PoolDiscardableMemory is a SkDiscardableMemory that relies on
78 * a DiscardableMemoryPool object to manage the memory.
79 */
80class PoolDiscardableMemory : public SkDiscardableMemory {
81public:
82 PoolDiscardableMemory(sk_sp<DiscardableMemoryPool> pool, UniqueVoidPtr pointer, size_t bytes);
83 ~PoolDiscardableMemory() override;
84 bool lock() override;
85 void* data() override;
86 void unlock() override;
87 friend class DiscardableMemoryPool;
88private:
89 SK_DECLARE_INTERNAL_LLIST_INTERFACE(PoolDiscardableMemory);
91 bool fLocked;
92 UniqueVoidPtr fPointer;
93 const size_t fBytes;
94};
95
96PoolDiscardableMemory::PoolDiscardableMemory(sk_sp<DiscardableMemoryPool> pool,
97 UniqueVoidPtr pointer,
98 size_t bytes)
99 : fPool(std::move(pool)), fLocked(true), fPointer(std::move(pointer)), fBytes(bytes) {
100 SkASSERT(fPool != nullptr);
101 SkASSERT(fPointer != nullptr);
102 SkASSERT(fBytes > 0);
103}
104
105PoolDiscardableMemory::~PoolDiscardableMemory() {
106 SkASSERT(!fLocked); // contract for SkDiscardableMemory
107 fPool->removeFromPool(this);
108}
109
110bool PoolDiscardableMemory::lock() {
111 SkASSERT(!fLocked); // contract for SkDiscardableMemory
112 return fPool->lock(this);
113}
114
116 SkASSERT(fLocked); // contract for SkDiscardableMemory
117 return fPointer.get();
118}
119
120void PoolDiscardableMemory::unlock() {
121 SkASSERT(fLocked); // contract for SkDiscardableMemory
122 fPool->unlock(this);
123}
124
125////////////////////////////////////////////////////////////////////////////////
126
127DiscardableMemoryPool::DiscardableMemoryPool(size_t budget)
128 : fBudget(budget)
129 , fUsed(0) {
130 #if SK_LAZY_CACHE_STATS
131 fCacheHits = 0;
132 fCacheMisses = 0;
133 #endif // SK_LAZY_CACHE_STATS
134}
135DiscardableMemoryPool::~DiscardableMemoryPool() {
136 // PoolDiscardableMemory objects that belong to this pool are
137 // always deleted before deleting this pool since each one has a
138 // ref to the pool.
139 SkASSERT(fList.isEmpty());
140}
141
142void DiscardableMemoryPool::dumpDownTo(size_t budget) {
143 fMutex.assertHeld();
144 if (fUsed <= budget) {
145 return;
146 }
148 Iter iter;
149 PoolDiscardableMemory* cur = iter.init(fList, Iter::kTail_IterStart);
150 while ((fUsed > budget) && (cur)) {
151 if (!cur->fLocked) {
152 PoolDiscardableMemory* dm = cur;
153 SkASSERT(dm->fPointer != nullptr);
154 dm->fPointer = nullptr;
155 SkASSERT(fUsed >= dm->fBytes);
156 fUsed -= dm->fBytes;
157 cur = iter.prev();
158 // Purged DMs are taken out of the list. This saves times
159 // looking them up. Purged DMs are NOT deleted.
160 fList.remove(dm);
161 } else {
162 cur = iter.prev();
163 }
164 }
165}
166
167std::unique_ptr<SkDiscardableMemory> DiscardableMemoryPool::make(size_t bytes) {
169 if (nullptr == addr) {
170 return nullptr;
171 }
172 auto dm = std::make_unique<PoolDiscardableMemory>(sk_ref_sp(this), std::move(addr), bytes);
173 SkAutoMutexExclusive autoMutexAcquire(fMutex);
174 fList.addToHead(dm.get());
175 fUsed += bytes;
176 this->dumpDownTo(fBudget);
177 return dm;
178}
179
180void DiscardableMemoryPool::removeFromPool(PoolDiscardableMemory* dm) {
181 SkAutoMutexExclusive autoMutexAcquire(fMutex);
182 // This is called by dm's destructor.
183 if (dm->fPointer != nullptr) {
184 SkASSERT(fUsed >= dm->fBytes);
185 fUsed -= dm->fBytes;
186 fList.remove(dm);
187 } else {
188 SkASSERT(!fList.isInList(dm));
189 }
190}
191
192bool DiscardableMemoryPool::lock(PoolDiscardableMemory* dm) {
193 SkASSERT(dm != nullptr);
194 SkAutoMutexExclusive autoMutexAcquire(fMutex);
195 if (nullptr == dm->fPointer) {
196 // May have been purged while waiting for lock.
197 #if SK_LAZY_CACHE_STATS
198 ++fCacheMisses;
199 #endif // SK_LAZY_CACHE_STATS
200 return false;
201 }
202 dm->fLocked = true;
203 fList.remove(dm);
204 fList.addToHead(dm);
205 #if SK_LAZY_CACHE_STATS
206 ++fCacheHits;
207 #endif // SK_LAZY_CACHE_STATS
208 return true;
209}
210
211void DiscardableMemoryPool::unlock(PoolDiscardableMemory* dm) {
212 SkASSERT(dm != nullptr);
213 SkAutoMutexExclusive autoMutexAcquire(fMutex);
214 dm->fLocked = false;
215 this->dumpDownTo(fBudget);
216}
217
218size_t DiscardableMemoryPool::getRAMUsed() {
219 return fUsed;
220}
221void DiscardableMemoryPool::setRAMBudget(size_t budget) {
222 SkAutoMutexExclusive autoMutexAcquire(fMutex);
223 fBudget = budget;
224 this->dumpDownTo(fBudget);
225}
226void DiscardableMemoryPool::dumpPool() {
227 SkAutoMutexExclusive autoMutexAcquire(fMutex);
228 this->dumpDownTo(0);
229}
230
231} // namespace
232
234 return sk_make_sp<DiscardableMemoryPool>(size);
235}
236
238 // Intentionally leak this global pool.
239 static SkDiscardableMemoryPool* global =
240 new DiscardableMemoryPool(SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE);
241 return global;
242}
AutoreleasePool pool
#define SkASSERT(cond)
Definition: SkAssert.h:116
SkDiscardableMemoryPool * SkGetGlobalDiscardableMemoryPool()
#define SK_DEFAULT_GLOBAL_DISCARDABLE_MEMORY_POOL_SIZE
static void * sk_malloc_canfail(size_t size)
Definition: SkMalloc.h:93
#define INHERITED(method,...)
Definition: SkRecorder.cpp:128
sk_sp< T > sk_ref_sp(T *obj)
Definition: SkRefCnt.h:381
#define SK_DECLARE_INTERNAL_LLIST_INTERFACE(ClassName)
virtual void dumpPool()=0
static sk_sp< SkDiscardableMemoryPool > Make(size_t size)
virtual size_t getRAMUsed()=0
virtual void setRAMBudget(size_t budget)=0
virtual size_t getRAMBudget()=0
virtual SkDiscardableMemory * create(size_t bytes)=0
virtual bool lock()=0
virtual void unlock()=0
virtual void * data()=0
T * init(const SkTInternalLList &list, IterStart startLoc)
SKSHAPER_API sk_sp< Factory > Factory()
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
std::unique_ptr< void, SkOverloadedFunctionObject< void(void *), sk_free > > UniqueVoidPtr
Definition: SkTemplates.h:431
static void make(SkBitmap *bitmap, SkColorType colorType, SkAlphaType alphaType, sk_sp< SkColorSpace > colorSpace)
Definition: encode_srgb.cpp:35
Definition: ref_ptr.h:256
std::shared_ptr< const fml::Mapping > data
Definition: texture_gles.cc:63