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>
26
32namespace Opm::gpuistl
33{
34
35
46template <typename T>
47std::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
67template <typename T>
68std::shared_ptr<T>
69make_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
87template <typename T>
88auto
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
109template <typename T>
110auto
111make_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
125template <class T>
127 void operator()(T* ptr) const noexcept
128 {
129 OPM_GPU_WARN_IF_ERROR(cudaFree(ptr));
130 }
131};
132
139template <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
165template <typename T>
166std::unique_ptr<T[], GpuArrayDeleter<T>>
167make_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
192template <typename T, class... Args>
193std::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
217template <class T>
218T
219copyFromGPU(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
238template <class T>
239T
240copyFromGPU(const std::shared_ptr<T>& value)
241{
242 return copyFromGPU(value.get());
243}
244
255template <class T, class Deleter>
256T
257copyFromGPU(const std::unique_ptr<T, Deleter>& value)
258{
259 return copyFromGPU(value.get());
260}
261
270template <class T>
271void
272copyToGPU(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
288template <class T>
289void
290copyToGPU(const T& value, const std::shared_ptr<T>& ptr)
291{
292 copyToGPU(value, ptr.get());
293}
294
304template <class T, class Deleter>
305void
306copyToGPU(const T& value, const std::unique_ptr<T, Deleter>& ptr)
307{
308 copyToGPU(value, ptr.get());
309}
310
319template <class T>
321{
322public:
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
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
361private:
362 T* ptr_;
363};
364
370template <>
371class PointerView<void>
372{
373public:
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
402private:
403 void* ptr_;
404};
405
406template <class T>
407PointerView<T>
408make_view(const std::shared_ptr<T>& ptr)
409{
410 return PointerView<T>(ptr);
411}
412
413template <class T, class Deleter>
414PointerView<T>
415make_view(const std::unique_ptr<T, Deleter>& ptr)
416{
417 return PointerView<T>(ptr);
418}
419
424template<class T>
426public:
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 }
456private:
457 T value;
458};
459} // namespace Opm::gpuistl
460#endif
PointerView(const std::unique_ptr< void, Deleter > &ptr)
Definition: gpu_smart_pointer.hpp:382
PointerView(const std::shared_ptr< void > &ptr)
Definition: gpu_smart_pointer.hpp:376
PointerView(void *ptr)
Definition: gpu_smart_pointer.hpp:387
OPM_HOST_DEVICE void * operator->() const
Definition: gpu_smart_pointer.hpp:397
PointerView(const PointerView &other)=default
OPM_HOST_DEVICE void * get() const
Definition: gpu_smart_pointer.hpp:392
A view towards a smart pointer to GPU-allocated memory.
Definition: gpu_smart_pointer.hpp:321
OPM_HOST_DEVICE const T & operator*() const
Definition: gpu_smart_pointer.hpp:346
OPM_HOST_DEVICE T & operator*()
Definition: gpu_smart_pointer.hpp:351
OPM_HOST_DEVICE T * operator->() const
Definition: gpu_smart_pointer.hpp:356
PointerView(const std::unique_ptr< T, Deleter > &ptr)
Definition: gpu_smart_pointer.hpp:331
PointerView(T *ptr)
Definition: gpu_smart_pointer.hpp:336
PointerView(const std::shared_ptr< T > &ptr)
Definition: gpu_smart_pointer.hpp:325
PointerView(const PointerView &other)=default
OPM_HOST_DEVICE T * get() const
Definition: gpu_smart_pointer.hpp:341
A value stored with a pointer interface. Can be used to wrap objects in GPU kernels that were otherwi...
Definition: gpu_smart_pointer.hpp:425
OPM_HOST_DEVICE T * operator->()
Definition: gpu_smart_pointer.hpp:433
T element_type
Definition: gpu_smart_pointer.hpp:427
OPM_HOST_DEVICE T * get()
Definition: gpu_smart_pointer.hpp:437
OPM_HOST_DEVICE T & operator*()
Definition: gpu_smart_pointer.hpp:449
OPM_HOST_DEVICE ValueAsPointer(const T &t)
Definition: gpu_smart_pointer.hpp:431
OPM_HOST_DEVICE ValueAsPointer()=default
OPM_HOST_DEVICE const T & operator*() const
Definition: gpu_smart_pointer.hpp:453
OPM_HOST_DEVICE const T * operator->() const
Definition: gpu_smart_pointer.hpp:441
OPM_HOST_DEVICE const T * get() const
Definition: gpu_smart_pointer.hpp:445
#define OPM_GPU_SAFE_CALL(expression)
OPM_GPU_SAFE_CALL checks the return type of the GPU expression (function call) and throws an exceptio...
Definition: gpu_safe_call.hpp:164
#define OPM_GPU_WARN_IF_ERROR(expression)
OPM_GPU_WARN_IF_ERROR checks the return type of the GPU expression (function call) and issues a warni...
Definition: gpu_safe_call.hpp:185
bool isGPUPointer(const T *ptr)
Checks whether the given pointer is associated with GPU device memory.
Definition: is_gpu_pointer.hpp:40
A small, fixed‑dimension MiniVector class backed by std::array that can be used in both host and CUDA...
Definition: AmgxInterface.hpp:38
void copyToGPU(const T &value, T *ptr)
Copies a value from the host to GPU-allocated memory.
Definition: gpu_smart_pointer.hpp:272
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
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
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
PointerView< T > make_view(const std::shared_ptr< T > &ptr)
Definition: gpu_smart_pointer.hpp:408
T copyFromGPU(const T *value)
Copies a value from GPU-allocated memory to the host.
Definition: gpu_smart_pointer.hpp:219
auto make_gpu_unique_ptr()
Creates a unique pointer managing GPU-allocated memory of the specified element type.
Definition: gpu_smart_pointer.hpp:89
Deleter that releases a GPU array allocation made with cudaMalloc.
Definition: gpu_smart_pointer.hpp:126
void operator()(T *ptr) const noexcept
Definition: gpu_smart_pointer.hpp:127
Deleter for objects living in unified (managed) GPU memory.
Definition: gpu_smart_pointer.hpp:140
void operator()(T *ptr) const noexcept
Definition: gpu_smart_pointer.hpp:141