updated Atomic array to use new excution object paradigm

This commit is contained in:
Matthew Letter 2018-06-07 13:16:28 -06:00
parent 6bc579e461
commit 3c9e7f049f
5 changed files with 95 additions and 193 deletions

@ -53,7 +53,8 @@ struct Transport<vtkm::cont::arg::TransportTagAtomicArray,
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>,
Device>
{
using ExecObjectType = vtkm::exec::AtomicArray<T, Device>;
using ExecObjectType = vtkm::exec::AtomicArrayExecutionObject<T, Device>;
using ExecType = vtkm::exec::AtomicArray<T>;
template <typename InputDomainType>
VTKM_CONT ExecObjectType operator()(vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> array,
@ -64,12 +65,12 @@ struct Transport<vtkm::cont::arg::TransportTagAtomicArray,
// Note: we ignore the size of the domain because the randomly accessed
// array might not have the same size depending on how the user is using
// the array.
return ExecObjectType(array);
ExecType obj = ExecType(array);
return obj.PrepareForExecution(Device());
}
};
}
}
} // namespace vtkm::cont::arg
#endif //vtk_m_cont_arg_TransportTagAtomicArray_h
#endif //vtk_m_cont_arg_TransportTagAtomicArray_h

@ -113,31 +113,23 @@ public:
IdPortalType OutputArray;
};
template <typename PortalType>
struct GenericClearArrayKernel
struct ClearArrayKernel
{
using ValueType = typename PortalType::ValueType;
VTKM_CONT
GenericClearArrayKernel(const PortalType& array,
const ValueType& fillValue = static_cast<ValueType>(OFFSET))
ClearArrayKernel(const IdPortalType& array)
: Array(array)
, Dims()
, FillValue(fillValue)
{
}
VTKM_CONT
GenericClearArrayKernel(const PortalType& array,
const vtkm::Id3& dims,
const ValueType& fillValue = static_cast<ValueType>(OFFSET))
ClearArrayKernel(const IdPortalType& array, const vtkm::Id3& dims)
: Array(array)
, Dims(dims)
, FillValue(fillValue)
{
}
VTKM_EXEC void operator()(vtkm::Id index) const { this->Array.Set(index, this->FillValue); }
VTKM_EXEC void operator()(vtkm::Id index) const { this->Array.Set(index, OFFSET); }
VTKM_EXEC void operator()(vtkm::Id3 index) const
{
@ -148,13 +140,10 @@ public:
VTKM_CONT void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
PortalType Array;
IdPortalType Array;
vtkm::Id3 Dims;
ValueType FillValue;
};
using ClearArrayKernel = GenericClearArrayKernel<IdPortalType>;
struct ClearArrayMapKernel //: public vtkm::exec::WorkletMapField
{
@ -202,57 +191,6 @@ public:
vtkm::Id3 Dims;
};
// Checks that each instance is only visited once:
struct OverlapKernel
{
using ArrayType = ArrayHandle<bool>;
using PortalType = typename ArrayType::template ExecutionTypes<DeviceAdapterTag>::Portal;
PortalType TrackerPortal;
PortalType ValidPortal;
vtkm::Id3 Dims;
VTKM_CONT
OverlapKernel(const PortalType& trackerPortal,
const PortalType& validPortal,
const vtkm::Id3& dims)
: TrackerPortal(trackerPortal)
, ValidPortal(validPortal)
, Dims(dims)
{
}
VTKM_CONT
OverlapKernel(const PortalType& trackerPortal, const PortalType& validPortal)
: TrackerPortal(trackerPortal)
, ValidPortal(validPortal)
, Dims()
{
}
VTKM_EXEC void operator()(vtkm::Id index) const
{
if (this->TrackerPortal.Get(index))
{ // this index has already been visited, that's an error
this->ValidPortal.Set(index, false);
}
else
{
this->TrackerPortal.Set(index, true);
this->ValidPortal.Set(index, true);
}
}
VTKM_EXEC void operator()(vtkm::Id3 index) const
{
//convert from id3 to id
vtkm::Id flatIndex = index[0] + this->Dims[0] * (index[1] + this->Dims[1] * index[2]);
this->operator()(flatIndex);
}
VTKM_CONT void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
};
struct OneErrorKernel
{
VTKM_EXEC void operator()(vtkm::Id index) const
@ -332,8 +270,8 @@ public:
struct AtomicKernel
{
VTKM_CONT
AtomicKernel(const vtkm::exec::AtomicArray<T, DeviceAdapterTag>& array)
: AArray(array)
AtomicKernel(const vtkm::exec::AtomicArray<T>& array)
: AArray(array.PrepareForExecution(DeviceAdapterTag()))
{
}
@ -345,15 +283,15 @@ public:
VTKM_CONT void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
vtkm::exec::AtomicArray<T, DeviceAdapterTag> AArray;
vtkm::exec::AtomicArrayExecutionObject<T, DeviceAdapterTag> AArray;
};
template <typename T>
struct AtomicCASKernel
{
VTKM_CONT
AtomicCASKernel(const vtkm::exec::AtomicArray<T, DeviceAdapterTag>& array)
: AArray(array)
AtomicCASKernel(const vtkm::exec::AtomicArray<T>& array)
: AArray(array.PrepareForExecution(DeviceAdapterTag()))
{
}
@ -374,7 +312,7 @@ public:
VTKM_CONT void SetErrorMessageBuffer(const vtkm::exec::internal::ErrorMessageBuffer&) {}
vtkm::exec::AtomicArray<T, DeviceAdapterTag> AArray;
vtkm::exec::AtomicArrayExecutionObject<T, DeviceAdapterTag> AArray;
};
class VirtualObjectTransferKernel
@ -704,78 +642,6 @@ private:
VTKM_TEST_ASSERT(value == index + OFFSET, "Got bad value for scheduled vtkm::Id3 kernels.");
}
} //release memory
// Ensure that each element is only visited once:
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Schedule for overlap" << std::endl;
{
using BoolArray = ArrayHandle<bool>;
using BoolPortal = typename BoolArray::template ExecutionTypes<DeviceAdapterTag>::Portal;
BoolArray tracker;
BoolArray valid;
// Initialize tracker with 'false' values
std::cout << "Allocating and initializing memory" << std::endl;
Algorithm::Schedule(GenericClearArrayKernel<BoolPortal>(
tracker.PrepareForOutput(ARRAY_SIZE, DeviceAdapterTag()), false),
ARRAY_SIZE);
Algorithm::Schedule(GenericClearArrayKernel<BoolPortal>(
valid.PrepareForOutput(ARRAY_SIZE, DeviceAdapterTag()), false),
ARRAY_SIZE);
std::cout << "Running Overlap kernel." << std::endl;
Algorithm::Schedule(OverlapKernel(tracker.PrepareForInPlace(DeviceAdapterTag()),
valid.PrepareForInPlace(DeviceAdapterTag())),
ARRAY_SIZE);
std::cout << "Checking results." << std::endl;
auto vPortal = valid.GetPortalConstControl();
for (vtkm::Id i = 0; i < ARRAY_SIZE; i++)
{
bool isValid = vPortal.Get(i);
VTKM_TEST_ASSERT(isValid, "Schedule executed some elements more than once.");
}
} // release memory
// Ensure that each element is only visited once:
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Schedule for overlap with vtkm::Id3" << std::endl;
{
static constexpr vtkm::Id numElems{ DIM_SIZE * DIM_SIZE * DIM_SIZE };
static const vtkm::Id3 dims{ DIM_SIZE, DIM_SIZE, DIM_SIZE };
using BoolArray = ArrayHandle<bool>;
using BoolPortal = typename BoolArray::template ExecutionTypes<DeviceAdapterTag>::Portal;
BoolArray tracker;
BoolArray valid;
// Initialize tracker with 'false' values
std::cout << "Allocating and initializing memory" << std::endl;
Algorithm::Schedule(GenericClearArrayKernel<BoolPortal>(
tracker.PrepareForOutput(numElems, DeviceAdapterTag()), dims, false),
numElems);
Algorithm::Schedule(GenericClearArrayKernel<BoolPortal>(
valid.PrepareForOutput(numElems, DeviceAdapterTag()), dims, false),
numElems);
std::cout << "Running Overlap kernel." << std::endl;
Algorithm::Schedule(OverlapKernel(tracker.PrepareForInPlace(DeviceAdapterTag()),
valid.PrepareForInPlace(DeviceAdapterTag()),
dims),
dims);
std::cout << "Checking results." << std::endl;
auto vPortal = valid.GetPortalConstControl();
for (vtkm::Id i = 0; i < numElems; i++)
{
bool isValid = vPortal.Get(i);
VTKM_TEST_ASSERT(isValid, "Id3 Schedule executed some elements more than once.");
}
} // release memory
}
static VTKM_CONT void TestCopyIf()
@ -2228,7 +2094,7 @@ private:
vtkm::cont::ArrayHandle<vtkm::Int32> atomicElement =
vtkm::cont::make_ArrayHandle(singleElement);
vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapterTag> atomic(atomicElement);
vtkm::exec::AtomicArray<vtkm::Int32> atomic(atomicElement);
Algorithm::Schedule(AtomicKernel<vtkm::Int32>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int32 expected = vtkm::Int32(atomicCount);
vtkm::Int32 actual = atomicElement.GetPortalControl().Get(0);
@ -2242,7 +2108,7 @@ private:
vtkm::cont::ArrayHandle<vtkm::Int64> atomicElement =
vtkm::cont::make_ArrayHandle(singleElement);
vtkm::exec::AtomicArray<vtkm::Int64, DeviceAdapterTag> atomic(atomicElement);
vtkm::exec::AtomicArray<vtkm::Int64> atomic(atomicElement);
Algorithm::Schedule(AtomicKernel<vtkm::Int64>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int64 expected = vtkm::Int64(atomicCount);
vtkm::Int64 actual = atomicElement.GetPortalControl().Get(0);
@ -2256,7 +2122,7 @@ private:
vtkm::cont::ArrayHandle<vtkm::Int32> atomicElement =
vtkm::cont::make_ArrayHandle(singleElement);
vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapterTag> atomic(atomicElement);
vtkm::exec::AtomicArray<vtkm::Int32> atomic(atomicElement);
Algorithm::Schedule(AtomicCASKernel<vtkm::Int32>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int32 expected = vtkm::Int32(atomicCount);
vtkm::Int32 actual = atomicElement.GetPortalControl().Get(0);
@ -2270,7 +2136,7 @@ private:
vtkm::cont::ArrayHandle<vtkm::Int64> atomicElement =
vtkm::cont::make_ArrayHandle(singleElement);
vtkm::exec::AtomicArray<vtkm::Int64, DeviceAdapterTag> atomic(atomicElement);
vtkm::exec::AtomicArray<vtkm::Int64> atomic(atomicElement);
Algorithm::Schedule(AtomicCASKernel<vtkm::Int64>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int64 expected = vtkm::Int64(atomicCount);
vtkm::Int64 actual = atomicElement.GetPortalControl().Get(0);
@ -2351,4 +2217,4 @@ public:
}
} // namespace vtkm::cont::testing
#endif //vtk_m_cont_testing_TestingDeviceAdapter_h
#endif //vtk_m_cont_testing_TestingDeviceAdapter_h

@ -36,34 +36,20 @@ struct AtomicArrayTypeListTag : vtkm::ListTagBase<vtkm::Int32, vtkm::Int64>
{
};
/// A class that can be used to atomically operate on an array of values safely
/// across multiple instances of the same worklet. This is useful when you have
/// an algorithm that needs to accumulate values in parallel, but writing out a
/// value per worklet might be memory prohibitive.
///
/// To construct an AtomicArray you will need to pass in an
/// vtkm::cont::ArrayHandle that is used as the underlying storage for the
/// AtomicArray
///
/// Supported Operations: add / compare and swap (CAS)
///
/// Supported Types: 32 / 64 bit signed integers
///
///
template <typename T, typename DeviceAdapterTag>
class AtomicArray : public vtkm::cont::ExecutionObjectBase
template <typename T, typename Device>
class AtomicArrayExecutionObject
{
public:
using ValueType = T;
VTKM_CONT
AtomicArray()
AtomicArrayExecutionObject()
: AtomicImplementation((vtkm::cont::ArrayHandle<T>()))
{
}
template <typename StorageType>
VTKM_CONT AtomicArray(vtkm::cont::ArrayHandle<T, StorageType> handle)
VTKM_CONT AtomicArrayExecutionObject(vtkm::cont::ArrayHandle<T, StorageType> handle)
: AtomicImplementation(handle)
{
}
@ -88,9 +74,61 @@ public:
}
private:
vtkm::cont::DeviceAdapterAtomicArrayImplementation<T, DeviceAdapterTag> AtomicImplementation;
vtkm::cont::DeviceAdapterAtomicArrayImplementation<T, Device> AtomicImplementation;
};
/// A class that can be used to atomically operate on an array of values safely
/// across multiple instances of the same worklet. This is useful when you have
/// an algorithm that needs to accumulate values in parallel, but writing out a
/// value per worklet might be memory prohibitive.
///
/// To construct an AtomicArray you will need to pass in an
/// vtkm::cont::ArrayHandle that is used as the underlying storage for the
/// AtomicArray
///
/// Supported Operations: add / compare and swap (CAS)
///
/// Supported Types: 32 / 64 bit signed integers
///
///
template <typename T>
class AtomicArray : public vtkm::cont::ExecutionObjectBase
{
public:
using ValueType = T;
template <typename Device>
VTKM_CONT AtomicArrayExecutionObject<T, Device> PrepareForExecution(Device) const
{
AtomicArrayExecutionObject<T, Device> execObject;
if (isHandle)
{
execObject = AtomicArrayExecutionObject<T, Device>(this->Handle);
}
else
{
execObject = AtomicArrayExecutionObject<T, Device>();
}
return execObject;
}
VTKM_CONT
AtomicArray()
: isHandle(false)
{
}
template <typename StorageType>
VTKM_CONT AtomicArray(vtkm::cont::ArrayHandle<T, StorageType> handle)
: isHandle(true)
, Handle(handle)
{
}
private:
bool isHandle;
vtkm::cont::ArrayHandle<T> Handle;
};
}
} // namespace vtkm::exec
#endif //vtk_m_exec_AtomicArray_h
#endif //vtk_m_exec_AtomicArray_h

@ -23,7 +23,6 @@
#include <vtkm/Assert.h>
#include <vtkm/Math.h>
#include <vtkm/Swap.h>
#include <vtkm/Types.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/ArrayHandle.h>
@ -158,7 +157,9 @@ template <typename DeviceTag>
class EdgePlotter : public vtkm::worklet::WorkletMapField
{
public:
using AtomicPackedFrameBufferHandle = vtkm::exec::AtomicArray<vtkm::Int64, DeviceTag>;
using AtomicPackedFrameBufferHandle =
vtkm::exec::AtomicArrayExecutionObject<vtkm::Int64, DeviceTag>;
using AtomicPackedFrameBuffer = vtkm::exec::AtomicArray<vtkm::Int64>;
using ControlSignature = void(FieldIn<Id2Type>, WholeArrayIn<Vec3>, WholeArrayIn<Scalar>);
using ExecutionSignature = void(_1, _2, _3);
@ -175,7 +176,7 @@ public:
bool assocPoints,
const vtkm::Range& fieldRange,
const ColorMapHandle& colorMap,
const AtomicPackedFrameBufferHandle& frameBuffer,
const AtomicPackedFrameBuffer& frameBuffer,
const vtkm::Range& clippingRange)
: WorldToProjection(worldToProjection)
, Width(width)
@ -187,7 +188,7 @@ public:
, AssocPoints(assocPoints)
, ColorMap(colorMap.PrepareForInput(DeviceTag()))
, ColorMapSize(vtkm::Float32(colorMap.GetNumberOfValues() - 1))
, FrameBuffer(frameBuffer)
, FrameBuffer(frameBuffer.PrepareForExecution(DeviceTag()))
, FieldMin(vtkm::Float32(fieldRange.Min))
{
InverseFieldDelta = 1.0f / vtkm::Float32(fieldRange.Length());
@ -220,16 +221,16 @@ public:
bool transposed = vtkm::Abs(y2 - y1) > vtkm::Abs(x2 - x1);
if (transposed)
{
vtkm::Swap(x1, y1);
vtkm::Swap(x2, y2);
std::swap(x1, y1);
std::swap(x2, y2);
}
// Ensure we are always going from left to right
if (x1 > x2)
{
vtkm::Swap(x1, x2);
vtkm::Swap(y1, y2);
vtkm::Swap(z1, z2);
std::swap(x1, x2);
std::swap(y1, y2);
std::swap(z1, z2);
}
vtkm::Float32 dx = x2 - x1;
@ -595,4 +596,4 @@ private:
}
} //namespace vtkm::rendering
#endif //vtk_m_rendering_Wireframer_h
#endif //vtk_m_rendering_Wireframer_h

@ -297,7 +297,7 @@ private:
vtkm::Int32 LeafCount;
//Int8Handle Counters;
//Int8ArrayPortal CountersPortal;
vtkm::exec::AtomicArray<vtkm::Int32, Device> Counters;
vtkm::exec::AtomicArrayExecutionObject<vtkm::Int32, Device> Counters;
public:
VTKM_CONT
@ -306,12 +306,12 @@ public:
IdArrayHandle& rightChildren,
vtkm::Int32 leafCount,
Float4ArrayHandle flatBVH,
const vtkm::exec::AtomicArray<vtkm::Int32, Device>& counters)
const vtkm::exec::AtomicArray<vtkm::Int32>& counters)
: Parents(parents.PrepareForInput(Device()))
, LeftChildren(leftChildren.PrepareForInput(Device()))
, RightChildren(rightChildren.PrepareForInput(Device()))
, LeafCount(leafCount)
, Counters(counters)
, Counters(counters.PrepareForExecution(Device()))
{
this->FlatBVH = flatBVH.PrepareForOutput((LeafCount - 1) * 4, Device());
@ -774,7 +774,7 @@ VTKM_CONT void LinearBVHBuilder::RunOnDevice(LinearBVH& linearBVH, Device device
vtkm::Int32 zero = 0;
vtkm::worklet::DispatcherMapField<MemSet<vtkm::Int32>, Device>(MemSet<vtkm::Int32>(zero))
.Invoke(counters);
vtkm::exec::AtomicArray<vtkm::Int32, Device> atomicCounters(counters);
vtkm::exec::AtomicArray<vtkm::Int32> atomicCounters(counters);
vtkm::worklet::DispatcherMapField<PropagateAABBs<Device>, Device>(
@ -905,10 +905,6 @@ template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<
template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagTBB>(
vtkm::cont::DeviceAdapterTagTBB);
#endif
#ifdef VTKM_ENABLE_OPENMP
template VTKM_CONT_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagOpenMP>(
vtkm::cont::DeviceAdapterTagOpenMP);
#endif
#ifdef VTKM_ENABLE_CUDA
template VTKM_RENDERING_EXPORT void LinearBVH::ConstructOnDevice<vtkm::cont::DeviceAdapterTagCuda>(
vtkm::cont::DeviceAdapterTagCuda);
@ -937,4 +933,4 @@ vtkm::Id LinearBVH::GetNumberOfTriangles() const
}
}
}
} // namespace vtkm::rendering::raytracing
} // namespace vtkm::rendering::raytracing