buffer.hpp
1 
5 #pragma once
6 
7 #include <array>
8 #include <atomic>
9 #include <cstddef>
10 #include <functional>
11 #include <memory>
12 #include <variant>
13 #include <vector>
14 
15 #include <cuda_runtime.h>
16 
17 #include <rmm/cuda_stream_view.hpp>
18 #include <rmm/device_buffer.hpp>
19 
20 #include <rapidsmpf/cuda_event.hpp>
21 #include <rapidsmpf/error.hpp>
22 #include <rapidsmpf/utils.hpp>
23 
24 namespace rapidsmpf {
25 
27 enum class MemoryType : int {
28  DEVICE = 0,
29  HOST = 1
30 };
31 
33 constexpr MemoryType LowestSpillType = MemoryType::HOST;
34 
37 constexpr std::array<MemoryType, 2> MEMORY_TYPES{{MemoryType::DEVICE, MemoryType::HOST}};
38 
53 class Buffer {
54  friend class BufferResource;
55 
56  public:
58  using DeviceStorageT = std::unique_ptr<rmm::device_buffer>;
59 
61  using HostStorageT = std::unique_ptr<std::vector<uint8_t>>;
62 
66  using StorageT = std::variant<DeviceStorageT, HostStorageT>;
67 
76  [[nodiscard]] HostStorageT const& host() const;
77 
86  [[nodiscard]] DeviceStorageT const& device() const;
87 
96  [[nodiscard]] std::byte const* data() const;
97 
140  template <typename F>
141  auto write_access(F&& f)
142  -> std::invoke_result_t<F, std::byte*, rmm::cuda_stream_view> {
143  using Fn = std::remove_reference_t<F>;
144  static_assert(
145  std::is_invocable_v<Fn, std::byte*, rmm::cuda_stream_view>,
146  "write_access() expects callable R(std::byte*, rmm::cuda_stream_view)"
147  );
148  using R = std::invoke_result_t<Fn, std::byte*, rmm::cuda_stream_view>;
149 
150  auto* ptr = const_cast<std::byte*>(data());
151  if constexpr (std::is_void_v<R>) {
152  std::invoke(std::forward<F>(f), ptr, stream_);
153  latest_write_event_.record(stream_);
154  } else {
155  auto ret = std::invoke(std::forward<F>(f), ptr, stream_);
156  latest_write_event_.record(stream_);
157  return ret;
158  }
159  }
160 
186  std::byte* exclusive_data_access();
187 
191  void unlock();
192 
200  [[nodiscard]] MemoryType constexpr mem_type() const {
201  return std::visit(
202  overloaded{
203  [](HostStorageT const&) -> MemoryType { return MemoryType::HOST; },
204  [](DeviceStorageT const&) -> MemoryType { return MemoryType::DEVICE; }
205  },
206  storage_
207  );
208  }
209 
218  [[nodiscard]] constexpr rmm::cuda_stream_view stream() const noexcept {
219  return stream_;
220  }
221 
251  [[nodiscard]] bool is_latest_write_done() const;
252 
254  Buffer(Buffer&&) = delete;
255  Buffer(Buffer const&) = delete;
256  Buffer& operator=(Buffer& o) = delete;
257  Buffer& operator=(Buffer&& o) = delete;
258 
259  private:
277  Buffer(
278  std::unique_ptr<std::vector<uint8_t>> host_buffer, rmm::cuda_stream_view stream
279  );
280 
298  Buffer(std::unique_ptr<rmm::device_buffer> device_buffer);
299 
305  void throw_if_locked() const;
306 
315  [[nodiscard]] HostStorageT& host();
316 
325  [[nodiscard]] DeviceStorageT& device();
326 
335  [[nodiscard]] DeviceStorageT release_device();
336 
345  [[nodiscard]] HostStorageT release_host();
346 
347  public:
348  std::size_t const size;
349 
350  private:
353  StorageT storage_;
354  rmm::cuda_stream_view stream_;
355  CudaEvent latest_write_event_;
356  std::atomic_bool lock_;
357 };
358 
372 void buffer_copy(
373  Buffer& dst,
374  Buffer const& src,
375  std::size_t size,
376  std::ptrdiff_t dst_offset = 0,
377  std::ptrdiff_t src_offset = 0
378 );
379 
380 } // namespace rapidsmpf
Class managing buffer resources.
Definition: resource.hpp:133
Buffer representing device or host memory.
Definition: buffer.hpp:53
std::unique_ptr< rmm::device_buffer > DeviceStorageT
Storage type for the device buffer.
Definition: buffer.hpp:58
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:141
std::unique_ptr< std::vector< uint8_t > > HostStorageT
Storage type for the host buffer.
Definition: buffer.hpp:61
HostStorageT const & host() const
Access the underlying host memory buffer (const).
std::byte * exclusive_data_access()
Acquire non-stream-ordered exclusive access to the buffer's memory.
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:348
Buffer(Buffer &&)=delete
Delete move and copy constructors and assignment operators.
std::variant< DeviceStorageT, HostStorageT > StorageT
Storage type in Buffer, which could be either host or device memory.
Definition: buffer.hpp:66
constexpr rmm::cuda_stream_view stream() const noexcept
Get the associated CUDA stream.
Definition: buffer.hpp:218
DeviceStorageT const & device() const
Access the underlying device memory buffer (const).
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:200
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.
Helper for overloaded lambdas using std::visit.
Definition: utils.hpp:379