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 
8 #include "Test.h"
9 // This is a GPU-backend specific test
10 #if SK_SUPPORT_GPU
11 #include "GrMemoryPool.h"
12 #include "SkRandom.h"
13 #include "SkTDArray.h"
14 #include "SkTemplates.h"
15 
16 // A is the top of an inheritance tree of classes that overload op new and
17 // and delete to use a GrMemoryPool. The objects have values of different types
18 // that can be set and checked.
19 class A {
20 public:
A()21     A() {};
setValues(int v)22     virtual void setValues(int v) {
23         fChar = static_cast<char>(v);
24     }
checkValues(int v)25     virtual bool checkValues(int v) {
26         return fChar == static_cast<char>(v);
27     }
~A()28     virtual ~A() {};
29 
operator new(size_t size)30     void* operator new(size_t size) {
31         if (!gPool.get()) {
32             return ::operator new(size);
33         } else {
34             return gPool->allocate(size);
35         }
36     }
37 
operator delete(void * p)38     void operator delete(void* p) {
39         if (!gPool.get()) {
40             ::operator delete(p);
41         } else {
42             return gPool->release(p);
43         }
44     }
45 
46     static A* Create(SkRandom* r);
47 
SetAllocator(size_t preallocSize,size_t minAllocSize)48     static void SetAllocator(size_t preallocSize, size_t minAllocSize) {
49         GrMemoryPool* pool = new GrMemoryPool(preallocSize, minAllocSize);
50         gPool.reset(pool);
51     }
52 
ResetAllocator()53     static void ResetAllocator() {
54         gPool.reset(nullptr);
55     }
56 
57 private:
58     static SkAutoTDelete<GrMemoryPool> gPool;
59     char fChar;
60 };
61 
62 SkAutoTDelete<GrMemoryPool> A::gPool;
63 
64 class B : public A {
65 public:
B()66     B() {};
setValues(int v)67     virtual void setValues(int v) {
68         fDouble = static_cast<double>(v);
69         this->INHERITED::setValues(v);
70     }
checkValues(int v)71     virtual bool checkValues(int v) {
72         return fDouble == static_cast<double>(v) &&
73                this->INHERITED::checkValues(v);
74     }
~B()75     virtual ~B() {};
76 
77 private:
78     double fDouble;
79 
80     typedef A INHERITED;
81 };
82 
83 class C : public A {
84 public:
C()85     C() {};
setValues(int v)86     virtual void setValues(int v) {
87         fInt64 = static_cast<int64_t>(v);
88         this->INHERITED::setValues(v);
89     }
checkValues(int v)90     virtual bool checkValues(int v) {
91         return fInt64 == static_cast<int64_t>(v) &&
92                this->INHERITED::checkValues(v);
93     }
~C()94     virtual ~C() {};
95 
96 private:
97     int64_t fInt64;
98 
99     typedef A INHERITED;
100 };
101 
102 // D derives from C and owns a dynamically created B
103 class D : public C {
104 public:
D()105     D() {
106         fB = new B();
107     }
setValues(int v)108     virtual void setValues(int v) {
109         fVoidStar = reinterpret_cast<void*>(static_cast<intptr_t>(v));
110         this->INHERITED::setValues(v);
111         fB->setValues(v);
112     }
checkValues(int v)113     virtual bool checkValues(int v) {
114         return fVoidStar == reinterpret_cast<void*>(static_cast<intptr_t>(v)) &&
115                fB->checkValues(v) &&
116                this->INHERITED::checkValues(v);
117     }
~D()118     virtual ~D() {
119         delete fB;
120     }
121 private:
122     void*   fVoidStar;
123     B*      fB;
124 
125     typedef C INHERITED;
126 };
127 
128 class E : public A {
129 public:
E()130     E() {}
setValues(int v)131     virtual void setValues(int v) {
132         for (size_t i = 0; i < SK_ARRAY_COUNT(fIntArray); ++i) {
133             fIntArray[i] = v;
134         }
135         this->INHERITED::setValues(v);
136     }
checkValues(int v)137     virtual bool checkValues(int v) {
138         bool ok = true;
139         for (size_t i = 0; ok && i < SK_ARRAY_COUNT(fIntArray); ++i) {
140             if (fIntArray[i] != v) {
141                 ok = false;
142             }
143         }
144         return ok && this->INHERITED::checkValues(v);
145     }
~E()146     virtual ~E() {}
147 private:
148     int   fIntArray[20];
149 
150     typedef A INHERITED;
151 };
152 
Create(SkRandom * r)153 A* A::Create(SkRandom* r) {
154     switch (r->nextRangeU(0, 4)) {
155         case 0:
156             return new A;
157         case 1:
158             return new B;
159         case 2:
160             return new C;
161         case 3:
162             return new D;
163         case 4:
164             return new E;
165         default:
166             // suppress warning
167             return nullptr;
168     }
169 }
170 
171 struct Rec {
172     A* fInstance;
173     int fValue;
174 };
175 
DEF_TEST(GrMemoryPool,reporter)176 DEF_TEST(GrMemoryPool, reporter) {
177     // prealloc and min alloc sizes for the pool
178     static const size_t gSizes[][2] = {
179         {0, 0},
180         {10 * sizeof(A), 20 * sizeof(A)},
181         {100 * sizeof(A), 100 * sizeof(A)},
182         {500 * sizeof(A), 500 * sizeof(A)},
183         {10000 * sizeof(A), 0},
184         {1, 100 * sizeof(A)},
185     };
186     // different percentages of creation vs deletion
187     static const float gCreateFraction[] = {1.f, .95f, 0.75f, .5f};
188     // number of create/destroys per test
189     static const int kNumIters = 20000;
190     // check that all the values stored in A objects are correct after this
191     // number of iterations
192     static const int kCheckPeriod = 500;
193 
194     SkRandom r;
195     for (size_t s = 0; s < SK_ARRAY_COUNT(gSizes); ++s) {
196         A::SetAllocator(gSizes[s][0], gSizes[s][1]);
197         for (size_t c = 0; c < SK_ARRAY_COUNT(gCreateFraction); ++c) {
198             SkTDArray<Rec> instanceRecs;
199             for (int i = 0; i < kNumIters; ++i) {
200                 float createOrDestroy = r.nextUScalar1();
201                 if (createOrDestroy < gCreateFraction[c] ||
202                     0 == instanceRecs.count()) {
203                     Rec* rec = instanceRecs.append();
204                     rec->fInstance = A::Create(&r);
205                     rec->fValue = static_cast<int>(r.nextU());
206                     rec->fInstance->setValues(rec->fValue);
207                 } else {
208                     int d = r.nextRangeU(0, instanceRecs.count() - 1);
209                     Rec& rec = instanceRecs[d];
210                     REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
211                     delete rec.fInstance;
212                     instanceRecs.removeShuffle(d);
213                 }
214                 if (0 == i % kCheckPeriod) {
215                     for (int r = 0; r < instanceRecs.count(); ++r) {
216                         Rec& rec = instanceRecs[r];
217                         REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
218                     }
219                 }
220             }
221             for (int i = 0; i < instanceRecs.count(); ++i) {
222                 Rec& rec = instanceRecs[i];
223                 REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue));
224                 delete rec.fInstance;
225             }
226         }
227     }
228 }
229 
230 #endif
231