SegregatedListsAllocatorBuilder.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <AnKi/Util/SegregatedListsAllocatorBuilder.h>
  6. #include <AnKi/Util/HighRezTimer.h>
  7. #include <Tests/Framework/Framework.h>
  8. using namespace anki;
  9. static constexpr U32 kClassCount = 6;
  10. class SegregatedListsAllocatorBuilderChunk : public SegregatedListsAllocatorBuilderChunkBase<SingletonMemoryPoolWrapper<DefaultMemoryPool>>
  11. {
  12. };
  13. class SegregatedListsAllocatorBuilderInterface
  14. {
  15. public:
  16. HeapMemoryPool m_pool = {allocAligned, nullptr};
  17. static constexpr PtrSize kChunkSize = 100_MB;
  18. U32 getClassCount() const
  19. {
  20. return kClassCount;
  21. }
  22. void getClassInfo(U32 idx, PtrSize& size) const
  23. {
  24. static const Array<PtrSize, kClassCount> classes = {512_KB, 1_MB, 5_MB, 10_MB, 30_MB, kChunkSize};
  25. size = classes[idx];
  26. }
  27. Error allocateChunk(SegregatedListsAllocatorBuilderChunk*& newChunk, PtrSize& chunkSize)
  28. {
  29. newChunk = newInstance<SegregatedListsAllocatorBuilderChunk>(m_pool);
  30. chunkSize = kChunkSize;
  31. return Error::kNone;
  32. }
  33. void deleteChunk(SegregatedListsAllocatorBuilderChunk* chunk)
  34. {
  35. deleteInstance(m_pool, chunk);
  36. }
  37. static constexpr PtrSize getMinSizeAlignment()
  38. {
  39. return 4;
  40. }
  41. HeapMemoryPool& getMemoryPool()
  42. {
  43. return m_pool;
  44. }
  45. };
  46. using SLAlloc = SegregatedListsAllocatorBuilder<SegregatedListsAllocatorBuilderChunk, SegregatedListsAllocatorBuilderInterface, Mutex,
  47. SingletonMemoryPoolWrapper<DefaultMemoryPool>>;
  48. template<typename TAlloc>
  49. static void printAllocatorBuilder(const TAlloc& sl)
  50. {
  51. StringList list;
  52. sl.printFreeBlocks(list);
  53. if(list.isEmpty())
  54. {
  55. return;
  56. }
  57. String str;
  58. list.join("", str);
  59. printf("%s\n", str.cstr());
  60. }
  61. template<Bool kValidate, U32 kIterationCount, Bool kStats, Bool kExtraValidation>
  62. static void fuzzyTest()
  63. {
  64. class Alloc
  65. {
  66. public:
  67. SegregatedListsAllocatorBuilderChunk* m_chunk;
  68. PtrSize m_address;
  69. PtrSize m_alignment;
  70. PtrSize m_size;
  71. };
  72. SLAlloc sl;
  73. std::vector<Alloc> allocs;
  74. allocs.reserve(kIterationCount);
  75. const Second start = HighRezTimer::getCurrentTime();
  76. F64 avgFragmentation = 0.0f;
  77. F64 maxFragmetation = 0.0f;
  78. for(U32 i = 0; i < kIterationCount; ++i)
  79. {
  80. const Bool doAllocation = (getRandom() % 2) == 0;
  81. if(doAllocation)
  82. {
  83. Alloc alloc;
  84. do
  85. {
  86. alloc.m_size = getRandom() % 70_MB;
  87. alloc.m_alignment = getAlignedRoundUp(4, getRandom() % 16);
  88. } while(alloc.m_size == 0 || alloc.m_alignment == 0);
  89. ANKI_TEST_EXPECT_NO_ERR(sl.allocate(alloc.m_size, alloc.m_alignment, alloc.m_chunk, alloc.m_address));
  90. allocs.push_back(alloc);
  91. }
  92. else if(allocs.size())
  93. {
  94. const U32 idx = U32(getRandom() % allocs.size());
  95. const Alloc alloc = allocs[idx];
  96. allocs.erase(allocs.begin() + idx);
  97. sl.free(alloc.m_chunk, alloc.m_address, alloc.m_size);
  98. }
  99. if(kExtraValidation)
  100. {
  101. // Make sure they don't overlap
  102. for(U32 a = 0; a < allocs.size(); ++a)
  103. {
  104. for(U32 b = 0; b < allocs.size(); ++b)
  105. {
  106. if(a == b)
  107. {
  108. continue;
  109. }
  110. const Alloc& allocA = allocs[a];
  111. const Alloc& allocB = allocs[b];
  112. if(allocA.m_chunk != allocB.m_chunk)
  113. {
  114. continue;
  115. }
  116. if(allocA.m_address < allocB.m_address)
  117. {
  118. ANKI_TEST_EXPECT_EQ(allocA.m_address + allocA.m_size <= allocB.m_address, true);
  119. }
  120. else
  121. {
  122. ANKI_TEST_EXPECT_EQ(allocB.m_address + allocB.m_size <= allocA.m_address, true);
  123. }
  124. }
  125. }
  126. }
  127. if(kStats)
  128. {
  129. const F64 f = sl.computeExternalFragmentation();
  130. avgFragmentation += f / F64(kIterationCount);
  131. maxFragmetation = max(maxFragmetation, f);
  132. }
  133. // printAllocatorBuilder(sl);
  134. if(kValidate)
  135. {
  136. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  137. }
  138. }
  139. // Free the rest of the mem
  140. for(const Alloc& alloc : allocs)
  141. {
  142. sl.free(alloc.m_chunk, alloc.m_address, alloc.m_size);
  143. }
  144. if(kStats)
  145. {
  146. const Second end = HighRezTimer::getCurrentTime();
  147. const Second dt = end - start;
  148. ANKI_TEST_LOGI("Operations/sec %f. Avg external fragmentation %f. Max external fragmentation %f", F64(kIterationCount) / dt, avgFragmentation,
  149. maxFragmetation);
  150. }
  151. }
  152. ANKI_TEST(Util, SegregatedListsAllocatorBuilder)
  153. {
  154. DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
  155. // Simple test
  156. {
  157. SLAlloc sl;
  158. SegregatedListsAllocatorBuilderChunk* chunk;
  159. PtrSize address;
  160. ANKI_TEST_EXPECT_NO_ERR(sl.allocate(66, 4, chunk, address));
  161. // printAllocatorBuilder(sl);
  162. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  163. SegregatedListsAllocatorBuilderChunk* chunk2;
  164. PtrSize address2;
  165. ANKI_TEST_EXPECT_NO_ERR(sl.allocate(512, 64, chunk2, address2));
  166. // printAllocatorBuilder(sl);
  167. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  168. SegregatedListsAllocatorBuilderChunk* chunk3;
  169. PtrSize address3;
  170. ANKI_TEST_EXPECT_NO_ERR(sl.allocate(4, 64, chunk3, address3));
  171. // printAllocatorBuilder(sl);
  172. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  173. sl.free(chunk, address2, 512);
  174. // printAllocatorBuilder(sl);
  175. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  176. sl.free(chunk, address3, 4);
  177. // printAllocatorBuilder(sl);
  178. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  179. sl.free(chunk, address, 66);
  180. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  181. }
  182. // Fuzzy test
  183. fuzzyTest<true, 1024, false, true>();
  184. DefaultMemoryPool::freeSingleton();
  185. }
  186. ANKI_TEST(Util, SegregatedListsAllocatorBuilderBenchmark)
  187. {
  188. DefaultMemoryPool::allocateSingleton(allocAligned, nullptr);
  189. fuzzyTest<false, 2000000, true, false>();
  190. DefaultMemoryPool::freeSingleton();
  191. }