Flutter Engine
The Flutter Engine
GrMemoryPoolTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2011 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
10#include "src/base/SkRandom.h"
12#include "tests/Test.h"
13
14#include <array>
15#include <cstddef>
16#include <cstdint>
17#include <memory>
18
19using namespace skia_private;
20
21// A is the top of an inheritance tree of classes that overload op new and
22// and delete to use a GrMemoryPool. The objects have values of different types
23// that can be set and checked.
24class A {
25public:
26 A() {}
27 virtual void setValues(int v) {
28 fChar = static_cast<char>(v & 0xFF);
29 }
30 virtual bool checkValues(int v) {
31 return fChar == static_cast<char>(v & 0xFF);
32 }
33 virtual ~A() {}
34
35 void* operator new(size_t size) {
36 if (!gPool) {
37 return ::operator new(size);
38 } else {
39 return gPool->allocate(size);
40 }
41 }
42
43 void operator delete(void* p) {
44 if (!gPool) {
45 ::operator delete(p);
46 } else {
47 return gPool->release(p);
48 }
49 }
50
51 static A* Create(SkRandom* r);
52
53 static void SetAllocator(size_t preallocSize, size_t minAllocSize) {
54 gPool = GrMemoryPool::Make(preallocSize, minAllocSize);
55 }
56
57 static void ResetAllocator() { gPool.reset(); }
58
59 static void ValidatePool() {
60#ifdef SK_DEBUG
61 gPool->validate();
62#endif
63 }
64
65private:
66 static std::unique_ptr<GrMemoryPool> gPool;
67 char fChar;
68};
69
70std::unique_ptr<GrMemoryPool> A::gPool;
71
72class B : public A {
73public:
74 B() {}
75 void setValues(int v) override {
76 fDouble = static_cast<double>(v);
77 this->INHERITED::setValues(v);
78 }
79 bool checkValues(int v) override {
80 return fDouble == static_cast<double>(v) &&
82 }
83
84private:
85 double fDouble;
86
87 using INHERITED = A;
88};
89
90class C : public A {
91public:
92 C() {}
93 void setValues(int v) override {
94 fInt64 = static_cast<int64_t>(v);
95 this->INHERITED::setValues(v);
96 }
97 bool checkValues(int v) override {
98 return fInt64 == static_cast<int64_t>(v) &&
100 }
101
102private:
103 int64_t fInt64;
104
105 using INHERITED = A;
106};
107
108// D derives from C and owns a dynamically created B
109class D : public C {
110public:
111 D() {
112 fB = new B();
113 }
114 void setValues(int v) override {
115 fVoidStar = reinterpret_cast<void*>(static_cast<intptr_t>(v));
116 this->INHERITED::setValues(v);
117 fB->setValues(v);
118 }
119 bool checkValues(int v) override {
120 return fVoidStar == reinterpret_cast<void*>(static_cast<intptr_t>(v)) &&
121 fB->checkValues(v) &&
122 this->INHERITED::checkValues(v);
123 }
124 ~D() override {
125 delete fB;
126 }
127private:
128 void* fVoidStar;
129 B* fB;
130
131 using INHERITED = C;
132};
133
134class E : public A {
135public:
136 E() {}
137 void setValues(int v) override {
138 for (size_t i = 0; i < std::size(fIntArray); ++i) {
139 fIntArray[i] = v;
140 }
141 this->INHERITED::setValues(v);
142 }
143 bool checkValues(int v) override {
144 bool ok = true;
145 for (size_t i = 0; ok && i < std::size(fIntArray); ++i) {
146 if (fIntArray[i] != v) {
147 ok = false;
148 }
149 }
150 return ok && this->INHERITED::checkValues(v);
151 }
152private:
153 int fIntArray[20];
154
155 using INHERITED = A;
156};
157
159 switch (r->nextRangeU(0, 4)) {
160 case 0:
161 return new A;
162 case 1:
163 return new B;
164 case 2:
165 return new C;
166 case 3:
167 return new D;
168 case 4:
169 return new E;
170 default:
171 // suppress warning
172 return nullptr;
173 }
174}
175
176struct Rec {
179};
180
182 // prealloc and min alloc sizes for the pool
183 static const size_t gSizes[][2] = {
184 {0, 0},
185 {10 * sizeof(A), 20 * sizeof(A)},
186 {100 * sizeof(A), 100 * sizeof(A)},
187 {500 * sizeof(A), 500 * sizeof(A)},
188 {10000 * sizeof(A), 0},
189 {1, 100 * sizeof(A)},
190 };
191
192 // different percentages of creation vs deletion
193 static const float gCreateFraction[] = {1.f, .95f, 0.75f, .5f};
194 // number of create/destroys per test
195 static const int kNumIters = 20000;
196 // check that all the values stored in A objects are correct after this
197 // number of iterations
198 static const int kCheckPeriod = 500;
199
200 SkRandom r;
201 for (size_t s = 0; s < std::size(gSizes); ++s) {
202 A::SetAllocator(gSizes[s][0], gSizes[s][1]);
204 for (size_t c = 0; c < std::size(gCreateFraction); ++c) {
205 SkTDArray<Rec> instanceRecs;
206 for (int i = 0; i < kNumIters; ++i) {
207 float createOrDestroy = r.nextUScalar1();
208 if (createOrDestroy < gCreateFraction[c] ||
209 0 == instanceRecs.size()) {
210 Rec* rec = instanceRecs.append();
211 rec->fInstance = A::Create(&r);
212 rec->fValue = static_cast<int>(r.nextU());
213 rec->fInstance->setValues(rec->fValue);
214 } else {
215 int d = r.nextRangeU(0, instanceRecs.size() - 1);
216 Rec& rec = instanceRecs[d];
218 delete rec.fInstance;
219 instanceRecs.removeShuffle(d);
220 }
221 if (0 == i % kCheckPeriod) {
223 for (Rec& rec : instanceRecs) {
224 REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
225 }
226 }
227 }
228 for (Rec& rec : instanceRecs) {
229 REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
230 delete rec.fInstance;
231 }
232 }
233 }
234}
235
236// GrMemoryPool requires that it's empty at the point of destruction. This helps
237// achieving that by releasing all added memory in the destructor.
239public:
241 }
243 for (void* ptr: fAllocated) {
244 fPool.release(ptr);
245 }
246 }
247 void add(void* ptr) {
248 fAllocated.push_back(ptr);
249 }
250private:
251 GrMemoryPool& fPool;
252 TArray<void*> fAllocated;
253};
254
255DEF_TEST(GrMemoryPoolAPI, reporter) {
256 constexpr size_t kSmallestMinAllocSize = GrMemoryPool::kMinAllocationSize;
257
258 // Allocates memory until pool adds a new block (pool->size() changes).
259 auto allocateMemory = [](GrMemoryPool& pool, AutoPoolReleaser& r) {
260 size_t origPoolSize = pool.size();
261 while (pool.size() == origPoolSize) {
262 r.add(pool.allocate(31));
263 }
264 };
265
266 // Effective prealloc space capacity is >= kMinAllocationSize.
267 {
268 auto pool = GrMemoryPool::Make(0, 0);
269 REPORTER_ASSERT(reporter, pool->preallocSize() == kSmallestMinAllocSize);
270 }
271
272 // Effective block size capacity >= kMinAllocationSize.
273 {
274 auto pool = GrMemoryPool::Make(kSmallestMinAllocSize, kSmallestMinAllocSize / 2);
276
277 allocateMemory(*pool, r);
278 REPORTER_ASSERT(reporter, pool->size() == kSmallestMinAllocSize);
279 }
280
281 // Pool allocates exactly preallocSize on creation.
282 {
283 constexpr size_t kPreallocSize = kSmallestMinAllocSize * 5;
284 auto pool = GrMemoryPool::Make(kPreallocSize, 0);
285 REPORTER_ASSERT(reporter, pool->preallocSize() == kPreallocSize);
286 }
287
288 // Pool allocates exactly minAllocSize when it expands.
289 {
290 constexpr size_t kMinAllocSize = kSmallestMinAllocSize * 7;
291 auto pool = GrMemoryPool::Make(0, kMinAllocSize);
293 REPORTER_ASSERT(reporter, pool->size() == 0);
294
295 allocateMemory(*pool, r);
296 REPORTER_ASSERT(reporter, pool->size() == kMinAllocSize);
297
298 allocateMemory(*pool, r);
299 REPORTER_ASSERT(reporter, pool->size() == 2 * kMinAllocSize);
300 }
301
302 // When asked to allocate amount > minAllocSize, pool allocates larger block
303 // to accommodate all internal structures.
304 {
305 constexpr size_t kMinAllocSize = kSmallestMinAllocSize * 2;
306 auto pool = GrMemoryPool::Make(kSmallestMinAllocSize, kMinAllocSize);
308
309 REPORTER_ASSERT(reporter, pool->size() == 0);
310
311 constexpr size_t hugeSize = 10 * kMinAllocSize;
312 r.add(pool->allocate(hugeSize));
313 REPORTER_ASSERT(reporter, pool->size() > hugeSize);
314
315 // Block size allocated to accommodate huge request doesn't include any extra
316 // space, so next allocation request allocates a new block.
317 size_t hugeBlockSize = pool->size();
318 r.add(pool->allocate(0));
319 REPORTER_ASSERT(reporter, pool->size() == hugeBlockSize + kMinAllocSize);
320 }
321}
AutoreleasePool pool
reporter
Definition: FontMgrTest.cpp:39
DEF_TEST(GrMemoryPool, reporter)
static bool ok(int result)
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
static A * Create(SkRandom *r)
static void ResetAllocator()
virtual void setValues(int v)
static void ValidatePool()
virtual ~A()
virtual bool checkValues(int v)
static void SetAllocator(size_t preallocSize, size_t minAllocSize)
AutoPoolReleaser(GrMemoryPool &pool)
void add(void *ptr)
bool checkValues(int v) override
void setValues(int v) override
void setValues(int v) override
bool checkValues(int v) override
void setValues(int v) override
bool checkValues(int v) override
~D() override
void setValues(int v) override
bool checkValues(int v) override
static std::unique_ptr< GrMemoryPool > Make(size_t preallocSize, size_t minAllocSize)
static constexpr size_t kMinAllocationSize
Definition: GrMemoryPool.h:44
void release(void *p)
uint32_t nextU()
Definition: SkRandom.h:42
SkScalar nextUScalar1()
Definition: SkRandom.h:101
uint32_t nextRangeU(uint32_t min, uint32_t max)
Definition: SkRandom.h:80
int size() const
Definition: SkTDArray.h:138
T * append()
Definition: SkTDArray.h:191
void removeShuffle(int index)
Definition: SkTDArray.h:214
#define C(TEST_CATEGORY)
Definition: colrv1.cpp:248
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
struct MyStruct s
#define B
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