chunked_memory_pool.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #include "chunked_memory_pool.h"
  2. namespace NYT {
  3. ////////////////////////////////////////////////////////////////////////////////
  4. TAllocationHolder::TAllocationHolder(TMutableRef ref, TRefCountedTypeCookie cookie)
  5. : Ref_(ref)
  6. #ifdef YT_ENABLE_REF_COUNTED_TRACKING
  7. , Cookie_(cookie)
  8. #endif
  9. {
  10. #ifdef YT_ENABLE_REF_COUNTED_TRACKING
  11. if (Cookie_ != NullRefCountedTypeCookie) {
  12. TRefCountedTrackerFacade::AllocateTagInstance(Cookie_);
  13. TRefCountedTrackerFacade::AllocateSpace(Cookie_, Ref_.Size());
  14. }
  15. #else
  16. Y_UNUSED(cookie);
  17. #endif
  18. }
  19. TAllocationHolder::~TAllocationHolder()
  20. {
  21. #ifdef YT_ENABLE_REF_COUNTED_TRACKING
  22. if (Cookie_ != NullRefCountedTypeCookie) {
  23. TRefCountedTrackerFacade::FreeTagInstance(Cookie_);
  24. TRefCountedTrackerFacade::FreeSpace(Cookie_, Ref_.Size());
  25. }
  26. #endif
  27. }
  28. ////////////////////////////////////////////////////////////////////////////////
  29. class TDefaultMemoryChunkProvider
  30. : public IMemoryChunkProvider
  31. {
  32. public:
  33. std::unique_ptr<TAllocationHolder> Allocate(size_t size, TRefCountedTypeCookie cookie) override
  34. {
  35. return std::unique_ptr<TAllocationHolder>(TAllocationHolder::Allocate<TAllocationHolder>(size, cookie));
  36. }
  37. };
  38. const IMemoryChunkProviderPtr& GetDefaultMemoryChunkProvider()
  39. {
  40. static const IMemoryChunkProviderPtr Result = New<TDefaultMemoryChunkProvider>();
  41. return Result;
  42. }
  43. ////////////////////////////////////////////////////////////////////////////////
  44. TChunkedMemoryPool::TChunkedMemoryPool(
  45. TRefCountedTypeCookie tagCookie,
  46. IMemoryChunkProviderPtr chunkProvider,
  47. size_t startChunkSize)
  48. : TagCookie_(tagCookie)
  49. , ChunkProviderHolder_(std::move(chunkProvider))
  50. , ChunkProvider_(ChunkProviderHolder_.Get())
  51. {
  52. Initialize(startChunkSize);
  53. }
  54. TChunkedMemoryPool::TChunkedMemoryPool(
  55. TRefCountedTypeCookie tagCookie,
  56. size_t startChunkSize)
  57. : TagCookie_(tagCookie)
  58. , ChunkProvider_(GetDefaultMemoryChunkProvider().Get())
  59. {
  60. Initialize(startChunkSize);
  61. }
  62. void TChunkedMemoryPool::Initialize(size_t startChunkSize)
  63. {
  64. NextSmallSize_ = startChunkSize;
  65. FreeZoneBegin_ = nullptr;
  66. FreeZoneEnd_ = nullptr;
  67. }
  68. void TChunkedMemoryPool::Purge()
  69. {
  70. Chunks_.clear();
  71. OtherBlocks_.clear();
  72. Size_ = 0;
  73. Capacity_ = 0;
  74. NextChunkIndex_ = 0;
  75. FreeZoneBegin_ = nullptr;
  76. FreeZoneEnd_ = nullptr;
  77. }
  78. char* TChunkedMemoryPool::AllocateUnalignedSlow(size_t size)
  79. {
  80. auto* large = AllocateSlowCore(size);
  81. if (large) {
  82. return large;
  83. }
  84. return AllocateUnaligned(size);
  85. }
  86. char* TChunkedMemoryPool::AllocateAlignedSlow(size_t size, int align)
  87. {
  88. // NB: Do not rely on any particular alignment of chunks.
  89. auto* large = AllocateSlowCore(size + align);
  90. if (large) {
  91. return AlignUp(large, align);
  92. }
  93. return AllocateAligned(size, align);
  94. }
  95. char* TChunkedMemoryPool::AllocateSlowCore(size_t size)
  96. {
  97. TMutableRef ref;
  98. if (size > RegularChunkSize) {
  99. auto block = ChunkProvider_->Allocate(size, TagCookie_);
  100. ref = block->GetRef();
  101. Size_ += size;
  102. Capacity_ += ref.Size();
  103. OtherBlocks_.push_back(std::move(block));
  104. return ref.Begin();
  105. }
  106. YT_VERIFY(NextChunkIndex_ <= std::ssize(Chunks_));
  107. if (NextSmallSize_ < RegularChunkSize) {
  108. auto block = ChunkProvider_->Allocate(std::max(NextSmallSize_, size), TagCookie_);
  109. ref = block->GetRef();
  110. Capacity_ += ref.Size();
  111. OtherBlocks_.push_back(std::move(block));
  112. NextSmallSize_ = 2 * ref.Size();
  113. } else if (NextChunkIndex_ == std::ssize(Chunks_)) {
  114. auto chunk = ChunkProvider_->Allocate(RegularChunkSize, TagCookie_);
  115. ref = chunk->GetRef();
  116. Capacity_ += ref.Size();
  117. Chunks_.push_back(std::move(chunk));
  118. ++NextChunkIndex_;
  119. } else {
  120. ref = Chunks_[NextChunkIndex_++]->GetRef();
  121. }
  122. FreeZoneBegin_ = ref.Begin();
  123. FreeZoneEnd_ = ref.End();
  124. return nullptr;
  125. }
  126. void TChunkedMemoryPool::Absorb(TChunkedMemoryPool&& other)
  127. {
  128. YT_VERIFY(ChunkProvider_ == other.ChunkProvider_);
  129. OtherBlocks_.reserve(OtherBlocks_.size() + other.OtherBlocks_.size());
  130. for (auto& block : other.OtherBlocks_) {
  131. OtherBlocks_.push_back(std::move(block));
  132. }
  133. other.OtherBlocks_.clear();
  134. // Suppose that
  135. // - "A" is filled blocks of the current pool;
  136. // - "a" is free blocks of the current pool;
  137. // - "B" is filled blocks of the other pool;
  138. // - "b" is free blocks of the other pool.
  139. // Then, from the initial layouts "AA...Aaa...a" and "BB...Bbb...b" we obtain "BB..BAA..Aaa...abb...b".
  140. Chunks_.reserve(Chunks_.size() + other.Chunks_.size());
  141. size_t oldSize = Chunks_.size();
  142. for (auto& chunk : other.Chunks_) {
  143. Chunks_.push_back(std::move(chunk));
  144. }
  145. // Transform "AA...Aaa...aBB...B" => "BB...BAA...Aaa...a"
  146. std::rotate(Chunks_.begin(), Chunks_.begin() + oldSize, Chunks_.begin() + oldSize + other.NextChunkIndex_);
  147. if (NextChunkIndex_ == 0) {
  148. FreeZoneBegin_ = other.FreeZoneBegin_;
  149. FreeZoneEnd_ = other.FreeZoneEnd_;
  150. }
  151. NextChunkIndex_ += other.NextChunkIndex_;
  152. other.Chunks_.clear();
  153. other.FreeZoneBegin_ = nullptr;
  154. other.FreeZoneEnd_ = nullptr;
  155. other.NextChunkIndex_ = 0;
  156. Size_ += other.Size_;
  157. Capacity_ += other.Capacity_;
  158. other.Size_ = 0;
  159. other.Capacity_ = 0;
  160. }
  161. size_t TChunkedMemoryPool::GetSize() const
  162. {
  163. return Size_;
  164. }
  165. size_t TChunkedMemoryPool::GetCapacity() const
  166. {
  167. return Capacity_;
  168. }
  169. size_t TChunkedMemoryPool::GetCurrentChunkSpareSize() const
  170. {
  171. return FreeZoneEnd_ - FreeZoneBegin_;
  172. }
  173. ////////////////////////////////////////////////////////////////////////////////
  174. } // namespace NYT