cuda-api-wrappers
Thin C++-flavored wrappers for the CUDA Runtime API
array.hpp
Go to the documentation of this file.
1 
11 #pragma once
12 #ifndef CUDA_API_WRAPPERS_ARRAY_HPP_
13 #define CUDA_API_WRAPPERS_ARRAY_HPP_
14 
15 #include "context.hpp"
16 #include "error.hpp"
17 
18 #ifndef CUDA_NO_HALF
19 #include <cuda_fp16.h>
20 #endif
21 
22 namespace cuda {
23 
25 class device_t;
27 
28 template <typename T, dimensionality_t NumDimensions>
29 class array_t;
30 
31 namespace array {
32 
34 using handle_t = CUarray;
35 
37 template <dimensionality_t NumDimensions>
38 using descriptor_t = typename ::std::conditional<NumDimensions == 2, CUDA_ARRAY_DESCRIPTOR, CUDA_ARRAY3D_DESCRIPTOR>::type;
39 
41 template <typename T, dimensionality_t NumDimensions>
43  device::id_t device_id,
44  context::handle_t context_handle,
45  handle_t handle,
46  dimensions_t<NumDimensions> dimensions) noexcept;
47 
48 namespace detail_ {
49 
50 template <typename T> struct format_specifier {};
51 
52 template <> struct format_specifier<uint8_t > { static constexpr const CUarray_format value = CU_AD_FORMAT_UNSIGNED_INT8; };
53 template <> struct format_specifier<uint16_t> { static constexpr const CUarray_format value = CU_AD_FORMAT_UNSIGNED_INT16; };
54 template <> struct format_specifier<uint32_t> { static constexpr const CUarray_format value = CU_AD_FORMAT_UNSIGNED_INT32; };
55 template <> struct format_specifier<int8_t > { static constexpr const CUarray_format value = CU_AD_FORMAT_SIGNED_INT8; };
56 template <> struct format_specifier<int16_t > { static constexpr const CUarray_format value = CU_AD_FORMAT_SIGNED_INT16; };
57 template <> struct format_specifier<int32_t > { static constexpr const CUarray_format value = CU_AD_FORMAT_SIGNED_INT32; };
58 #ifndef CUDA_NO_HALF
59 template <> struct format_specifier<half > { static constexpr const CUarray_format value = CU_AD_FORMAT_HALF; };
60 #endif
61 template <> struct format_specifier<float > { static constexpr const CUarray_format value = CU_AD_FORMAT_FLOAT; };
62 
63 template<typename T>
64 handle_t create_in_current_context(dimensions_t<3> dimensions)
65 {
66  handle_t handle;
67  CUDA_ARRAY3D_DESCRIPTOR descriptor;
68  descriptor.Width = dimensions.width;
69  descriptor.Height = dimensions.height;
70  descriptor.Depth = dimensions.depth;
71  descriptor.Format = format_specifier<T>::value;
72  descriptor.NumChannels = 1;
73  // We don't currently support an array of packed pairs or quadruplets; if you want this,
74  // file an issue.
75  descriptor.Flags = 0;
76 
77  auto status = cuArray3DCreate(&handle, &descriptor);
78  throw_if_error_lazy(status, "failed allocating 3D CUDA array");
79  return handle;
80 }
81 
82 template<typename T>
83 handle_t create_in_current_context(dimensions_t<2> dimensions)
84 {
85  CUDA_ARRAY_DESCRIPTOR descriptor;
86  descriptor.Width = dimensions.width;
87  descriptor.Height = dimensions.height;
88  descriptor.Format = format_specifier<T>::value;
89  descriptor.NumChannels = 1;
90  handle_t handle;
91  auto status = cuArrayCreate(&handle, &descriptor);
92  throw_if_error_lazy(status, "failed allocating 2D CUDA array");
93  return handle;
94 }
95 
96 template <typename T, dimensionality_t NumDimensions>
98 {
99  CAW_SET_SCOPE_CONTEXT(context_handle);
100  return create_in_current_context<T>(dimensions);
101 }
102 
103 inline void destroy(handle_t handle, context::handle_t context_handle)
104 {
105  CAW_SET_SCOPE_CONTEXT(context_handle);
106  auto status = cuArrayDestroy(handle);
107  throw_if_error_lazy(status, "Failed destroying the array at " + cuda::detail_::ptr_as_hex(handle));
108 }
109 
110 template <dimensionality_t NumDimensions>
111 descriptor_t<NumDimensions> get_descriptor_in_current_context(handle_t handle);
112 
113 template <>
114 inline descriptor_t<2> get_descriptor_in_current_context<2>(handle_t handle)
115 {
116  descriptor_t<2> result;
117  auto status = cuArrayGetDescriptor(&result, handle);
118  throw_if_error_lazy(status,
119  ::std::string("Failed obtaining the descriptor of the CUDA 2D array at ")
120  + cuda::detail_::ptr_as_hex(handle));
121  return result;
122 }
123 
124 template <>
125 inline descriptor_t<4> get_descriptor_in_current_context<3>(handle_t handle)
126 {
127  descriptor_t<3> result;
128  auto status = cuArray3DGetDescriptor(&result, handle);
129  throw_if_error_lazy(status,
130  ::std::string("Failed obtaining the descriptor of the CUDA 3D array at ")
131  + cuda::detail_::ptr_as_hex(handle));
132  return result;
133 }
134 
135 template <dimensionality_t NumDimensions>
136 descriptor_t<NumDimensions> get_descriptor(context::handle_t context_handle, handle_t handle)
137 {
138  CAW_SET_SCOPE_CONTEXT(context_handle);
139  return get_descriptor_in_current_context<NumDimensions>(handle);
140 }
141 
142 template <dimensionality_t NumDimensions>
143 dimensions_t<NumDimensions> dimensions_of(const descriptor_t<NumDimensions>& descriptor);
144 
145 template <>
146 inline dimensions_t<3> dimensions_of(const descriptor_t<3>& descriptor)
147 {
148  return { descriptor.Width, descriptor.Height, descriptor.Depth };
149 }
150 
151 template <>
152 inline dimensions_t<2> dimensions_of(const descriptor_t<2>& descriptor)
153 {
154  return { descriptor.Width, descriptor.Height };
155 }
156 
157 template <dimensionality_t NumDimensions>
158 dimensions_t<NumDimensions> dimensions_of_in_current_context(handle_t handle_in_current_context)
159 {
160  auto descriptor = get_descriptor_in_current_context<NumDimensions>(handle_in_current_context);
161  return dimensions_of<NumDimensions>(descriptor);
162 }
163 
164 template <dimensionality_t NumDimensions>
165 dimensions_t<NumDimensions> dimensions_of(context::handle_t context_handle, handle_t handle)
166 {
167  CAW_SET_SCOPE_CONTEXT(context_handle);
168  return dimensions_of_in_current_context<NumDimensions>(handle);
169 }
170 
171 } // namespace detail_
172 
173 } // namespace array
174 
200 template <typename T, dimensionality_t NumDimensions>
201 class array_t {
202  static_assert(NumDimensions == 2 or NumDimensions == 3, "CUDA only supports 2D and 3D arrays");
203 
204 public:
211 
216  array_t(device::id_t device_id, context::handle_t context_handle, handle_type handle, dimensions_type dimensions) :
217  dimensions_(dimensions), device_id_(device_id), context_handle_(context_handle), handle_(handle)
218  {
219  assert(handle != nullptr);
220  }
221 
222  array_t(const array_t& other) = delete;
223  array_t(array_t&& other) noexcept : array_t(other.device_id_, other.context_handle_, other.handle_, other.dimensions_)
224  {
225  other.handle_ = nullptr;
226  }
227 
228  ~array_t() DESTRUCTOR_EXCEPTION_SPEC
229  {
230  if (not handle_) { return; }
231 #ifndef THROW_IN_DESTRUCTORS
232  try
233 #endif
234  {
235  array::detail_::destroy(handle_, context_handle_);
236  }
237 #ifndef THROW_IN_DESTRUCTORS
238  catch (...) {}
239 #endif
240  }
241 
242  friend array_t array::wrap<T, NumDimensions>(device::id_t, context::handle_t, handle_type, dimensions_type) noexcept;
243 
244  handle_type get() const noexcept { return handle_; }
245  device::id_t device_id() const noexcept { return device_id_; }
246  context::handle_t context_handle() const noexcept { return context_handle_; }
247  dimensions_type dimensions() const noexcept { return dimensions_; }
248  device_t device() const noexcept;
249  context_t context() const;
250 
252  ::std::size_t size() const noexcept { return dimensions().size(); }
253 
255  ::std::size_t size_bytes() const noexcept { return size() * sizeof(T); }
256 
259  descriptor_type descriptor() const { return array::detail_::get_descriptor<NumDimensions>(context_handle_, handle_); }
260 
261 protected:
262  dimensions_type dimensions_;
263  device::id_t device_id_;
264  context::handle_t context_handle_;
265  handle_type handle_;
266 };
267 
268 namespace array {
269 
270 template <typename T, dimensionality_t NumDimensions>
272  device::id_t device_id,
273  context::handle_t context_handle,
274  handle_t handle,
275  dimensions_t<NumDimensions> dimensions) noexcept
276 {
277  return { device_id, context_handle, handle, dimensions };
278 }
279 
283 template <typename T, dimensionality_t NumDimensions>
285  const context_t& context,
286  dimensions_t<NumDimensions> dimensions);
287 
289 template <typename T, dimensionality_t NumDimensions>
291  const device_t& device,
292  dimensions_t<NumDimensions> dimensions);
294 
295 } // namespace array
296 
297 } // namespace cuda
298 
299 #endif // CUDA_API_WRAPPERS_ARRAY_HPP_
typename ::std::conditional< NumDimensions==2, CUDA_ARRAY_DESCRIPTOR, CUDA_ARRAY3D_DESCRIPTOR >::type descriptor_t
Raw CUDA driver descriptor structure for an array of dimension.
Definition: array.hpp:38
Wrapper class for a CUDA context.
Definition: context.hpp:249
Definitions and functionality wrapping CUDA APIs.
Definition: array.hpp:22
CUcontext handle_t
Raw CUDA driver handle for a context; see {context_t}.
Definition: types.hpp:880
dimension_t width
The three constituent individual dimensions, named.
Definition: types.hpp:109
Owning wrapper for CUDA 2D and 3D arrays.
Definition: array.hpp:29
CUdevice id_t
Numeric ID of a CUDA device used by the CUDA Runtime API.
Definition: types.hpp:852
::std::size_t size_bytes() const noexcept
Overall size in bytes of the elements of the array, over all dimensions.
Definition: array.hpp:255
Dimensions for 2D CUDA arrays.
Definition: types.hpp:156
array::descriptor_t< NumDimensions > descriptor_type
See array::descriptor_t.
Definition: array.hpp:208
array::handle_t handle_type
See array::handle_t.
Definition: array.hpp:206
array_t(device::id_t device_id, context::handle_t context_handle, handle_type handle, dimensions_type dimensions)
Constructs a CUDA array wrapper from the raw type used by the CUDA Runtime API - and takes ownership ...
Definition: array.hpp:216
Contains a proxy class for CUDA execution contexts.
Dimensions for 3D CUDA arrays.
Definition: types.hpp:106
dimension_t width
The two constituent individual dimensions, named; no "depth" for the 2D case.
Definition: types.hpp:159
::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:78
::std::size_t size() const noexcept
Overall number of elements in the array, over all dimensions.
Definition: array.hpp:252
array_t< T, NumDimensions > create(const context_t &context, dimensions_t< NumDimensions > dimensions)
Create a new (typed) CUDA array of the specified dimensions.
Definition: array.hpp:27
#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
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:271
Facilities for exception-based handling of Runtime and Driver API errors, including a basic exception...
descriptor_type descriptor() const
Get the full set of features of this array in a single structure, recognizable by the CUDA driver (e...
Definition: array.hpp:259
Wrapper class for a CUDA device.
Definition: device.hpp:135
CUDA&#39;s array memory-objects are multi-dimensional; but their dimensions, or extents, are not the same as cuda::grid::dimensions_t ; they may be much larger in each axis.
Definition: types.hpp:102