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