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