SENSEI
A frame work for generic in situ analytics
svtkHAMRDataArray.h
1 #ifndef svtkHAMRDataArray_h
2 #define svtkHAMRDataArray_h
3 
4 #include "senseiConfig.h"
5 
6 #include "hamr_buffer.h"
7 #include "hamr_buffer_allocator.h"
8 #include "hamr_buffer_transfer.h"
9 #include "hamr_stream.h"
10 
11 #include "svtkDataArray.h"
12 #include "svtkAOSDataArrayTemplate.h"
13 #include "svtkCommonCoreModule.h"
14 
15 #include <cstdint>
16 #include <string>
17 
18 using svtkAllocator = hamr::buffer_allocator;
19 using svtkStreamMode = hamr::buffer_transfer;
20 using svtkStream = hamr::stream;
21 
22 /// get the allocator type most suitable for the current build configuration
23 inline svtkAllocator GetDeviceAllocator() { return hamr::get_device_allocator(); }
24 
25 /// get the allocator type most suitable for the current build configuration
26 inline svtkAllocator GetHostAllocator() { return hamr::get_host_allocator(); }
27 
28 /// get the allocator type most suitable for the current build configuration
29 inline svtkAllocator GetCPUAllocator() { return hamr::buffer_allocator::malloc; }
30 
31 /** An accelerator aware container for array based data. The svtkHAMRDataArray
32  * can be used to allocate and manage data on the host and on accelerators. The
33  * purpose of the container is to pass data in between simulation and analysis
34  * codes in a platform portable, programming model portable, efficient manner.
35  *
36  * Data can be allocated on the host or a specific accelerator. See ::New
37  * overloads in the "construct and allocate" group.
38  *
39  * Data can be explicitly moved between devices and between the host and any
40  * device. See ::SetAllocator.
41  *
42  * Zero-copy tansfer of device memory is supported, see ::New overloads in the
43  * "zero-copy construct" group for zero-copy construction and ::SetData overloads
44  * in the "zero-copy data transfer" group.
45  *
46  * When consuming data passed from an unknown sorce, accessibility methods can
47  * be used to access the data on the host or desired device. These may move the
48  * data to the requested device or the host. Data movement is only done if the
49  * data is not in the reqeusted location. Smart pointers are used to automate
50  * and hide the details from the caller. See ::GetHostAccessible,
51  * ::GetDeviceAccessible and programming model specific overloads
52  * ::GetCUDAAccessible, ::GetHIPAccessible, and ::GetOpenMPAccessible.
53  *
54  * When one knows where data resides direct access methods provide access to
55  * the raw pointers. See ::GetData and ::GetPointer.
56  *
57  * By default all operations including allocations, and data movement, are
58  * asynchronous. Care must be taken before accessing the data to be sure
59  * outstanding operations have been completed. See ::Synchronize.
60  */
61 template <typename T>
62 class SENSEI_EXPORT svtkHAMRDataArray : public svtkDataArray
63 {
64 public:
65  svtkTypeMacro(svtkHAMRDataArray, svtkDataArray);
66  void PrintSelf(ostream& os, svtkIndent indent) override;
67 
68 
69  ///@name construct uninitialized
70  ///@{
71 
72  /** construct a new instance that is uninitiazed. Before use call
73  * ::SetAllocator (and optionally ::SetStream), and either ::SetData or some
74  * combination of ::SetNumberOfTuples, ::SetNumberOfComponents, and/or
75  * ::Resize.
76  * @returns an empty instance.
77  */
78  static svtkHAMRDataArray *New();
79 
80  ///@}
81 
82  ///@name copy construct
83  ///@{
84  /** copy construct from the passed instance. this is a deep copy.
85  *
86  * @note the allocator is determined by the passed instance, while the
87  * default svtkStream and svtkStreamMode will be used. Use the overload
88  * that accepts an allocator when you want control over the location of
89  * the copy.
90  *
91  * @param[in] da the array to deep copy.
92  */
93  static svtkHAMRDataArray *New(svtkDataArray *da);
94 
95  /** copy construct from the passed instance. this is a deep copy. if the
96  * allocator is a device allocator the memory is allocated on the active
97  * device.
98  *
99  * @param[in] da the array to deep copy.
100  * @param[in] alloc the allocator to use to allocate memory for the copy
101  * @param[in] stream the stream to make the allocation and copy on
102  * @param[in] streamMode the sychnronization behavior of the container.
103  * @returns a new instance with the data copied.
104  */
105  static svtkHAMRDataArray *New(svtkDataArray *da, svtkAllocator alloc,
106  svtkStream stream, svtkStreamMode streamMode);
107  ///@}
108 
109  ///@name zero-copy construct
110  ///@{
111 
112  /** zero-copy the passed data.
113  * @param[in] name the name of the array
114  * @param[in] data a pointer to the data
115  * @param[in] numTuples the number of data tuples
116  * @param[in] numComps the numper of components per tuple
117  * @param[in] alloc an ::svtkAllocator instance declaring where the data resides
118  * @param[in] stream an ::svtkStream instance providing an ordering on operations
119  * @param[in] streamMode an ::svtkStreamMode instance declaring synchronous behavior or not
120  * @param[in] owner the device id where the data resides, or -1 for the host
121  * @param[in] take if true the pointed to data will be released using the
122  * deleter associated with the declared ::svtkAllocator alloc
123  * @returns a new instance that must be deleted by the caller
124  */
125  static svtkHAMRDataArray *New(const std::string &name, T *data,
126  size_t numTuples, int numComps, svtkAllocator alloc, svtkStream stream,
127  svtkStreamMode streamMode, int owner, int take);
128 
129  /** zero-copy the passed data. This override gives one direct control over the
130  * management and reference counting of the pointed to data.
131  * @param[in] name the name of the array
132  * @param[in] data a smart pointer that manages the pointed to data
133  * @param[in] numTuples the number of data tuples
134  * @param[in] numComps the numper of components per tuple
135  * @param[in] alloc an ::svtkAllocator instance declaring where the data resides
136  * @param[in] stream an ::svtkStream instance providing an ordering on operations
137  * @param[in] streamMode an ::svtkStreamMode instance declaring synchronous behavior or not
138  * @param[in] owner the device id where the data resides, or -1 for the host
139  * @returns a new instance that must be deleted by the caller
140  */
141  static svtkHAMRDataArray *New(const std::string &name,
142  const std::shared_ptr<T> &data, size_t numTuples, int numComps,
143  svtkAllocator alloc, svtkStream stream, svtkStreamMode streamMode,
144  int owner);
145 
146  /** zero-copy the passed data. This override gives one direct control over the
147  * method that is used to release the pointed to array.
148  * @param[in] name the name of the array
149  * @param[in] data a smart pointer that manages the pointed to data
150  * @param[in] numTuples the number of data tuples
151  * @param[in] numComps the numper of components per tuple
152  * @param[in] alloc an ::svtkAllocator instance declaring where the data resides
153  * @param[in] stream an ::svtkStream instance providing an ordering on operations
154  * @param[in] streamMode an ::svtkStreamMode instance declaring synchronous behavior or not
155  * @param[in] owner the device id where the data resides, or -1 for the host
156  * @returns a new instance that must be deleted by the caller
157  */
158  template <typename deleter_t>
159  static svtkHAMRDataArray *New(const std::string &name, T *data, size_t numTuples,
160  int numComps, svtkAllocator alloc, svtkStream stream, svtkStreamMode streamMode,
161  int owner, deleter_t deleter);
162 
163  ///@}
164 
165  ///@name construct and allocate
166  ///@{
167 
168  /** Allocate a new array of the specified size using the specified allocator
169  * @param[in] name the name of the array
170  * @param[in] numTuples the number of data tuples
171  * @param[in] numComps the numper of components per tuple
172  * @param[in] alloc an ::svtkAllocator instance declaring where the data resides
173  * @param[in] stream an ::svtkStream instance providing an ordering on operations
174  * @param[in] streamMode an ::svtkStreamMode instance declaring synchronous behavior or not
175  * @returns a new instance that must be deleted by the caller
176  */
177  static svtkHAMRDataArray *New(const std::string &name,
178  size_t numTuples, int numComps, svtkAllocator alloc, svtkStream stream,
179  svtkStreamMode streamMode);
180 
181  /** Allocate a new array of the specified size using the specified allocator
182  * initialized to the specified value
183  * @param[in] name the name of the array
184  * @param[in] numTuples the number of data tuples
185  * @param[in] numComps the numper of components per tuple
186  * @param[in] alloc an ::svtkAllocator instance declaring where the data resides
187  * @param[in] stream an ::svtkStream instance providing an ordering on operations
188  * @param[in] streamMode an ::svtkStreamMode instance declaring synchronous behavior or not
189  * @param[in] initVal the value to initialize the contents to
190  * @returns a new instance that must be deleted by the caller
191  */
192  static svtkHAMRDataArray *New(const std::string &name,
193  size_t numTuples, int numComps, svtkAllocator alloc, svtkStream stream,
194  svtkStreamMode streamMode, const T &initVal);
195 
196  ///@}
197 
198  ///@name zero-copy data transfer
199  ///@{
200 
201  /** zero-copy the passed data. the allocator is used to tell where the data
202  * resides. the callee (array instance) takes ownership of the pointer.
203  */
204  void SetData(T *data, size_t numTuples, int numComps, svtkAllocator alloc,
205  svtkStream stream, svtkStreamMode streamMode, int owner);
206 
207  /** zero-copy the passed data. the allocator is used to tell where the data
208  * resides.
209  */
210  void SetData(const std::shared_ptr<T> &data, size_t numTuples, int numComps,
211  svtkAllocator alloc, svtkStream stream, svtkStreamMode, int owner);
212 
213  /** zero-copy the passed data. the allocator is used to tell where the data
214  * resides the deleter will be called as void deleter(void *dataPtr) when the
215  * data is no longer needed
216  */
217  template <typename deleter_t>
218  void SetData(T *dataPtr, size_t numTuples, int numComps,
219  svtkAllocator alloc, svtkStream stream, svtkStreamMode,
220  int owner, deleter_t deleter);
221 
222  ///@}
223 
224  ///@name location agnostic access
225  ///@{
226 
227  /// @returns a pointer to the data that is safe to use on the host
228  std::shared_ptr<const T> GetHostAccessible() const { return this->Data->get_host_accessible(); }
229 
230  /// @returns a pointer to the data that is safe for the compiled device
231  std::shared_ptr<const T> GetDeviceAccessible() const { return this->Data->get_device_accessible(); }
232 
233  /// @returns a pointer to the data that is safe to use with CUDA
234  std::shared_ptr<const T> GetCUDAAccessible() const { return this->Data->get_cuda_accessible(); }
235 
236  /// @returns a pointer to the data that is safe to use with HIP
237  std::shared_ptr<const T> GetHIPAccessible() const { return this->Data->get_hip_accessible(); }
238 
239  /// @returns a pointer to the data that is safe to use with OpenMP device off load
240  std::shared_ptr<const T> GetOpenMPAccessible() const { return this->Data->get_openmp_accessible(); }
241 
242  ///@}
243 
244  ///@name direct access
245  ///@{
246 
247  /** fast access to the internally managed memory. Use this only when you know
248  * where the data resides and will access it in that location. This method
249  * saves the cost of a smart_ptr copy construct and the cost of the logic
250  * that determines if a temporary is needed. For all other cases use
251  * GetXAccessible to access the data.
252  */
253  T *GetData() { return this->Data->data(); }
254 
255  /** fast access to the internally managed memory. Use this only when you know
256  * where the data resides and will access it in that location. This method
257  * saves the cost of the logic determining if a temporary is needed. For all
258  * other cases use GetXAccessible to access the data.
259  */
260  std::shared_ptr<T> GetDataPointer() { return this->Data->pointer(); }
261 
262  ///@}
263 
264  ///@name device location
265  ///@{
266 
267  /// get the device where the memory was allocated.
268  int GetOwner() const { return this->Data->get_owner(); }
269 
270  /** Set the device id that owns the memory to the currently aactive device.
271  * this may be used to move the data from one device to another.
272  */
273  void SetOwner()
274  {
275  this->Data->move(this->GetAllocator());
276  }
277 
278  /** Sets or changes the allocator used to manage the menory, this may move
279  * the data from one device to another
280  */
281  void SetAllocator(svtkAllocator alloc)
282  {
283  this->Data->move(alloc);
284  }
285 
286  /// @returns the current allocator
287  svtkAllocator GetAllocator()
288  {
289  return this->Data->get_allocator();
290  }
291 
292  /// return true if a pooniter to the data is safe to use on the Host
293  bool HostAccessible() { return this->Data->host_accessible(); }
294 
295  /// return true if a pooniter to the data is safe to use with CUDA
296  bool CUDAAccessible() { return this->Data->cuda_accessible(); }
297 
298  /// returns a pointer to the data that is safe to use with HIP
299  bool HIPAccessible() { return this->Data->hip_accessible(); }
300 
301  /// return true if a pooniter to the data is safe to use with OpenMP device off load
302  bool OpenMPAccessible() { return this->Data->openmp_accessible(); }
303 
304  ///@}
305 
306  ///@name synchronization
307  ///@{
308 
309  /// sets the stream. mode indicate synchronous behavior or not.
310  void SetStream(const svtkStream &stream, svtkStreamMode &mode)
311  {
312  this->Data->set_stream(stream, mode);
313  }
314 
315  /// @returns the stream
316  svtkStream &GetStream() { return this->Data->get_stream(); }
317  const svtkStream &GetStream() const { return this->Data->get_stream(); }
318 
319  /// synchronizes on the internal stream
320  void Synchronize() const { this->Data->synchronize(); }
321 
322  ///@}
323 
324  ///@name modify the size of the array
325  ///@{
326 
327  /// returns the number of values. this is the current size, not the capacity.
328  svtkIdType GetNumberOfValues() const override { return this->Data->size(); }
329 
330  /// sets the current size and may change the capacity of the array
331  void SetNumberOfTuples(svtkIdType numTuples) override;
332  void SetNumberOfTuples(svtkIdType numTuples, svtkAllocator alloc);
333 
334  /// resize the container using the current allocator
335  svtkTypeBool Resize(svtkIdType numTuples) override;
336 
337  ///@}
338 
339  ///@name conversions
340  ///@{
341 
342  /** Convert to an svtkAOSDataArrayTemplate instance. Because SVTK only
343  * supports host based data, a deep-copy is made when this array is located on
344  * the GPU. Otherwise the data is passed via zero-copy
345  * @param[in] zeroCopy if true and the data resides on the host, the data is
346  * passed to the new svtkAOSDataArrayTemplate instance by
347  * zero-copy. Otehrwise a deep-copy is made.
348  * @returns a new instance that must be deleted by the caller
349  */
350  svtkAOSDataArrayTemplate<T> *AsSvtkAOSDataArray(int zeroCopy);
351 
352  ///@}
353 
354  ///@cond
355 
356  /** @name not implemented
357  * These methods are not impelemented, and will abort if called. This is
358  * because these methods assume host accessibility and/or would be
359  * inefficient if implemented for heterogeneous accellerators. An example of
360  * this is the methods dealing with single tuples. Access to a single tuple
361  * stored on an accelerator from the host in a loop would be very
362  * inefficient. Instead the data can be accessed in bulk. See ::GetData.
363  */
364  ///@{
365  svtkTypeBool Allocate(svtkIdType numValues, svtkIdType ext) override;
366 
367  void Initialize() override;
368 
369  int GetDataType() const override;
370 
371  int GetDataTypeSize() const override;
372 
373  int GetElementComponentSize() const override;
374 
375  void SetTuple(svtkIdType dstTupleIdx, svtkIdType srcTupleIdx, svtkAbstractArray* source) override;
376 
377  void InsertTuple(svtkIdType dstTupleIdx, svtkIdType srcTupleIdx, svtkAbstractArray* source) override;
378 
379  void InsertTuples(svtkIdList* dstIds, svtkIdList* srcIds, svtkAbstractArray* source) override;
380 
381  void InsertTuples(svtkIdType dstStart, svtkIdType n, svtkIdType srcStart, svtkAbstractArray* source) override;
382 
383  svtkIdType InsertNextTuple(svtkIdType srcTupleIdx, svtkAbstractArray* source) override;
384 
385  void GetTuples(svtkIdList* tupleIds, svtkAbstractArray* output) override;
386 
387  void GetTuples(svtkIdType p1, svtkIdType p2, svtkAbstractArray* output) override;
388 
389  bool HasStandardMemoryLayout() const override;
390 
391  void* GetVoidPointer(svtkIdType valueIdx) override;
392 
393  void DeepCopy(svtkAbstractArray* da) override;
394 
395  void InterpolateTuple(svtkIdType dstTupleIdx, svtkIdList* ptIndices, svtkAbstractArray* source, double* weights) override;
396 
397  void InterpolateTuple(svtkIdType dstTupleIdx, svtkIdType srcTupleIdx1, svtkAbstractArray* source1, svtkIdType srcTupleIdx2, svtkAbstractArray* source2, double t) override;
398 
399  void Squeeze() override;
400 
401  void SetVoidArray(void* svtkNotUsed(array), svtkIdType svtkNotUsed(size), int svtkNotUsed(save)) override;
402 
403  void SetVoidArray(void* ptr, svtkIdType size, int save, int deleteMethod) override;
404 
405  void SetArrayFreeFunction(void (*callback)(void*)) override;
406 
407  void ExportToVoidPointer(void* out_ptr) override;
408 
409  unsigned long GetActualMemorySize() const override;
410 
411  int IsNumeric() const override;
412 
413  SVTK_NEWINSTANCE svtkArrayIterator* NewIterator() override;
414 
415  svtkIdType LookupValue(svtkVariant value) override;
416  void LookupValue(svtkVariant value, svtkIdList* valueIds) override;
417  svtkVariant GetVariantValue(svtkIdType valueIdx) override;
418 
419  void InsertVariantValue(svtkIdType valueIdx, svtkVariant value) override;
420 
421  void SetVariantValue(svtkIdType valueIdx, svtkVariant value) override;
422 
423  void DataChanged() override;
424 
425  void ClearLookup() override;
426 
427  void GetProminentComponentValues(int comp, svtkVariantArray* values, double uncertainty = 1.e-6, double minimumProminence = 1.e-3) override;
428 
429  int CopyInformation(svtkInformation* infoFrom, int deep = 1) override;
430 
431  double* GetTuple(svtkIdType tupleIdx) override;
432 
433  void GetTuple(svtkIdType tupleIdx, double* tuple) override;
434 
435  void SetTuple(svtkIdType tupleIdx, const float* tuple) override;
436  void SetTuple(svtkIdType tupleIdx, const double* tuple) override;
437 
438  void InsertTuple(svtkIdType tupleIdx, const float* tuple) override;
439  void InsertTuple(svtkIdType tupleIdx, const double* tuple) override;
440 
441  svtkIdType InsertNextTuple(const float* tuple) override;
442  svtkIdType InsertNextTuple(const double* tuple) override;
443 
444  void RemoveTuple(svtkIdType tupleIdx) override;
445  void RemoveFirstTuple() override { this->RemoveTuple(0); }
446  void RemoveLastTuple() override;
447 
448  double GetComponent(svtkIdType tupleIdx, int compIdx) override;
449 
450  void SetComponent(svtkIdType tupleIdx, int compIdx, double value) override;
451 
452  void InsertComponent(svtkIdType tupleIdx, int compIdx, double value) override;
453 
454  void GetData(svtkIdType tupleMin, svtkIdType tupleMax, int compMin, int compMax, svtkDoubleArray* data) override;
455 
456  void DeepCopy(svtkDataArray* da) override;
457 
458  void ShallowCopy(svtkDataArray* other) override;
459 
460  void FillComponent(int compIdx, double value) override;
461 
462  void Fill(double value) override;
463 
464  void CopyComponent(int dstComponent, svtkDataArray* src, int srcComponent) override;
465 
466  void* WriteVoidPointer(svtkIdType valueIdx, svtkIdType numValues) override;
467 
468  double GetMaxNorm() override;
469 
470  int GetArrayType() const override;
471  ///@}
472 
473  ///@endcond
474 
475 protected:
477  ~svtkHAMRDataArray() override;
478 
479 private:
480  hamr::buffer<T> *Data;
481 
482 private:
483  svtkHAMRDataArray(const svtkHAMRDataArray&) = delete;
484  void operator=(const svtkHAMRDataArray&) = delete;
485 
486  template<typename U> friend class svtkHAMRDataArray;
487 };
488 
489 #if !defined(SENSEI_SEPARATE_IMPL)
490 #include "svtkHAMRDataArrayImpl.h"
491 #endif
492 
505 
506 #endif
void SetOwner()
Set the device id that owns the memory to the currently aactive device.
Definition: svtkHAMRDataArray.h:273
int Initialize(MPI_Comm comm, const std::string &fileName, InTransitDataAdaptor *&dataAdaptor)
Creates a sensei::ConfigurableAnalysis adaptor and sensei::InTransitDataAdaptor based on a SENSEI XML...
std::shared_ptr< const T > GetDeviceAccessible() const
Definition: svtkHAMRDataArray.h:231
bool OpenMPAccessible()
return true if a pooniter to the data is safe to use with OpenMP device off load
Definition: svtkHAMRDataArray.h:302
int GetOwner() const
get the device where the memory was allocated.
Definition: svtkHAMRDataArray.h:268
std::shared_ptr< const T > GetHIPAccessible() const
Definition: svtkHAMRDataArray.h:237
std::shared_ptr< T > GetDataPointer()
fast access to the internally managed memory.
Definition: svtkHAMRDataArray.h:260
svtkAllocator GetAllocator()
Definition: svtkHAMRDataArray.h:287
std::shared_ptr< const T > GetCUDAAccessible() const
Definition: svtkHAMRDataArray.h:234
void Synchronize() const
synchronizes on the internal stream
Definition: svtkHAMRDataArray.h:320
svtkIdType GetNumberOfValues() const override
returns the number of values. this is the current size, not the capacity.
Definition: svtkHAMRDataArray.h:328
bool HIPAccessible()
returns a pointer to the data that is safe to use with HIP
Definition: svtkHAMRDataArray.h:299
An accelerator aware container for array based data.
Definition: svtkHAMRDataArray.h:62
bool CUDAAccessible()
return true if a pooniter to the data is safe to use with CUDA
Definition: svtkHAMRDataArray.h:296
bool HostAccessible()
return true if a pooniter to the data is safe to use on the Host
Definition: svtkHAMRDataArray.h:293
void SetStream(const svtkStream &stream, svtkStreamMode &mode)
sets the stream. mode indicate synchronous behavior or not.
Definition: svtkHAMRDataArray.h:310
void SetAllocator(svtkAllocator alloc)
Sets or changes the allocator used to manage the menory, this may move the data from one device to an...
Definition: svtkHAMRDataArray.h:281
T * GetData()
fast access to the internally managed memory.
Definition: svtkHAMRDataArray.h:253
svtkStream & GetStream()
Definition: svtkHAMRDataArray.h:316
std::shared_ptr< const T > GetOpenMPAccessible() const
Definition: svtkHAMRDataArray.h:240
std::shared_ptr< const T > GetHostAccessible() const
Definition: svtkHAMRDataArray.h:228