123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- /*
- * 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 "include/private/SkTArray.h"
- #include "include/private/SkTDArray.h"
- #include "include/private/SkTemplates.h"
- #include "include/utils/SkRandom.h"
- #include "src/gpu/GrMemoryPool.h"
- #include "tests/Test.h"
- // 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<char>(v & 0xFF);
- }
- virtual bool checkValues(int v) {
- return fChar == static_cast<char>(v & 0xFF);
- }
- 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);
- }
- }
- static A* Create(SkRandom* r);
- static void SetAllocator(size_t preallocSize, size_t minAllocSize) {
- GrMemoryPool* pool = new GrMemoryPool(preallocSize, minAllocSize);
- gPool.reset(pool);
- }
- static void ResetAllocator() {
- gPool.reset(nullptr);
- }
- private:
- static std::unique_ptr<GrMemoryPool> gPool;
- char fChar;
- };
- std::unique_ptr<GrMemoryPool> A::gPool;
- class B : public A {
- public:
- B() {}
- virtual void setValues(int v) {
- fDouble = static_cast<double>(v);
- this->INHERITED::setValues(v);
- }
- virtual bool checkValues(int v) {
- return fDouble == static_cast<double>(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<int64_t>(v);
- this->INHERITED::setValues(v);
- }
- virtual bool checkValues(int v) {
- return fInt64 == static_cast<int64_t>(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<void*>(static_cast<intptr_t>(v));
- this->INHERITED::setValues(v);
- fB->setValues(v);
- }
- virtual bool checkValues(int v) {
- return fVoidStar == reinterpret_cast<void*>(static_cast<intptr_t>(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 nullptr;
- }
- }
- struct Rec {
- A* fInstance;
- int fValue;
- };
- DEF_TEST(GrMemoryPool, 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<Rec> 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<int>(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;
- }
- }
- }
- }
- // GrMemoryPool requires that it's empty at the point of destruction. This helps
- // achieving that by releasing all added memory in the destructor.
- class AutoPoolReleaser {
- public:
- AutoPoolReleaser(GrMemoryPool& pool): fPool(pool) {
- }
- ~AutoPoolReleaser() {
- for (void* ptr: fAllocated) {
- fPool.release(ptr);
- }
- }
- void add(void* ptr) {
- fAllocated.push_back(ptr);
- }
- private:
- GrMemoryPool& fPool;
- SkTArray<void*> fAllocated;
- };
- DEF_TEST(GrMemoryPoolAPI, reporter) {
- constexpr size_t kSmallestMinAllocSize = GrMemoryPool::kSmallestMinAllocSize;
- // Allocates memory until pool adds a new block (pool.size() changes).
- auto allocateMemory = [](GrMemoryPool& pool, AutoPoolReleaser& r) {
- size_t origPoolSize = pool.size();
- while (pool.size() == origPoolSize) {
- r.add(pool.allocate(31));
- }
- };
- // Effective prealloc space capacity is >= kSmallestMinAllocSize.
- {
- GrMemoryPool pool(0, 0);
- REPORTER_ASSERT(reporter, pool.preallocSize() == kSmallestMinAllocSize);
- }
- // Effective prealloc space capacity is >= minAllocSize.
- {
- constexpr size_t kMinAllocSize = kSmallestMinAllocSize * 2;
- GrMemoryPool pool(kSmallestMinAllocSize, kMinAllocSize);
- REPORTER_ASSERT(reporter, pool.preallocSize() == kMinAllocSize);
- }
- // Effective block size capacity >= kSmallestMinAllocSize.
- {
- GrMemoryPool pool(kSmallestMinAllocSize, kSmallestMinAllocSize / 2);
- AutoPoolReleaser r(pool);
- allocateMemory(pool, r);
- REPORTER_ASSERT(reporter, pool.size() == kSmallestMinAllocSize);
- }
- // Pool allocates exactly preallocSize on creation.
- {
- constexpr size_t kPreallocSize = kSmallestMinAllocSize * 5;
- GrMemoryPool pool(kPreallocSize, 0);
- REPORTER_ASSERT(reporter, pool.preallocSize() == kPreallocSize);
- }
- // Pool allocates exactly minAllocSize when it expands.
- {
- constexpr size_t kMinAllocSize = kSmallestMinAllocSize * 7;
- GrMemoryPool pool(0, kMinAllocSize);
- AutoPoolReleaser r(pool);
- allocateMemory(pool, r);
- REPORTER_ASSERT(reporter, pool.size() == kMinAllocSize);
- allocateMemory(pool, r);
- REPORTER_ASSERT(reporter, pool.size() == 2 * kMinAllocSize);
- }
- // When asked to allocate amount > minAllocSize, pool allocates larger block
- // to accommodate all internal structures.
- {
- constexpr size_t kMinAllocSize = kSmallestMinAllocSize * 2;
- GrMemoryPool pool(kSmallestMinAllocSize, kMinAllocSize);
- AutoPoolReleaser r(pool);
- REPORTER_ASSERT(reporter, pool.size() == 0);
- constexpr size_t hugeSize = 10 * kMinAllocSize;
- r.add(pool.allocate(hugeSize));
- REPORTER_ASSERT(reporter, pool.size() > hugeSize);
- // Block size allocated to accommodate huge request doesn't include any extra
- // space, so next allocation request allocates a new block.
- size_t hugeBlockSize = pool.size();
- r.add(pool.allocate(0));
- REPORTER_ASSERT(reporter, pool.size() == hugeBlockSize + kMinAllocSize);
- }
- }
|