opm-simulators
gpu_smart_pointer.hpp
Go to the documentation of this file.
1 /*
2  Copyright 2025 Equinor ASA
3  This file is part of the Open Porous Media project (OPM).
4  OPM is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8  OPM is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12  You should have received a copy of the GNU General Public License
13  along with OPM. If not, see <http://www.gnu.org/licenses/>.
14 */
15 
16 #ifndef OPM_SIMULATORS_LINALG_GPUISTL_GPU_SMART_POINTER_HPP
17 #define OPM_SIMULATORS_LINALG_GPUISTL_GPU_SMART_POINTER_HPP
18 
19 #include <cuda_runtime.h>
20 
21 #include <memory>
22 
23 #include <opm/common/utility/gpuDecorators.hpp>
24 #include <opm/simulators/linalg/gpuistl/detail/gpu_safe_call.hpp>
25 #include <opm/simulators/linalg/gpuistl/detail/is_gpu_pointer.hpp>
26 
32 namespace Opm::gpuistl
33 {
34 
35 
46 template <typename T>
47 std::shared_ptr<T>
49 {
50  T* ptr = nullptr;
51  OPM_GPU_SAFE_CALL(cudaMalloc(&ptr, sizeof(T)));
52  auto deleter = [](T* ptrToDelete) { OPM_GPU_WARN_IF_ERROR(cudaFree(ptrToDelete)); };
53  return std::shared_ptr<T>(ptr, deleter);
54 }
55 
67 template <typename T>
68 std::shared_ptr<T>
69 make_gpu_shared_ptr(const T& value)
70 {
71  auto ptr = make_gpu_shared_ptr<T>();
72  OPM_GPU_SAFE_CALL(cudaMemcpy(ptr.get(), &value, sizeof(T), cudaMemcpyHostToDevice));
73  return ptr;
74 }
75 
76 
87 template <typename T>
88 auto
90 {
91  T* ptr = nullptr;
92  OPM_GPU_SAFE_CALL(cudaMalloc(&ptr, sizeof(T)));
93 
94  auto deleter = [](T* ptrToDelete) { OPM_GPU_WARN_IF_ERROR(cudaFree(ptrToDelete)); };
95  return std::unique_ptr<T, decltype(deleter)>(ptr, deleter);
96 }
97 
109 template <typename T>
110 auto
111 make_gpu_unique_ptr(const T& value)
112 {
113  auto ptr = make_gpu_unique_ptr<T>();
114  OPM_GPU_SAFE_CALL(cudaMemcpy(ptr.get(), &value, sizeof(T), cudaMemcpyHostToDevice));
115  return ptr;
116 }
117 
125 template <class T>
127  void operator()(T* ptr) const noexcept
128  {
129  OPM_GPU_WARN_IF_ERROR(cudaFree(ptr));
130  }
131 };
132 
139 template <class T>
141  void operator()(T* ptr) const noexcept
142  {
143  if (ptr != nullptr) {
144  ptr->~T();
145  OPM_GPU_WARN_IF_ERROR(cudaFree(ptr));
146  }
147  }
148 };
149 
165 template <typename T>
166 std::unique_ptr<T[], GpuArrayDeleter<T>>
167 make_gpu_unique_ptr_array(std::size_t numElements)
168 {
169  T* ptr = nullptr;
170  OPM_GPU_SAFE_CALL(cudaMalloc(&ptr, numElements * sizeof(T)));
171  return std::unique_ptr<T[], GpuArrayDeleter<T>>(ptr);
172 }
173 
192 template <typename T, class... Args>
193 std::unique_ptr<T, GpuManagedDeleter<T>>
195 {
196  void* raw = nullptr;
197  OPM_GPU_SAFE_CALL(cudaMallocManaged(&raw, sizeof(T)));
198  T* ptr = nullptr;
199  try {
200  ptr = new (raw) T(std::forward<Args>(args)...);
201  } catch (...) {
202  OPM_GPU_WARN_IF_ERROR(cudaFree(raw));
203  throw;
204  }
205  return std::unique_ptr<T, GpuManagedDeleter<T>>(ptr);
206 }
207 
217 template <class T>
218 T
219 copyFromGPU(const T* value)
220 {
221 #ifndef NDEBUG
222  OPM_ERROR_IF(!Opm::gpuistl::detail::isGPUPointer(value), "The pointer is not associated with GPU memory.");
223 #endif
224  T result;
225  OPM_GPU_SAFE_CALL(cudaMemcpy(&result, value, sizeof(T), cudaMemcpyDeviceToHost));
226  return result;
227 }
228 
238 template <class T>
239 T
240 copyFromGPU(const std::shared_ptr<T>& value)
241 {
242  return copyFromGPU(value.get());
243 }
244 
255 template <class T, class Deleter>
256 T
257 copyFromGPU(const std::unique_ptr<T, Deleter>& value)
258 {
259  return copyFromGPU(value.get());
260 }
261 
270 template <class T>
271 void
272 copyToGPU(const T& value, T* ptr)
273 {
274 #ifndef NDEBUG
275  OPM_ERROR_IF(!Opm::gpuistl::detail::isGPUPointer(ptr), "The pointer is not associated with GPU memory.");
276 #endif
277  OPM_GPU_SAFE_CALL(cudaMemcpy(ptr, &value, sizeof(T), cudaMemcpyHostToDevice));
278 }
279 
288 template <class T>
289 void
290 copyToGPU(const T& value, const std::shared_ptr<T>& ptr)
291 {
292  copyToGPU(value, ptr.get());
293 }
294 
304 template <class T, class Deleter>
305 void
306 copyToGPU(const T& value, const std::unique_ptr<T, Deleter>& ptr)
307 {
308  copyToGPU(value, ptr.get());
309 }
310 
319 template <class T>
321 {
322 public:
323  PointerView(const PointerView& other) = default;
324 
325  PointerView(const std::shared_ptr<T>& ptr)
326  : ptr_(ptr.get())
327  {
328  }
329 
330  template <class Deleter>
331  PointerView(const std::unique_ptr<T, Deleter>& ptr)
332  : ptr_(ptr.get())
333  {
334  }
335 
336  PointerView(T* ptr)
337  : ptr_(ptr)
338  {
339  }
340 
341  OPM_HOST_DEVICE T* get() const
342  {
343  return ptr_;
344  }
345 
346  OPM_HOST_DEVICE const T& operator*() const
347  {
348  return *ptr_;
349  }
350 
351  OPM_HOST_DEVICE T& operator*()
352  {
353  return *ptr_;
354  }
355 
356  OPM_HOST_DEVICE T* operator->() const
357  {
358  return ptr_;
359  }
360 
361 private:
362  T* ptr_;
363 };
364 
370 template <>
371 class PointerView<void>
372 {
373 public:
374  PointerView(const PointerView& other) = default;
375 
376  PointerView(const std::shared_ptr<void>& ptr)
377  : ptr_(ptr.get())
378  {
379  }
380 
381  template <class Deleter>
382  PointerView(const std::unique_ptr<void, Deleter>& ptr)
383  : ptr_(ptr.get())
384  {
385  }
386 
387  PointerView(void* ptr)
388  : ptr_(ptr)
389  {
390  }
391 
392  OPM_HOST_DEVICE void* get() const
393  {
394  return ptr_;
395  }
396 
397  OPM_HOST_DEVICE void* operator->() const
398  {
399  return ptr_;
400  }
401 
402 private:
403  void* ptr_;
404 };
405 
406 template <class T>
408 make_view(const std::shared_ptr<T>& ptr)
409 {
410  return PointerView<T>(ptr);
411 }
412 
413 template <class T, class Deleter>
414 PointerView<T>
415 make_view(const std::unique_ptr<T, Deleter>& ptr)
416 {
417  return PointerView<T>(ptr);
418 }
419 
424 template<class T>
426 public:
427  using element_type = T;
428 
429  OPM_HOST_DEVICE ValueAsPointer() = default;
430 
431  OPM_HOST_DEVICE explicit ValueAsPointer(const T& t) : value(t) {}
432 
433  OPM_HOST_DEVICE T* operator->() {
434  return &value;
435  }
436 
437  OPM_HOST_DEVICE T* get() {
438  return &value;
439  }
440 
441  OPM_HOST_DEVICE const T* operator->() const {
442  return &value;
443  }
444 
445  OPM_HOST_DEVICE const T* get() const {
446  return &value;
447  }
448 
449  OPM_HOST_DEVICE T& operator*() {
450  return value;
451  }
452 
453  OPM_HOST_DEVICE const T& operator*() const {
454  return value;
455  }
456 private:
457  T value;
458 };
459 } // namespace Opm::gpuistl
460 #endif
A view towards a smart pointer to GPU-allocated memory.
Definition: gpu_smart_pointer.hpp:320
Deleter that releases a GPU array allocation made with cudaMalloc.
Definition: gpu_smart_pointer.hpp:126
Deleter for objects living in unified (managed) GPU memory.
Definition: gpu_smart_pointer.hpp:140
std::unique_ptr< T, GpuManagedDeleter< T > > make_gpu_managed_unique_ptr(Args &&... args)
Creates a unique pointer managing GPU unified (managed) memory for a single object.
Definition: gpu_smart_pointer.hpp:194
auto make_gpu_unique_ptr()
Creates a unique pointer managing GPU-allocated memory of the specified element type.
Definition: gpu_smart_pointer.hpp:89
T copyFromGPU(const T *value)
Copies a value from GPU-allocated memory to the host.
Definition: gpu_smart_pointer.hpp:219
A small, fixed‑dimension MiniVector class backed by std::array that can be used in both host and CUD...
Definition: ThermalGasWaterFlowProblem.hpp:94
A value stored with a pointer interface.
Definition: gpu_smart_pointer.hpp:425
std::unique_ptr< T[], GpuArrayDeleter< T > > make_gpu_unique_ptr_array(std::size_t numElements)
Creates a unique pointer managing a GPU-allocated array of numElements elements.
Definition: gpu_smart_pointer.hpp:167
bool isGPUPointer(const T *ptr)
Checks whether the given pointer is associated with GPU device memory.
Definition: is_gpu_pointer.hpp:40
std::shared_ptr< T > make_gpu_shared_ptr()
Creates a shared pointer managing GPU-allocated memory of the specified element type.
Definition: gpu_smart_pointer.hpp:48
void copyToGPU(const T &value, T *ptr)
Copies a value from the host to GPU-allocated memory.
Definition: gpu_smart_pointer.hpp:272