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 template <typename T, dimensionality_t NumDimensions>
104 handle_t create(const context_t& context, dimensions_t<NumDimensions> dimensions);
105 
106 template <dimensionality_t NumDimensions>
107 descriptor_t<NumDimensions> get_descriptor_in_current_context(handle_t handle);
108 
109 template <>
110 inline descriptor_t<2> get_descriptor_in_current_context<2>(handle_t handle)
111 {
112  descriptor_t<2> result;
113  auto status = cuArrayGetDescriptor(&result, handle);
114  throw_if_error_lazy(status,
115  ::std::string("Failed obtaining the descriptor of the CUDA 2D array at ")
116  + cuda::detail_::ptr_as_hex(handle));
117  return result;
118 }
119 
120 template <>
121 inline descriptor_t<4> get_descriptor_in_current_context<3>(handle_t handle)
122 {
123  descriptor_t<3> result;
124  auto status = cuArray3DGetDescriptor(&result, handle);
125  throw_if_error_lazy(status,
126  ::std::string("Failed obtaining the descriptor of the CUDA 3D array at ")
127  + cuda::detail_::ptr_as_hex(handle));
128  return result;
129 }
130 
131 template <dimensionality_t NumDimensions>
132 descriptor_t<NumDimensions> get_descriptor(context::handle_t context_handle, handle_t handle)
133 {
134  CAW_SET_SCOPE_CONTEXT(context_handle);
135  return get_descriptor_in_current_context<NumDimensions>(handle);
136 }
137 
138 template <dimensionality_t NumDimensions>
139 dimensions_t<NumDimensions> dimensions_of(const descriptor_t<NumDimensions>& descriptor);
140 
141 template <>
142 inline dimensions_t<3> dimensions_of(const descriptor_t<3>& descriptor)
143 {
144  return { descriptor.Width, descriptor.Height, descriptor.Depth };
145 }
146 
147 template <>
148 inline dimensions_t<2> dimensions_of(const descriptor_t<2>& descriptor)
149 {
150  return { descriptor.Width, descriptor.Height };
151 }
152 
153 template <dimensionality_t NumDimensions>
154 dimensions_t<NumDimensions> dimensions_of_in_current_context(handle_t handle_in_current_context)
155 {
156  auto descriptor = get_descriptor_in_current_context<NumDimensions>(handle_in_current_context);
157  return dimensions_of<NumDimensions>(descriptor);
158 }
159 
160 template <dimensionality_t NumDimensions>
161 dimensions_t<NumDimensions> dimensions_of(context::handle_t context_handle, handle_t handle)
162 {
163  CAW_SET_SCOPE_CONTEXT(context_handle);
164  return dimensions_of_in_current_context<NumDimensions>(handle);
165 }
166 
167 } // namespace detail_
168 
169 } // namespace array
170 
196 template <typename T, dimensionality_t NumDimensions>
197 class array_t {
198  static_assert(NumDimensions == 2 or NumDimensions == 3, "CUDA only supports 2D and 3D arrays");
199 
200 public:
207 
212  array_t(device::id_t device_id, context::handle_t context_handle, handle_type handle, dimensions_type dimensions) :
213  dimensions_(dimensions), device_id_(device_id), context_handle_(context_handle), handle_(handle)
214  {
215  assert(handle != nullptr);
216  }
217 
218  array_t(const array_t& other) = delete;
219  array_t(array_t&& other) noexcept : array_t(other.device_id_, other.context_handle_, other.handle_, other.dimensions_)
220  {
221  other.handle_ = nullptr;
222  }
223 
224  ~array_t() noexcept(false)
225  {
226  CAW_SET_SCOPE_CONTEXT(context_handle_);
227  if (handle_) {
228  auto status = cuArrayDestroy(handle_);
229  // Note: Throwing in a noexcept destructor; if the free'ing fails, the program
230  // will likely terminate
231  throw_if_error_lazy(status, "Failed destroying CUDA array " + cuda::detail_::ptr_as_hex(handle_));
232  }
233  }
234 
235  friend array_t array::wrap<T, NumDimensions>(device::id_t, context::handle_t, handle_type, dimensions_type) noexcept;
236 
237  handle_type get() const noexcept { return handle_; }
238  device::id_t device_id() const noexcept { return device_id_; }
239  context::handle_t context_handle() const noexcept { return context_handle_; }
240  dimensions_type dimensions() const noexcept { return dimensions_; }
241  device_t device() const noexcept;
242  context_t context() const;
243 
245  ::std::size_t size() const noexcept { return dimensions().size(); }
246 
248  ::std::size_t size_bytes() const noexcept { return size() * sizeof(T); }
249 
252  descriptor_type descriptor() const { return array::detail_::get_descriptor<NumDimensions>(context_handle_, handle_); }
253 
254 protected:
255  dimensions_type dimensions_;
256  device::id_t device_id_;
257  context::handle_t context_handle_;
258  handle_type handle_;
259 };
260 
261 namespace array {
262 
263 template <typename T, dimensionality_t NumDimensions>
265  device::id_t device_id,
266  context::handle_t context_handle,
267  handle_t handle,
268  dimensions_t<NumDimensions> dimensions) noexcept
269 {
270  return { device_id, context_handle, handle, dimensions };
271 }
272 
276 template <typename T, dimensionality_t NumDimensions>
278  const context_t& context,
279  dimensions_t<NumDimensions> dimensions);
280 
282 template <typename T, dimensionality_t NumDimensions>
284  const device_t& device,
285  dimensions_t<NumDimensions> dimensions);
287 
288 } // namespace array
289 
290 } // namespace cuda
291 
292 #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:244
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:878
dimension_t width
The three constituent individual dimensions, named.
Definition: types.hpp:112
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:850
::std::size_t size_bytes() const noexcept
Overall size in bytes of the elements of the array, over all dimensions.
Definition: array.hpp:248
Dimensions for 2D CUDA arrays.
Definition: types.hpp:159
array::descriptor_t< NumDimensions > descriptor_type
See array::descriptor_t.
Definition: array.hpp:204
array::handle_t handle_type
See array::handle_t.
Definition: array.hpp:202
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:212
Contains a proxy class for CUDA execution contexts.
Dimensions for 3D CUDA arrays.
Definition: types.hpp:109
dimension_t width
The two constituent individual dimensions, named; no "depth" for the 2D case.
Definition: types.hpp:162
::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
::std::size_t size() const noexcept
Overall number of elements in the array, over all dimensions.
Definition: array.hpp:245
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: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
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:252
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:105