cuda-api-wrappers
Thin C++-flavored wrappers for the CUDA Runtime API
builder.hpp
Go to the documentation of this file.
1 
6 #pragma once
7 #ifndef CUDA_API_WRAPPERS_FATBIN_BUILDER_HPP_
8 #define CUDA_API_WRAPPERS_FATBIN_BUILDER_HPP_
9 
10 #if CUDA_VERSION >= 12040
11 
12 #include "../api/detail/region.hpp"
13 #include "builder_options.hpp"
14 #include "types.hpp"
15 
16 #include <string>
17 
18 namespace cuda {
19 
21 class fatbin_builder_t;
23 
24 namespace fatbin_builder {
25 
26 inline fatbin_builder_t wrap(handle_t handle, bool take_ownership = false) noexcept;
27 
28 inline fatbin_builder_t create(const options_t & options);
29 
30 namespace detail_ {
31 
32 inline ::std::string identify(handle_t handle)
33 {
34  return "Fatbin builder with handle " + cuda::detail_::ptr_as_hex(handle);
35 }
36 
37 inline ::std::string identify(const fatbin_builder_t&);
38 
39 } // namespace detail_
40 
41 } // namespace fatbin_builder
42 
43 
44 class fatbin_builder_t {
45 public: // type definitions
46  using size_type = ::size_t;
47 
48  struct deleter_type {
49  void operator()(void * data) { operator delete(data); }
50  };
51 
52 public: // getters
53 
54  fatbin_builder::handle_t handle() const
55  { return handle_; }
56 
59  bool is_owning() const noexcept
60  { return owning; }
61 
62 protected: // unsafe actions
63 
64  void build_without_size_check_in(memory::region_t target_region) const
65  {
66  auto status = nvFatbinGet(handle_, target_region.data());
67  throw_if_error_lazy(status, "Failed completing the generation of a fatbin at " +
68  cuda::detail_::ptr_as_hex(target_region.data()));
69  }
70 
71 public:
72  size_type size() const
73  {
74  size_type result;
75  auto status = nvFatbinSize(handle_, &result);
76  throw_if_error_lazy(status, "Failed determining prospective fatbin size for " + fatbin_builder::detail_::identify(*this));
77  return result;
78  }
79 
80  void build_in(memory::region_t target_region) const
81  {
82  auto required_size = size();
83  if (target_region.size() < required_size) {
84  throw ::std::invalid_argument("Provided region for fatbin creation is of size "
85  + ::std::to_string(target_region.size()) + " bytes, while the fatbin requires " + ::std::to_string(required_size));
86  }
87  return build_without_size_check_in(target_region);
88  }
89 
90  memory::unique_region<deleter_type> build() const
91  {
92  auto size_ = size();
93  auto ptr = operator new(size_);
94  memory::region_t target_region{ptr, size_};
95  build_in(target_region);
96  return memory::unique_region<deleter_type>(target_region);
97  }
98 
99  void add_ptx_source(
100  const char* identifier,
101  span<char> nul_terminated_ptx_source,
102  device::compute_capability_t target_compute_capability) const // no support for options, for now
103  {
104 #ifndef NDEBUG
105  if (nul_terminated_ptx_source.empty()) {
106  throw ::std::invalid_argument("Empty PTX source code passed for addition into fatbin");
107  }
108  if (nul_terminated_ptx_source[nul_terminated_ptx_source.size() - 1] != '\0') {
109  throw ::std::invalid_argument("PTX source code passed for addition into fatbin was not nul-character-terminated");
110  }
111 #endif
112  auto compute_capability_str = ::std::to_string(target_compute_capability.as_combined_number());
113  auto empty_cmdline = "";
114  auto status = nvFatbinAddPTX(handle_,
115  nul_terminated_ptx_source.data(),
116  nul_terminated_ptx_source.size(),
117  compute_capability_str.c_str(),
118  identifier,
119  empty_cmdline);
120  throw_if_error_lazy(status, "Failed adding PTX source fragment "
121  + ::std::string(identifier) + " at " + detail_::ptr_as_hex(nul_terminated_ptx_source.data())
122  + " to a fat binary for target compute capability " + compute_capability_str);
123  }
124 
125  void add_lto_ir(
126  const char* identifier,
127  memory::region_t lto_ir,
128  device::compute_capability_t target_compute_capability) const
129  {
130  auto compute_capability_str = ::std::to_string(target_compute_capability.as_combined_number());
131  auto empty_cmdline = "";
132  auto status = nvFatbinAddLTOIR(
133  handle_, lto_ir.data(), lto_ir.size(), compute_capability_str.c_str(), identifier, empty_cmdline);
134  throw_if_error_lazy(status, "Failed adding LTO IR fragment "
135  + ::std::string(identifier) + " at " + detail_::ptr_as_hex(lto_ir.data())
136  + " to a fat binary for target compute capability " + compute_capability_str);
137  }
138 
139  void add_cubin(
140  const char* identifier,
141  memory::region_t cubin,
142  device::compute_capability_t target_compute_capability) const
143  {
144  auto compute_capability_str = ::std::to_string(target_compute_capability.as_combined_number());
145  auto status = nvFatbinAddCubin(
146  handle_, cubin.data(), cubin.size(), compute_capability_str.c_str(), identifier);
147  throw_if_error_lazy(status, "Failed adding cubin fragment "
148  + ::std::string(identifier) + " at " + detail_::ptr_as_hex(cubin.data())
149  + " to a fat binary for target compute capability " + compute_capability_str);
150  }
151 
152 #if CUDA_VERSION >= 12050
153 
160  void add_relocatable_ptx(memory::region_t ptx_code) const
161  {
162  auto status = nvFatbinAddReloc(handle_, ptx_code.data(), ptx_code.size());
163  throw_if_error_lazy(status, "Failed adding relocatable PTX code at " + detail_::ptr_as_hex(ptx_code.data())
164  + "to fatbin builder " + fatbin_builder::detail_::identify(*this) );
165  }
166 
167  // TODO: WTF is an index?
168  void add_index(const char* identifier, memory::region_t index) const
169  {
170  auto status = nvFatbinAddIndex(handle_, index.data(), index.size(), identifier);
171  throw_if_error_lazy(status, "Failed adding index " + ::std::string(identifier) + " at "
172  + detail_::ptr_as_hex(index.data()) + " to a fat binary");
173  }
174 #endif // CUDA_VERSION >= 12050
175 
176 protected: // constructors
177 
178  fatbin_builder_t(
180  // no support for options, for now
181  bool take_ownership) noexcept
182  : handle_(handle), owning(take_ownership)
183  {}
184 
185 public: // friendship
186 
187  friend fatbin_builder_t fatbin_builder::wrap(fatbin_builder::handle_t, bool) noexcept;
188 
189 public: // constructors and destructor
190 
191  fatbin_builder_t(const fatbin_builder_t &) = delete;
192 
193  fatbin_builder_t(fatbin_builder_t &&other) noexcept:
194  fatbin_builder_t(other.handle_, other.owning)
195  {
196  other.owning = false;
197  };
198 
199  ~fatbin_builder_t() noexcept(false)
200  {
201  if (owning) {
202  auto status = nvFatbinDestroy(&handle_); // this nullifies the handle :-O
203  throw_if_error_lazy(status,
204  ::std::string("Failed destroying fatbin builder ") + detail_::ptr_as_hex(handle_) +
205  " in " + fatbin_builder::detail_::identify(handle_));
206  }
207  }
208 
209 public: // operators
210 
211  fatbin_builder_t &operator=(const fatbin_builder_t &) = delete;
212 
213  fatbin_builder_t &operator=(fatbin_builder_t &&other) noexcept
214  {
215  ::std::swap(handle_, other.handle_);
216  ::std::swap(owning, owning);
217  return *this;
218  }
219 
220 protected: // data members
221  fatbin_builder::handle_t handle_;
222  bool owning;
223  // this field is mutable only for enabling move construction; other
224  // than in that case it must not be altered
225 };
226 
227 namespace fatbin_builder {
228 
230 inline fatbin_builder_t create(const options_t & options)
231 {
232  handle_t new_handle;
233  auto marshalled_options = marshalling::marshal(options);
234  auto option_ptrs = marshalled_options.option_ptrs();
235  auto status = nvFatbinCreate(&new_handle, option_ptrs.data(), option_ptrs.size());
236  throw_if_error_lazy(status, "Failed creating a new fatbin builder");
237  auto do_take_ownership = true;
238  return wrap(new_handle, do_take_ownership);
239 }
240 
241 inline fatbin_builder_t wrap(handle_t handle, bool take_ownership) noexcept
242 {
243  return fatbin_builder_t{handle, take_ownership};
244 }
245 
246 namespace detail_ {
247 
248 inline ::std::string identify(const fatbin_builder_t& builder)
249 {
250  return identify(builder.handle());
251 }
252 
253 } // namespace detail_
254 
255 } // namespace fatbin_builder
256 
257 
258 } // namespace cuda
259 
260 #endif // CUDA_VERSION >= 12040
261 
262 #endif // CUDA_API_WRAPPERS_FATBIN_BUILDER_HPP_
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
::std::size_t size_t
A size type for use throughout the wrappers library (except when specific API functions limit the siz...
Definition: types.hpp:81
Contains fatbin_builder::options_t class and related definitions.
#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
CUarray handle_t
Raw CUDA driver handle for arrays (of any dimension)
Definition: array.hpp:34
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:264