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 
24 class module_t;
25 
26 class link_t;
28 
29 namespace link {
30 
31 enum class input_kind_t {
32  cubin,
33  ptx,
34  fatbin,
35  object,
36  library,
37 };
38 
39 using handle_t = CUlinkState;
40 
41 // TODO: Check if the linking has been completed!
42 inline link_t wrap(
43  device::id_t device_id,
44  context::handle_t context_handle,
45  link::handle_t handle,
46  const link::options_t &options,
47  bool take_ownership = false) noexcept;
48 
49 inline link_t create(const void *image, const link::options_t &options);
50 
51 // TODO: Use a clase-class with C++17 of later, made up of the two classes here
52 namespace input {
53 
59  const char *name;
60  link::input_kind_t type;
61 };
62 
63 struct file_t {
64  const char *path; // TODO: Use a proper path in C++14 and later
65  link::input_kind_t type;
66 };
67 
68 } // namespace input
69 
70 } // namespace link
71 
79 class link_t {
80 
81 public: // getters
83  device::id_t device_id() const noexcept
84  { return device_id_; };
85 
87  context::handle_t context_handle() const noexcept
88  { return context_handle_; }
89 
91  bool is_owning() const noexcept
92  { return owning; }
93 
95  device_t device() const;
96 
98  context_t context() const;
99 
100 public:
109  {
110  void *cubin_output_start;
111  size_t cubin_output_size;
112  auto status = cuLinkComplete(handle_, &cubin_output_start, &cubin_output_size);
113  throw_if_error_lazy(status,
114  "Failed completing the link with state at address " + cuda::detail_::ptr_as_hex(handle_));
115  return memory::region_t{cubin_output_start, cubin_output_size};
116  }
117 
118  // TODO: Replace this with methods which take wrapper classes.
119  void add(link::input::image_t image, const link::options_t &ptx_compilation_options = {}) const
120  {
121  auto marshalled_options = marshal(ptx_compilation_options);
122  auto status = cuLinkAddData(
123  handle_,
124  static_cast<CUjitInputType>(image.type),
125  image.data(), // TODO: Is this really safe?
126  image.size(),
127  image.name,
128  marshalled_options.count(),
129  const_cast<link::option_t *>(marshalled_options.options()),
130  const_cast<void **>(marshalled_options.values())
131  );
132  throw_if_error_lazy(status,
133  "Failed adding input " + ::std::string(image.name) + " of type "
134  + ::std::to_string(static_cast<int>(image.type)) + " to a link.");
135  }
136 
137  void add_file(link::input::file_t file_input, const link::options_t &options) const
138  {
139  auto marshalled_options = marshal(options);
140  auto status = cuLinkAddFile(
141  handle_,
142  static_cast<CUjitInputType_enum>(file_input.type),
143  file_input.path,
144  marshalled_options.count(),
145  const_cast<link::option_t *>(marshalled_options.options()),
146  const_cast<void **>(marshalled_options.values())
147  );
148  throw_if_error_lazy(status,
149  "Failed loading an object of type " + ::std::to_string(static_cast<int>(file_input.type))
150  + " from file " + file_input.path);
151  }
152 
153 #if __cplusplus >= 201703L
154  void add_file(const ::std::filesystem::path& path, link::input_kind_t file_contents_type) const
155  {
156  return add_file(path.c_str(), file_contents_type);
157  }
158 #endif
159 
160 protected: // constructors
161 
162  link_t(
163  device::id_t device_id,
164  context::handle_t context,
165  link::handle_t handle,
166  const link::options_t &options,
167  bool take_ownership) noexcept
168  : device_id_(device_id), context_handle_(context), handle_(handle), options_(options), owning(take_ownership)
169  {}
170 
171 public: // friendship
172 
173  friend link_t link::wrap(device::id_t, context::handle_t, link::handle_t, const link::options_t &, bool) noexcept;
174 
175 public: // constructors and destructor
176 
177  link_t(const link_t &) = delete;
178 
179  link_t(link_t &&other) noexcept:
180  link_t(other.device_id_, other.context_handle_, other.handle_, other.options_, other.owning)
181  {
182  other.owning = false;
183  };
184 
185  ~link_t() noexcept(false)
186  {
187  if (owning) {
188  CAW_SET_SCOPE_CONTEXT(context_handle_);
189  auto status = cuLinkDestroy(handle_);
190  throw_if_error_lazy(status,
191  ::std::string("Failed destroying the link ") + detail_::ptr_as_hex(handle_) +
192  " in " + context::detail_::identify(context_handle_, device_id_));
193  }
194  }
195 
196 public: // operators
197 
198  link_t &operator=(const link_t &) = delete;
199 
200  link_t &operator=(link_t &&other) noexcept
201  {
202  ::std::swap(device_id_, other.device_id_);
203  ::std::swap(context_handle_, other.context_handle_);
204  ::std::swap(handle_, other.handle_);
205  ::std::swap(options_, other.options_);
206  ::std::swap(owning, owning);
207  return *this;
208  }
209 
210 protected: // data members
211  device::id_t device_id_;
212  context::handle_t context_handle_;
213  link::handle_t handle_;
214  link::options_t options_;
215  bool owning;
216  // this field is mutable only for enabling move construction; other
217  // than in that case it must not be altered
218 };
219 
220 namespace link {
221 
222 inline link_t create(const link::options_t &options = link::options_t{})
223 {
224  handle_t new_link_handle;
225  auto marshalled_options = marshal(options);
226  auto status = cuLinkCreate(
227  marshalled_options.count(),
228  const_cast<link::option_t *>(marshalled_options.options()),
229  const_cast<void **>(marshalled_options.values()),
230  &new_link_handle
231  );
232  throw_if_error_lazy(status, "Failed creating a new link ");
233  auto do_take_ownership = true;
234  auto context_handle = context::current::detail_::get_handle();
235  auto device_id = context::current::detail_::get_device_id();
236  return wrap(
237  device_id,
238  context_handle,
239  new_link_handle,
240  options,
241  do_take_ownership);
242 }
243 
244 // TODO: Check if the linking has been completed!
245 inline link_t wrap(
246  device::id_t device_id,
247  context::handle_t context_handle,
248  link::handle_t handle,
249  const link::options_t &options,
250  bool take_ownership) noexcept
251 {
252  return link_t{device_id, context_handle, handle, options, take_ownership};
253 }
254 
255 } // namespace link
256 
257 } // namespace cuda
258 
259 #endif // CUDA_API_WRAPPERS_LINK_HPP_
Wrappers for working with modules of compiled CUDA code.
array_t< T, NumDimensions > wrap(device::id_t device_id, context::handle_t context_handle, handle_t handle, dimensions_t< NumDimensions > dimensions) noexcept
Wrap an existing CUDA array in an array_t instance.
Definition: array.hpp:248
Wrapper class for a CUDA context.
Definition: context.hpp:220
All definitions and functionality wrapping the CUDA Runtime API.
Definition: array.hpp:22
CUdevice id_t
Numeric ID of a CUDA device used by the CUDA Runtime API.
Definition: types.hpp:752
Definition: region.hpp:128
freestanding wrapper functions for working with CUDA&#39;s various kinds of memory spaces, arranged into a relevant namespace hierarchy.