ClassAllocatorBuilder.inl.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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/ClassAllocatorBuilder.h>
  6. namespace anki {
  7. template<typename TChunk, typename TInterface, typename TLock, typename TMemoryPool>
  8. void ClassAllocatorBuilder<TChunk, TInterface, TLock, TMemoryPool>::init()
  9. {
  10. m_classes.resize(m_interface.getClassCount());
  11. for(U32 classIdx = 0; classIdx < m_classes.getSize(); ++classIdx)
  12. {
  13. Class& c = m_classes[classIdx];
  14. m_interface.getClassInfo(classIdx, c.m_chunkSize, c.m_suballocationSize);
  15. ANKI_ASSERT(c.m_suballocationSize > 0 && c.m_chunkSize > 0 && c.m_chunkSize >= c.m_suballocationSize);
  16. ANKI_ASSERT((c.m_chunkSize % c.m_suballocationSize) == 0);
  17. }
  18. }
  19. template<typename TChunk, typename TInterface, typename TLock, typename TMemoryPool>
  20. void ClassAllocatorBuilder<TChunk, TInterface, TLock, TMemoryPool>::destroy()
  21. {
  22. for([[maybe_unused]] const Class& c : m_classes)
  23. {
  24. ANKI_ASSERT(c.m_chunkList.isEmpty() && "Forgot to deallocate");
  25. }
  26. m_classes.destroy();
  27. }
  28. template<typename TChunk, typename TInterface, typename TLock, typename TMemoryPool>
  29. typename ClassAllocatorBuilder<TChunk, TInterface, TLock, TMemoryPool>::Class*
  30. ClassAllocatorBuilder<TChunk, TInterface, TLock, TMemoryPool>::findClass(PtrSize size, PtrSize alignment)
  31. {
  32. ANKI_ASSERT(size > 0 && alignment > 0);
  33. PtrSize lowLimit = 0;
  34. Class* it = m_classes.getBegin();
  35. const Class* end = m_classes.getEnd();
  36. while(it != end)
  37. {
  38. const PtrSize highLimit = it->m_suballocationSize;
  39. if(size > lowLimit && size <= highLimit)
  40. {
  41. if(alignment <= highLimit)
  42. {
  43. // Found the class
  44. return it;
  45. }
  46. else
  47. {
  48. // The class found doesn't have the proper alignment. Need to go higher
  49. while(++it != end)
  50. {
  51. if(alignment <= it->m_suballocationSize)
  52. {
  53. // Now found something
  54. return it;
  55. }
  56. }
  57. }
  58. }
  59. lowLimit = highLimit;
  60. ++it;
  61. }
  62. ANKI_UTIL_LOGF("Memory class not found");
  63. return nullptr;
  64. }
  65. template<typename TChunk, typename TInterface, typename TLock, typename TMemoryPool>
  66. Error ClassAllocatorBuilder<TChunk, TInterface, TLock, TMemoryPool>::allocate(PtrSize size, PtrSize alignment, TChunk*& chunk, PtrSize& offset)
  67. {
  68. ANKI_ASSERT(isInitialized());
  69. ANKI_ASSERT(size > 0 && alignment > 0);
  70. chunk = nullptr;
  71. offset = kMaxPtrSize;
  72. // Find the class for the given size
  73. Class* cl = findClass(size, alignment);
  74. const PtrSize maxSuballocationCount = cl->m_chunkSize / cl->m_suballocationSize;
  75. LockGuard<TLock> lock(cl->m_mtx);
  76. // Find chunk with free suballocation
  77. auto it = cl->m_chunkList.getBegin();
  78. const auto end = cl->m_chunkList.getEnd();
  79. while(it != end)
  80. {
  81. if(it->m_suballocationCount < maxSuballocationCount)
  82. {
  83. chunk = &(*it);
  84. break;
  85. }
  86. ++it;
  87. }
  88. // Create a new chunk if needed
  89. if(chunk == nullptr)
  90. {
  91. ANKI_CHECK(m_interface.allocateChunk(U32(cl - &m_classes[0]), chunk));
  92. chunk->m_inUseSuballocations.unsetAll();
  93. chunk->m_suballocationCount = 0;
  94. chunk->m_class = cl;
  95. cl->m_chunkList.pushBack(chunk);
  96. }
  97. // Allocate from chunk
  98. const U32 bitCount = U32(maxSuballocationCount);
  99. for(U32 i = 0; i < bitCount; ++i)
  100. {
  101. if(!chunk->m_inUseSuballocations.get(i))
  102. {
  103. // Found an empty slot, allocate from it
  104. chunk->m_inUseSuballocations.set(i);
  105. ++chunk->m_suballocationCount;
  106. offset = i * cl->m_suballocationSize;
  107. break;
  108. }
  109. }
  110. ANKI_ASSERT(chunk);
  111. ANKI_ASSERT(isAligned(alignment, offset));
  112. ANKI_ASSERT(offset + size <= cl->m_chunkSize);
  113. return Error::kNone;
  114. }
  115. template<typename TChunk, typename TInterface, typename TLock, typename TMemoryPool>
  116. void ClassAllocatorBuilder<TChunk, TInterface, TLock, TMemoryPool>::free(TChunk* chunk, PtrSize offset)
  117. {
  118. ANKI_ASSERT(isInitialized());
  119. ANKI_ASSERT(chunk);
  120. Class& cl = *static_cast<Class*>(chunk->m_class);
  121. ANKI_ASSERT(offset < cl.m_chunkSize);
  122. LockGuard<TLock> lock(cl.m_mtx);
  123. const U32 suballocationIdx = U32(offset / cl.m_suballocationSize);
  124. ANKI_ASSERT(chunk->m_inUseSuballocations.get(suballocationIdx));
  125. ANKI_ASSERT(chunk->m_suballocationCount > 0);
  126. chunk->m_inUseSuballocations.unset(suballocationIdx);
  127. --chunk->m_suballocationCount;
  128. if(chunk->m_suballocationCount == 0)
  129. {
  130. cl.m_chunkList.erase(chunk);
  131. m_interface.freeChunk(chunk);
  132. }
  133. }
  134. template<typename TChunk, typename TInterface, typename TLock, typename TMemoryPool>
  135. void ClassAllocatorBuilder<TChunk, TInterface, TLock, TMemoryPool>::getStats(ClassAllocatorBuilderStats& stats) const
  136. {
  137. stats = {};
  138. for(const Class& c : m_classes)
  139. {
  140. LockGuard<TLock> lock(c.m_mtx);
  141. for(const TChunk& chunk : c.m_chunkList)
  142. {
  143. stats.m_allocatedSize += c.m_chunkSize;
  144. stats.m_inUseSize += c.m_suballocationSize * chunk.m_suballocationCount;
  145. ++stats.m_chunkCount;
  146. }
  147. }
  148. }
  149. } // end namespace anki