opm-simulators
GpuView.hpp
1 /*
2  Copyright 2024 SINTEF AS
3 
4  This file is part of the Open Porous Media project (OPM).
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #ifndef OPM_GPUVIEW_HEADER_HPP
20 #define OPM_GPUVIEW_HEADER_HPP
21 
22 #include <dune/common/fvector.hh>
23 
24 #include <opm/common/ErrorMacros.hpp>
25 
26 #include <opm/common/utility/gpuDecorators.hpp>
27 #include <opm/simulators/linalg/gpuistl/detail/safe_conversion.hpp>
28 
29 #include <stdexcept>
30 #include <vector>
31 
32 #include <fmt/core.h>
33 
34 namespace Opm::gpuistl
35 {
36 
51 template <typename T>
52 class GpuView
53 {
54 public:
55  using value_type = T;
59  explicit GpuView() = default;
60 
61  //TODO: we probably dont need anything like this or is it useful to have views also be able to handle things on CPU?
64  GpuView(std::vector<T>& data);
65 
71  __host__ __device__ T& operator[](size_t idx){
72 #ifndef NDEBUG
73  assertInRange(idx);
74 #endif
75  return m_dataPtr[idx];
76  }
77 
83  __host__ __device__ T operator[](size_t idx) const {
84 #ifndef NDEBUG
85  assertInRange(idx);
86 #endif
87  return m_dataPtr[idx];
88  }
89 
90 
100  GpuView(T* dataOnHost, size_t numberOfElements)
101  : m_dataPtr(dataOnHost), m_numberOfElements(numberOfElements)
102  {
103  }
104 
108  ~GpuView() = default;
109 
113  __host__ __device__ T* data(){
114  return m_dataPtr;
115  }
116 
120  __host__ __device__ const T* data() const{
121  return m_dataPtr;
122  }
123 
127  __host__ __device__ bool empty() const {
128  return m_numberOfElements == 0;
129  }
130 
134  __host__ __device__ T& front()
135  {
136 #ifndef NDEBUG
137  assertHasElements();
138 #endif
139  return m_dataPtr[0];
140  }
141 
145  __host__ __device__ T& back()
146  {
147 #ifndef NDEBUG
148  assertHasElements();
149 #endif
150  return m_dataPtr[m_numberOfElements-1];
151  }
152 
156  __host__ __device__ T front() const
157  {
158 #ifndef NDEBUG
159  assertHasElements();
160 #endif
161  return m_dataPtr[0];
162  }
163 
167  __host__ __device__ T back() const
168  {
169 #ifndef NDEBUG
170  assertHasElements();
171 #endif
172  return m_dataPtr[m_numberOfElements-1];
173  }
174 
182  void copyFromHost(const T* dataPointer, size_t numberOfElements);
183 
191  void copyToHost(T* dataPointer, size_t numberOfElements) const;
192 
200  void copyFromHost(const std::vector<T>& data);
201 
209  void copyToHost(std::vector<T>& data) const;
210 
215  __host__ __device__ size_t size() const{
216  return m_numberOfElements;
217  }
218 
223  std::vector<T> asStdVector() const;
225  class iterator {
226  public:
227  // Iterator typedefs
228  using iterator_category = std::forward_iterator_tag;
229  using difference_type = std::ptrdiff_t;
230  using value_type = T;
231  using pointer = T*;
232  using reference = T&;
233 
237  __host__ __device__ iterator(T* ptr) : m_ptr(ptr) {}
238 
241  __host__ __device__ reference operator*() const {
242  return *m_ptr;
243  }
244 
247  __host__ __device__ iterator& operator++() {
248  ++m_ptr;
249  return *this;
250  }
251 
255  __host__ __device__ iterator operator++(int) {
256  iterator tmp = *this;
257  ++m_ptr;
258  return tmp;
259  }
260 
263  __host__ __device__ iterator& operator--() {
264  --m_ptr;
265  return *this;
266  }
267 
271  __host__ __device__ iterator operator--(int) {
272  iterator tmp = *this;
273  --m_ptr;
274  return tmp;
275  }
276 
279  __host__ __device__ bool operator!=(const iterator& other) const {
280  return !(m_ptr == other.m_ptr);
281  }
282 
285  __host__ __device__ bool operator==(const iterator& other) const {
286  return m_ptr == other.m_ptr;
287  }
288 
292  __host__ __device__ difference_type operator-(const iterator& other) const {
293  return std::distance(other.m_ptr, m_ptr);
294  }
295 
299  __host__ __device__ iterator operator-(difference_type n) const {
300  return iterator(m_ptr-n);
301  }
302 
306  __host__ __device__ iterator operator+(difference_type n) const {
307  return iterator(m_ptr + n);
308  }
309 
313  __host__ __device__ bool operator<(const iterator& other) const {
314  return m_ptr < other.m_ptr;
315  }
316 
320  __host__ __device__ bool operator>(const iterator& other) const {
321  return m_ptr > other.m_ptr;
322  }
323 
324  private:
325  // Pointer to the current element
326  T* m_ptr;
327  };
328 
333  __host__ __device__ iterator begin(){
334  return iterator(m_dataPtr);
335  }
336 
341  __host__ __device__ iterator begin() const {
342  return iterator(m_dataPtr);
343  }
344 
349  __host__ __device__ iterator end(){
350  return iterator(m_dataPtr + m_numberOfElements);
351  }
352 
357  __host__ __device__ iterator end() const {
358  return iterator(m_dataPtr + m_numberOfElements);
359  }
360 
361 private:
362  T* m_dataPtr;
363  size_t m_numberOfElements;
364 
367  __host__ __device__ void assertSameSize(const GpuView<T>& other) const
368  {
369  assertSameSize(other.m_numberOfElements);
370  }
373  __host__ __device__ void assertSameSize(size_t size) const
374  {
375 #if OPM_IS_INSIDE_DEVICE_FUNCTION
376  // TODO: find a better way to handle exceptions in kernels, this will possibly be printed many times
377  assert(size == m_numberOfElements && "Views did not have the same size");
378 #else
379  if (size != m_numberOfElements) {
380  OPM_THROW(std::invalid_argument,
381  fmt::format(fmt::runtime("Given view has {}, while this View has {}."), size, m_numberOfElements));
382  }
383 #endif
384  }
385 
387  __host__ __device__ void assertHasElements() const
388  {
389 #if OPM_IS_INSIDE_DEVICE_FUNCTION
390  // TODO: find a better way to handle exceptions in kernels, this will possibly be printed many times
391  assert(m_numberOfElements > 0 && "View has 0 elements");
392 #else
393  if (m_numberOfElements <= 0) {
394  OPM_THROW(std::invalid_argument, "View has 0 elements");
395  }
396 #endif
397  }
398 
400  __host__ __device__ void assertInRange(size_t idx) const
401  {
402 #if OPM_IS_INSIDE_DEVICE_FUNCTION
403  // TODO: find a better way to handle exceptions in kernels, this will possibly be printed many times
404  assert(idx < m_numberOfElements && "The index provided was not in the range [0, buffersize-1]");
405 #else
406  if (idx >= m_numberOfElements) {
407  OPM_THROW(std::invalid_argument,
408  fmt::format(fmt::runtime("The index provided was not in the range [0, buffersize-1]")));
409  }
410 #endif
411  }
412 };
413 
414 } // namespace Opm::gpuistl
415 
416 #endif
__host__ __device__ iterator operator+(difference_type n) const
Addition operator with diffptr.
Definition: GpuView.hpp:306
__host__ __device__ iterator operator++(int)
Post-increment operator.
Definition: GpuView.hpp:255
__host__ __device__ difference_type operator-(const iterator &other) const
subtraction operator
Definition: GpuView.hpp:292
__host__ __device__ size_t size() const
size returns the size (number of T elements) in the vector
Definition: GpuView.hpp:215
__host__ __device__ iterator & operator--()
Pre-decrement operator.
Definition: GpuView.hpp:263
__host__ __device__ T back() const
Definition: GpuView.hpp:167
__host__ __device__ T & back()
Definition: GpuView.hpp:145
The GpuView class is provides a view of some data allocated on the GPU Essenstially is only stores a ...
Definition: GpuView.hpp:52
__host__ __device__ bool operator<(const iterator &other) const
Less than comparison.
Definition: GpuView.hpp:313
__host__ __device__ bool operator>(const iterator &other) const
Greater than comparison.
Definition: GpuView.hpp:320
__host__ __device__ iterator end()
Get an iterator pointing to the address after the last element of the buffer.
Definition: GpuView.hpp:349
Iterator class to make GpuViews more similar to std containers.
Definition: GpuView.hpp:225
__host__ __device__ T & operator[](size_t idx)
operator[] to retrieve a reference to an item in the buffer
Definition: GpuView.hpp:71
__host__ __device__ T front() const
Definition: GpuView.hpp:156
std::vector< T > asStdVector() const
creates an std::vector of the same size and copies the GPU data to this std::vector ...
Definition: GpuView.cpp:37
__host__ __device__ iterator begin()
Get an iterator pointing to the first element of the buffer.
Definition: GpuView.hpp:333
__host__ __device__ bool operator!=(const iterator &other) const
Inequality comparison operator.
Definition: GpuView.hpp:279
__host__ __device__ iterator operator-(difference_type n) const
Subtraction of given number of elements from iterator.
Definition: GpuView.hpp:299
__host__ __device__ T & front()
Definition: GpuView.hpp:134
void copyFromHost(const T *dataPointer, size_t numberOfElements)
copyFromHost copies numberOfElements from the CPU memory dataPointer
Definition: GpuView.cpp:46
__host__ __device__ iterator end() const
Get a const iterator pointing to the address after the last element of the buffer.
Definition: GpuView.hpp:357
void copyToHost(T *dataPointer, size_t numberOfElements) const
copyFromHost copies numberOfElements to the CPU memory dataPointer
Definition: GpuView.cpp:59
__host__ __device__ T * data()
Definition: GpuView.hpp:113
__host__ __device__ iterator begin() const
Get a const iterator pointing to the first element of the buffer.
Definition: GpuView.hpp:341
__host__ __device__ bool empty() const
Definition: GpuView.hpp:127
__host__ __device__ iterator & operator++()
Pre-increment operator.
Definition: GpuView.hpp:247
A small, fixed‑dimension MiniVector class backed by std::array that can be used in both host and CUD...
Definition: AmgxInterface.hpp:37
__host__ __device__ iterator operator--(int)
Post-decrement operator.
Definition: GpuView.hpp:271
~GpuView()=default
~GpuView calls cudaFree
GpuView(T *dataOnHost, size_t numberOfElements)
GpuView allocates new GPU memory of size numberOfElements * sizeof(T) and copies numberOfElements fro...
Definition: GpuView.hpp:100
__host__ __device__ iterator(T *ptr)
Create iterator from a pointer.
Definition: GpuView.hpp:237
__host__ __device__ bool operator==(const iterator &other) const
Inequality comparison operator.
Definition: GpuView.hpp:285
__host__ __device__ const T * data() const
Definition: GpuView.hpp:120
GpuView()=default
Default constructor that will initialize cublas and allocate 0 bytes of memory.
__host__ __device__ reference operator*() const
Dereference operator.
Definition: GpuView.hpp:241
__host__ __device__ T operator[](size_t idx) const
operator[] to retrieve a copy of an item in the buffer
Definition: GpuView.hpp:83