cuda-api-wrappers
Thin C++-flavored wrappers for the CUDA Runtime API
link.hpp
Go to the documentation of this file.
1 
6 #pragma once
7 #ifndef CUDA_API_WRAPPERS_LINK_HPP_
8 #define CUDA_API_WRAPPERS_LINK_HPP_
9 
10 #include "current_context.hpp"
11 #include "link_options.hpp"
12 #include "memory.hpp"
13 #include "module.hpp"
14 
15 #if __cplusplus >= 201703L
16 #include <filesystem>
17 #endif
18 
19 namespace cuda {
20 
22 class device_t;
23 class module_t;
24 class link_t;
26 
28 namespace link {
29 
31 enum class input_kind_t {
32  cubin,
33  ptx,
34  fatbin,
35  object,
36  library,
37 };
38 
40 using handle_t = CUlinkState;
41 
47 inline link_t wrap(
48  device::id_t device_id,
49  context::handle_t context_handle,
50  link::handle_t handle,
51  const link::options_t &options,
52  bool take_ownership = false) noexcept;
53 
54 inline link_t create(const void *image, const link::options_t &options);
55 
57 namespace input {
58 
61  const char *name;
63 };
64 
66 struct file_t {
67  const char *path;
68  link::input_kind_t type;
69 };
70 
71 } // namespace input
72 
73 } // namespace link
74 
82 class link_t {
83 
84 public: // getters
86  device::id_t device_id() const noexcept
87  { return device_id_; };
88 
91  { return context_handle_; }
92 
94  bool is_owning() const noexcept
95  { return owning; }
96 
98  device_t device() const;
99 
101  context_t context() const;
102 
103 public:
112  {
113  void *cubin_output_start;
114  size_t cubin_output_size;
115  auto status = cuLinkComplete(handle_, &cubin_output_start, &cubin_output_size);
116  throw_if_error_lazy(status,
117  "Failed completing the link with state at address " + cuda::detail_::ptr_as_hex(handle_));
118  return memory::region_t{cubin_output_start, cubin_output_size};
119  }
120 
131  void add(link::input::image_t image, const link::options_t &ptx_compilation_options = {}) const
132  {
133  auto marshalled_options = link::detail_::marshal(ptx_compilation_options);
134  auto status = cuLinkAddData(
135  handle_,
136  static_cast<CUjitInputType>(image.type),
137  image.data(), // TODO: Is this really safe?
138  image.size(),
139  image.name,
140  marshalled_options.count(),
141  const_cast<link::detail_::option_t *>(marshalled_options.options()),
142  const_cast<void **>(marshalled_options.values())
143  );
144  throw_if_error_lazy(status,
145  "Failed adding input " + ::std::string(image.name) + " of type "
146  + ::std::to_string(static_cast<int>(image.type)) + " to a link.");
147  }
148 
159  void add_file(link::input::file_t file_input, const link::options_t &options = {}) const
161  {
162  auto marshalled_options = link::detail_::marshal(options);
163  auto status = cuLinkAddFile(
164  handle_,
165  static_cast<CUjitInputType_enum>(file_input.type),
166  file_input.path,
167  marshalled_options.count(),
168  const_cast<link::detail_::option_t *>(marshalled_options.options()),
169  const_cast<void **>(marshalled_options.values())
170  );
171  throw_if_error_lazy(status,
172  "Failed loading an object of type " + ::std::to_string(static_cast<int>(file_input.type))
173  + " from file " + file_input.path);
174  }
175 
176  void add_file(
177  const char* path,
178  link::input_kind_t file_contents_type,
179  const link::options_t &options = {}) const
180  {
181  auto link_file_spec = link::input::file_t { path, file_contents_type };
182  return add_file(link_file_spec, options);
183  }
184 
185 #if __cplusplus >= 201703L
186  void add_file(
187  const ::std::filesystem::path& path,
188  link::input_kind_t file_contents_type,
189  const link::options_t &options = {}) const
190  {
191  return add_file(path.c_str(), file_contents_type, options);
192  }
193 #endif
194 
196 protected: // constructors
197 
198  link_t(
199  device::id_t device_id,
200  context::handle_t context,
201  link::handle_t handle,
202  const link::options_t &options,
203  bool take_ownership) noexcept
204  : device_id_(device_id), context_handle_(context), handle_(handle), options_(options), owning(take_ownership)
205  {}
206 
207 public: // friendship
208 
210 
211 public: // constructors and destructor
212 
213  link_t(const link_t &) = delete;
214 
215  link_t(link_t &&other) noexcept:
216  link_t(other.device_id_, other.context_handle_, other.handle_, other.options_, other.owning)
217  {
218  other.owning = false;
219  };
220 
221  ~link_t() noexcept(false)
222  {
223  if (owning) {
224  CAW_SET_SCOPE_CONTEXT(context_handle_);
225  auto status = cuLinkDestroy(handle_);
226  throw_if_error_lazy(status,
227  ::std::string("Failed destroying the link ") + detail_::ptr_as_hex(handle_) +
228  " in " + context::detail_::identify(context_handle_, device_id_));
229  }
230  }
231 
232 public: // operators
233 
234  link_t &operator=(const link_t &) = delete;
235 
236  link_t &operator=(link_t &&other) noexcept
237  {
238  ::std::swap(device_id_, other.device_id_);
239  ::std::swap(context_handle_, other.context_handle_);
240  ::std::swap(handle_, other.handle_);
241  ::std::swap(options_, other.options_);
242  ::std::swap(owning, owning);
243  return *this;
244  }
245 
246 protected: // data members
247  device::id_t device_id_;
248  context::handle_t context_handle_;
249  link::handle_t handle_;
250  link::options_t options_;
251  bool owning;
252  // this field is mutable only for enabling move construction; other
253  // than in that case it must not be altered
254 };
255 
256 namespace link {
257 
259 inline link_t create(const link::options_t &options = link::options_t{})
260 {
261  handle_t new_link_handle;
262  auto marshalled_options = link::detail_::marshal(options);
263  auto status = cuLinkCreate(
264  marshalled_options.count(),
265  const_cast<link::detail_::option_t *>(marshalled_options.options()),
266  const_cast<void **>(marshalled_options.values()),
267  &new_link_handle
268  );
269  throw_if_error_lazy(status, "Failed creating a new link ");
270  auto do_take_ownership = true;
271  auto context_handle = context::current::detail_::get_handle();
272  auto device_id = context::current::detail_::get_device_id();
273  return wrap(
274  device_id,
275  context_handle,
276  new_link_handle,
277  options,
278  do_take_ownership);
279 }
280 
281 inline link_t wrap(
282  device::id_t device_id,
283  context::handle_t context_handle,
284  link::handle_t handle,
285  const link::options_t & options,
286  bool take_ownership) noexcept
287 {
288  return link_t{device_id, context_handle, handle, options, take_ownership};
289 }
290 
291 } // namespace link
292 
293 } // namespace cuda
294 
295 #endif // CUDA_API_WRAPPERS_LINK_HPP_
Wrappers for working with modules of compiled CUDA code.
Wrapper class for a CUDA context.
Definition: context.hpp:244
Definitions and functionality wrapping CUDA APIs.
Definition: array.hpp:22
detail_::region_helper< memory::region_t > region_t
A child class of the generic region_t with some managed-memory-specific functionality.
Definition: memory.hpp:1960
CUcontext handle_t
Raw CUDA driver handle for a context; see {context_t}.
Definition: types.hpp:878
CUdevice id_t
Numeric ID of a CUDA device used by the CUDA Runtime API.
Definition: types.hpp:850
#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:316
Wrapper class for a CUDA device.
Definition: device.hpp:135
freestanding wrapper functions for working with CUDA&#39;s various kinds of memory spaces, arranged into a relevant namespace hierarchy.