1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2011 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/private/SkTArray.h" 9cb93a386Sopenharmony_ci#include "include/private/SkTDArray.h" 10cb93a386Sopenharmony_ci#include "include/private/SkTemplates.h" 11cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h" 12cb93a386Sopenharmony_ci#include "src/gpu/GrMemoryPool.h" 13cb93a386Sopenharmony_ci#include "tests/Test.h" 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci// A is the top of an inheritance tree of classes that overload op new and 16cb93a386Sopenharmony_ci// and delete to use a GrMemoryPool. The objects have values of different types 17cb93a386Sopenharmony_ci// that can be set and checked. 18cb93a386Sopenharmony_ciclass A { 19cb93a386Sopenharmony_cipublic: 20cb93a386Sopenharmony_ci A() {} 21cb93a386Sopenharmony_ci virtual void setValues(int v) { 22cb93a386Sopenharmony_ci fChar = static_cast<char>(v & 0xFF); 23cb93a386Sopenharmony_ci } 24cb93a386Sopenharmony_ci virtual bool checkValues(int v) { 25cb93a386Sopenharmony_ci return fChar == static_cast<char>(v & 0xFF); 26cb93a386Sopenharmony_ci } 27cb93a386Sopenharmony_ci virtual ~A() {} 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci void* operator new(size_t size) { 30cb93a386Sopenharmony_ci if (!gPool) { 31cb93a386Sopenharmony_ci return ::operator new(size); 32cb93a386Sopenharmony_ci } else { 33cb93a386Sopenharmony_ci return gPool->allocate(size); 34cb93a386Sopenharmony_ci } 35cb93a386Sopenharmony_ci } 36cb93a386Sopenharmony_ci 37cb93a386Sopenharmony_ci void operator delete(void* p) { 38cb93a386Sopenharmony_ci if (!gPool) { 39cb93a386Sopenharmony_ci ::operator delete(p); 40cb93a386Sopenharmony_ci } else { 41cb93a386Sopenharmony_ci return gPool->release(p); 42cb93a386Sopenharmony_ci } 43cb93a386Sopenharmony_ci } 44cb93a386Sopenharmony_ci 45cb93a386Sopenharmony_ci static A* Create(SkRandom* r); 46cb93a386Sopenharmony_ci 47cb93a386Sopenharmony_ci static void SetAllocator(size_t preallocSize, size_t minAllocSize) { 48cb93a386Sopenharmony_ci gPool = GrMemoryPool::Make(preallocSize, minAllocSize); 49cb93a386Sopenharmony_ci } 50cb93a386Sopenharmony_ci 51cb93a386Sopenharmony_ci static void ResetAllocator() { gPool.reset(); } 52cb93a386Sopenharmony_ci 53cb93a386Sopenharmony_ci static void ValidatePool() { 54cb93a386Sopenharmony_ci#ifdef SK_DEBUG 55cb93a386Sopenharmony_ci gPool->validate(); 56cb93a386Sopenharmony_ci#endif 57cb93a386Sopenharmony_ci } 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_ciprivate: 60cb93a386Sopenharmony_ci static std::unique_ptr<GrMemoryPool> gPool; 61cb93a386Sopenharmony_ci char fChar; 62cb93a386Sopenharmony_ci}; 63cb93a386Sopenharmony_ci 64cb93a386Sopenharmony_cistd::unique_ptr<GrMemoryPool> A::gPool; 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ciclass B : public A { 67cb93a386Sopenharmony_cipublic: 68cb93a386Sopenharmony_ci B() {} 69cb93a386Sopenharmony_ci void setValues(int v) override { 70cb93a386Sopenharmony_ci fDouble = static_cast<double>(v); 71cb93a386Sopenharmony_ci this->INHERITED::setValues(v); 72cb93a386Sopenharmony_ci } 73cb93a386Sopenharmony_ci bool checkValues(int v) override { 74cb93a386Sopenharmony_ci return fDouble == static_cast<double>(v) && 75cb93a386Sopenharmony_ci this->INHERITED::checkValues(v); 76cb93a386Sopenharmony_ci } 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ciprivate: 79cb93a386Sopenharmony_ci double fDouble; 80cb93a386Sopenharmony_ci 81cb93a386Sopenharmony_ci using INHERITED = A; 82cb93a386Sopenharmony_ci}; 83cb93a386Sopenharmony_ci 84cb93a386Sopenharmony_ciclass C : public A { 85cb93a386Sopenharmony_cipublic: 86cb93a386Sopenharmony_ci C() {} 87cb93a386Sopenharmony_ci void setValues(int v) override { 88cb93a386Sopenharmony_ci fInt64 = static_cast<int64_t>(v); 89cb93a386Sopenharmony_ci this->INHERITED::setValues(v); 90cb93a386Sopenharmony_ci } 91cb93a386Sopenharmony_ci bool checkValues(int v) override { 92cb93a386Sopenharmony_ci return fInt64 == static_cast<int64_t>(v) && 93cb93a386Sopenharmony_ci this->INHERITED::checkValues(v); 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ciprivate: 97cb93a386Sopenharmony_ci int64_t fInt64; 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci using INHERITED = A; 100cb93a386Sopenharmony_ci}; 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci// D derives from C and owns a dynamically created B 103cb93a386Sopenharmony_ciclass D : public C { 104cb93a386Sopenharmony_cipublic: 105cb93a386Sopenharmony_ci D() { 106cb93a386Sopenharmony_ci fB = new B(); 107cb93a386Sopenharmony_ci } 108cb93a386Sopenharmony_ci void setValues(int v) override { 109cb93a386Sopenharmony_ci fVoidStar = reinterpret_cast<void*>(static_cast<intptr_t>(v)); 110cb93a386Sopenharmony_ci this->INHERITED::setValues(v); 111cb93a386Sopenharmony_ci fB->setValues(v); 112cb93a386Sopenharmony_ci } 113cb93a386Sopenharmony_ci bool checkValues(int v) override { 114cb93a386Sopenharmony_ci return fVoidStar == reinterpret_cast<void*>(static_cast<intptr_t>(v)) && 115cb93a386Sopenharmony_ci fB->checkValues(v) && 116cb93a386Sopenharmony_ci this->INHERITED::checkValues(v); 117cb93a386Sopenharmony_ci } 118cb93a386Sopenharmony_ci ~D() override { 119cb93a386Sopenharmony_ci delete fB; 120cb93a386Sopenharmony_ci } 121cb93a386Sopenharmony_ciprivate: 122cb93a386Sopenharmony_ci void* fVoidStar; 123cb93a386Sopenharmony_ci B* fB; 124cb93a386Sopenharmony_ci 125cb93a386Sopenharmony_ci using INHERITED = C; 126cb93a386Sopenharmony_ci}; 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ciclass E : public A { 129cb93a386Sopenharmony_cipublic: 130cb93a386Sopenharmony_ci E() {} 131cb93a386Sopenharmony_ci void setValues(int v) override { 132cb93a386Sopenharmony_ci for (size_t i = 0; i < SK_ARRAY_COUNT(fIntArray); ++i) { 133cb93a386Sopenharmony_ci fIntArray[i] = v; 134cb93a386Sopenharmony_ci } 135cb93a386Sopenharmony_ci this->INHERITED::setValues(v); 136cb93a386Sopenharmony_ci } 137cb93a386Sopenharmony_ci bool checkValues(int v) override { 138cb93a386Sopenharmony_ci bool ok = true; 139cb93a386Sopenharmony_ci for (size_t i = 0; ok && i < SK_ARRAY_COUNT(fIntArray); ++i) { 140cb93a386Sopenharmony_ci if (fIntArray[i] != v) { 141cb93a386Sopenharmony_ci ok = false; 142cb93a386Sopenharmony_ci } 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci return ok && this->INHERITED::checkValues(v); 145cb93a386Sopenharmony_ci } 146cb93a386Sopenharmony_ciprivate: 147cb93a386Sopenharmony_ci int fIntArray[20]; 148cb93a386Sopenharmony_ci 149cb93a386Sopenharmony_ci using INHERITED = A; 150cb93a386Sopenharmony_ci}; 151cb93a386Sopenharmony_ci 152cb93a386Sopenharmony_ciA* A::Create(SkRandom* r) { 153cb93a386Sopenharmony_ci switch (r->nextRangeU(0, 4)) { 154cb93a386Sopenharmony_ci case 0: 155cb93a386Sopenharmony_ci return new A; 156cb93a386Sopenharmony_ci case 1: 157cb93a386Sopenharmony_ci return new B; 158cb93a386Sopenharmony_ci case 2: 159cb93a386Sopenharmony_ci return new C; 160cb93a386Sopenharmony_ci case 3: 161cb93a386Sopenharmony_ci return new D; 162cb93a386Sopenharmony_ci case 4: 163cb93a386Sopenharmony_ci return new E; 164cb93a386Sopenharmony_ci default: 165cb93a386Sopenharmony_ci // suppress warning 166cb93a386Sopenharmony_ci return nullptr; 167cb93a386Sopenharmony_ci } 168cb93a386Sopenharmony_ci} 169cb93a386Sopenharmony_ci 170cb93a386Sopenharmony_cistruct Rec { 171cb93a386Sopenharmony_ci A* fInstance; 172cb93a386Sopenharmony_ci int fValue; 173cb93a386Sopenharmony_ci}; 174cb93a386Sopenharmony_ci 175cb93a386Sopenharmony_ciDEF_TEST(GrMemoryPool, reporter) { 176cb93a386Sopenharmony_ci // prealloc and min alloc sizes for the pool 177cb93a386Sopenharmony_ci static const size_t gSizes[][2] = { 178cb93a386Sopenharmony_ci {0, 0}, 179cb93a386Sopenharmony_ci {10 * sizeof(A), 20 * sizeof(A)}, 180cb93a386Sopenharmony_ci {100 * sizeof(A), 100 * sizeof(A)}, 181cb93a386Sopenharmony_ci {500 * sizeof(A), 500 * sizeof(A)}, 182cb93a386Sopenharmony_ci {10000 * sizeof(A), 0}, 183cb93a386Sopenharmony_ci {1, 100 * sizeof(A)}, 184cb93a386Sopenharmony_ci }; 185cb93a386Sopenharmony_ci 186cb93a386Sopenharmony_ci // different percentages of creation vs deletion 187cb93a386Sopenharmony_ci static const float gCreateFraction[] = {1.f, .95f, 0.75f, .5f}; 188cb93a386Sopenharmony_ci // number of create/destroys per test 189cb93a386Sopenharmony_ci static const int kNumIters = 20000; 190cb93a386Sopenharmony_ci // check that all the values stored in A objects are correct after this 191cb93a386Sopenharmony_ci // number of iterations 192cb93a386Sopenharmony_ci static const int kCheckPeriod = 500; 193cb93a386Sopenharmony_ci 194cb93a386Sopenharmony_ci SkRandom r; 195cb93a386Sopenharmony_ci for (size_t s = 0; s < SK_ARRAY_COUNT(gSizes); ++s) { 196cb93a386Sopenharmony_ci A::SetAllocator(gSizes[s][0], gSizes[s][1]); 197cb93a386Sopenharmony_ci A::ValidatePool(); 198cb93a386Sopenharmony_ci for (size_t c = 0; c < SK_ARRAY_COUNT(gCreateFraction); ++c) { 199cb93a386Sopenharmony_ci SkTDArray<Rec> instanceRecs; 200cb93a386Sopenharmony_ci for (int i = 0; i < kNumIters; ++i) { 201cb93a386Sopenharmony_ci float createOrDestroy = r.nextUScalar1(); 202cb93a386Sopenharmony_ci if (createOrDestroy < gCreateFraction[c] || 203cb93a386Sopenharmony_ci 0 == instanceRecs.count()) { 204cb93a386Sopenharmony_ci Rec* rec = instanceRecs.append(); 205cb93a386Sopenharmony_ci rec->fInstance = A::Create(&r); 206cb93a386Sopenharmony_ci rec->fValue = static_cast<int>(r.nextU()); 207cb93a386Sopenharmony_ci rec->fInstance->setValues(rec->fValue); 208cb93a386Sopenharmony_ci } else { 209cb93a386Sopenharmony_ci int d = r.nextRangeU(0, instanceRecs.count() - 1); 210cb93a386Sopenharmony_ci Rec& rec = instanceRecs[d]; 211cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue)); 212cb93a386Sopenharmony_ci delete rec.fInstance; 213cb93a386Sopenharmony_ci instanceRecs.removeShuffle(d); 214cb93a386Sopenharmony_ci } 215cb93a386Sopenharmony_ci if (0 == i % kCheckPeriod) { 216cb93a386Sopenharmony_ci A::ValidatePool(); 217cb93a386Sopenharmony_ci for (Rec& rec : instanceRecs) { 218cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue)); 219cb93a386Sopenharmony_ci } 220cb93a386Sopenharmony_ci } 221cb93a386Sopenharmony_ci } 222cb93a386Sopenharmony_ci for (Rec& rec : instanceRecs) { 223cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, rec.fInstance->checkValues(rec.fValue)); 224cb93a386Sopenharmony_ci delete rec.fInstance; 225cb93a386Sopenharmony_ci } 226cb93a386Sopenharmony_ci } 227cb93a386Sopenharmony_ci } 228cb93a386Sopenharmony_ci} 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci// GrMemoryPool requires that it's empty at the point of destruction. This helps 231cb93a386Sopenharmony_ci// achieving that by releasing all added memory in the destructor. 232cb93a386Sopenharmony_ciclass AutoPoolReleaser { 233cb93a386Sopenharmony_cipublic: 234cb93a386Sopenharmony_ci AutoPoolReleaser(GrMemoryPool& pool): fPool(pool) { 235cb93a386Sopenharmony_ci } 236cb93a386Sopenharmony_ci ~AutoPoolReleaser() { 237cb93a386Sopenharmony_ci for (void* ptr: fAllocated) { 238cb93a386Sopenharmony_ci fPool.release(ptr); 239cb93a386Sopenharmony_ci } 240cb93a386Sopenharmony_ci } 241cb93a386Sopenharmony_ci void add(void* ptr) { 242cb93a386Sopenharmony_ci fAllocated.push_back(ptr); 243cb93a386Sopenharmony_ci } 244cb93a386Sopenharmony_ciprivate: 245cb93a386Sopenharmony_ci GrMemoryPool& fPool; 246cb93a386Sopenharmony_ci SkTArray<void*> fAllocated; 247cb93a386Sopenharmony_ci}; 248cb93a386Sopenharmony_ci 249cb93a386Sopenharmony_ciDEF_TEST(GrMemoryPoolAPI, reporter) { 250cb93a386Sopenharmony_ci constexpr size_t kSmallestMinAllocSize = GrMemoryPool::kMinAllocationSize; 251cb93a386Sopenharmony_ci 252cb93a386Sopenharmony_ci // Allocates memory until pool adds a new block (pool->size() changes). 253cb93a386Sopenharmony_ci auto allocateMemory = [](GrMemoryPool& pool, AutoPoolReleaser& r) { 254cb93a386Sopenharmony_ci size_t origPoolSize = pool.size(); 255cb93a386Sopenharmony_ci while (pool.size() == origPoolSize) { 256cb93a386Sopenharmony_ci r.add(pool.allocate(31)); 257cb93a386Sopenharmony_ci } 258cb93a386Sopenharmony_ci }; 259cb93a386Sopenharmony_ci 260cb93a386Sopenharmony_ci // Effective prealloc space capacity is >= kMinAllocationSize. 261cb93a386Sopenharmony_ci { 262cb93a386Sopenharmony_ci auto pool = GrMemoryPool::Make(0, 0); 263cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pool->preallocSize() == kSmallestMinAllocSize); 264cb93a386Sopenharmony_ci } 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci // Effective block size capacity >= kMinAllocationSize. 267cb93a386Sopenharmony_ci { 268cb93a386Sopenharmony_ci auto pool = GrMemoryPool::Make(kSmallestMinAllocSize, kSmallestMinAllocSize / 2); 269cb93a386Sopenharmony_ci AutoPoolReleaser r(*pool); 270cb93a386Sopenharmony_ci 271cb93a386Sopenharmony_ci allocateMemory(*pool, r); 272cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pool->size() == kSmallestMinAllocSize); 273cb93a386Sopenharmony_ci } 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_ci // Pool allocates exactly preallocSize on creation. 276cb93a386Sopenharmony_ci { 277cb93a386Sopenharmony_ci constexpr size_t kPreallocSize = kSmallestMinAllocSize * 5; 278cb93a386Sopenharmony_ci auto pool = GrMemoryPool::Make(kPreallocSize, 0); 279cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pool->preallocSize() == kPreallocSize); 280cb93a386Sopenharmony_ci } 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci // Pool allocates exactly minAllocSize when it expands. 283cb93a386Sopenharmony_ci { 284cb93a386Sopenharmony_ci constexpr size_t kMinAllocSize = kSmallestMinAllocSize * 7; 285cb93a386Sopenharmony_ci auto pool = GrMemoryPool::Make(0, kMinAllocSize); 286cb93a386Sopenharmony_ci AutoPoolReleaser r(*pool); 287cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pool->size() == 0); 288cb93a386Sopenharmony_ci 289cb93a386Sopenharmony_ci allocateMemory(*pool, r); 290cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pool->size() == kMinAllocSize); 291cb93a386Sopenharmony_ci 292cb93a386Sopenharmony_ci allocateMemory(*pool, r); 293cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pool->size() == 2 * kMinAllocSize); 294cb93a386Sopenharmony_ci } 295cb93a386Sopenharmony_ci 296cb93a386Sopenharmony_ci // When asked to allocate amount > minAllocSize, pool allocates larger block 297cb93a386Sopenharmony_ci // to accommodate all internal structures. 298cb93a386Sopenharmony_ci { 299cb93a386Sopenharmony_ci constexpr size_t kMinAllocSize = kSmallestMinAllocSize * 2; 300cb93a386Sopenharmony_ci auto pool = GrMemoryPool::Make(kSmallestMinAllocSize, kMinAllocSize); 301cb93a386Sopenharmony_ci AutoPoolReleaser r(*pool); 302cb93a386Sopenharmony_ci 303cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pool->size() == 0); 304cb93a386Sopenharmony_ci 305cb93a386Sopenharmony_ci constexpr size_t hugeSize = 10 * kMinAllocSize; 306cb93a386Sopenharmony_ci r.add(pool->allocate(hugeSize)); 307cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pool->size() > hugeSize); 308cb93a386Sopenharmony_ci 309cb93a386Sopenharmony_ci // Block size allocated to accommodate huge request doesn't include any extra 310cb93a386Sopenharmony_ci // space, so next allocation request allocates a new block. 311cb93a386Sopenharmony_ci size_t hugeBlockSize = pool->size(); 312cb93a386Sopenharmony_ci r.add(pool->allocate(0)); 313cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, pool->size() == hugeBlockSize + kMinAllocSize); 314cb93a386Sopenharmony_ci } 315cb93a386Sopenharmony_ci} 316