chunked_memory_pool-inl.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #ifndef CHUNKED_MEMORY_POOL_INL_H_
  2. #error "Direct inclusion of this file is not allowed, include chunked_memory_pool.h"
  3. // For the sake of sane code completion.
  4. #include "chunked_memory_pool.h"
  5. #endif
  6. #include "serialize.h"
  7. #include <library/cpp/yt/system/exit.h>
  8. #include <library/cpp/yt/malloc/malloc.h>
  9. #include <util/system/align.h>
  10. namespace NYT {
  11. ////////////////////////////////////////////////////////////////////////////////
  12. inline void TAllocationHolder::operator delete(void* ptr) noexcept
  13. {
  14. ::free(ptr);
  15. }
  16. inline TMutableRef TAllocationHolder::GetRef() const
  17. {
  18. return Ref_;
  19. }
  20. template <class TDerived>
  21. TDerived* TAllocationHolder::Allocate(size_t size, TRefCountedTypeCookie cookie)
  22. {
  23. auto requestedSize = sizeof(TDerived) + size;
  24. auto* ptr = ::malloc(requestedSize);
  25. if (Y_UNLIKELY(!ptr)) {
  26. AbortProcessDramatically(
  27. EProcessExitCode::OutOfMemory,
  28. "Out-of-memory during chunked memory pool allocation");
  29. }
  30. #ifndef _win_
  31. auto allocatedSize = ::malloc_usable_size(ptr);
  32. if (allocatedSize) {
  33. size += allocatedSize - requestedSize;
  34. }
  35. #endif
  36. auto* instance = static_cast<TDerived*>(ptr);
  37. try {
  38. new (instance) TDerived(TMutableRef(instance + 1, size), cookie);
  39. } catch (const std::exception& ex) {
  40. // Do not forget to free the memory.
  41. ::free(ptr);
  42. throw;
  43. }
  44. return instance;
  45. }
  46. ////////////////////////////////////////////////////////////////////////////////
  47. inline TChunkedMemoryPool::TChunkedMemoryPool()
  48. : TChunkedMemoryPool(
  49. GetRefCountedTypeCookie<TDefaultChunkedMemoryPoolTag>())
  50. { }
  51. template <class TTag>
  52. inline TChunkedMemoryPool::TChunkedMemoryPool(
  53. TTag,
  54. size_t startChunkSize)
  55. : TChunkedMemoryPool(
  56. GetRefCountedTypeCookie<TTag>(),
  57. startChunkSize)
  58. {
  59. static_assert(IsEmptyClass<TTag>());
  60. }
  61. inline char* TChunkedMemoryPool::AllocateUnaligned(size_t size)
  62. {
  63. // Fast path.
  64. if (FreeZoneBegin_ && FreeZoneEnd_ >= FreeZoneBegin_ + size) {
  65. FreeZoneEnd_ -= size;
  66. Size_ += size;
  67. return FreeZoneEnd_;
  68. }
  69. // Slow path.
  70. return AllocateUnalignedSlow(size);
  71. }
  72. inline char* TChunkedMemoryPool::AllocateAligned(size_t size, int align)
  73. {
  74. if (FreeZoneBegin_) {
  75. // NB: This can lead to FreeZoneBegin_ >= FreeZoneEnd_ in which case the chunk is full.
  76. FreeZoneBegin_ = AlignUp(FreeZoneBegin_, align);
  77. // Fast path.
  78. if (FreeZoneBegin_ + size <= FreeZoneEnd_) {
  79. char* result = FreeZoneBegin_;
  80. Size_ += size;
  81. FreeZoneBegin_ += size;
  82. return result;
  83. }
  84. }
  85. // Slow path.
  86. return AllocateAlignedSlow(size, align);
  87. }
  88. template <class T>
  89. inline T* TChunkedMemoryPool::AllocateUninitialized(int n, int align)
  90. {
  91. return reinterpret_cast<T*>(AllocateAligned(sizeof(T) * n, align));
  92. }
  93. template <class T>
  94. inline TMutableRange<T> TChunkedMemoryPool::Capture(TRange<T> src, int align)
  95. {
  96. auto* dst = AllocateUninitialized<T>(src.Size(), align);
  97. ::memcpy(dst, src.Begin(), sizeof(T) * src.Size());
  98. return TMutableRange<T>(dst, src.Size());
  99. }
  100. inline void TChunkedMemoryPool::Free(char* from, char* to)
  101. {
  102. if (FreeZoneBegin_ == to) {
  103. FreeZoneBegin_ = from;
  104. }
  105. if (FreeZoneEnd_ == from) {
  106. FreeZoneEnd_ = to;
  107. }
  108. }
  109. inline void TChunkedMemoryPool::Clear()
  110. {
  111. Size_ = 0;
  112. if (Chunks_.empty()) {
  113. FreeZoneBegin_ = nullptr;
  114. FreeZoneEnd_ = nullptr;
  115. NextChunkIndex_ = 0;
  116. } else {
  117. FreeZoneBegin_ = Chunks_.front()->GetRef().Begin();
  118. FreeZoneEnd_ = Chunks_.front()->GetRef().End();
  119. NextChunkIndex_ = 1;
  120. }
  121. for (const auto& block : OtherBlocks_) {
  122. Capacity_ -= block->GetRef().Size();
  123. }
  124. OtherBlocks_.clear();
  125. }
  126. ////////////////////////////////////////////////////////////////////////////////
  127. } // namespace NYT