cuda_memcpy_async.hpp
1 
5 #pragma once
6 
7 #include <cstddef>
8 #include <vector>
9 
10 #include <cuda_runtime.h>
11 
12 #include <rmm/cuda_stream_view.hpp>
13 
14 namespace rapidsmpf {
15 
34 [[nodiscard]] inline cudaError_t cuda_memcpy_batch_async(
35  void* const* dsts,
36  void const* const* srcs,
37  std::size_t const* sizes,
38  std::size_t count,
40 ) {
41 #if CUDART_VERSION >= 13000
42  if (!stream.is_default()) {
43  // Filter out invalid copies; cudaMemcpyBatchAsync does not support
44  // nullptr dst/src or size==0.
45  auto is_invalid = [&](std::size_t i) {
46  return dsts[i] == nullptr || srcs[i] == nullptr || sizes[i] == 0;
47  };
48 
49  std::vector<void*> valid_dsts;
50  std::vector<void const*> valid_srcs;
51  std::vector<std::size_t> valid_sizes;
52 
53  bool has_invalid = false;
54  for (std::size_t i = 0; i < count; ++i) {
55  if (is_invalid(i)) {
56  has_invalid = true;
57  break;
58  }
59  }
60 
61  if (has_invalid) {
62  valid_dsts.reserve(count);
63  valid_srcs.reserve(count);
64  valid_sizes.reserve(count);
65  for (std::size_t i = 0; i < count; ++i) {
66  if (dsts[i] != nullptr && srcs[i] != nullptr && sizes[i] != 0) {
67  valid_dsts.push_back(dsts[i]);
68  valid_srcs.push_back(srcs[i]);
69  valid_sizes.push_back(sizes[i]);
70  }
71  }
72  if (valid_dsts.empty()) {
73  return cudaSuccess;
74  }
75  dsts = valid_dsts.data();
76  srcs = valid_srcs.data();
77  sizes = valid_sizes.data();
78  count = valid_dsts.size();
79  }
80 
81  cudaMemcpyAttributes attrs = {
82  .srcAccessOrder = cudaMemcpySrcAccessOrderStream,
83  .flags = cudaMemcpyFlagPreferOverlapWithCompute
84  };
85  std::size_t attrs_idxs = 0;
86  return cudaMemcpyBatchAsync(
87  dsts, srcs, sizes, count, &attrs, &attrs_idxs, 1, stream.value()
88  );
89  }
90 #endif // CUDART_VERSION >= 13000
91  for (std::size_t i = 0; i < count; ++i) {
92  if (dsts[i] == nullptr || srcs[i] == nullptr || sizes[i] == 0) {
93  continue;
94  }
95  cudaError_t status = cudaMemcpyAsync(
96  dsts[i], srcs[i], sizes[i], cudaMemcpyDefault, stream.value()
97  );
98  if (status != cudaSuccess) {
99  return status;
100  }
101  }
102  return cudaSuccess;
103 }
104 
135 [[nodiscard]] inline cudaError_t cuda_memcpy_async(
136  void* dst, void const* src, std::size_t count, rmm::cuda_stream_view stream
137 ) {
138  if (count == 0) {
139  return cudaSuccess;
140  }
141  void const* src_ptr = src;
142  return cuda_memcpy_batch_async(&dst, &src_ptr, &count, 1, stream);
143 }
144 
145 } // namespace rapidsmpf
cudaStream_t value() const noexcept
bool is_default() const noexcept
RAPIDS Multi-Processor interfaces.
Definition: backend.hpp:14
cudaError_t cuda_memcpy_batch_async(void *const *dsts, void const *const *srcs, std::size_t const *sizes, std::size_t count, rmm::cuda_stream_view stream)
Asynchronously copies a batch of buffers using the most efficient available API.
cudaError_t cuda_memcpy_async(void *dst, void const *src, std::size_t count, rmm::cuda_stream_view stream)
Asynchronously copies memory between host and/or device buffers.