chunked_memory_pool.cpp 5.6 KB

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