GEOSX
ChaiBuffer.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020, Lawrence Livermore National Security, LLC and LvArray contributors.
3  * All rights reserved.
4  * See the LICENSE file for details.
5  * SPDX-License-Identifier: (BSD-3-Clause)
6  */
7 
13 #pragma once
14 
15 // Source includes
16 #include "LvArrayConfig.hpp"
17 #include "Macros.hpp"
18 #include "typeManipulation.hpp"
19 #include "arrayManipulation.hpp"
20 #include "system.hpp"
21 #include "bufferManipulation.hpp"
22 
23 // TPL includes
24 #include <chai/ArrayManager.hpp>
25 
26 // System includes
27 #include <mutex>
28 
29 
30 namespace LvArray
31 {
32 
33 namespace internal
34 {
35 
39 inline chai::ArrayManager & getArrayManager()
40 {
41  static chai::ArrayManager & arrayManager = *chai::ArrayManager::getInstance();
42  return arrayManager;
43 }
44 
46 static std::mutex chaiLock;
47 
52 inline chai::ExecutionSpace toChaiExecutionSpace( MemorySpace const space )
53 {
54  if( space == MemorySpace::NONE )
55  return chai::NONE;
56  if( space == MemorySpace::CPU )
57  return chai::CPU;
58 #if defined(LVARRAY_USE_CUDA)
59  if( space == MemorySpace::GPU )
60  return chai::GPU;
61 #endif
62 
63  LVARRAY_ERROR( "Unrecognized memory space " << static_cast< int >( space ) );
64 
65  return chai::NONE;
66 }
67 
72 inline MemorySpace toMemorySpace( chai::ExecutionSpace const space )
73 {
74  if( space == chai::NONE )
75  return MemorySpace::NONE;
76  if( space == chai::CPU )
77  return MemorySpace::CPU;
78 #if defined(LVARRAY_USE_CUDA)
79  if( space == chai::GPU )
80  return MemorySpace::GPU;
81 #endif
82 
83  LVARRAY_ERROR( "Unrecognized execution space " << static_cast< int >( space ) );
84 
85  return MemorySpace::NONE;
86 }
87 
88 } // namespace internal
89 
103 template< typename T >
105 {
106 public:
107 
109  using value_type = T;
110 
112  constexpr static bool hasShallowCopy = true;
113 
115  using T_non_const = std::remove_const_t< T >;
116 
122  LVARRAY_HOST_DEVICE inline constexpr
124  m_pointer( nullptr ),
125  m_capacity( 0 ),
126  m_pointerRecord( nullptr )
127  {}
128 
134  ChaiBuffer( bool ):
135  m_pointer( nullptr ),
136  m_capacity( 0 ),
137  m_pointerRecord( new chai::PointerRecord{} )
138  {
139  m_pointerRecord->m_size = 0;
140  setName( "" );
141 
142  for( int space = chai::CPU; space < chai::NUM_EXECUTION_SPACES; ++space )
143  {
144  m_pointerRecord->m_allocators[ space ] = internal::getArrayManager().getAllocatorId( chai::ExecutionSpace( space ) );
145  }
146  }
147 
154  LVARRAY_HOST_DEVICE inline
155  ChaiBuffer( ChaiBuffer const & src ):
156  m_pointer( src.m_pointer ),
157  m_capacity( src.m_capacity ),
158  m_pointerRecord( src.m_pointerRecord )
159  {
160  #if defined(LVARRAY_USE_CUDA) && !defined(__CUDA_ARCH__)
161  move( internal::toMemorySpace( internal::getArrayManager().getExecutionSpace() ), true );
162  #endif
163  }
164 
172  LVARRAY_HOST_DEVICE inline
173  ChaiBuffer( ChaiBuffer const & src, std::ptrdiff_t const size ):
174  m_pointer( src.m_pointer ),
175  m_capacity( src.m_capacity ),
176  m_pointerRecord( src.m_pointerRecord )
177  {
178  #if defined(LVARRAY_USE_CUDA) && !defined(__CUDA_ARCH__)
179  moveNested( internal::toMemorySpace( internal::getArrayManager().getExecutionSpace() ), size, true );
180  #else
181  LVARRAY_UNUSED_VARIABLE( size );
182  #endif
183  }
184 
189  LVARRAY_HOST_DEVICE inline constexpr
191  m_pointer( src.m_pointer ),
192  m_capacity( src.m_capacity ),
193  m_pointerRecord( src.m_pointerRecord )
194  {
195  src.m_capacity = 0;
196  src.m_pointer = nullptr;
197  src.m_pointerRecord = nullptr;
198  }
199 
205  template< typename _T=T, typename=std::enable_if_t< std::is_const< _T >::value > >
206  LVARRAY_HOST_DEVICE inline constexpr
207  ChaiBuffer( ChaiBuffer< std::remove_const_t< T > > const & src ):
208  m_pointer( src.data() ),
209  m_capacity( src.capacity() ),
210  m_pointerRecord( &src.pointerRecord() )
211  {}
212 
218  LVARRAY_HOST_DEVICE inline LVARRAY_INTEL_CONSTEXPR
219  ChaiBuffer & operator=( ChaiBuffer const & src )
220  {
221  m_capacity = src.m_capacity;
222  m_pointer = src.m_pointer;
223  m_pointerRecord = src.m_pointerRecord;
224  return *this;
225  }
226 
232  LVARRAY_HOST_DEVICE inline LVARRAY_INTEL_CONSTEXPR
234  {
235  m_capacity = src.m_capacity;
236  m_pointer = src.m_pointer;
237  m_pointerRecord = src.m_pointerRecord;
238 
239  src.m_capacity = 0;
240  src.m_pointer = nullptr;
241  src.m_pointerRecord = nullptr;
242 
243  return *this;
244  }
245 
254  void reallocate( std::ptrdiff_t const size, std::ptrdiff_t const newCapacity )
255  {
256  chai::PointerRecord * const newRecord = new chai::PointerRecord{};
257  newRecord->m_size = newCapacity * sizeof( T );
258  newRecord->m_user_callback = m_pointerRecord->m_user_callback;
259 
260  for( int space = chai::CPU; space < chai::NUM_EXECUTION_SPACES; ++space )
261  {
262  newRecord->m_allocators[ space ] = m_pointerRecord->m_allocators[ space ];
263  }
264 
265  internal::chaiLock.lock();
266  internal::getArrayManager().allocate( newRecord, chai::CPU );
267  internal::chaiLock.unlock();
268 
269  T * const newPointer = static_cast< T * >( newRecord->m_pointers[ chai::CPU ] );
270 
271  std::ptrdiff_t const overlapAmount = std::min( newCapacity, size );
272  arrayManipulation::uninitializedMove( newPointer, overlapAmount, m_pointer );
273  arrayManipulation::destroy( m_pointer, size );
274 
275  free();
276  m_capacity = newCapacity;
277  m_pointer = newPointer;
278  m_pointerRecord = newRecord;
279  registerTouch( MemorySpace::CPU );
280  }
281 
286  inline
287  void free()
288  {
289  std::lock_guard< std::mutex > lock( internal::chaiLock );
290  internal::getArrayManager().free( m_pointerRecord );
291  m_capacity = 0;
292  m_pointer = nullptr;
293  m_pointerRecord = nullptr;
294  }
295 
299  LVARRAY_HOST_DEVICE inline constexpr
300  std::ptrdiff_t capacity() const
301  { return m_capacity; }
302 
306  LVARRAY_HOST_DEVICE inline constexpr
307  T * data() const
308  { return m_pointer; }
309 
314  LVARRAY_HOST_DEVICE inline constexpr
315  chai::PointerRecord & pointerRecord() const
316  { return *m_pointerRecord; }
317 
324  template< typename INDEX_TYPE >
325  LVARRAY_HOST_DEVICE inline constexpr
326  T & operator[]( INDEX_TYPE const i ) const
327  { return m_pointer[ i ]; }
328 
336  inline
337  void moveNested( MemorySpace const space, std::ptrdiff_t const size, bool const touch ) const
338  {
339  #if defined(LVARRAY_USE_CUDA)
340  chai::ExecutionSpace const chaiSpace = internal::toChaiExecutionSpace( space );
341  if( m_pointerRecord == nullptr ||
342  m_capacity == 0 ||
343  chaiSpace == chai::NONE ) return;
344 
345  chai::ExecutionSpace const prevSpace = m_pointerRecord->m_last_space;
346 
347  if( prevSpace == chai::CPU && prevSpace != chaiSpace ) moveInnerData( space, size, touch );
348 
349  move( space, touch );
350 
351  if( prevSpace == chai::GPU && prevSpace != chaiSpace ) moveInnerData( space, size, touch );
352  #else
353  LVARRAY_ERROR_IF_NE( space, MemorySpace::CPU );
354  LVARRAY_UNUSED_VARIABLE( size );
355  LVARRAY_UNUSED_VARIABLE( touch );
356  #endif
357  }
358 
365  void move( MemorySpace const space, bool const touch ) const
366  {
367  #if defined(LVARRAY_USE_CUDA)
368  chai::ExecutionSpace const chaiSpace = internal::toChaiExecutionSpace( space );
369  if( m_pointerRecord == nullptr ||
370  m_capacity == 0 ||
371  chaiSpace == chai::NONE ) return;
372 
373  const_cast< T * & >( m_pointer ) =
374  static_cast< T * >( internal::getArrayManager().move( const_cast< T_non_const * >( m_pointer ),
375  m_pointerRecord,
376  chaiSpace ) );
377 
378  if( !std::is_const< T >::value && touch ) m_pointerRecord->m_touched[ chaiSpace ] = true;
379  m_pointerRecord->m_last_space = chaiSpace;
380  #else
381  LVARRAY_ERROR_IF_NE( space, MemorySpace::CPU );
382  LVARRAY_UNUSED_VARIABLE( touch );
383  #endif
384  }
385 
390  inline constexpr
391  void registerTouch( MemorySpace const space ) const
392  {
393  chai::ExecutionSpace const chaiSpace = internal::toChaiExecutionSpace( space );
394  m_pointerRecord->m_touched[ chaiSpace ] = true;
395  m_pointerRecord->m_last_space = chaiSpace;
396  }
397 
403  template< typename U=ChaiBuffer< T > >
404  void setName( std::string const & name )
405  {
406  std::string const typeString = LvArray::system::demangleType< U >();
407  m_pointerRecord->m_user_callback =
408  [name, typeString]( chai::PointerRecord const * const record, chai::Action const act, chai::ExecutionSpace const s )
409  {
410  if( act == chai::ACTION_MOVE )
411  {
412  std::string const size = system::calculateSize( record->m_size );
413  std::string const paddedSize = std::string( 9 - size.size(), ' ' ) + size;
414  char const * const spaceStr = ( s == chai::CPU ) ? "HOST " : "DEVICE";
415  LVARRAY_LOG( "Moved " << paddedSize << " to the " << spaceStr << ": " << typeString << " " << name );
416  }
417  };
418  }
419 
420 private:
421 
431  template< typename U=T_non_const >
432  std::enable_if_t< bufferManipulation::HasMemberFunction_move< U > >
433  moveInnerData( MemorySpace const space, std::ptrdiff_t const size, bool const touch ) const
434  {
435  if( space == MemorySpace::NONE ) return;
436 
437  for( std::ptrdiff_t i = 0; i < size; ++i )
438  {
439  const_cast< T_non_const * >( m_pointer )[ i ].move( space, touch );
440  }
441  }
442 
449  template< typename U=T_non_const >
450  std::enable_if_t< !bufferManipulation::HasMemberFunction_move< U > >
451  moveInnerData( MemorySpace const, std::ptrdiff_t const, bool const ) const
452  {}
453 
455  T * LVARRAY_RESTRICT m_pointer = nullptr;
456 
458  std::ptrdiff_t m_capacity = 0;
459 
461  chai::PointerRecord * m_pointerRecord = nullptr;
462 };
463 
464 } /* namespace LvArray */
LVARRAY_INTEL_CONSTEXPR ChaiBuffer & operator=(ChaiBuffer &&src)
Move assignment operator.
Definition: ChaiBuffer.hpp:233
#define LVARRAY_UNUSED_VARIABLE(X)
Mark X as an unused variable, used to silence compiler warnings.
Definition: Macros.hpp:51
void free()
Free the data in the buffer but does not destroy any values.
Definition: ChaiBuffer.hpp:287
constexpr ChaiBuffer()
Default constructor, creates an uninitialized ChaiBuffer.
Definition: ChaiBuffer.hpp:123
void setName(std::string const &name)
Set the name associated with this buffer which is used in the chai callback.
Definition: ChaiBuffer.hpp:404
T value_type
Alias for T used used in the bufferManipulation functions.
Definition: ChaiBuffer.hpp:109
constexpr std::ptrdiff_t capacity() const
Definition: ChaiBuffer.hpp:300
void uninitializedMove(T *const LVARRAY_RESTRICT dst, std::ptrdiff_t const size, T *const LVARRAY_RESTRICT src)
Move construct values from the source to the destination.
void moveNested(MemorySpace const space, std::ptrdiff_t const size, bool const touch) const
Move the buffer to the given execution space, optionally touching it.
Definition: ChaiBuffer.hpp:337
Contains functions that interact with the system or runtime environment.
ChaiBuffer(ChaiBuffer const &src)
Copy constructor.
Definition: ChaiBuffer.hpp:155
Contains templates useful for type manipulation.
Implements the Buffer interface using CHAI.
Definition: ChaiBuffer.hpp:104
constexpr chai::PointerRecord & pointerRecord() const
Return a reference to the associated CHAI PointerRecord.
Definition: ChaiBuffer.hpp:315
void destroy(T *const LVARRAY_RESTRICT ptr, std::ptrdiff_t const size)
Destory the values in the array.
#define LVARRAY_LOG(...)
Print the expression.
Definition: Macros.hpp:77
void move(MemorySpace const space, bool const touch) const
Move the buffer to the given execution space, optionally touching it.
Definition: ChaiBuffer.hpp:365
void free(BUFFER &buf, std::ptrdiff_t const size)
Destroy the values in the buffer and free it&#39;s memory.
constexpr ChaiBuffer(ChaiBuffer< std::remove_const_t< T > > const &src)
Create a copy of src with const T.
Definition: ChaiBuffer.hpp:207
Contains functions for manipulating buffers.
constexpr ChaiBuffer(ChaiBuffer &&src)
Move constructor.
Definition: ChaiBuffer.hpp:190
#define LVARRAY_ERROR(MSG)
Abort execution.
Definition: Macros.hpp:122
Contains functions for manipulating a contiguous array of values.
ChaiBuffer(bool)
Constructor for creating an empty Buffer.
Definition: ChaiBuffer.hpp:134
MemorySpace
An enum containing the available memory spaces.
The top level namespace.
Definition: Array.hpp:24
std::remove_const_t< T > T_non_const
An alias for the non const version of T.
Definition: ChaiBuffer.hpp:115
Contains a bunch of macro definitions.
LVARRAY_INTEL_CONSTEXPR ChaiBuffer & operator=(ChaiBuffer const &src)
Copy assignment operator.
Definition: ChaiBuffer.hpp:219
constexpr T & operator[](INDEX_TYPE const i) const
Definition: ChaiBuffer.hpp:326
std::string string
String type.
Definition: DataTypes.hpp:131
constexpr std::enable_if_t< std::is_arithmetic< T >::value, T > min(T const a, T const b)
Definition: math.hpp:65
ChaiBuffer(ChaiBuffer const &src, std::ptrdiff_t const size)
Copy constructor.
Definition: ChaiBuffer.hpp:173
#define LVARRAY_ERROR_IF_NE(lhs, rhs)
Raise a hard error if two values are not equal.
Definition: Macros.hpp:237
void reallocate(std::ptrdiff_t const size, std::ptrdiff_t const newCapacity)
Reallocate the buffer to the new capacity.
Definition: ChaiBuffer.hpp:254
constexpr T * data() const
Definition: ChaiBuffer.hpp:307
constexpr void registerTouch(MemorySpace const space) const
Touch the buffer in the given space.
Definition: ChaiBuffer.hpp:391
std::string calculateSize(size_t const bytes)
#define LVARRAY_HOST_DEVICE
Mark a function for both host and device usage.
Definition: Macros.hpp:389