/* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "Test.h" #include "GrMemoryPool.h" #include "SkRandom.h" #include "SkTDArray.h" #include "SkTScopedPtr.h" #include "SkInstCnt.h" namespace { // A is the top of an inheritance tree of classes that overload op new and // and delete to use a GrMemoryPool. The objects have values of different types // that can be set and checked. class A { public: A() {}; virtual void setValues(int v) { fChar = static_cast(v); } virtual bool checkValues(int v) { return fChar == static_cast(v); } virtual ~A() {}; void* operator new(size_t size) { if (!gPool.get()) { return ::operator new(size); } else { return gPool->allocate(size); } } void operator delete(void* p) { if (!gPool.get()) { ::operator delete(p); } else { return gPool->release(p); } } SK_DECLARE_INST_COUNT_ROOT(A); static A* Create(SkRandom* r); static void SetAllocator(size_t preallocSize, size_t minAllocSize) { #ifdef SK_ENABLE_INST_COUNT SkASSERT(0 == GetInstanceCount()); #endif GrMemoryPool* pool = new GrMemoryPool(preallocSize, minAllocSize); gPool.reset(pool); } static void ResetAllocator() { #ifdef SK_ENABLE_INST_COUNT SkASSERT(0 == GetInstanceCount()); #endif gPool.reset(NULL); } private: static SkTScopedPtr gPool; char fChar; }; SK_DEFINE_INST_COUNT(A); SkTScopedPtr A::gPool; class B : public A { public: B() {}; virtual void setValues(int v) { fDouble = static_cast(v); this->INHERITED::setValues(v); } virtual bool checkValues(int v) { return fDouble == static_cast(v) && this->INHERITED::checkValues(v); } virtual ~B() {}; private: double fDouble; typedef A INHERITED; }; class C : public A { public: C() {}; virtual void setValues(int v) { fInt64 = static_cast(v); this->INHERITED::setValues(v); } virtual bool checkValues(int v) { return fInt64 == static_cast(v) && this->INHERITED::checkValues(v); } virtual ~C() {}; private: int64_t fInt64; typedef A INHERITED; }; // D derives from C and owns a dynamically created B class D : public C { public: D() { fB = new B(); } virtual void setValues(int v) { fVoidStar = reinterpret_cast(v); this->INHERITED::setValues(v); fB->setValues(v); } virtual bool checkValues(int v) { return fVoidStar == reinterpret_cast(v) && fB->checkValues(v) && this->INHERITED::checkValues(v); } virtual ~D() { delete fB; } private: void* fVoidStar; B* fB; typedef C INHERITED; }; class E : public A { public: E() {} virtual void setValues(int v) { for (size_t i = 0; i < SK_ARRAY_COUNT(fIntArray); ++i) { fIntArray[i] = v; } this->INHERITED::setValues(v); } virtual bool checkValues(int v) { bool ok = true; for (size_t i = 0; ok && i < SK_ARRAY_COUNT(fIntArray); ++i) { if (fIntArray[i] != v) { ok = false; } } return ok && this->INHERITED::checkValues(v); } virtual ~E() {} private: int fIntArray[20]; typedef A INHERITED; }; A* A::Create(SkRandom* r) { switch (r->nextRangeU(0, 4)) { case 0: return new A; case 1: return new B; case 2: return new C; case 3: return new D; case 4: return new E; default: // suppress warning return NULL; } } } struct Rec { A* fInstance; int fValue; }; static void test_memory_pool(skiatest::Reporter* reporter) { // prealloc and min alloc sizes for the pool static const size_t gSizes[][2] = { {0, 0}, {10 * sizeof(A), 20 * sizeof(A)}, {100 * sizeof(A), 100 * sizeof(A)}, {500 * sizeof(A), 500 * sizeof(A)}, {10000 * sizeof(A), 0}, {1, 100 * sizeof(A)}, }; // different percentages of creation vs deletion static const float gCreateFraction[] = {1.f, .95f, 0.75f, .5f}; // number of create/destroys per test static const int kNumIters = 20000; // check that all the values stored in A objects are correct after this // number of iterations static const int kCheckPeriod = 500; SkRandom r; for (size_t s = 0; s < SK_ARRAY_COUNT(gSizes); ++s) { A::SetAllocator(gSizes[s][0], gSizes[s][1]); for (size_t c = 0; c < SK_ARRAY_COUNT(gCreateFraction); ++c) { SkTDArray instanceRecs; for (int i = 0; i < kNumIters; ++i) { float createOrDestroy = r.nextUScalar1(); if (createOrDestroy < gCreateFraction[c] || 0 == instanceRecs.count()) { Rec* rec = instanceRecs.append(); rec->fInstance = A::Create(&r); rec->fValue = static_cast(r.nextU()); rec->fInstance->setValues(rec->fValue); } else { int d = r.nextRangeU(0, instanceRecs.count() - 1); Rec& rec = instanceRecs[d]; REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue)); delete rec.fInstance; instanceRecs.removeShuffle(d); } if (0 == i % kCheckPeriod) { for (int r = 0; r < instanceRecs.count(); ++r) { Rec& rec = instanceRecs[r]; REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue)); } } } for (int i = 0; i < instanceRecs.count(); ++i) { Rec& rec = instanceRecs[i]; REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue)); delete rec.fInstance; } #ifdef SK_DEBUG REPORTER_ASSERT(reporter, !A::GetInstanceCount()); #endif } } } #include "TestClassDef.h" DEFINE_TESTCLASS("GrMemoryPool", GrMemoryPoolClass, test_memory_pool)