memory_allocator.h 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // Copyright 2021 The gRPC Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef GRPC_EVENT_ENGINE_MEMORY_ALLOCATOR_H
  15. #define GRPC_EVENT_ENGINE_MEMORY_ALLOCATOR_H
  16. #include <grpc/impl/codegen/port_platform.h>
  17. #include <stdlib.h> // for abort()
  18. #include <algorithm>
  19. #include <memory>
  20. #include <type_traits>
  21. #include <vector>
  22. #include <grpc/event_engine/internal/memory_allocator_impl.h>
  23. #include <grpc/slice.h>
  24. // forward-declaring an internal struct, not used publicly.
  25. struct grpc_slice_buffer;
  26. namespace grpc_event_engine {
  27. namespace experimental {
  28. // TODO(nnoble): needs implementation
  29. class SliceBuffer {
  30. public:
  31. SliceBuffer() { abort(); }
  32. explicit SliceBuffer(grpc_slice_buffer*) { abort(); }
  33. grpc_slice_buffer* RawSliceBuffer() { return slice_buffer_; }
  34. private:
  35. grpc_slice_buffer* slice_buffer_;
  36. };
  37. // Tracks memory allocated by one system.
  38. // Is effectively a thin wrapper/smart pointer for a MemoryAllocatorImpl,
  39. // providing a convenient and stable API.
  40. class MemoryAllocator {
  41. public:
  42. /// Construct a MemoryAllocator given an internal::MemoryAllocatorImpl
  43. /// implementation. The constructed MemoryAllocator will call
  44. /// MemoryAllocatorImpl::Shutdown() upon destruction.
  45. explicit MemoryAllocator(
  46. std::shared_ptr<internal::MemoryAllocatorImpl> allocator)
  47. : allocator_(std::move(allocator)) {}
  48. // Construct an invalid MemoryAllocator.
  49. MemoryAllocator() : allocator_(nullptr) {}
  50. ~MemoryAllocator() {
  51. if (allocator_ != nullptr) allocator_->Shutdown();
  52. }
  53. MemoryAllocator(const MemoryAllocator&) = delete;
  54. MemoryAllocator& operator=(const MemoryAllocator&) = delete;
  55. MemoryAllocator(MemoryAllocator&&) = default;
  56. MemoryAllocator& operator=(MemoryAllocator&&) = default;
  57. /// Drop the underlying allocator and make this an empty object.
  58. /// The object will not be usable after this call unless it's a valid
  59. /// allocator is moved into it.
  60. void Reset() {
  61. if (allocator_ != nullptr) allocator_->Shutdown();
  62. allocator_.reset();
  63. }
  64. /// Reserve bytes from the quota.
  65. /// If we enter overcommit, reclamation will begin concurrently.
  66. /// Returns the number of bytes reserved.
  67. size_t Reserve(MemoryRequest request) { return allocator_->Reserve(request); }
  68. /// Release some bytes that were previously reserved.
  69. void Release(size_t n) { return allocator_->Release(n); }
  70. //
  71. // The remainder of this type are helper functions implemented in terms of
  72. // Reserve/Release.
  73. //
  74. /// An automatic releasing reservation of memory.
  75. class Reservation {
  76. public:
  77. Reservation() = default;
  78. Reservation(const Reservation&) = delete;
  79. Reservation& operator=(const Reservation&) = delete;
  80. Reservation(Reservation&&) = default;
  81. Reservation& operator=(Reservation&&) = default;
  82. ~Reservation() {
  83. if (allocator_ != nullptr) allocator_->Release(size_);
  84. }
  85. private:
  86. friend class MemoryAllocator;
  87. Reservation(std::shared_ptr<internal::MemoryAllocatorImpl> allocator,
  88. size_t size)
  89. : allocator_(std::move(allocator)), size_(size) {}
  90. std::shared_ptr<internal::MemoryAllocatorImpl> allocator_;
  91. size_t size_ = 0;
  92. };
  93. /// Reserve bytes from the quota and automatically release them when
  94. /// Reservation is destroyed.
  95. Reservation MakeReservation(MemoryRequest request) {
  96. return Reservation(allocator_, Reserve(request));
  97. }
  98. /// Allocate a new object of type T, with constructor arguments.
  99. /// The returned type is wrapped, and upon destruction the reserved memory
  100. /// will be released to the allocator automatically. As such, T must have a
  101. /// virtual destructor so we can insert the necessary hook.
  102. template <typename T, typename... Args>
  103. typename std::enable_if<std::has_virtual_destructor<T>::value, T*>::type New(
  104. Args&&... args) {
  105. // Wrap T such that when it's destroyed, we can release memory back to the
  106. // allocator.
  107. class Wrapper final : public T {
  108. public:
  109. explicit Wrapper(std::shared_ptr<internal::MemoryAllocatorImpl> allocator,
  110. Args&&... args)
  111. : T(std::forward<Args>(args)...), allocator_(std::move(allocator)) {}
  112. ~Wrapper() override { allocator_->Release(sizeof(*this)); }
  113. private:
  114. const std::shared_ptr<internal::MemoryAllocatorImpl> allocator_;
  115. };
  116. Reserve(sizeof(Wrapper));
  117. return new Wrapper(allocator_, std::forward<Args>(args)...);
  118. }
  119. /// Construct a unique_ptr immediately.
  120. template <typename T, typename... Args>
  121. std::unique_ptr<T> MakeUnique(Args&&... args) {
  122. return std::unique_ptr<T>(New<T>(std::forward<Args>(args)...));
  123. }
  124. /// Allocate a slice, using MemoryRequest to size the number of returned
  125. /// bytes. For a variable length request, check the returned slice length to
  126. /// verify how much memory was allocated. Takes care of reserving memory for
  127. /// any relevant control structures also.
  128. grpc_slice MakeSlice(MemoryRequest request);
  129. /// A C++ allocator for containers of T.
  130. template <typename T>
  131. class Container {
  132. public:
  133. using value_type = T;
  134. /// Construct the allocator: \a underlying_allocator is borrowed, and must
  135. /// outlive this object.
  136. explicit Container(MemoryAllocator* underlying_allocator)
  137. : underlying_allocator_(underlying_allocator) {}
  138. template <typename U>
  139. explicit Container(const Container<U>& other)
  140. : underlying_allocator_(other.underlying_allocator()) {}
  141. MemoryAllocator* underlying_allocator() const {
  142. return underlying_allocator_;
  143. }
  144. T* allocate(size_t n) {
  145. underlying_allocator_->Reserve(n * sizeof(T));
  146. return static_cast<T*>(::operator new(n * sizeof(T)));
  147. }
  148. void deallocate(T* p, size_t n) {
  149. ::operator delete(p);
  150. underlying_allocator_->Release(n * sizeof(T));
  151. }
  152. private:
  153. MemoryAllocator* underlying_allocator_;
  154. };
  155. protected:
  156. /// Return a pointer to the underlying implementation.
  157. /// Note that the interface of said implementation is unstable and likely to
  158. /// change at any time.
  159. internal::MemoryAllocatorImpl* get_internal_impl_ptr() {
  160. return allocator_.get();
  161. }
  162. const internal::MemoryAllocatorImpl* get_internal_impl_ptr() const {
  163. return allocator_.get();
  164. }
  165. private:
  166. std::shared_ptr<internal::MemoryAllocatorImpl> allocator_;
  167. };
  168. // Wrapper type around std::vector to make initialization against a
  169. // MemoryAllocator based container allocator easy.
  170. template <typename T>
  171. class Vector : public std::vector<T, MemoryAllocator::Container<T>> {
  172. public:
  173. explicit Vector(MemoryAllocator* allocator)
  174. : std::vector<T, MemoryAllocator::Container<T>>(
  175. MemoryAllocator::Container<T>(allocator)) {}
  176. };
  177. class MemoryAllocatorFactory {
  178. public:
  179. virtual ~MemoryAllocatorFactory() = default;
  180. /// On Endpoint creation, call \a CreateMemoryAllocator to create a new
  181. /// allocator for the endpoint.
  182. /// \a name is used to label the memory allocator in debug logs.
  183. /// Typically we'll want to:
  184. /// auto allocator = factory->CreateMemoryAllocator(peer_address_string);
  185. /// auto* endpoint = allocator->New<MyEndpoint>(std::move(allocator), ...);
  186. virtual MemoryAllocator CreateMemoryAllocator(absl::string_view name) = 0;
  187. };
  188. } // namespace experimental
  189. } // namespace grpc_event_engine
  190. #endif // GRPC_EVENT_ENGINE_MEMORY_ALLOCATOR_H