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 
13 #if __cplusplus >= 201703L
14 #include <filesystem>
15 #endif
16 
17 namespace cuda {
18 
20 class device_t;
21 class module_t;
22 class link_t;
24 
26 namespace link {
27 
29 enum class input_kind_t {
30  cubin,
31  ptx,
32  fatbin,
33  object,
34  library,
35 };
36 
38 using handle_t = CUlinkState;
39 
45 inline link_t wrap(
46  device::id_t device_id,
47  context::handle_t context_handle,
48  link::handle_t handle,
49  const link::options_t &options,
50  bool take_ownership = false) noexcept;
51 
53 namespace input {
54 
57  const char *name;
59 };
60 
62 struct file_t {
63  const char *path;
64  link::input_kind_t type;
65 };
66 
67 } // namespace input
68 
69 namespace detail_ {
70 
71 inline void destroy(handle_t handle, context::handle_t context_handle, device::id_t device_id)
72 {
73  CAW_SET_SCOPE_CONTEXT(context_handle);
74  auto status = cuLinkDestroy(handle);
75  throw_if_error_lazy(status,
76  ::std::string("Failed destroying the link ") + cuda::detail_::ptr_as_hex(handle)
77  + " in " + context::detail_::identify(context_handle)
78  + " on " + device::detail_::identify(device_id));
79 }
80 
81 } // namespace detail_
82 
83 } // namespace link
84 
92 class link_t {
93 
94 public: // getters
96  device::id_t device_id() const noexcept
97  { return device_id_; };
98 
101  { return context_handle_; }
102 
104  bool is_owning() const noexcept
105  { return owning; }
106 
108  device_t device() const;
109 
111  context_t context() const;
112 
113 public:
122  {
123  void *cubin_output_start;
124  size_t cubin_output_size;
125  auto status = cuLinkComplete(handle_, &cubin_output_start, &cubin_output_size);
126  throw_if_error_lazy(status,
127  "Failed completing the link with state at address " + cuda::detail_::ptr_as_hex(handle_));
128  return memory::region_t{cubin_output_start, cubin_output_size};
129  }
130 
141  void add(link::input::image_t image, const link::options_t &ptx_compilation_options = {}) const
142  {
143  auto marshalled_options = link::detail_::marshal(ptx_compilation_options);
144  auto status = cuLinkAddData(
145  handle_,
146  static_cast<CUjitInputType>(image.type),
147  image.data(), // TODO: Is this really safe?
148  image.size(),
149  image.name,
150  marshalled_options.count(),
151  const_cast<link::detail_::option_t *>(marshalled_options.options()),
152  const_cast<void **>(marshalled_options.values())
153  );
154  throw_if_error_lazy(status,
155  "Failed adding input " + ::std::string(image.name) + " of type "
156  + ::std::to_string(static_cast<int>(image.type)) + " to a link.");
157  }
158 
169  void add_file(link::input::file_t file_input, const link::options_t &options = {}) const
171  {
172  auto marshalled_options = link::detail_::marshal(options);
173  auto status = cuLinkAddFile(
174  handle_,
175  static_cast<CUjitInputType_enum>(file_input.type),
176  file_input.path,
177  marshalled_options.count(),
178  const_cast<link::detail_::option_t *>(marshalled_options.options()),
179  const_cast<void **>(marshalled_options.values())
180  );
181  throw_if_error_lazy(status,
182  "Failed loading an object of type " + ::std::to_string(static_cast<int>(file_input.type))
183  + " from file " + file_input.path);
184  }
185 
186  void add_file(
187  const char* path,
188  link::input_kind_t file_contents_type,
189  const link::options_t &options = {}) const
190  {
191  auto link_file_spec = link::input::file_t { path, file_contents_type };
192  return add_file(link_file_spec, options);
193  }
194 
195 #if __cplusplus >= 201703L
196  void add_file(
197  const ::std::filesystem::path& path,
198  link::input_kind_t file_contents_type,
199  const link::options_t &options = {}) const
200  {
201  return add_file(path.c_str(), file_contents_type, options);
202  }
203 #endif
204 
206 protected: // constructors
207 
208  link_t(
209  device::id_t device_id,
210  context::handle_t context,
211  link::handle_t handle,
212  const link::options_t &options,
213  bool take_ownership) noexcept
214  : device_id_(device_id), context_handle_(context), handle_(handle), options_(options), owning(take_ownership)
215  {}
216 
217 public: // friendship
218 
220 
221 public: // constructors and destructor
222 
223  link_t(const link_t &) = delete;
224 
225  link_t(link_t &&other) noexcept:
226  link_t(other.device_id_, other.context_handle_, other.handle_, other.options_, other.owning)
227  {
228  other.owning = false;
229  };
230 
231  ~link_t() DESTRUCTOR_EXCEPTION_SPEC
232  {
233  if (not owning) { return; }
234 #ifndef THROW_IN_DESTRUCTORS
235  try
236 #endif
237  {
238  link::detail_::destroy(handle_, context_handle_, device_id_);
239  }
240 #ifndef THROW_IN_DESTRUCTORS
241  catch (...) {}
242 #endif
243  }
244 
245 public: // operators
246 
247  link_t &operator=(const link_t &) = delete;
248 
249  link_t &operator=(link_t &&other) noexcept
250  {
251  ::std::swap(device_id_, other.device_id_);
252  ::std::swap(context_handle_, other.context_handle_);
253  ::std::swap(handle_, other.handle_);
254  ::std::swap(options_, other.options_);
255  ::std::swap(owning, owning);
256  return *this;
257  }
258 
259 protected: // data members
260  device::id_t device_id_;
261  context::handle_t context_handle_;
262  link::handle_t handle_;
263  link::options_t options_;
264  bool owning;
265  // this field is mutable only for enabling move construction; other
266  // than in that case it must not be altered
267 };
268 
269 namespace link {
270 
272 inline link_t create(const link::options_t &options = link::options_t{})
273 {
274  handle_t new_link_handle;
275  auto marshalled_options = link::detail_::marshal(options);
276  auto status = cuLinkCreate(
277  marshalled_options.count(),
278  const_cast<link::detail_::option_t *>(marshalled_options.options()),
279  const_cast<void **>(marshalled_options.values()),
280  &new_link_handle
281  );
282  throw_if_error_lazy(status, "Failed creating a new link ");
283  auto do_take_ownership = true;
284  auto context_handle = context::current::detail_::get_handle();
285  auto device_id = context::current::detail_::get_device_id();
286  return wrap(
287  device_id,
288  context_handle,
289  new_link_handle,
290  options,
291  do_take_ownership);
292 }
293 
294 inline link_t wrap(
295  device::id_t device_id,
296  context::handle_t context_handle,
297  link::handle_t handle,
298  const link::options_t & options,
299  bool take_ownership) noexcept
300 {
301  return link_t{device_id, context_handle, handle, options, take_ownership};
302 }
303 
304 } // namespace link
305 
306 } // namespace cuda
307 
308 #endif // CUDA_API_WRAPPERS_LINK_HPP_
Wrapper class for a CUDA context.
Definition: context.hpp:249
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:1974
CUcontext handle_t
Raw CUDA driver handle for a context; see {context_t}.
Definition: types.hpp:880
CUdevice id_t
Numeric ID of a CUDA device used by the CUDA Runtime API.
Definition: types.hpp:852
#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
Wrapper class for a CUDA device.
Definition: device.hpp:135