buffer_resource.hpp
1 
6 #pragma once
7 
8 #include <array>
9 #include <atomic>
10 #include <cstdint>
11 #include <memory>
12 #include <mutex>
13 #include <optional>
14 #include <ranges>
15 #include <unordered_map>
16 #include <utility>
17 
18 #include <cuda/memory_resource>
19 
20 #include <rmm/cuda_stream_pool.hpp>
21 
22 #include <rapidsmpf/error.hpp>
23 #include <rapidsmpf/memory/buffer.hpp>
24 #include <rapidsmpf/memory/host_memory_resource.hpp>
25 #include <rapidsmpf/memory/memory_reservation.hpp>
26 #include <rapidsmpf/memory/pinned_memory_resource.hpp>
27 #include <rapidsmpf/memory/resource_types.hpp>
28 #include <rapidsmpf/memory/spill_manager.hpp>
29 #include <rapidsmpf/rmm_resource_adaptor.hpp>
30 #include <rapidsmpf/statistics.hpp>
31 #include <rapidsmpf/utils/misc.hpp>
32 
33 namespace rapidsmpf {
34 
42 enum class AllowOverbooking : bool {
43  NO,
44  YES,
45 };
46 
76 class BufferResource : public std::enable_shared_from_this<BufferResource> {
77  public:
111  [[nodiscard]] static std::shared_ptr<BufferResource> create(
112  cuda::mr::any_resource<cuda::mr::device_accessible> device_mr,
113  std::optional<PinnedPoolProperties> pinned_pool_properties = PinnedMemoryDisabled,
114  std::unordered_map<MemoryType, std::int64_t> memory_limits = {},
115  std::optional<Duration> periodic_spill_check = std::chrono::milliseconds{1},
116  std::shared_ptr<rmm::cuda_stream_pool> stream_pool = std::make_shared<
118  std::shared_ptr<Statistics> statistics = Statistics::disabled()
119  );
120 
134  static std::shared_ptr<BufferResource> from_options(
135  cuda::mr::any_resource<cuda::mr::device_accessible> mr,
136  config::Options options,
137  std::shared_ptr<Statistics> statistics = Statistics::disabled()
138  );
139 
140  ~BufferResource() noexcept = default;
141 
145  BufferResource(BufferResource const&) = delete;
154  BufferResource& operator=(BufferResource const&) = delete;
159  BufferResource& operator=(BufferResource&&) = delete;
160 
202  [[nodiscard]] rmm::device_async_resource_ref device_mr() noexcept;
203 
219  [[nodiscard]] RmmResourceAdaptor& device_mr_adaptor() noexcept;
220 
231  [[nodiscard]] rmm::host_async_resource_ref host_mr() noexcept;
232 
245 
253  [[nodiscard]] std::optional<PinnedMemoryResource> try_pinned_mr() const;
254 
266  [[nodiscard]] std::int64_t memory_available(MemoryType mem_type) const noexcept;
267 
282  void set_memory_limit(MemoryType mem_type, std::int64_t limit) noexcept;
283 
290  [[nodiscard]] std::size_t memory_reserved(MemoryType mem_type) const {
291  return memory_reserved_[static_cast<std::size_t>(mem_type)];
292  }
293 
316  std::pair<MemoryReservation, std::size_t> reserve(
317  MemoryType mem_type, std::size_t size, AllowOverbooking allow_overbooking
318  );
319 
338  std::size_t size, AllowOverbooking allow_overbooking
339  );
340 
354  template <std::ranges::input_range Range>
355  requires std::convertible_to<std::ranges::range_value_t<Range>, MemoryType>
356  [[nodiscard]] MemoryReservation reserve_or_fail(std::size_t size, Range mem_types) {
357  // try to reserve memory from the given order
358  for (auto const& mem_type : mem_types) {
359  if (mem_type == MemoryType::PINNED_HOST && !pinned_mr_.has_value()) {
360  // Pinned host memory is only available if the memory resource is
361  // available.
362  continue;
363  }
364  auto [res, _] = reserve(mem_type, size, AllowOverbooking::NO);
365  if (res.size() == size) {
366  return std::move(res);
367  }
368  }
369  RAPIDSMPF_FAIL("failed to reserve memory", std::runtime_error);
370  }
371 
382  std::size_t size, MemoryType mem_type
383  ) {
384  return reserve_or_fail(size, std::ranges::single_view{mem_type});
385  }
386 
399  std::size_t release(MemoryReservation& reservation, std::size_t size);
400 
412  std::unique_ptr<Buffer> make_buffer(
413  std::size_t size, rmm::cuda_stream_view stream, MemoryReservation& reservation
414  );
415 
426  std::unique_ptr<Buffer> make_buffer(
427  rmm::cuda_stream_view stream, MemoryReservation&& reservation
428  );
429 
449  std::unique_ptr<Buffer> move(
450  std::unique_ptr<rmm::device_buffer> data, rmm::cuda_stream_view stream
451  );
452 
466  std::unique_ptr<Buffer> move(
467  std::unique_ptr<Buffer> buffer, MemoryReservation& reservation
468  );
469 
484  std::unique_ptr<rmm::device_buffer> move_to_device_buffer(
485  std::unique_ptr<Buffer> buffer, MemoryReservation& reservation
486  );
487 
502  std::unique_ptr<HostBuffer> move_to_host_buffer(
503  std::unique_ptr<Buffer> buffer, MemoryReservation& reservation
504  );
505 
513  std::shared_ptr<rmm::cuda_stream_pool> const& stream_pool() const;
514 
521 
528  std::shared_ptr<Statistics> statistics() const noexcept;
529 
530  private:
533  cuda::mr::any_resource<cuda::mr::device_accessible> device_mr,
534  std::optional<PinnedMemoryResource> pinned_mr,
535  std::unordered_map<MemoryType, std::int64_t> memory_limits,
536  std::optional<Duration> periodic_spill_check,
537  std::shared_ptr<rmm::cuda_stream_pool> stream_pool,
538  std::shared_ptr<Statistics> statistics
539  );
540 
541  std::mutex mutex_;
542  RmmResourceAdaptor owning_mr_;
543  std::optional<PinnedMemoryResource> pinned_mr_;
544  HostMemoryResource host_mr_;
545  std::array<std::atomic<std::int64_t>, MEMORY_TYPES.size()> memory_limits_;
546  // Zero initialized reserved counters.
547  std::array<std::size_t, MEMORY_TYPES.size()> memory_reserved_ = {};
548  std::shared_ptr<rmm::cuda_stream_pool> stream_pool_;
549  SpillManager spill_manager_;
550  std::shared_ptr<Statistics> statistics_;
551 };
552 
553 static_assert(StatisticsProvider<BufferResource>);
554 
567 
576 std::optional<Duration> periodic_spill_check_from_options(config::Options options);
577 
585 std::shared_ptr<rmm::cuda_stream_pool> stream_pool_from_options(config::Options options);
586 
587 
588 } // namespace rapidsmpf
Class managing buffer resources.
std::size_t release(MemoryReservation &reservation, std::size_t size)
Consume a portion of the reserved memory.
std::shared_ptr< Statistics > statistics() const noexcept
Gets a shared pointer to the statistics associated with this buffer resource.
rmm::host_async_resource_ref host_mr() noexcept
Get the RMM host memory resource.
static std::shared_ptr< BufferResource > create(cuda::mr::any_resource< cuda::mr::device_accessible > device_mr, std::optional< PinnedPoolProperties > pinned_pool_properties=PinnedMemoryDisabled, std::unordered_map< MemoryType, std::int64_t > memory_limits={}, std::optional< Duration > periodic_spill_check=std::chrono::milliseconds{1}, std::shared_ptr< rmm::cuda_stream_pool > stream_pool=std::make_shared< rmm::cuda_stream_pool >(16, rmm::cuda_stream::flags::non_blocking), std::shared_ptr< Statistics > statistics=Statistics::disabled())
Construct a BufferResource managed by std::shared_ptr.
std::unique_ptr< Buffer > make_buffer(std::size_t size, rmm::cuda_stream_view stream, MemoryReservation &reservation)
Allocate a buffer of the specified memory type by the reservation.
std::unique_ptr< Buffer > make_buffer(rmm::cuda_stream_view stream, MemoryReservation &&reservation)
Allocate a buffer consuming the entire reservation.
RmmResourceAdaptor & device_mr_adaptor() noexcept
Access the concrete device memory resource adaptor.
rmm::device_async_resource_ref device_mr() noexcept
Get the device memory resource.
std::unique_ptr< Buffer > move(std::unique_ptr< Buffer > buffer, MemoryReservation &reservation)
Move a Buffer to the memory type specified by the reservation.
std::size_t memory_reserved(MemoryType mem_type) const
Get the current reserved memory of the specified memory type.
std::unique_ptr< rmm::device_buffer > move_to_device_buffer(std::unique_ptr< Buffer > buffer, MemoryReservation &reservation)
Move a Buffer to a device buffer.
MemoryReservation reserve_device_memory_and_spill(std::size_t size, AllowOverbooking allow_overbooking)
Reserve device memory and spill if necessary.
MemoryReservation reserve_or_fail(std::size_t size, MemoryType mem_type)
Make a memory reservation or fail.
requires std::convertible_to< std::ranges::range_value_t< Range >, MemoryType > MemoryReservation reserve_or_fail(std::size_t size, Range mem_types)
Make a memory reservation or fail based on the given order of memory types.
std::int64_t memory_available(MemoryType mem_type) const noexcept
Returns the currently available memory for a given memory type, in bytes.
void set_memory_limit(MemoryType mem_type, std::int64_t limit) noexcept
Updates the memory limit for a given memory type at runtime.
rmm::host_device_async_resource_ref pinned_mr()
Get the RMM pinned host memory resource.
static std::shared_ptr< BufferResource > from_options(cuda::mr::any_resource< cuda::mr::device_accessible > mr, config::Options options, std::shared_ptr< Statistics > statistics=Statistics::disabled())
Construct a BufferResource from configuration options.
SpillManager & spill_manager()
Gets a reference to the spill manager used.
std::optional< PinnedMemoryResource > try_pinned_mr() const
Get the pinned host memory resource if available.
std::unique_ptr< HostBuffer > move_to_host_buffer(std::unique_ptr< Buffer > buffer, MemoryReservation &reservation)
Move a Buffer into a host buffer.
std::pair< MemoryReservation, std::size_t > reserve(MemoryType mem_type, std::size_t size, AllowOverbooking allow_overbooking)
Reserve an amount of the specified memory type.
std::shared_ptr< rmm::cuda_stream_pool > const & stream_pool() const
Returns the CUDA stream pool used by this buffer resource.
std::unique_ptr< Buffer > move(std::unique_ptr< rmm::device_buffer > data, rmm::cuda_stream_view stream)
Move device or pinned host buffer data into a Buffer.
Host memory resource using standard CPU allocation.
Represents a reservation for future memory allocation.
Memory resource that provides pinned (page-locked) host memory using a pool.
A RMM memory resource adaptor tailored to RapidsMPF.
Manages memory spilling to free up device memory when needed.
Tracks statistics across rapidsmpf operations.
Definition: statistics.hpp:74
static std::shared_ptr< Statistics > disabled()
Returns a disabled Statistics instance which can be enabled later.
Definition: statistics.hpp:134
Manages configuration options for RapidsMPF operations.
Definition: config.hpp:144
cuda::mr::resource_ref< cuda::mr::host_accessible > host_async_resource_ref
cuda::mr::resource_ref< cuda::mr::device_accessible > device_async_resource_ref
cuda::mr::resource_ref< cuda::mr::host_accessible, cuda::mr::device_accessible > host_device_async_resource_ref
RAPIDS Multi-Processor interfaces.
Definition: backend.hpp:14
std::optional< Duration > periodic_spill_check_from_options(config::Options options)
Get the periodic_spill_check parameter from configuration options.
constexpr std::optional< PinnedPoolProperties > PinnedMemoryDisabled
Sentinel used to disable pinned host memory.
AllowOverbooking
Policy controlling whether a memory reservation is allowed to overbook.
@ YES
Overbooking is allowed.
@ NO
Overbooking is not allowed.
std::chrono::duration< double > Duration
Alias for a duration type representing time in seconds as a double.
Definition: misc.hpp:35
constexpr std::array< MemoryType, 3 > MEMORY_TYPES
All memory types sorted in decreasing order of preference.
Definition: memory_type.hpp:23
MemoryType
Enum representing the type of memory sorted in decreasing order of preference.
Definition: memory_type.hpp:16
@ PINNED_HOST
Pinned host memory.
std::int64_t device_limit_from_options(config::Options options)
Parse the spill_device_limit parameter from configuration options.
std::shared_ptr< rmm::cuda_stream_pool > stream_pool_from_options(config::Options options)
Get a new CUDA stream pool from configuration options.