buffer.hpp
1 
5 #pragma once
6 
7 #include <atomic>
8 #include <cstddef>
9 #include <functional>
10 #include <memory>
11 #include <variant>
12 
13 #include <cuda_runtime.h>
14 
15 #include <rmm/cuda_stream_view.hpp>
16 #include <rmm/device_buffer.hpp>
17 
18 #include <rapidsmpf/cuda_event.hpp>
19 #include <rapidsmpf/error.hpp>
20 #include <rapidsmpf/memory/host_buffer.hpp>
21 #include <rapidsmpf/memory/memory_type.hpp>
22 #include <rapidsmpf/statistics.hpp>
23 #include <rapidsmpf/utils/misc.hpp>
24 
25 namespace rapidsmpf {
26 
47 class Buffer {
48  friend class BufferResource;
49 
50  public:
52  using DeviceBufferT = std::unique_ptr<rmm::device_buffer>;
53 
55  using HostBufferT = std::unique_ptr<HostBuffer>;
56 
64  static constexpr std::array<MemoryType, 1> device_buffer_types{MemoryType::DEVICE};
65 
73  static constexpr std::array<MemoryType, 2> host_buffer_types{
75  };
76 
85  [[nodiscard]] std::byte const* data() const;
86 
128  template <typename F>
129  auto write_access(F&& f)
130  -> std::invoke_result_t<F, std::byte*, rmm::cuda_stream_view> {
131  using Fn = std::remove_reference_t<F>;
132  static_assert(
133  std::is_invocable_v<Fn, std::byte*, rmm::cuda_stream_view>,
134  "write_access() expects callable R(std::byte*, rmm::cuda_stream_view)"
135  );
136  using R = std::invoke_result_t<Fn, std::byte*, rmm::cuda_stream_view>;
137 
138  auto* ptr = const_cast<std::byte*>(data());
139  if constexpr (std::is_void_v<R>) {
140  std::invoke(std::forward<F>(f), ptr, stream_);
141  latest_write_event_.record(stream_);
142  } else {
143  auto ret = std::invoke(std::forward<F>(f), ptr, stream_);
144  latest_write_event_.record(stream_);
145  return ret;
146  }
147  }
148 
178  std::byte* exclusive_data_access();
179 
183  void unlock();
184 
192  [[nodiscard]] MemoryType constexpr mem_type() const {
193  return mem_type_;
194  }
195 
204  [[nodiscard]] constexpr rmm::cuda_stream_view stream() const noexcept {
205  return stream_;
206  }
207 
213  [[nodiscard]] CudaEvent const& latest_write_event() const noexcept {
214  return latest_write_event_;
215  }
216 
242 
277  [[nodiscard]] bool is_latest_write_done() const;
278 
280  Buffer(Buffer&&) = delete;
281  Buffer(Buffer const&) = delete;
282  Buffer& operator=(Buffer& o) = delete;
283  Buffer& operator=(Buffer&& o) = delete;
284 
285  private:
308  Buffer(
309  std::unique_ptr<HostBuffer> host_buffer,
312  );
313 
336  Buffer(std::unique_ptr<rmm::device_buffer> device_buffer, MemoryType mem_type);
337 
343  void throw_if_locked() const;
344 
353  [[nodiscard]] DeviceBufferT release_device_buffer();
354 
363  [[nodiscard]] HostBufferT release_host_buffer();
364 
365  public:
366  std::size_t const size;
367 
368  private:
369  MemoryType const mem_type_;
370  std::variant<DeviceBufferT, HostBufferT> storage_;
371  rmm::cuda_stream_view stream_;
372  CudaEvent latest_write_event_;
373  std::atomic<bool> lock_;
374 };
375 
393  std::shared_ptr<Statistics> statistics,
394  Buffer& dst,
395  Buffer const& src,
396  std::size_t size,
397  std::ptrdiff_t dst_offset = 0,
398  std::ptrdiff_t src_offset = 0
399 );
400 
401 } // namespace rapidsmpf
Class managing buffer resources.
Buffer representing device or host memory.
Definition: buffer.hpp:47
auto write_access(F &&f) -> std::invoke_result_t< F, std::byte *, rmm::cuda_stream_view >
Provides stream-ordered write access to the buffer.
Definition: buffer.hpp:129
static constexpr std::array< MemoryType, 1 > device_buffer_types
Memory types suitable for constructing a device backed buffer.
Definition: buffer.hpp:64
CudaEvent const & latest_write_event() const noexcept
Get the CUDA event that tracks the latest write into the buffer.
Definition: buffer.hpp:213
std::byte * exclusive_data_access()
Acquire non-stream-ordered exclusive access to the buffer's memory.
void rebind_stream(rmm::cuda_stream_view new_stream)
Rebind the buffer to a new CUDA stream.
std::unique_ptr< rmm::device_buffer > DeviceBufferT
Storage type for a device buffer.
Definition: buffer.hpp:52
bool is_latest_write_done() const
Check whether the buffer's most recent write has completed.
std::byte const * data() const
Access the underlying memory buffer (host or device memory).
std::size_t const size
The size of the buffer in bytes.
Definition: buffer.hpp:366
static constexpr std::array< MemoryType, 2 > host_buffer_types
Memory types suitable for constructing a host backed buffer.
Definition: buffer.hpp:73
Buffer(Buffer &&)=delete
Delete move and copy constructors and assignment operators.
std::unique_ptr< HostBuffer > HostBufferT
Storage type for a host buffer.
Definition: buffer.hpp:55
constexpr rmm::cuda_stream_view stream() const noexcept
Get the associated CUDA stream.
Definition: buffer.hpp:204
void unlock()
Release the exclusive lock acquired by exclusive_data_access().
constexpr MemoryType mem_type() const
Get the memory type of the buffer.
Definition: buffer.hpp:192
RAII wrapper for a CUDA event with convenience methods.
Definition: cuda_event.hpp:35
void record(rmm::cuda_stream_view stream)
Record the event on a CUDA stream.
RAPIDS Multi-Processor interfaces.
Definition: backend.hpp:14
MemoryType
Enum representing the type of memory sorted in decreasing order of preference.
Definition: memory_type.hpp:16
@ PINNED_HOST
Pinned host memory.
@ HOST
Host memory.
@ DEVICE
Device memory.
void buffer_copy(std::shared_ptr< Statistics > statistics, Buffer &dst, Buffer const &src, std::size_t size, std::ptrdiff_t dst_offset=0, std::ptrdiff_t src_offset=0)
Asynchronously copy data between buffers.