Cholla 3.0.1-dev
Cholla - Massively parallel hydro on GPUs
Loading...
Searching...
No Matches
DeviceVector.h
Go to the documentation of this file.
1
10#pragma once
11
12// STL Includes
13#include <algorithm>
14#include <stdexcept>
15#include <string>
16#include <type_traits>
17#include <utility>
18#include <vector>
19
20// External Includes
21
22// Local Includes
23#include "../global/global.h"
24#include "../global/global_cuda.h"
25#include "../utils/gpu.hpp"
26
27// =============================================================================
28// Declaration of DeviceVector class
29// =============================================================================
30namespace cuda_utilities
31{
43template <typename T>
45{
46 static_assert(std::is_trivially_copyable_v<T>,
47 "DeviceVector can only be used with trivially_copyable types due to the internal "
48 "usage of functions like cudaMemcpy, cudaMemcpyPeer, cudaMemset");
49
50 public:
51 typedef T value_type;
52
54 DeviceVector() noexcept : _size(0), _ptr(nullptr) {}
55
65 DeviceVector(size_t const size, bool const initialize = false);
66
68 DeviceVector(DeviceVector<T> &&other) noexcept
69 : _size(std::exchange(other._size, 0)), _ptr(std::exchange(other._ptr, nullptr))
70 {
71 }
72
75 {
76 std::swap(_size, other._size);
77 std::swap(_ptr, other._ptr);
78 return *this;
79 }
80
86 ~DeviceVector() { _deAllocate(); }
87
88 /* The following are deleted because they currently lead to invalid state.
89 * (But they can all easily be implemented in the future).
90 */
91 DeviceVector(const DeviceVector<T> &) = delete;
92 DeviceVector<T> &operator=(const DeviceVector<T> &other) = delete;
93
99 T *data() { return _ptr; }
100
106 size_t size() { return _size; }
107
117 T operator[](size_t const &index);
118
127 T at(size_t const index);
128
137 void assign(T const &hostValue, size_t const &index = 0);
138
152 void resize(size_t const newSize);
153
162 void reset(size_t const newSize);
163
171 void cpyHostToDevice(const T *arrIn, size_t const &arrSize);
172
178 void cpyHostToDevice(std::vector<T> const &vecIn) { cpyHostToDevice(vecIn.data(), vecIn.size()); }
179
187 void cpyDeviceToHost(T *arrOut, size_t const &arrSize);
188
195 void cpyDeviceToHost(std::vector<T> &vecOut) { cpyDeviceToHost(vecOut.data(), vecOut.size()); }
196
197 private:
199 size_t _size;
200
202 T *_ptr = nullptr;
203
209 void _allocate(size_t const size)
210 {
211 _size = size;
212 if (size == 0) {
213 _ptr = nullptr;
214 } else {
215 GPU_Error_Check(cudaMalloc(&_ptr, _size * sizeof(T)));
216 }
217 }
218
223 void _deAllocate()
224 {
225 if (_ptr != nullptr) GPU_Error_Check(cudaFree(_ptr));
226 }
227};
228} // namespace cuda_utilities
229// =============================================================================
230// End declaration of DeviceVector class
231// =============================================================================
232
233// =============================================================================
234// Definition of DeviceVector class
235// =============================================================================
236namespace cuda_utilities
237{
238// =========================================================================
239// Public Methods
240// =========================================================================
241
242// =========================================================================
243template <typename T>
244DeviceVector<T>::DeviceVector(size_t const size, bool const initialize) : DeviceVector()
245{
246 if (size > 0) {
247 _allocate(size);
248
249 if (initialize) {
250 GPU_Error_Check(cudaMemset(_ptr, 0, _size * sizeof(T)));
251 }
252 }
253}
254// =========================================================================
255
256// =========================================================================
257template <typename T>
258void DeviceVector<T>::resize(size_t const newSize)
259{
260 // Assign old array to a new pointer
261 T *oldDevPtr = _ptr;
262
263 // Determine how many elements to copy
264 size_t const count = std::min(_size, newSize) * sizeof(T);
265
266 // Allocate new array
267 _allocate(newSize);
268
269 if (oldDevPtr != nullptr) {
270 // Copy the values from the old array to the new array
271 GPU_Error_Check(cudaMemcpyPeer(_ptr, 0, oldDevPtr, 0, count));
272
273 // Free the old array
274 GPU_Error_Check(cudaFree(oldDevPtr));
275 }
276}
277// =========================================================================
278
279// =========================================================================
280template <typename T>
281void DeviceVector<T>::reset(size_t const newSize)
282{
283 _deAllocate();
284 _allocate(newSize);
285}
286// =========================================================================
287
288// =========================================================================
289template <typename T>
290T DeviceVector<T>::operator[](size_t const &index)
291{
292 T hostValue;
293 GPU_Error_Check(cudaMemcpy(&hostValue, &(_ptr[index]), sizeof(T), cudaMemcpyDeviceToHost));
294 return hostValue;
295}
296// =========================================================================
297
298// =========================================================================
299template <typename T>
300T DeviceVector<T>::at(size_t const index)
301{
302 if (index < _size) {
303 // Use the overloaded [] operator to grab the value from GPU memory
304 // into host memory
305 return (*this)[index];
306 } else {
307 throw std::out_of_range(
308 "Warning: DeviceVector.at() detected an"
309 " out of bounds memory access. Tried to"
310 " access element " +
311 std::to_string(index) + " of " + std::to_string(_size));
312 }
313}
314// =========================================================================
315
316// =========================================================================
317template <typename T>
318void DeviceVector<T>::assign(T const &hostValue, size_t const &index)
319{
320 GPU_Error_Check(cudaMemcpy(&(_ptr[index]), // destination
321 &hostValue, // source
322 sizeof(T), cudaMemcpyHostToDevice));
323}
324// =========================================================================
325
326// =========================================================================
327template <typename T>
328void DeviceVector<T>::cpyHostToDevice(const T *arrIn, size_t const &arrSize)
329{
330 if (arrSize <= _size) {
331 GPU_Error_Check(cudaMemcpy(_ptr, arrIn, arrSize * sizeof(T), cudaMemcpyHostToDevice));
332 } else {
333 throw std::out_of_range(
334 "Warning: Couldn't copy array to device,"
335 " device array is too small. Host array"
336 " size=" +
337 std::to_string(arrSize) + ", device array size=" + std::to_string(arrSize));
338 }
339}
340// =========================================================================
341
342// =========================================================================
343template <typename T>
344void DeviceVector<T>::cpyDeviceToHost(T *arrOut, size_t const &arrSize)
345{
346 if (_size <= arrSize) {
347 GPU_Error_Check(cudaMemcpy(arrOut, _ptr, _size * sizeof(T), cudaMemcpyDeviceToHost));
348 } else {
349 throw std::out_of_range(
350 "Warning: Couldn't copy array to host, "
351 "host array is too small. Host array "
352 "size=" +
353 std::to_string(arrSize) + ", device array size=" + std::to_string(arrSize));
354 }
355}
356// =========================================================================
357} // end namespace cuda_utilities
358 // =============================================================================
359 // End definition of DeviceVector class
360 // =============================================================================
A templatized class to encapsulate a device global memory pointer in a std::vector like interface com...
Definition DeviceVector.h:45
void assign(T const &hostValue, size_t const &index=0)
Assign a single value in the array. Should generally only be used when the pointer points to a scalar...
Definition DeviceVector.h:318
void cpyDeviceToHost(T *arrOut, size_t const &arrSize)
Copy the array from the device to a host array. Checks if the host array is large enough based on the...
Definition DeviceVector.h:344
~DeviceVector()
Destroy the Device Vector object by calling the _deAllocate private method.
Definition DeviceVector.h:86
void cpyHostToDevice(const T *arrIn, size_t const &arrSize)
Copy the first arrSize elements of arrIn to the device.
Definition DeviceVector.h:328
void cpyHostToDevice(std::vector< T > const &vecIn)
Copy the contents of a std::vector to the device.
Definition DeviceVector.h:178
T at(size_t const index)
Return a value from device memory. This method performs a cudaMemcpy to copy the desired element to t...
Definition DeviceVector.h:300
void reset(size_t const newSize)
Reset the size of the array. This frees the old array and allocates a new one; all values in the arra...
Definition DeviceVector.h:281
DeviceVector(DeviceVector< T > &&other) noexcept
Definition DeviceVector.h:68
T * data()
Get the raw device pointer.
Definition DeviceVector.h:99
void resize(size_t const newSize)
Resize the device container to contain newSize elements. If newSize is greater than the current size ...
Definition DeviceVector.h:258
DeviceVector() noexcept
Definition DeviceVector.h:54
T operator[](size_t const &index)
Overload the [] operator to return a value from device memory. This method performs a cudaMemcpy to c...
Definition DeviceVector.h:290
DeviceVector(size_t const size, bool const initialize=false)
Construct a new Device Vector object by calling the _allocate private method.
Definition DeviceVector.h:244
void cpyDeviceToHost(std::vector< T > &vecOut)
Copy the array from the device to a host std::vector. Checks if the host array is large enough.
Definition DeviceVector.h:195
DeviceVector & operator=(DeviceVector< T > &&other) noexcept
Definition DeviceVector.h:74
size_t size()
Get the number of elements in the array.
Definition DeviceVector.h:106