2014-02-11 17:34:56 +00:00
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) Kitware, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
// See LICENSE.txt for details.
|
|
|
|
// This software is distributed WITHOUT ANY WARRANTY; without even
|
|
|
|
// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
// PURPOSE. See the above copyright notice for more information.
|
|
|
|
//
|
2017-09-20 21:33:44 +00:00
|
|
|
// Copyright 2014 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
|
2014-02-11 17:34:56 +00:00
|
|
|
// Copyright 2014 UT-Battelle, LLC.
|
2015-05-21 12:09:22 +00:00
|
|
|
// Copyright 2014 Los Alamos National Security.
|
2014-02-11 17:34:56 +00:00
|
|
|
//
|
2017-09-20 21:33:44 +00:00
|
|
|
// Under the terms of Contract DE-NA0003525 with NTESS,
|
2014-02-11 17:34:56 +00:00
|
|
|
// the U.S. Government retains certain rights in this software.
|
|
|
|
//
|
|
|
|
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
|
|
|
|
// Laboratory (LANL), the U.S. Government retains certain rights in
|
|
|
|
// this software.
|
|
|
|
//============================================================================
|
2016-09-15 23:46:09 +00:00
|
|
|
|
2014-03-07 15:19:09 +00:00
|
|
|
#ifndef vtk_m_cont_internal_DeviceAdapterAlgorithmGeneral_h
|
|
|
|
#define vtk_m_cont_internal_DeviceAdapterAlgorithmGeneral_h
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
2017-08-24 14:22:35 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleDiscard.h>
|
2015-04-28 13:31:50 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleImplicit.h>
|
2015-09-15 04:11:09 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleIndex.h>
|
2017-05-18 14:51:24 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleStreaming.h>
|
2015-04-23 17:25:37 +00:00
|
|
|
#include <vtkm/cont/ArrayHandleZip.h>
|
2015-07-16 19:40:22 +00:00
|
|
|
#include <vtkm/cont/internal/FunctorsGeneral.h>
|
2014-06-10 17:35:13 +00:00
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
#include <vtkm/exec/internal/ErrorMessageBuffer.h>
|
2016-09-12 14:30:03 +00:00
|
|
|
#include <vtkm/exec/internal/TaskSingular.h>
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-10-24 22:53:09 +00:00
|
|
|
#include <vtkm/BinaryPredicates.h>
|
2017-03-09 00:05:28 +00:00
|
|
|
#include <vtkm/TypeTraits.h>
|
|
|
|
|
2016-11-23 21:14:56 +00:00
|
|
|
#include <vtkm/internal/Windows.h>
|
2016-03-14 13:51:17 +00:00
|
|
|
|
2017-08-24 14:22:35 +00:00
|
|
|
#include <type_traits>
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace cont
|
|
|
|
{
|
|
|
|
namespace internal
|
|
|
|
{
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
/// \brief
|
|
|
|
///
|
|
|
|
/// This struct provides algorithms that implement "general" device adapter
|
|
|
|
/// algorithms. If a device adapter provides implementations for Schedule,
|
|
|
|
/// and Synchronize, the rest of the algorithms can be implemented by calling
|
|
|
|
/// these functions.
|
|
|
|
///
|
|
|
|
/// It should be noted that we recommend that you also implement Sort,
|
|
|
|
/// ScanInclusive, and ScanExclusive for improved performance.
|
|
|
|
///
|
|
|
|
/// An easy way to implement the DeviceAdapterAlgorithm specialization is to
|
|
|
|
/// subclass this and override the implementation of methods as necessary.
|
|
|
|
/// As an example, the code would look something like this.
|
|
|
|
///
|
|
|
|
/// \code{.cpp}
|
|
|
|
/// template<>
|
|
|
|
/// struct DeviceAdapterAlgorithm<DeviceAdapterTagFoo>
|
|
|
|
/// : DeviceAdapterAlgorithmGeneral<DeviceAdapterAlgorithm<DeviceAdapterTagFoo>,
|
|
|
|
/// DeviceAdapterTagFoo>
|
|
|
|
/// {
|
|
|
|
/// template<class Functor>
|
2016-10-19 22:42:58 +00:00
|
|
|
/// VTKM_CONT static void Schedule(Functor functor,
|
2014-02-11 17:34:56 +00:00
|
|
|
/// vtkm::Id numInstances)
|
|
|
|
/// {
|
|
|
|
/// ...
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// template<class Functor>
|
2016-10-19 22:42:58 +00:00
|
|
|
/// VTKM_CONT static void Schedule(Functor functor,
|
2014-02-11 17:34:56 +00:00
|
|
|
/// vtkm::Id3 maxRange)
|
|
|
|
/// {
|
|
|
|
/// ...
|
|
|
|
/// }
|
|
|
|
///
|
2016-10-19 22:42:58 +00:00
|
|
|
/// VTKM_CONT static void Synchronize()
|
2014-02-11 17:34:56 +00:00
|
|
|
/// {
|
|
|
|
/// ...
|
|
|
|
/// }
|
|
|
|
/// };
|
|
|
|
/// \endcode
|
|
|
|
///
|
|
|
|
/// You might note that DeviceAdapterAlgorithmGeneral has two template
|
|
|
|
/// parameters that are redundant. Although the first parameter, the class for
|
|
|
|
/// the actual DeviceAdapterAlgorithm class containing Schedule, and
|
|
|
|
/// Synchronize is the same as DeviceAdapterAlgorithm<DeviceAdapterTag>, it is
|
|
|
|
/// made a separate template parameter to avoid a recursive dependence between
|
|
|
|
/// DeviceAdapterAlgorithmGeneral.h and DeviceAdapterAlgorithm.h
|
|
|
|
///
|
2017-05-18 14:29:41 +00:00
|
|
|
template <class DerivedAlgorithm, class DeviceAdapterTag>
|
2014-02-11 17:34:56 +00:00
|
|
|
struct DeviceAdapterAlgorithmGeneral
|
|
|
|
{
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Get Execution Value
|
|
|
|
// This method is used internally to get a single element from the execution
|
|
|
|
// array. Might want to expose this and/or allow actual device adapter
|
|
|
|
// implementations to provide one.
|
|
|
|
private:
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn>
|
|
|
|
VTKM_CONT static T GetExecutionValue(const vtkm::cont::ArrayHandle<T, CIn>& input, vtkm::Id index)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2017-08-10 19:26:05 +00:00
|
|
|
using OutputArrayType = vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>;
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
OutputArrayType output;
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto outputPortal = output.PrepareForOutput(1, DeviceAdapterTag());
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
CopyKernel<decltype(inputPortal), decltype(outputPortal)> kernel(
|
|
|
|
inputPortal, outputPortal, index);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(kernel, 1);
|
|
|
|
|
|
|
|
return output.GetPortalConstControl().Get(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2015-07-16 19:40:22 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Copy
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class COut>
|
|
|
|
VTKM_CONT static void Copy(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<U, COut>& output)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2016-08-12 16:39:42 +00:00
|
|
|
const vtkm::Id inSize = input.GetNumberOfValues();
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto outputPortal = output.PrepareForOutput(inSize, DeviceAdapterTag());
|
2016-08-12 16:39:42 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
CopyKernel<decltype(inputPortal), decltype(outputPortal)> kernel(inputPortal, outputPortal);
|
2016-08-12 16:39:42 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, inSize);
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-03-03 22:17:43 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// CopyIf
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class CStencil, class COut, class UnaryPredicate>
|
|
|
|
VTKM_CONT static void CopyIf(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<U, CStencil>& stencil,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output,
|
|
|
|
UnaryPredicate unary_predicate)
|
2017-03-03 22:17:43 +00:00
|
|
|
{
|
|
|
|
VTKM_ASSERT(input.GetNumberOfValues() == stencil.GetNumberOfValues());
|
|
|
|
vtkm::Id arrayLength = stencil.GetNumberOfValues();
|
|
|
|
|
2017-08-10 19:26:05 +00:00
|
|
|
using IndexArrayType = vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic>;
|
2017-03-03 22:17:43 +00:00
|
|
|
IndexArrayType indices;
|
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto stencilPortal = stencil.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto indexPortal = indices.PrepareForOutput(arrayLength, DeviceAdapterTag());
|
2017-03-03 22:17:43 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
StencilToIndexFlagKernel<decltype(stencilPortal), decltype(indexPortal), UnaryPredicate>
|
|
|
|
indexKernel(stencilPortal, indexPortal, unary_predicate);
|
2017-03-03 22:17:43 +00:00
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(indexKernel, arrayLength);
|
|
|
|
|
|
|
|
vtkm::Id outArrayLength = DerivedAlgorithm::ScanExclusive(indices, indices);
|
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto outputPortal = output.PrepareForOutput(outArrayLength, DeviceAdapterTag());
|
2017-05-18 14:29:41 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
CopyIfKernel<decltype(inputPortal),
|
|
|
|
decltype(stencilPortal),
|
|
|
|
decltype(indexPortal),
|
|
|
|
decltype(outputPortal),
|
2017-05-18 14:29:41 +00:00
|
|
|
UnaryPredicate>
|
|
|
|
copyKernel(inputPortal, stencilPortal, indexPortal, outputPortal, unary_predicate);
|
2017-03-03 22:17:43 +00:00
|
|
|
DerivedAlgorithm::Schedule(copyKernel, arrayLength);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class CStencil, class COut>
|
|
|
|
VTKM_CONT static void CopyIf(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<U, CStencil>& stencil,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output)
|
2017-03-03 22:17:43 +00:00
|
|
|
{
|
|
|
|
::vtkm::NotZeroInitialized unary_predicate;
|
|
|
|
DerivedAlgorithm::CopyIf(input, stencil, output, unary_predicate);
|
|
|
|
}
|
|
|
|
|
2016-08-12 16:39:42 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// CopySubRange
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class COut>
|
|
|
|
VTKM_CONT static bool CopySubRange(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Id inputStartIndex,
|
|
|
|
vtkm::Id numberOfElementsToCopy,
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<U, COut>& output,
|
|
|
|
vtkm::Id outputIndex = 0)
|
2016-08-12 16:39:42 +00:00
|
|
|
{
|
|
|
|
const vtkm::Id inSize = input.GetNumberOfValues();
|
2017-10-10 19:30:49 +00:00
|
|
|
|
|
|
|
// Check if the ranges overlap and fail if they do.
|
|
|
|
if (input == output && ((outputIndex >= inputStartIndex &&
|
|
|
|
outputIndex < inputStartIndex + numberOfElementsToCopy) ||
|
|
|
|
(inputStartIndex >= outputIndex &&
|
|
|
|
inputStartIndex < outputIndex + numberOfElementsToCopy)))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
if (inputStartIndex < 0 || numberOfElementsToCopy < 0 || outputIndex < 0 ||
|
|
|
|
inputStartIndex >= inSize)
|
|
|
|
{ //invalid parameters
|
2016-08-12 16:39:42 +00:00
|
|
|
return false;
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2016-08-12 16:39:42 +00:00
|
|
|
//determine if the numberOfElementsToCopy needs to be reduced
|
2017-05-18 14:29:41 +00:00
|
|
|
if (inSize < (inputStartIndex + numberOfElementsToCopy))
|
|
|
|
{ //adjust the size
|
2016-08-12 16:39:42 +00:00
|
|
|
numberOfElementsToCopy = (inSize - inputStartIndex);
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2016-08-12 16:39:42 +00:00
|
|
|
|
|
|
|
const vtkm::Id outSize = output.GetNumberOfValues();
|
|
|
|
const vtkm::Id copyOutEnd = outputIndex + numberOfElementsToCopy;
|
2017-05-18 14:29:41 +00:00
|
|
|
if (outSize < copyOutEnd)
|
2016-08-12 16:39:42 +00:00
|
|
|
{ //output is not large enough
|
2017-05-18 14:29:41 +00:00
|
|
|
if (outSize == 0)
|
2016-08-12 16:39:42 +00:00
|
|
|
{ //since output has nothing, just need to allocate to correct length
|
|
|
|
output.Allocate(copyOutEnd);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ //we currently have data in this array, so preserve it in the new
|
|
|
|
//resized array
|
|
|
|
vtkm::cont::ArrayHandle<U, COut> temp;
|
|
|
|
temp.Allocate(copyOutEnd);
|
|
|
|
DerivedAlgorithm::CopySubRange(output, 0, outSize, temp);
|
|
|
|
output = temp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto outputPortal = output.PrepareForInPlace(DeviceAdapterTag());
|
|
|
|
|
|
|
|
CopyKernel<decltype(inputPortal), decltype(outputPortal)> kernel(
|
|
|
|
inputPortal, outputPortal, inputStartIndex, outputIndex);
|
2016-08-12 16:39:42 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numberOfElementsToCopy);
|
|
|
|
return true;
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Lower Bounds
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class CVal, class COut>
|
|
|
|
VTKM_CONT static void LowerBounds(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<T, CVal>& values,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& output)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
|
|
|
vtkm::Id arraySize = values.GetNumberOfValues();
|
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto valuesPortal = values.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto outputPortal = output.PrepareForOutput(arraySize, DeviceAdapterTag());
|
|
|
|
|
|
|
|
LowerBoundsKernel<decltype(inputPortal), decltype(valuesPortal), decltype(outputPortal)> kernel(
|
|
|
|
inputPortal, valuesPortal, outputPortal);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(kernel, arraySize);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class CVal, class COut, class BinaryCompare>
|
|
|
|
VTKM_CONT static void LowerBounds(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<T, CVal>& values,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& output,
|
|
|
|
BinaryCompare binary_compare)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
|
|
|
vtkm::Id arraySize = values.GetNumberOfValues();
|
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto valuesPortal = values.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto outputPortal = output.PrepareForOutput(arraySize, DeviceAdapterTag());
|
|
|
|
|
|
|
|
LowerBoundsComparisonKernel<decltype(inputPortal),
|
|
|
|
decltype(valuesPortal),
|
|
|
|
decltype(outputPortal),
|
|
|
|
BinaryCompare>
|
|
|
|
kernel(inputPortal, valuesPortal, outputPortal, binary_compare);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(kernel, arraySize);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <class CIn, class COut>
|
|
|
|
VTKM_CONT static void LowerBounds(const vtkm::cont::ArrayHandle<vtkm::Id, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& values_output)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
DeviceAdapterAlgorithmGeneral<DerivedAlgorithm, DeviceAdapterTag>::LowerBounds(
|
|
|
|
input, values_output, values_output);
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
2015-04-28 13:31:50 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Reduce
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn>
|
|
|
|
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input, U initialValue)
|
2015-04-30 13:01:52 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
return DerivedAlgorithm::Reduce(input, initialValue, vtkm::Add());
|
2015-04-30 13:01:52 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class BinaryFunctor>
|
2017-05-26 17:53:28 +00:00
|
|
|
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
U initialValue,
|
2017-05-18 14:29:41 +00:00
|
|
|
BinaryFunctor binary_functor)
|
2015-04-28 13:31:50 +00:00
|
|
|
{
|
|
|
|
//Crazy Idea:
|
|
|
|
//We create a implicit array handle that wraps the input
|
|
|
|
//array handle. The implicit functor is passed the input array handle, and
|
|
|
|
//the number of elements it needs to sum. This way the implicit handle
|
|
|
|
//acts as the first level reduction. Say for example reducing 16 values
|
|
|
|
//at a time.
|
|
|
|
//
|
|
|
|
//Now that we have an implicit array that is 1/16 the length of full array
|
|
|
|
//we can use scan inclusive to compute the final sum
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag());
|
|
|
|
ReduceKernel<decltype(inputPortal), U, BinaryFunctor> kernel(
|
|
|
|
inputPortal, initialValue, binary_functor);
|
2015-07-16 19:40:22 +00:00
|
|
|
|
2015-04-28 13:31:50 +00:00
|
|
|
vtkm::Id length = (input.GetNumberOfValues() / 16);
|
|
|
|
length += (input.GetNumberOfValues() % 16 == 0) ? 0 : 1;
|
2017-08-10 20:13:55 +00:00
|
|
|
auto reduced = vtkm::cont::make_ArrayHandleImplicit(kernel, length);
|
2015-04-28 13:31:50 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandle<U, vtkm::cont::StorageTagBasic> inclusiveScanStorage;
|
2017-05-18 14:29:41 +00:00
|
|
|
const U scanResult =
|
|
|
|
DerivedAlgorithm::ScanInclusive(reduced, inclusiveScanStorage, binary_functor);
|
2016-11-22 23:03:27 +00:00
|
|
|
return scanResult;
|
2015-04-28 13:31:50 +00:00
|
|
|
}
|
|
|
|
|
2016-09-29 21:06:34 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Streaming Reduce
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn>
|
|
|
|
VTKM_CONT static U StreamingReduce(const vtkm::Id numBlocks,
|
2017-05-26 17:53:28 +00:00
|
|
|
const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
U initialValue)
|
2016-09-29 21:06:34 +00:00
|
|
|
{
|
2016-11-09 21:21:50 +00:00
|
|
|
return DerivedAlgorithm::StreamingReduce(numBlocks, input, initialValue, vtkm::Add());
|
2016-09-29 21:06:34 +00:00
|
|
|
}
|
2016-10-23 13:24:28 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class CIn, class BinaryFunctor>
|
|
|
|
VTKM_CONT static U StreamingReduce(const vtkm::Id numBlocks,
|
2017-05-26 17:53:28 +00:00
|
|
|
const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
U initialValue,
|
2017-05-18 14:29:41 +00:00
|
|
|
BinaryFunctor binary_functor)
|
2016-09-29 21:06:34 +00:00
|
|
|
{
|
|
|
|
vtkm::Id fullSize = input.GetNumberOfValues();
|
|
|
|
vtkm::Id blockSize = fullSize / numBlocks;
|
2017-05-18 14:29:41 +00:00
|
|
|
if (fullSize % numBlocks != 0)
|
|
|
|
blockSize += 1;
|
2016-09-29 21:06:34 +00:00
|
|
|
|
2017-09-21 14:33:17 +00:00
|
|
|
U lastResult = vtkm::TypeTraits<U>::ZeroInitialization();
|
2017-05-18 14:29:41 +00:00
|
|
|
for (vtkm::Id block = 0; block < numBlocks; block++)
|
2016-09-29 21:06:34 +00:00
|
|
|
{
|
|
|
|
vtkm::Id numberOfInstances = blockSize;
|
2017-05-18 14:29:41 +00:00
|
|
|
if (block == numBlocks - 1)
|
|
|
|
numberOfInstances = fullSize - blockSize * block;
|
2016-09-29 21:06:34 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandleStreaming<vtkm::cont::ArrayHandle<T, CIn>> streamIn(
|
|
|
|
input, block, blockSize, numberOfInstances);
|
2016-09-29 21:06:34 +00:00
|
|
|
|
2016-10-21 16:58:14 +00:00
|
|
|
if (block == 0)
|
2016-09-29 21:06:34 +00:00
|
|
|
lastResult = DerivedAlgorithm::Reduce(streamIn, initialValue, binary_functor);
|
2016-10-21 16:58:14 +00:00
|
|
|
else
|
|
|
|
lastResult = DerivedAlgorithm::Reduce(streamIn, lastResult, binary_functor);
|
2016-09-29 21:06:34 +00:00
|
|
|
}
|
|
|
|
return lastResult;
|
|
|
|
}
|
|
|
|
|
2015-05-04 19:53:35 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Reduce By Key
|
2017-05-26 17:53:28 +00:00
|
|
|
template <typename T,
|
|
|
|
typename U,
|
|
|
|
class KIn,
|
|
|
|
class VIn,
|
|
|
|
class KOut,
|
|
|
|
class VOut,
|
2017-05-18 14:29:41 +00:00
|
|
|
class BinaryFunctor>
|
|
|
|
VTKM_CONT static void ReduceByKey(const vtkm::cont::ArrayHandle<T, KIn>& keys,
|
|
|
|
const vtkm::cont::ArrayHandle<U, VIn>& values,
|
|
|
|
vtkm::cont::ArrayHandle<T, KOut>& keys_output,
|
|
|
|
vtkm::cont::ArrayHandle<U, VOut>& values_output,
|
|
|
|
BinaryFunctor binary_functor)
|
2015-05-04 19:53:35 +00:00
|
|
|
{
|
2017-08-24 14:22:35 +00:00
|
|
|
using KeysOutputType = vtkm::cont::ArrayHandle<U, KOut>;
|
|
|
|
|
2016-04-20 21:41:14 +00:00
|
|
|
VTKM_ASSERT(keys.GetNumberOfValues() == values.GetNumberOfValues());
|
2015-05-04 19:53:35 +00:00
|
|
|
const vtkm::Id numberOfKeys = keys.GetNumberOfValues();
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
if (numberOfKeys <= 1)
|
|
|
|
{ //we only have a single key/value so that is our output
|
2015-05-04 19:53:35 +00:00
|
|
|
DerivedAlgorithm::Copy(keys, keys_output);
|
|
|
|
DerivedAlgorithm::Copy(values, values_output);
|
|
|
|
return;
|
2017-05-18 14:29:41 +00:00
|
|
|
}
|
2015-05-04 19:53:35 +00:00
|
|
|
|
|
|
|
//we need to determine based on the keys what is the keystate for
|
|
|
|
//each key. The states are start, middle, end of a series and the special
|
|
|
|
//state start and end of a series
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<ReduceKeySeriesStates> keystate;
|
2015-05-04 19:53:35 +00:00
|
|
|
|
|
|
|
{
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = keys.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto keyStatePortal = keystate.PrepareForOutput(numberOfKeys, DeviceAdapterTag());
|
|
|
|
ReduceStencilGeneration<decltype(inputPortal), decltype(keyStatePortal)> kernel(
|
|
|
|
inputPortal, keyStatePortal);
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numberOfKeys);
|
2015-05-04 19:53:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//next step is we need to reduce the values for each key. This is done
|
|
|
|
//by running an inclusive scan over the values array using the stencil.
|
|
|
|
//
|
|
|
|
// this inclusive scan will write out two values, the first being
|
|
|
|
// the value summed currently, the second being 0 or 1, with 1 being used
|
|
|
|
// when this is a value of a key we need to write ( END or START_AND_END)
|
|
|
|
{
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandle<ReduceKeySeriesStates> stencil;
|
|
|
|
vtkm::cont::ArrayHandle<U, VOut> reducedValues;
|
2015-05-04 19:53:35 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto scanInput = vtkm::cont::make_ArrayHandleZip(values, keystate);
|
|
|
|
auto scanOutput = vtkm::cont::make_ArrayHandleZip(reducedValues, stencil);
|
2017-05-18 14:29:41 +00:00
|
|
|
|
2017-05-26 17:53:28 +00:00
|
|
|
DerivedAlgorithm::ScanInclusive(
|
|
|
|
scanInput, scanOutput, ReduceByKeyAdd<BinaryFunctor>(binary_functor));
|
2017-05-18 14:29:41 +00:00
|
|
|
|
|
|
|
//at this point we are done with keystate, so free the memory
|
|
|
|
keystate.ReleaseResources();
|
|
|
|
|
|
|
|
// all we need know is an efficient way of doing the write back to the
|
|
|
|
// reduced global memory. this is done by using CopyIf with the
|
|
|
|
// stencil and values we just created with the inclusive scan
|
|
|
|
DerivedAlgorithm::CopyIf(reducedValues, stencil, values_output, ReduceByKeyUnaryStencilOp());
|
|
|
|
|
|
|
|
} //release all temporary memory
|
2015-05-04 19:53:35 +00:00
|
|
|
|
2017-08-24 14:22:35 +00:00
|
|
|
// Don't bother with the keys_output if it's an ArrayHandleDiscard -- there
|
|
|
|
// will be a runtime exception in Unique() otherwise:
|
|
|
|
if (!vtkm::cont::IsArrayHandleDiscard<KeysOutputType>::Value)
|
|
|
|
{
|
|
|
|
//find all the unique keys
|
|
|
|
DerivedAlgorithm::Copy(keys, keys_output);
|
|
|
|
DerivedAlgorithm::Unique(keys_output);
|
|
|
|
}
|
2015-05-04 19:53:35 +00:00
|
|
|
}
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Scan Exclusive
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class COut, class BinaryFunctor>
|
|
|
|
VTKM_CONT static T ScanExclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output,
|
2017-05-26 17:53:28 +00:00
|
|
|
BinaryFunctor binaryFunctor,
|
|
|
|
const T& initialValue)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2015-08-27 17:50:32 +00:00
|
|
|
vtkm::Id numValues = input.GetNumberOfValues();
|
|
|
|
if (numValues <= 0)
|
2014-02-11 21:20:30 +00:00
|
|
|
{
|
2015-08-27 17:50:32 +00:00
|
|
|
return initialValue;
|
2014-02-11 21:20:30 +00:00
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> inclusiveScan;
|
2015-08-27 17:50:32 +00:00
|
|
|
T result = DerivedAlgorithm::ScanInclusive(input, inclusiveScan, binaryFunctor);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = inclusiveScan.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto outputPortal = output.PrepareForOutput(numValues, DeviceAdapterTag());
|
|
|
|
|
|
|
|
InclusiveToExclusiveKernel<decltype(inputPortal), decltype(outputPortal), BinaryFunctor>
|
|
|
|
inclusiveToExclusive(inputPortal, outputPortal, binaryFunctor, initialValue);
|
2015-08-27 17:50:32 +00:00
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(inclusiveToExclusive, numValues);
|
|
|
|
|
|
|
|
return binaryFunctor(initialValue, result);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class COut>
|
|
|
|
VTKM_CONT static T ScanExclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output)
|
2015-08-27 17:50:32 +00:00
|
|
|
{
|
2017-05-26 17:53:28 +00:00
|
|
|
return DerivedAlgorithm::ScanExclusive(
|
|
|
|
input, output, vtkm::Sum(), vtkm::TypeTraits<T>::ZeroInitialization());
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
2016-10-23 13:24:28 +00:00
|
|
|
|
2017-04-13 17:50:56 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Scan Exclusive By Key
|
2017-10-24 22:12:30 +00:00
|
|
|
template <typename KeyT,
|
|
|
|
typename ValueT,
|
|
|
|
typename KIn,
|
|
|
|
typename VIn,
|
|
|
|
typename VOut,
|
|
|
|
class BinaryFunctor>
|
|
|
|
VTKM_CONT static void ScanExclusiveByKey(const vtkm::cont::ArrayHandle<KeyT, KIn>& keys,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueT, VIn>& values,
|
|
|
|
vtkm::cont::ArrayHandle<ValueT, VOut>& output,
|
|
|
|
const ValueT& initialValue,
|
2017-05-26 17:53:28 +00:00
|
|
|
BinaryFunctor binaryFunctor)
|
2017-04-13 17:50:56 +00:00
|
|
|
{
|
2017-04-18 19:26:15 +00:00
|
|
|
VTKM_ASSERT(keys.GetNumberOfValues() == values.GetNumberOfValues());
|
|
|
|
|
|
|
|
// 0. Special case for 0 and 1 element input
|
2017-04-17 21:03:49 +00:00
|
|
|
vtkm::Id numberOfKeys = keys.GetNumberOfValues();
|
|
|
|
|
2017-04-18 19:26:15 +00:00
|
|
|
if (numberOfKeys == 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (numberOfKeys == 1)
|
|
|
|
{
|
|
|
|
output.PrepareForOutput(1, DeviceAdapterTag());
|
|
|
|
output.GetPortalControl().Set(0, initialValue);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-04-17 21:03:49 +00:00
|
|
|
// 1. Create head flags
|
|
|
|
//we need to determine based on the keys what is the keystate for
|
|
|
|
//each key. The states are start, middle, end of a series and the special
|
|
|
|
//state start and end of a series
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<ReduceKeySeriesStates> keystate;
|
2017-04-17 21:03:49 +00:00
|
|
|
|
|
|
|
{
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = keys.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto keyStatePortal = keystate.PrepareForOutput(numberOfKeys, DeviceAdapterTag());
|
|
|
|
ReduceStencilGeneration<decltype(inputPortal), decltype(keyStatePortal)> kernel(
|
|
|
|
inputPortal, keyStatePortal);
|
2017-04-17 21:03:49 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numberOfKeys);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 2. Shift input and initialize elements at head flags position to initValue
|
2017-10-24 22:12:30 +00:00
|
|
|
vtkm::cont::ArrayHandle<ValueT, vtkm::cont::StorageTagBasic> temp;
|
2017-04-17 21:03:49 +00:00
|
|
|
{
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = values.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto keyStatePortal = keystate.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto tempPortal = temp.PrepareForOutput(numberOfKeys, DeviceAdapterTag());
|
2017-04-17 21:03:49 +00:00
|
|
|
|
2017-10-24 22:12:30 +00:00
|
|
|
ShiftCopyAndInit<ValueT,
|
|
|
|
decltype(inputPortal),
|
|
|
|
decltype(keyStatePortal),
|
|
|
|
decltype(tempPortal)>
|
2017-08-10 20:13:55 +00:00
|
|
|
kernel(inputPortal, keyStatePortal, tempPortal, initialValue);
|
2017-04-17 21:03:49 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numberOfKeys);
|
|
|
|
}
|
2017-04-17 22:11:02 +00:00
|
|
|
// 3. Perform a ScanInclusiveByKey
|
2017-04-17 21:03:49 +00:00
|
|
|
DerivedAlgorithm::ScanInclusiveByKey(keys, temp, output, binaryFunctor);
|
2017-04-13 17:50:56 +00:00
|
|
|
}
|
|
|
|
|
2017-10-24 22:12:30 +00:00
|
|
|
template <typename KeyT, typename ValueT, class KIn, typename VIn, typename VOut>
|
|
|
|
VTKM_CONT static void ScanExclusiveByKey(const vtkm::cont::ArrayHandle<KeyT, KIn>& keys,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueT, VIn>& values,
|
|
|
|
vtkm::cont::ArrayHandle<ValueT, VOut>& output)
|
2017-04-13 17:50:56 +00:00
|
|
|
{
|
2017-05-26 17:53:28 +00:00
|
|
|
DerivedAlgorithm::ScanExclusiveByKey(
|
2017-10-24 22:12:30 +00:00
|
|
|
keys, values, output, vtkm::TypeTraits<ValueT>::ZeroInitialization(), vtkm::Sum());
|
2017-04-13 17:50:56 +00:00
|
|
|
}
|
|
|
|
|
2016-09-29 00:29:04 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Streaming exclusive scan
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class COut>
|
|
|
|
VTKM_CONT static T StreamingScanExclusive(const vtkm::Id numBlocks,
|
|
|
|
const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output)
|
2016-09-29 00:29:04 +00:00
|
|
|
{
|
2017-05-26 17:53:28 +00:00
|
|
|
return DerivedAlgorithm::StreamingScanExclusive(
|
|
|
|
numBlocks, input, output, vtkm::Sum(), vtkm::TypeTraits<T>::ZeroInitialization());
|
2016-09-29 00:29:04 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class COut, class BinaryFunctor>
|
|
|
|
VTKM_CONT static T StreamingScanExclusive(const vtkm::Id numBlocks,
|
|
|
|
const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output,
|
2017-05-26 17:53:28 +00:00
|
|
|
BinaryFunctor binary_functor,
|
|
|
|
const T& initialValue)
|
2016-09-29 00:29:04 +00:00
|
|
|
{
|
|
|
|
vtkm::Id fullSize = input.GetNumberOfValues();
|
|
|
|
vtkm::Id blockSize = fullSize / numBlocks;
|
2017-05-18 14:29:41 +00:00
|
|
|
if (fullSize % numBlocks != 0)
|
|
|
|
blockSize += 1;
|
2016-09-29 00:29:04 +00:00
|
|
|
|
2017-09-21 14:33:17 +00:00
|
|
|
T lastResult = vtkm::TypeTraits<T>::ZeroInitialization();
|
2017-05-18 14:29:41 +00:00
|
|
|
for (vtkm::Id block = 0; block < numBlocks; block++)
|
2016-09-29 00:29:04 +00:00
|
|
|
{
|
|
|
|
vtkm::Id numberOfInstances = blockSize;
|
2017-05-18 14:29:41 +00:00
|
|
|
if (block == numBlocks - 1)
|
|
|
|
numberOfInstances = fullSize - blockSize * block;
|
2016-09-29 00:29:04 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandleStreaming<vtkm::cont::ArrayHandle<T, CIn>> streamIn(
|
|
|
|
input, block, blockSize, numberOfInstances);
|
2016-09-29 00:29:04 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandleStreaming<vtkm::cont::ArrayHandle<T, COut>> streamOut(
|
|
|
|
output, block, blockSize, numberOfInstances);
|
2016-09-29 00:29:04 +00:00
|
|
|
|
|
|
|
if (block == 0)
|
|
|
|
{
|
|
|
|
streamOut.AllocateFullArray(fullSize);
|
2017-05-18 14:29:41 +00:00
|
|
|
lastResult =
|
|
|
|
DerivedAlgorithm::ScanExclusive(streamIn, streamOut, binary_functor, initialValue);
|
2016-09-29 00:29:04 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
lastResult =
|
|
|
|
DerivedAlgorithm::ScanExclusive(streamIn, streamOut, binary_functor, lastResult);
|
2016-09-29 00:29:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
streamOut.SyncControlArray();
|
|
|
|
}
|
|
|
|
return lastResult;
|
|
|
|
}
|
2016-10-23 13:24:28 +00:00
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Scan Inclusive
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class COut>
|
|
|
|
VTKM_CONT static T ScanInclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output)
|
2015-04-29 19:48:25 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
return DerivedAlgorithm::ScanInclusive(input, output, vtkm::Add());
|
2015-04-29 19:48:25 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class COut, class BinaryFunctor>
|
|
|
|
VTKM_CONT static T ScanInclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<T, COut>& output,
|
|
|
|
BinaryFunctor binary_functor)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
|
|
|
DerivedAlgorithm::Copy(input, output);
|
|
|
|
|
|
|
|
vtkm::Id numValues = output.GetNumberOfValues();
|
|
|
|
if (numValues < 1)
|
2017-03-09 00:05:28 +00:00
|
|
|
{
|
|
|
|
return vtkm::TypeTraits<T>::ZeroInitialization();
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto portal = output.PrepareForInPlace(DeviceAdapterTag());
|
|
|
|
using ScanKernelType = ScanKernel<decltype(portal), BinaryFunctor>;
|
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
vtkm::Id stride;
|
2017-05-18 14:29:41 +00:00
|
|
|
for (stride = 2; stride - 1 < numValues; stride *= 2)
|
2014-02-11 21:20:30 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
ScanKernelType kernel(portal, binary_functor, stride, stride / 2 - 1);
|
|
|
|
DerivedAlgorithm::Schedule(kernel, numValues / stride);
|
2014-02-11 21:20:30 +00:00
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
// Do reverse operation on odd indices. Start at stride we were just at.
|
|
|
|
for (stride /= 2; stride > 1; stride /= 2)
|
2014-02-11 21:20:30 +00:00
|
|
|
{
|
2015-06-23 12:25:06 +00:00
|
|
|
ScanKernelType kernel(portal, binary_functor, stride, stride - 1);
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numValues / stride);
|
2014-02-11 21:20:30 +00:00
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
return GetExecutionValue(output, numValues - 1);
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
2016-10-23 13:24:28 +00:00
|
|
|
|
2017-10-24 22:12:30 +00:00
|
|
|
template <typename KeyT, typename ValueT, class KIn, class VIn, class VOut>
|
|
|
|
VTKM_CONT static void ScanInclusiveByKey(const vtkm::cont::ArrayHandle<KeyT, KIn>& keys,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueT, VIn>& values,
|
|
|
|
vtkm::cont::ArrayHandle<ValueT, VOut>& values_output)
|
2017-03-29 15:29:11 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
return DerivedAlgorithm::ScanInclusiveByKey(keys, values, values_output, vtkm::Add());
|
2017-03-29 15:29:11 +00:00
|
|
|
}
|
|
|
|
|
2017-10-24 22:12:30 +00:00
|
|
|
template <typename KeyT, typename ValueT, class KIn, class VIn, class VOut, class BinaryFunctor>
|
|
|
|
VTKM_CONT static void ScanInclusiveByKey(const vtkm::cont::ArrayHandle<KeyT, KIn>& keys,
|
|
|
|
const vtkm::cont::ArrayHandle<ValueT, VIn>& values,
|
|
|
|
vtkm::cont::ArrayHandle<ValueT, VOut>& values_output,
|
2017-05-18 14:29:41 +00:00
|
|
|
BinaryFunctor binary_functor)
|
2017-03-29 15:29:11 +00:00
|
|
|
{
|
|
|
|
VTKM_ASSERT(keys.GetNumberOfValues() == values.GetNumberOfValues());
|
|
|
|
const vtkm::Id numberOfKeys = keys.GetNumberOfValues();
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
if (numberOfKeys <= 1)
|
2017-03-29 15:29:11 +00:00
|
|
|
{ //we only have a single key/value so that is our output
|
|
|
|
DerivedAlgorithm::Copy(values, values_output);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
//we need to determine based on the keys what is the keystate for
|
|
|
|
//each key. The states are start, middle, end of a series and the special
|
|
|
|
//state start and end of a series
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<ReduceKeySeriesStates> keystate;
|
2017-03-29 15:29:11 +00:00
|
|
|
|
|
|
|
{
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = keys.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto keyStatePortal = keystate.PrepareForOutput(numberOfKeys, DeviceAdapterTag());
|
|
|
|
ReduceStencilGeneration<decltype(inputPortal), decltype(keyStatePortal)> kernel(
|
|
|
|
inputPortal, keyStatePortal);
|
2017-03-29 15:29:11 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, numberOfKeys);
|
|
|
|
}
|
|
|
|
|
|
|
|
//next step is we need to reduce the values for each key. This is done
|
|
|
|
//by running an inclusive scan over the values array using the stencil.
|
|
|
|
//
|
|
|
|
// this inclusive scan will write out two values, the first being
|
|
|
|
// the value summed currently, the second being 0 or 1, with 1 being used
|
|
|
|
// when this is a value of a key we need to write ( END or START_AND_END)
|
|
|
|
{
|
2017-10-24 22:12:30 +00:00
|
|
|
vtkm::cont::ArrayHandle<ValueT, VOut> reducedValues;
|
2017-08-10 20:13:55 +00:00
|
|
|
vtkm::cont::ArrayHandle<ReduceKeySeriesStates> stencil;
|
|
|
|
auto scanInput = vtkm::cont::make_ArrayHandleZip(values, keystate);
|
|
|
|
auto scanOutput = vtkm::cont::make_ArrayHandleZip(reducedValues, stencil);
|
2017-03-29 15:29:11 +00:00
|
|
|
|
2017-05-26 17:53:28 +00:00
|
|
|
DerivedAlgorithm::ScanInclusive(
|
|
|
|
scanInput, scanOutput, ReduceByKeyAdd<BinaryFunctor>(binary_functor));
|
2017-03-29 15:29:11 +00:00
|
|
|
//at this point we are done with keystate, so free the memory
|
|
|
|
keystate.ReleaseResources();
|
|
|
|
DerivedAlgorithm::Copy(reducedValues, values_output);
|
|
|
|
}
|
|
|
|
}
|
2017-04-13 17:50:56 +00:00
|
|
|
|
2016-09-15 23:46:09 +00:00
|
|
|
//--------------------------------------------------------------------------
|
2014-02-11 17:34:56 +00:00
|
|
|
// Sort
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class Storage, class BinaryCompare>
|
|
|
|
VTKM_CONT static void Sort(vtkm::cont::ArrayHandle<T, Storage>& values,
|
|
|
|
BinaryCompare binary_compare)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
|
|
|
vtkm::Id numValues = values.GetNumberOfValues();
|
2017-05-18 14:29:41 +00:00
|
|
|
if (numValues < 2)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
vtkm::Id numThreads = 1;
|
2017-05-18 14:29:41 +00:00
|
|
|
while (numThreads < numValues)
|
|
|
|
{
|
|
|
|
numThreads *= 2;
|
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
numThreads /= 2;
|
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto portal = values.PrepareForInPlace(DeviceAdapterTag());
|
|
|
|
using MergeKernel = BitonicSortMergeKernel<decltype(portal), BinaryCompare>;
|
|
|
|
using CrossoverKernel = BitonicSortCrossoverKernel<decltype(portal), BinaryCompare>;
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
for (vtkm::Id crossoverSize = 1; crossoverSize < numValues; crossoverSize *= 2)
|
2014-02-11 21:20:30 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Schedule(CrossoverKernel(portal, binary_compare, crossoverSize),
|
2014-02-11 17:34:56 +00:00
|
|
|
numThreads);
|
2017-05-18 14:29:41 +00:00
|
|
|
for (vtkm::Id mergeSize = crossoverSize / 2; mergeSize > 0; mergeSize /= 2)
|
2014-02-11 21:20:30 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Schedule(MergeKernel(portal, binary_compare, mergeSize), numThreads);
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
2014-02-11 21:20:30 +00:00
|
|
|
}
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class Storage>
|
|
|
|
VTKM_CONT static void Sort(vtkm::cont::ArrayHandle<T, Storage>& values)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
|
|
|
DerivedAlgorithm::Sort(values, DefaultCompareFunctor());
|
2015-04-23 17:25:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Sort by Key
|
|
|
|
public:
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class StorageT, class StorageU>
|
|
|
|
VTKM_CONT static void SortByKey(vtkm::cont::ArrayHandle<T, StorageT>& keys,
|
|
|
|
vtkm::cont::ArrayHandle<U, StorageU>& values)
|
2015-04-23 17:25:37 +00:00
|
|
|
{
|
|
|
|
//combine the keys and values into a ZipArrayHandle
|
|
|
|
//we than need to specify a custom compare function wrapper
|
|
|
|
//that only checks for key side of the pair, using a custom compare functor.
|
2017-08-10 20:13:55 +00:00
|
|
|
auto zipHandle = vtkm::cont::make_ArrayHandleZip(keys, values);
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Sort(zipHandle, internal::KeyCompare<T, U>());
|
2015-04-23 17:25:37 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename U, class StorageT, class StorageU, class BinaryCompare>
|
|
|
|
VTKM_CONT static void SortByKey(vtkm::cont::ArrayHandle<T, StorageT>& keys,
|
|
|
|
vtkm::cont::ArrayHandle<U, StorageU>& values,
|
|
|
|
BinaryCompare binary_compare)
|
2015-04-23 17:25:37 +00:00
|
|
|
{
|
|
|
|
//combine the keys and values into a ZipArrayHandle
|
|
|
|
//we than need to specify a custom compare function wrapper
|
|
|
|
//that only checks for key side of the pair, using the custom compare
|
|
|
|
//functor that the user passed in
|
2017-08-10 20:13:55 +00:00
|
|
|
auto zipHandle = vtkm::cont::make_ArrayHandleZip(keys, values);
|
2017-05-18 14:29:41 +00:00
|
|
|
DerivedAlgorithm::Sort(zipHandle, internal::KeyCompare<T, U, BinaryCompare>(binary_compare));
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
2018-01-16 21:43:31 +00:00
|
|
|
template <typename T,
|
|
|
|
typename U,
|
|
|
|
typename V,
|
|
|
|
typename StorageT,
|
|
|
|
typename StorageU,
|
|
|
|
typename StorageV,
|
|
|
|
typename BinaryFunctor>
|
|
|
|
VTKM_CONT static void Transform(const vtkm::cont::ArrayHandle<T, StorageT>& input1,
|
|
|
|
const vtkm::cont::ArrayHandle<U, StorageU>& input2,
|
|
|
|
vtkm::cont::ArrayHandle<V, StorageV>& output,
|
2017-12-22 17:31:02 +00:00
|
|
|
BinaryFunctor binaryFunctor)
|
|
|
|
{
|
|
|
|
vtkm::Id numValues = vtkm::Min(input1.GetNumberOfValues(), input2.GetNumberOfValues());
|
|
|
|
if (numValues <= 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto input1Portal = input1.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto input2Portal = input2.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto outputPortal = output.PrepareForOutput(numValues, DeviceAdapterTag());
|
|
|
|
|
2018-01-16 21:43:31 +00:00
|
|
|
BinaryTransformKernel<decltype(input1Portal),
|
|
|
|
decltype(input2Portal),
|
|
|
|
decltype(outputPortal),
|
|
|
|
BinaryFunctor>
|
2017-12-22 17:31:02 +00:00
|
|
|
binaryKernel(input1Portal, input2Portal, outputPortal, binaryFunctor);
|
|
|
|
DerivedAlgorithm::Schedule(binaryKernel, numValues);
|
|
|
|
}
|
|
|
|
|
|
|
|
//};
|
2014-02-11 17:34:56 +00:00
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Unique
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class Storage>
|
|
|
|
VTKM_CONT static void Unique(vtkm::cont::ArrayHandle<T, Storage>& values)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2017-10-24 22:53:09 +00:00
|
|
|
DerivedAlgorithm::Unique(values, vtkm::Equal());
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class Storage, class BinaryCompare>
|
|
|
|
VTKM_CONT static void Unique(vtkm::cont::ArrayHandle<T, Storage>& values,
|
|
|
|
BinaryCompare binary_compare)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, vtkm::cont::StorageTagBasic> stencilArray;
|
2014-02-11 17:34:56 +00:00
|
|
|
vtkm::Id inputSize = values.GetNumberOfValues();
|
|
|
|
|
2017-08-10 19:26:05 +00:00
|
|
|
using WrappedBOpType = internal::WrappedBinaryOperator<bool, BinaryCompare>;
|
2016-03-18 20:39:21 +00:00
|
|
|
WrappedBOpType wrappedCompare(binary_compare);
|
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto valuesPortal = values.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto stencilPortal = stencilArray.PrepareForOutput(inputSize, DeviceAdapterTag());
|
|
|
|
ClassifyUniqueComparisonKernel<decltype(valuesPortal), decltype(stencilPortal), WrappedBOpType>
|
|
|
|
classifyKernel(valuesPortal, stencilPortal, wrappedCompare);
|
2016-03-18 20:39:21 +00:00
|
|
|
|
2014-02-11 17:34:56 +00:00
|
|
|
DerivedAlgorithm::Schedule(classifyKernel, inputSize);
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> outputArray;
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-03-03 22:17:43 +00:00
|
|
|
DerivedAlgorithm::CopyIf(values, stencilArray, outputArray);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2016-08-12 16:39:42 +00:00
|
|
|
values.Allocate(outputArray.GetNumberOfValues());
|
2014-02-11 17:34:56 +00:00
|
|
|
DerivedAlgorithm::Copy(outputArray, values);
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Upper bounds
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class CVal, class COut>
|
|
|
|
VTKM_CONT static void UpperBounds(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<T, CVal>& values,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& output)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
|
|
|
vtkm::Id arraySize = values.GetNumberOfValues();
|
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto valuesPortal = values.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto outputPortal = output.PrepareForOutput(arraySize, DeviceAdapterTag());
|
2014-02-11 17:34:56 +00:00
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
UpperBoundsKernel<decltype(inputPortal), decltype(valuesPortal), decltype(outputPortal)> kernel(
|
|
|
|
inputPortal, valuesPortal, outputPortal);
|
2014-02-11 17:34:56 +00:00
|
|
|
DerivedAlgorithm::Schedule(kernel, arraySize);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, class CIn, class CVal, class COut, class BinaryCompare>
|
|
|
|
VTKM_CONT static void UpperBounds(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
|
|
|
const vtkm::cont::ArrayHandle<T, CVal>& values,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& output,
|
|
|
|
BinaryCompare binary_compare)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
|
|
|
vtkm::Id arraySize = values.GetNumberOfValues();
|
|
|
|
|
2017-08-10 20:13:55 +00:00
|
|
|
auto inputPortal = input.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto valuesPortal = values.PrepareForInput(DeviceAdapterTag());
|
|
|
|
auto outputPortal = output.PrepareForOutput(arraySize, DeviceAdapterTag());
|
|
|
|
|
|
|
|
UpperBoundsKernelComparisonKernel<decltype(inputPortal),
|
|
|
|
decltype(valuesPortal),
|
|
|
|
decltype(outputPortal),
|
|
|
|
BinaryCompare>
|
|
|
|
kernel(inputPortal, valuesPortal, outputPortal, binary_compare);
|
2014-02-11 17:34:56 +00:00
|
|
|
|
|
|
|
DerivedAlgorithm::Schedule(kernel, arraySize);
|
|
|
|
}
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
template <class CIn, class COut>
|
|
|
|
VTKM_CONT static void UpperBounds(const vtkm::cont::ArrayHandle<vtkm::Id, CIn>& input,
|
|
|
|
vtkm::cont::ArrayHandle<vtkm::Id, COut>& values_output)
|
2014-02-11 17:34:56 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
DeviceAdapterAlgorithmGeneral<DerivedAlgorithm, DeviceAdapterTag>::UpperBounds(
|
|
|
|
input, values_output, values_output);
|
2014-02-11 17:34:56 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace vtkm::cont::internal
|
|
|
|
|
2017-05-18 14:29:41 +00:00
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace cont
|
|
|
|
{
|
2016-02-10 15:51:31 +00:00
|
|
|
/// \brief Class providing a device-specific atomic interface.
|
|
|
|
///
|
|
|
|
/// The class provide the actual implementation used by vtkm::exec::AtomicArray.
|
|
|
|
/// A serial default implementation is provided. But each device will have a different
|
|
|
|
/// implementation.
|
|
|
|
///
|
|
|
|
/// Serial requires no form of atomicity
|
|
|
|
///
|
2017-05-18 14:29:41 +00:00
|
|
|
template <typename T, typename DeviceTag>
|
2016-02-10 15:51:31 +00:00
|
|
|
class DeviceAdapterAtomicArrayImplementation
|
|
|
|
{
|
|
|
|
public:
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_CONT
|
2016-03-14 13:51:17 +00:00
|
|
|
DeviceAdapterAtomicArrayImplementation(
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> handle)
|
|
|
|
: Iterators(IteratorsType(handle.PrepareForInPlace(DeviceTag())))
|
2016-02-10 15:51:31 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_EXEC
|
2016-02-10 15:51:31 +00:00
|
|
|
T Add(vtkm::Id index, const T& value) const
|
|
|
|
{
|
2016-03-14 13:51:17 +00:00
|
|
|
T* lockedValue;
|
2016-06-13 20:34:27 +00:00
|
|
|
#if defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0
|
2017-08-10 19:26:05 +00:00
|
|
|
using IteratorType = typename vtkm::cont::ArrayPortalToIterators<PortalType>::IteratorType;
|
2016-05-03 22:13:09 +00:00
|
|
|
typename IteratorType::pointer temp =
|
2017-05-18 14:29:41 +00:00
|
|
|
&(*(Iterators.GetBegin() + static_cast<std::ptrdiff_t>(index)));
|
2016-03-14 13:51:17 +00:00
|
|
|
lockedValue = temp;
|
|
|
|
return vtkmAtomicAdd(lockedValue, value);
|
|
|
|
#else
|
2017-05-18 14:29:41 +00:00
|
|
|
lockedValue = (Iterators.GetBegin() + index);
|
2016-03-14 13:51:17 +00:00
|
|
|
return vtkmAtomicAdd(lockedValue, value);
|
|
|
|
#endif
|
2016-02-10 15:51:31 +00:00
|
|
|
}
|
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_EXEC
|
2016-03-08 17:41:02 +00:00
|
|
|
T CompareAndSwap(vtkm::Id index, const T& newValue, const T& oldValue) const
|
|
|
|
{
|
2016-03-14 13:51:17 +00:00
|
|
|
T* lockedValue;
|
2016-06-13 20:34:27 +00:00
|
|
|
#if defined(_ITERATOR_DEBUG_LEVEL) && _ITERATOR_DEBUG_LEVEL > 0
|
2017-08-10 19:26:05 +00:00
|
|
|
using IteratorType = typename vtkm::cont::ArrayPortalToIterators<PortalType>::IteratorType;
|
2016-05-03 22:13:09 +00:00
|
|
|
typename IteratorType::pointer temp =
|
2017-05-18 14:29:41 +00:00
|
|
|
&(*(Iterators.GetBegin() + static_cast<std::ptrdiff_t>(index)));
|
2016-03-14 13:51:17 +00:00
|
|
|
lockedValue = temp;
|
|
|
|
return vtkmCompareAndSwap(lockedValue, newValue, oldValue);
|
|
|
|
#else
|
2017-05-18 14:29:41 +00:00
|
|
|
lockedValue = (Iterators.GetBegin() + index);
|
2016-03-14 13:51:17 +00:00
|
|
|
return vtkmCompareAndSwap(lockedValue, newValue, oldValue);
|
|
|
|
#endif
|
2016-03-08 17:41:02 +00:00
|
|
|
}
|
|
|
|
|
2016-02-10 15:51:31 +00:00
|
|
|
private:
|
2017-08-10 19:26:05 +00:00
|
|
|
using PortalType =
|
|
|
|
typename vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic>::template ExecutionTypes<
|
|
|
|
DeviceTag>::Portal;
|
2017-06-23 18:50:34 +00:00
|
|
|
using IteratorsType = vtkm::cont::ArrayPortalToIterators<PortalType>;
|
2016-03-14 13:51:17 +00:00
|
|
|
IteratorsType Iterators;
|
|
|
|
|
|
|
|
#if defined(VTKM_MSVC) //MSVC atomics
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_EXEC
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::Int32 vtkmAtomicAdd(vtkm::Int32* address, const vtkm::Int32& value) const
|
2016-03-14 13:51:17 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
return InterlockedExchangeAdd(reinterpret_cast<volatile long*>(address), value);
|
2016-03-14 13:51:17 +00:00
|
|
|
}
|
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_EXEC
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::Int64 vtkmAtomicAdd(vtkm::Int64* address, const vtkm::Int64& value) const
|
2016-03-14 13:51:17 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
return InterlockedExchangeAdd64(reinterpret_cast<volatile long long*>(address), value);
|
2016-03-14 13:51:17 +00:00
|
|
|
}
|
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_EXEC
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Int32 vtkmCompareAndSwap(vtkm::Int32* address,
|
|
|
|
const vtkm::Int32& newValue,
|
2017-05-18 14:29:41 +00:00
|
|
|
const vtkm::Int32& oldValue) const
|
2016-03-14 13:51:17 +00:00
|
|
|
{
|
2017-05-26 17:53:28 +00:00
|
|
|
return InterlockedCompareExchange(
|
|
|
|
reinterpret_cast<volatile long*>(address), newValue, oldValue);
|
2016-03-14 13:51:17 +00:00
|
|
|
}
|
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_EXEC
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Int64 vtkmCompareAndSwap(vtkm::Int64* address,
|
|
|
|
const vtkm::Int64& newValue,
|
2017-05-18 14:29:41 +00:00
|
|
|
const vtkm::Int64& oldValue) const
|
2016-03-14 13:51:17 +00:00
|
|
|
{
|
2017-05-26 17:53:28 +00:00
|
|
|
return InterlockedCompareExchange64(
|
|
|
|
reinterpret_cast<volatile long long*>(address), newValue, oldValue);
|
2016-03-14 13:51:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else //gcc built-in atomics
|
2016-03-08 18:39:23 +00:00
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_EXEC
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::Int32 vtkmAtomicAdd(vtkm::Int32* address, const vtkm::Int32& value) const
|
2016-03-08 18:39:23 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
return __sync_fetch_and_add(address, value);
|
2016-03-08 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_EXEC
|
2017-05-18 14:29:41 +00:00
|
|
|
vtkm::Int64 vtkmAtomicAdd(vtkm::Int64* address, const vtkm::Int64& value) const
|
2016-03-08 18:39:23 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
return __sync_fetch_and_add(address, value);
|
2016-03-08 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_EXEC
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Int32 vtkmCompareAndSwap(vtkm::Int32* address,
|
|
|
|
const vtkm::Int32& newValue,
|
2017-05-18 14:29:41 +00:00
|
|
|
const vtkm::Int32& oldValue) const
|
2016-03-08 18:39:23 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
return __sync_val_compare_and_swap(address, oldValue, newValue);
|
2016-03-08 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2016-10-19 22:42:58 +00:00
|
|
|
VTKM_EXEC
|
2017-05-26 17:53:28 +00:00
|
|
|
vtkm::Int64 vtkmCompareAndSwap(vtkm::Int64* address,
|
|
|
|
const vtkm::Int64& newValue,
|
2017-05-18 14:29:41 +00:00
|
|
|
const vtkm::Int64& oldValue) const
|
2016-03-08 18:39:23 +00:00
|
|
|
{
|
2017-05-18 14:29:41 +00:00
|
|
|
return __sync_val_compare_and_swap(address, oldValue, newValue);
|
2016-03-08 18:39:23 +00:00
|
|
|
}
|
|
|
|
|
2016-03-14 13:51:17 +00:00
|
|
|
#endif
|
2016-02-10 15:51:31 +00:00
|
|
|
};
|
2016-09-12 14:30:03 +00:00
|
|
|
|
|
|
|
/// \brief Class providing a device-specific support for selecting the optimal
|
|
|
|
/// Task type for a given worklet.
|
|
|
|
///
|
|
|
|
/// When worklets are launched inside the execution enviornment we need to
|
|
|
|
/// ask the device adapter what is the preferred execution style, be it
|
|
|
|
/// a tiled iteration pattern, or strided. This class
|
|
|
|
///
|
|
|
|
/// By default if not specialized for a device adapter the default
|
|
|
|
/// is to use vtkm::exec::internal::TaskSingular
|
|
|
|
///
|
|
|
|
template <typename DeviceTag>
|
|
|
|
class DeviceTaskTypes
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
template <typename WorkletType, typename InvocationType>
|
|
|
|
static vtkm::exec::internal::TaskSingular<WorkletType, InvocationType> MakeTask(
|
2017-05-26 17:53:28 +00:00
|
|
|
const WorkletType& worklet,
|
|
|
|
const InvocationType& invocation,
|
|
|
|
vtkm::Id,
|
2016-09-12 14:30:03 +00:00
|
|
|
vtkm::Id globalIndexOffset = 0)
|
|
|
|
{
|
|
|
|
using Task = vtkm::exec::internal::TaskSingular<WorkletType, InvocationType>;
|
|
|
|
return Task(worklet, invocation, globalIndexOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename WorkletType, typename InvocationType>
|
|
|
|
static vtkm::exec::internal::TaskSingular<WorkletType, InvocationType> MakeTask(
|
2017-05-26 17:53:28 +00:00
|
|
|
const WorkletType& worklet,
|
|
|
|
const InvocationType& invocation,
|
|
|
|
vtkm::Id3,
|
2016-09-12 14:30:03 +00:00
|
|
|
vtkm::Id globalIndexOffset = 0)
|
|
|
|
{
|
|
|
|
using Task = vtkm::exec::internal::TaskSingular<WorkletType, InvocationType>;
|
|
|
|
return Task(worklet, invocation, globalIndexOffset);
|
|
|
|
}
|
|
|
|
};
|
2016-02-10 16:21:38 +00:00
|
|
|
}
|
|
|
|
} // namespace vtkm::cont
|
|
|
|
|
2014-06-11 16:43:36 +00:00
|
|
|
#endif //vtk_m_cont_internal_DeviceAdapterAlgorithmGeneral_h
|