cuda-api-wrappers
Thin C++-flavored wrappers for the CUDA Runtime API
ipc.hpp
Go to the documentation of this file.
1 
23 #pragma once
24 #ifndef CUDA_API_WRAPPERS_IPC_HPP_
25 #define CUDA_API_WRAPPERS_IPC_HPP_
26 
27 #include "context.hpp"
28 #include "types.hpp"
29 #include "error.hpp"
30 
31 #include <string>
32 
33 namespace cuda {
34 
36 class device_t;
37 class event_t;
39 
40 namespace memory {
41 
42 class pool_t;
43 
44 namespace ipc {
45 
50 using ptr_handle_t = CUipcMemHandle;
51 
52 class imported_ptr_t;
53 imported_ptr_t wrap(void * ptr, bool owning) noexcept;
54 
55 namespace detail_ {
56 
67 inline void* import(const ptr_handle_t& handle)
68 {
69  CUdeviceptr device_ptr;
70  auto status = cuIpcOpenMemHandle(&device_ptr, handle, CU_IPC_MEM_LAZY_ENABLE_PEER_ACCESS);
71  throw_if_error_lazy(status, "Failed obtaining a device pointer from an IPC memory handle");
72  return memory::as_pointer(device_ptr);
73 }
74 
81 inline status_t unmap_nothrow(void* ipc_mapped_ptr) noexcept
82 {
83  return cuIpcCloseMemHandle(device::address(ipc_mapped_ptr));
84 }
85 
91 inline void unmap(void* ipc_mapped_ptr)
92 {
93  auto status = unmap_nothrow(ipc_mapped_ptr);
94  throw_if_error_lazy(status, "Failed unmapping IPC memory mapped to " + cuda::detail_::ptr_as_hex(ipc_mapped_ptr));
95 }
96 
97 } // namespace detail_
98 
111 inline ptr_handle_t export_(void* device_ptr)
112 {
113  ptr_handle_t handle;
114  auto status = cuIpcGetMemHandle(&handle, device::address(device_ptr));
115  throw_if_error_lazy(status, "Failed producing an IPC memory handle for device pointer "
116  + cuda::detail_::ptr_as_hex(device_ptr));
117  return handle;
118 }
119 
129 protected: // constructors & destructor
130  imported_ptr_t(void* ptr, bool owning) : ptr_(ptr), owning_(owning)
131  {
132  if (ptr_ == nullptr) {
133  throw ::std::logic_error("IPC memory handle yielded a null pointer");
134  }
135  }
136 
137 public: // constructors & destructors
138  friend imported_ptr_t wrap(void * ptr, bool owning) noexcept;
139 
140  ~imported_ptr_t() DESTRUCTOR_EXCEPTION_SPEC
141  {
142  if (not owning_) { return; }
143 #if THROW_IN_DESTRUCTORS
144  detail_::unmap(ptr_);
145 #else
146  detail_::unmap_nothrow(ptr_);
147 #endif
148  }
149 
150 public: // operators
151 
152  imported_ptr_t(const imported_ptr_t& other) = delete;
153  imported_ptr_t& operator=(const imported_ptr_t& other) = delete;
154  imported_ptr_t& operator=(imported_ptr_t&& other) noexcept
155  {
156  ::std::swap(ptr_, other.ptr_);
157  ::std::swap(owning_, other.owning_);
158  return *this;
159  }
160  imported_ptr_t(imported_ptr_t&& other) noexcept = default;
161 
162 public: // getters
163 
165  template <typename T = void>
166  T* get() const noexcept
167  {
168  // If you're wondering why this cast is necessary - some IDEs/compilers
169  // have the notion that if the method is const, `ptr_` is a const void* within it
170  return static_cast<T*>(const_cast<void*>(ptr_));
171  }
172 
174  bool is_owning() const noexcept { return owning_; }
175 
176 protected: // data members
177  void* ptr_;
178  bool owning_;
179 }; // class imported_ptr_t
180 
182 inline imported_ptr_t wrap(void * ptr, bool owning) noexcept
183 {
184  return imported_ptr_t(ptr, owning);
185 }
186 
188 inline imported_ptr_t import(const ptr_handle_t& ptr_handle)
189 {
190  auto raw_ptr = detail_::import(ptr_handle);
191  return wrap(raw_ptr, do_take_ownership);
192 }
193 
194 } // namespace ipc
195 
196 #if CUDA_VERSION >= 11020
197 namespace pool {
198 
199 namespace ipc {
200 
201 using handle_t = void *;
202 
203 template <shared_handle_kind_t Kind>
204 shared_handle_t<Kind> export_(const pool_t& pool);
205 
206 namespace detail_ {
207 
208 template <shared_handle_kind_t Kind>
209 pool::handle_t import(const shared_handle_t<Kind>& shared_pool_handle)
210 {
211  memory::pool::handle_t result;
212  static constexpr const unsigned long long flags { 0 };
213  void * ptr_to_handle = static_cast<void*>(const_cast<shared_handle_t<Kind>*>(&shared_pool_handle));
214  auto status = cuMemPoolImportFromShareableHandle(
215  &result, ptr_to_handle, static_cast<CUmemAllocationHandleType>(Kind), flags);
216  throw_if_error_lazy(status, "Importing an IPC-shared memory pool handle");
217  return result;
218 }
219 
220 } // namespace detail_
221 
222 template <shared_handle_kind_t Kind>
223 pool_t import(const device_t& device, const shared_handle_t<Kind>& shared_pool_handle);
224 
225 inline ptr_handle_t export_ptr(void* pool_allocated) {
226  ptr_handle_t handle;
227  auto status = cuMemPoolExportPointer(&handle, device::address(pool_allocated));
228  throw_if_error_lazy(status,
229  "Failed producing an IPC handle for memory-pool-allocated pointer "
230  + cuda::detail_::ptr_as_hex(pool_allocated));
231  return handle;
232 }
233 
234 namespace detail_ {
235 
236 inline void* import_ptr(const pool::handle_t pool_handle, const ptr_handle_t& handle)
237 {
238  CUdeviceptr imported;
239  auto status = cuMemPoolImportPointer(&imported, pool_handle, const_cast<ptr_handle_t*>(&handle));
240  throw_if_error_lazy(status, "Failed importing an IPC-exported a pool-allocated pointer");
241  return as_pointer(imported);
242 }
243 
244 } // namespace detail_
245 
257 class imported_ptr_t;
258 
259 imported_ptr_t import_ptr(const pool_t& shared_pool, const ptr_handle_t& ptr_handle);
260 imported_ptr_t import_ptr(const pool_t& shared_pool, const ptr_handle_t& ptr_handle, const stream_t& freeing_stream);
261 
262 } // namespace ipc
263 
264 } // namespace pool
265 #endif // CUDA_VERSION >= 11020
266 
267 } // namespace memory
268 
269 namespace event {
270 namespace ipc {
271 
276 using handle_t = CUipcEventHandle;
277 
278 namespace detail_ {
279 
280 inline handle_t export_(event::handle_t event_handle)
281 {
282  handle_t ipc_handle;
283  auto status = cuIpcGetEventHandle(&ipc_handle, event_handle);
284  throw_if_error_lazy(status, "Failed obtaining an IPC event handle for " +
285  event::detail_::identify(event_handle));
286  return ipc_handle;
287 }
288 
289 inline event::handle_t import(const handle_t& handle)
290 {
291  event::handle_t event_handle;
292  auto status = cuIpcOpenEventHandle(&event_handle, handle);
293  throw_if_error_lazy(status, "Failed obtaining an event handle from an IPC event handle");
294  return event_handle;
295 }
296 
297 } // namespace detail_
298 
307 inline handle_t export_(const event_t& event);
308 
319 
324 inline event_t import(const device_t& device, const handle_t& event_ipc_handle);
325 
331 inline event_t import(const context_t& context, const handle_t& event_ipc_handle);
333 
334 } // namespace ipc
335 } // namespace event
336 } // namespace cuda
337 
338 #endif // CUDA_API_WRAPPERS_IPC_HPP_
Proxy class for a CUDA stream.
Definition: stream.hpp:258
Wrapper class for a CUDA context.
Definition: context.hpp:249
Definitions and functionality wrapping CUDA APIs.
Definition: array.hpp:22
handle_t export_(const event_t &event)
Enable use of an event which this process created by other processes.
Definition: event.hpp:71
event_t import(const context_t &context, const handle_t &event_ipc_handle)
Definition: event.hpp:76
Wrapper class for a CUDA event.
Definition: event.hpp:147
Contains a proxy class for CUDA execution contexts.
CUevent handle_t
The CUDA driver&#39;s raw handle for events.
Definition: types.hpp:214
CUipcEventHandle handle_t
The concrete value passed between processes, used to tell the CUDA Runtime API which event is desired...
Definition: ipc.hpp:276
CUipcMemHandle ptr_handle_t
The concrete value passed between processes, used to tell the CUDA Runtime API which memory area is d...
Definition: ipc.hpp:50
#define throw_if_error_lazy(status__,...)
A macro for only throwing an error if we&#39;ve failed - which also ensures no string is constructed unle...
Definition: error.hpp:327
bool is_owning() const noexcept
Definition: ipc.hpp:174
A smart-pointer-like class for memory obtained via inter-process communication.
Definition: ipc.hpp:128
Facilities for exception-based handling of Runtime and Driver API errors, including a basic exception...
address_t address(const void *device_ptr) noexcept
Definition: types.hpp:684
void * as_pointer(device::address_t address) noexcept
Definition: types.hpp:702
Wrapper class for a CUDA device.
Definition: device.hpp:135
Fundamental CUDA-related type definitions.
CUresult status_t
Indicates either the result (success or error index) of a CUDA Runtime or Driver API call...
Definition: types.hpp:74