SegregatedListsAllocatorBuilder.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // Copyright (C) 2009-2022, 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
  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,
  47. SegregatedListsAllocatorBuilderInterface, Mutex>;
  48. template<typename TAlloc>
  49. static void printAllocatorBuilder(const TAlloc& sl)
  50. {
  51. HeapMemoryPool pool(allocAligned, nullptr);
  52. StringListRaii list(&pool);
  53. sl.printFreeBlocks(list);
  54. if(list.isEmpty())
  55. {
  56. return;
  57. }
  58. StringRaii str(&pool);
  59. list.join("", str);
  60. printf("%s\n", str.cstr());
  61. }
  62. template<Bool kValidate, U32 kIterationCount, Bool kStats>
  63. static void fuzzyTest()
  64. {
  65. class Alloc
  66. {
  67. public:
  68. SegregatedListsAllocatorBuilderChunk* m_chunk;
  69. PtrSize m_address;
  70. PtrSize m_alignment;
  71. PtrSize m_size;
  72. };
  73. SLAlloc sl;
  74. std::vector<Alloc> allocs;
  75. allocs.reserve(kIterationCount);
  76. const Second start = HighRezTimer::getCurrentTime();
  77. F64 avgFragmentation = 0.0f;
  78. F64 maxFragmetation = 0.0f;
  79. for(U32 i = 0; i < kIterationCount; ++i)
  80. {
  81. const Bool doAllocation = (getRandom() % 2) == 0;
  82. if(doAllocation)
  83. {
  84. Alloc alloc;
  85. do
  86. {
  87. alloc.m_size = getRandom() % 70_MB;
  88. alloc.m_alignment = nextPowerOfTwo(getRandom() % 16);
  89. } while(alloc.m_size == 0 || alloc.m_alignment == 0);
  90. ANKI_TEST_EXPECT_NO_ERR(sl.allocate(alloc.m_size, alloc.m_alignment, alloc.m_chunk, alloc.m_address));
  91. allocs.push_back(alloc);
  92. }
  93. else if(allocs.size())
  94. {
  95. const U32 idx = U32(getRandom() % allocs.size());
  96. const Alloc alloc = allocs[idx];
  97. allocs.erase(allocs.begin() + idx);
  98. sl.free(alloc.m_chunk, alloc.m_address, alloc.m_size);
  99. }
  100. if(kStats)
  101. {
  102. const F64 f = sl.computeExternalFragmentation();
  103. avgFragmentation += f / F64(kIterationCount);
  104. maxFragmetation = max(maxFragmetation, f);
  105. }
  106. // printAllocatorBuilder(sl);
  107. if(kValidate)
  108. {
  109. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  110. }
  111. }
  112. // Free the rest of the mem
  113. for(const Alloc& alloc : allocs)
  114. {
  115. sl.free(alloc.m_chunk, alloc.m_address, alloc.m_size);
  116. }
  117. if(kStats)
  118. {
  119. const Second end = HighRezTimer::getCurrentTime();
  120. const Second dt = end - start;
  121. ANKI_TEST_LOGI("Operations/sec %f. Avg external fragmentation %f. Max external fragmentation %f",
  122. F64(kIterationCount) / dt, avgFragmentation, maxFragmetation);
  123. }
  124. }
  125. ANKI_TEST(Util, SegregatedListsAllocatorBuilder)
  126. {
  127. // Simple test
  128. {
  129. SLAlloc sl;
  130. SegregatedListsAllocatorBuilderChunk* chunk;
  131. PtrSize address;
  132. ANKI_TEST_EXPECT_NO_ERR(sl.allocate(66, 4, chunk, address));
  133. // printAllocatorBuilder(sl);
  134. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  135. SegregatedListsAllocatorBuilderChunk* chunk2;
  136. PtrSize address2;
  137. ANKI_TEST_EXPECT_NO_ERR(sl.allocate(512, 64, chunk2, address2));
  138. // printAllocatorBuilder(sl);
  139. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  140. SegregatedListsAllocatorBuilderChunk* chunk3;
  141. PtrSize address3;
  142. ANKI_TEST_EXPECT_NO_ERR(sl.allocate(4, 64, chunk3, address3));
  143. // printAllocatorBuilder(sl);
  144. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  145. sl.free(chunk, address2, 512);
  146. // printAllocatorBuilder(sl);
  147. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  148. sl.free(chunk, address3, 4);
  149. // printAllocatorBuilder(sl);
  150. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  151. sl.free(chunk, address, 66);
  152. ANKI_TEST_EXPECT_NO_ERR(sl.validate());
  153. }
  154. // Fuzzy test
  155. fuzzyTest<true, 1024, false>();
  156. }
  157. ANKI_TEST(Util, SegregatedListsAllocatorBuilderBenchmark)
  158. {
  159. fuzzyTest<false, 2000000, true>();
  160. }