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