Viskores  1.0
AtomicArrayExecutionObject.h
Go to the documentation of this file.
1 //============================================================================
2 // The contents of this file are covered by the Viskores license. See
3 // LICENSE.txt for details.
4 //
5 // By contributing to this file, all contributors agree to the Developer
6 // Certificate of Origin Version 1.1 (DCO 1.1) as stated in DCO.txt.
7 //============================================================================
8 
9 //============================================================================
10 // Copyright (c) Kitware, Inc.
11 // All rights reserved.
12 // See LICENSE.txt for details.
13 //
14 // This software is distributed WITHOUT ANY WARRANTY; without even
15 // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 // PURPOSE. See the above copyright notice for more information.
17 //============================================================================
18 #ifndef viskores_exec_AtomicArrayExecutionObject_h
19 #define viskores_exec_AtomicArrayExecutionObject_h
20 
21 #include <viskores/Atomic.h>
22 #include <viskores/List.h>
25 
26 #include <type_traits>
27 
28 namespace viskores
29 {
30 namespace exec
31 {
32 
33 namespace detail
34 {
35 // Clang-7 as host compiler under nvcc returns types from std::make_unsigned
36 // that are not compatible with the viskores::Atomic API, so we define our own
37 // mapping. This must exist for every entry in viskores::cont::AtomicArrayTypeList.
38 template <typename>
39 struct MakeUnsigned;
40 template <>
41 struct MakeUnsigned<viskores::UInt32>
42 {
43  using type = viskores::UInt32;
44 };
45 template <>
46 struct MakeUnsigned<viskores::Int32>
47 {
48  using type = viskores::UInt32;
49 };
50 template <>
51 struct MakeUnsigned<viskores::UInt64>
52 {
53  using type = viskores::UInt64;
54 };
55 template <>
56 struct MakeUnsigned<viskores::Int64>
57 {
58  using type = viskores::UInt64;
59 };
60 template <>
61 struct MakeUnsigned<viskores::Float32>
62 {
63  using type = viskores::UInt32;
64 };
65 template <>
66 struct MakeUnsigned<viskores::Float64>
67 {
68  using type = viskores::UInt64;
69 };
70 
71 template <typename T>
72 struct ArithType
73 {
74  using type = typename MakeUnsigned<T>::type;
75 };
76 template <>
77 struct ArithType<viskores::Float32>
78 {
79  using type = viskores::Float32;
80 };
81 template <>
82 struct ArithType<viskores::Float64>
83 {
84  using type = viskores::Float64;
85 };
86 }
87 
95 template <typename T>
97 {
98  // Checks if PortalType has a GetIteratorBegin() method that returns a
99  // pointer.
100  template <typename PortalType,
101  typename PointerType = decltype(std::declval<PortalType>().GetIteratorBegin())>
102  struct HasPointerAccess : public std::is_pointer<PointerType>
103  {
104  };
105 
106 public:
107  using ValueType = T;
108 
109  AtomicArrayExecutionObject() = default;
110 
113  viskores::cont::Token& token)
114  : Data{ handle.PrepareForInPlace(device, token).GetIteratorBegin() }
115  , NumberOfValues{ handle.GetNumberOfValues() }
116  {
117  using PortalType = decltype(handle.PrepareForInPlace(device, token));
118  VISKORES_STATIC_ASSERT_MSG(HasPointerAccess<PortalType>::value,
119  "Source portal must return a pointer from "
120  "GetIteratorBegin().");
121  }
122 
127 
138  {
139  // We only support 32/64 bit signed/unsigned ints, and viskores::Atomic
140  // currently only provides API for unsigned types.
141  // We'll cast the signed types to unsigned to work around this.
142  using APIType = typename detail::MakeUnsigned<ValueType>::type;
143 
144  return static_cast<T>(
145  viskores::AtomicLoad(reinterpret_cast<APIType*>(this->Data + index), order));
146  }
147 
159  const ValueType& value,
161  {
162  // We only support 32/64 bit signed/unsigned ints, and viskores::Atomic
163  // currently only provides API for unsigned types.
164  // We'll cast the signed types to unsigned to work around this.
165  // This is safe, since the only difference between signed/unsigned types
166  // is how overflow works, and signed overflow is already undefined. We also
167  // document that overflow is undefined for this operation.
168  using APIType = typename detail::ArithType<ValueType>::type;
169 
170  return static_cast<T>(viskores::AtomicAdd(
171  reinterpret_cast<APIType*>(this->Data + index), static_cast<APIType>(value), order));
172  }
173 
188  void Set(viskores::Id index,
189  const ValueType& value,
191  {
192  // We only support 32/64 bit signed/unsigned ints, and viskores::Atomic
193  // currently only provides API for unsigned types.
194  // We'll cast the signed types to unsigned to work around this.
195  // This is safe, since the only difference between signed/unsigned types
196  // is how overflow works, and signed overflow is already undefined. We also
197  // document that overflow is undefined for this operation.
198  using APIType = typename detail::MakeUnsigned<ValueType>::type;
199 
201  reinterpret_cast<APIType*>(this->Data + index), static_cast<APIType>(value), order);
202  }
203 
251  viskores::Id index,
252  ValueType* oldValue,
253  const ValueType& newValue,
255  {
256  // We only support 32/64 bit signed/unsigned ints, and viskores::Atomic
257  // currently only provides API for unsigned types.
258  // We'll cast the signed types to unsigned to work around this.
259  // This is safe, since the only difference between signed/unsigned types
260  // is how overflow works, and signed overflow is already undefined.
261  using APIType = typename detail::MakeUnsigned<ValueType>::type;
262 
263  return viskores::AtomicCompareExchange(reinterpret_cast<APIType*>(this->Data + index),
264  reinterpret_cast<APIType*>(oldValue),
265  static_cast<APIType>(newValue),
266  order);
267  }
268 
269 private:
270  ValueType* Data{ nullptr };
272 };
273 }
274 } // namespace viskores::exec
275 
276 #endif //viskores_exec_AtomicArrayExecutionObject_h
viskores::exec::AtomicArrayExecutionObject::CompareExchange
bool CompareExchange(viskores::Id index, ValueType *oldValue, const ValueType &newValue, viskores::MemoryOrder order=viskores::MemoryOrder::SequentiallyConsistent) const
Perform an atomic compare and exchange operation with sequentially consistent memory ordering.
Definition: AtomicArrayExecutionObject.h:250
Atomic.h
ArrayHandle.h
viskores::exec::AtomicArrayExecutionObject::Data
ValueType * Data
Definition: AtomicArrayExecutionObject.h:270
viskores::exec::AtomicArrayExecutionObject::AtomicArrayExecutionObject
AtomicArrayExecutionObject()=default
viskores::MemoryOrder::SequentiallyConsistent
@ SequentiallyConsistent
An atomic with SequentiallyConsistent memory order will enforce any appropriate semantics as Acquire,...
viskores::exec::AtomicArrayExecutionObject::ValueType
T ValueType
Definition: AtomicArrayExecutionObject.h:107
VISKORES_SUPPRESS_EXEC_WARNINGS
#define VISKORES_SUPPRESS_EXEC_WARNINGS
Definition: ExportMacros.h:61
viskores::cont::ArrayHandle
Manages an array-worth of data.
Definition: ArrayHandle.h:313
viskores::AtomicStore
void AtomicStore(T *pointer, T value, viskores::MemoryOrder order=viskores::MemoryOrder::Release)
Atomic function to save a value to a shared memory location.
Definition: Atomic.h:827
viskores::Int64
signed long long Int64
Base type to use for 64-bit signed integer numbers.
Definition: Types.h:212
DeviceAdapter.h
viskores::Id
viskores::Int64 Id
Base type to use to index arrays.
Definition: Types.h:235
VISKORES_CONT
#define VISKORES_CONT
Definition: ExportMacros.h:65
viskores
Groups connected points that have the same field value.
Definition: Atomic.h:27
viskores::cont::ArrayHandle::PrepareForInPlace
WritePortalType PrepareForInPlace(viskores::cont::DeviceAdapterId device, viskores::cont::Token &token) const
Prepares this array to be used in an in-place operation (both as input and output) in the execution e...
Definition: ArrayHandle.h:634
viskores::Float32
float Float32
Base type to use for 32-bit floating-point numbers.
Definition: Types.h:165
viskores::AtomicCompareExchange
bool AtomicCompareExchange(T *shared, T *expected, T desired, viskores::MemoryOrder order=viskores::MemoryOrder::SequentiallyConsistent)
Atomic function that replaces a value given a condition.
Definition: Atomic.h:1004
viskores::MemoryOrder::Acquire
@ Acquire
A load operation with Acquire memory order will enforce that any local read or write operations liste...
viskores::MemoryOrder
MemoryOrder
Specifies memory order semantics for atomic operations.
Definition: Atomic.h:64
viskores::exec::AtomicArrayExecutionObject::NumberOfValues
viskores::Id NumberOfValues
Definition: AtomicArrayExecutionObject.h:271
viskores::exec::AtomicArrayExecutionObject::Add
ValueType Add(viskores::Id index, const ValueType &value, viskores::MemoryOrder order=viskores::MemoryOrder::SequentiallyConsistent) const
Peform an atomic addition with sequentially consistent memory ordering.
Definition: AtomicArrayExecutionObject.h:158
VISKORES_STATIC_ASSERT_MSG
#define VISKORES_STATIC_ASSERT_MSG(condition, message)
Definition: StaticAssert.h:26
viskores::UInt64
unsigned long long UInt64
Base type to use for 64-bit signed integer numbers.
Definition: Types.h:215
viskores::cont::DeviceAdapterId
An object used to specify a device.
Definition: DeviceAdapterTag.h:66
viskores::Int32
int32_t Int32
Base type to use for 32-bit signed integer numbers.
Definition: Types.h:189
viskores::exec::AtomicArrayExecutionObject::AtomicArrayExecutionObject
AtomicArrayExecutionObject(viskores::cont::ArrayHandle< T > handle, viskores::cont::DeviceAdapterId device, viskores::cont::Token &token)
Definition: AtomicArrayExecutionObject.h:111
viskores::exec::AtomicArrayExecutionObject::GetNumberOfValues
viskores::Id GetNumberOfValues() const
Retrieve the number of values in the atomic array.
Definition: AtomicArrayExecutionObject.h:126
viskores::exec::AtomicArrayExecutionObject
An object passed to a worklet when accessing an atomic array.
Definition: AtomicArrayExecutionObject.h:96
viskores::exec::AtomicArrayExecutionObject::Get
ValueType Get(viskores::Id index, viskores::MemoryOrder order=viskores::MemoryOrder::Acquire) const
Perform an atomic load of the indexed element with acquire memory ordering.
Definition: AtomicArrayExecutionObject.h:136
viskores::AtomicLoad
T AtomicLoad(T *const pointer, viskores::MemoryOrder order=viskores::MemoryOrder::Acquire)
Atomic function to load a value from a shared memory location.
Definition: Atomic.h:812
viskores::AtomicAdd
T AtomicAdd(T *pointer, T operand, viskores::MemoryOrder order=viskores::MemoryOrder::SequentiallyConsistent)
Atomic function to add a value to a shared memory location.
Definition: Atomic.h:855
viskores::exec::AtomicArrayExecutionObject::Set
void Set(viskores::Id index, const ValueType &value, viskores::MemoryOrder order=viskores::MemoryOrder::Release) const
Peform an atomic store to memory while enforcing, at minimum, "release" memory ordering.
Definition: AtomicArrayExecutionObject.h:188
viskores::exec::AtomicArrayExecutionObject::HasPointerAccess
Definition: AtomicArrayExecutionObject.h:102
viskores::Float64
double Float64
Base type to use for 64-bit floating-point numbers.
Definition: Types.h:169
viskores::cont::Token
A token to hold the scope of an ArrayHandle or other object.
Definition: Token.h:43
viskores::UInt32
uint32_t UInt32
Base type to use for 32-bit unsigned integer numbers.
Definition: Types.h:193
VISKORES_EXEC
#define VISKORES_EXEC
Definition: ExportMacros.h:59
List.h
viskores::MemoryOrder::Release
@ Release
A store operation with Release memory order will enforce that any local read or write operations list...