GrMemoryPoolTest.cpp 9.2 KB

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