Commit add10f56 authored by Kenneth Moreland's avatar Kenneth Moreland

Add Value[In][Out] tags for WorkletReduceByKey

This lets you give arrays of values paired with the keys that will be
grouped into (hopefully) small Vecs.
parent 58eb8f16
......@@ -27,6 +27,9 @@ set(headers
TransportTagAtomicArray.h
TransportTagCellSetIn.h
TransportTagExecObject.h
TransportTagKeyedValuesIn.h
TransportTagKeyedValuesInOut.h
TransportTagKeyedValuesOut.h
TransportTagKeysIn.h
TransportTagTopologyFieldIn.h
TransportTagWholeArrayIn.h
......
//============================================================================
// 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.
//
// Copyright 2016 Sandia Corporation.
// Copyright 2016 UT-Battelle, LLC.
// Copyright 2016 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#ifndef vtk_m_cont_arg_TransportTagKeyedValuesIn_h
#define vtk_m_cont_arg_TransportTagKeyedValuesIn_h
#include <vtkm/cont/arg/Transport.h>
namespace vtkm {
namespace cont {
namespace arg {
/// \brief \c Transport tag for input values in a reduce by key.
///
/// \c TransportTagKeyedValuesIn is a tag used with the \c Transport class to
/// transport \c ArrayHandle objects for input values. The values are
/// rearranged and grouped based on the keys they are associated with.
///
struct TransportTagKeyedValuesIn { };
// Specialization of Transport class for TransportTagKeyedValuesIn is
// implemented in vtkm/worklet/Keys.h. That class is not accessible from here
// due to VTK-m package dependencies.
}
}
}
#endif //vtk_m_cont_arg_TransportTagKeyedValuesIn_h
//============================================================================
// 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.
//
// Copyright 2016 Sandia Corporation.
// Copyright 2016 UT-Battelle, LLC.
// Copyright 2016 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#ifndef vtk_m_cont_arg_TransportTagKeyedValuesInOut_h
#define vtk_m_cont_arg_TransportTagKeyedValuesInOut_h
#include <vtkm/cont/arg/Transport.h>
namespace vtkm {
namespace cont {
namespace arg {
/// \brief \c Transport tag for input values in a reduce by key.
///
/// \c TransportTagKeyedValuesInOut is a tag used with the \c Transport class
/// to transport \c ArrayHandle objects for input/output values. The values are
/// rearranged and grouped based on the keys they are associated with.
///
struct TransportTagKeyedValuesInOut { };
// Specialization of Transport class for TransportTagKeyedValuesInOut is
// implemented in vtkm/worklet/Keys.h. That class is not accessible from here
// due to VTK-m package dependencies.
}
}
}
#endif //vtk_m_cont_arg_TransportTagKeyedValuesInOut_h
//============================================================================
// 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.
//
// Copyright 2016 Sandia Corporation.
// Copyright 2016 UT-Battelle, LLC.
// Copyright 2016 Los Alamos National Security.
//
// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
// 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.
//============================================================================
#ifndef vtk_m_cont_arg_TransportTagKeyedValuesOut_h
#define vtk_m_cont_arg_TransportTagKeyedValuesOut_h
#include <vtkm/cont/arg/Transport.h>
namespace vtkm {
namespace cont {
namespace arg {
/// \brief \c Transport tag for input values in a reduce by key.
///
/// \c TransportTagKeyedValuesOut is a tag used with the \c Transport class
/// to transport \c ArrayHandle objects for output values. The values are
/// rearranged and grouped based on the keys they are associated with.
///
struct TransportTagKeyedValuesOut { };
// Specialization of Transport class for TransportTagKeyedValuesOut is
// implemented in vtkm/worklet/Keys.h. That class is not accessible from here
// due to VTK-m package dependencies.
}
}
}
#endif //vtk_m_cont_arg_TransportTagKeyedValuesOut_h
......@@ -23,11 +23,16 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleGroupVecVariable.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/exec/internal/ReduceByKeyLookup.h>
#include <vtkm/cont/arg/TransportTagKeyedValuesIn.h>
#include <vtkm/cont/arg/TransportTagKeyedValuesInOut.h>
#include <vtkm/cont/arg/TransportTagKeyedValuesOut.h>
#include <vtkm/cont/arg/TransportTagKeysIn.h>
#include <vtkm/cont/arg/TypeCheckTagKeys.h>
......@@ -102,6 +107,12 @@ public:
return this->Counts;
}
VTKM_CONT
vtkm::Id GetNumberOfValues() const
{
return this->SortedValuesMap.GetNumberOfValues();
}
template<typename Device>
struct ExecutionTypes
{
......@@ -177,10 +188,10 @@ private:
}
} // namespace vtkm::worklet
// Here we implement the type checks, transports, and fetches the rely on the
// Keys class. We implement them here because the Keys class is not accessible
// to the arg classes. (The worklet package depends on the cont and exec
// packages, not the other way around.)
// Here we implement the type checks and transports that rely on the Keys
// class. We implement them here because the Keys class is not accessible to
// the arg classes. (The worklet package depends on the cont and exec packages,
// not the other way around.)
namespace vtkm {
namespace cont {
......@@ -226,6 +237,117 @@ struct Transport<vtkm::cont::arg::TransportTagKeysIn,
}
};
template<typename ArrayHandleType, typename Device>
struct Transport<
vtkm::cont::arg::TransportTagKeyedValuesIn, ArrayHandleType, Device>
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
using ContObjectType = ArrayHandleType;
using IdArrayType = vtkm::cont::ArrayHandle<vtkm::Id>;
using PermutedArrayType =
vtkm::cont::ArrayHandlePermutation<IdArrayType,ContObjectType>;
using GroupedArrayType =
vtkm::cont::ArrayHandleGroupVecVariable<PermutedArrayType,IdArrayType>;
using ExecObjectType =
typename GroupedArrayType::template ExecutionTypes<Device>::PortalConst;
template<typename KeyType>
VTKM_CONT
ExecObjectType operator()(const ContObjectType &object,
const vtkm::worklet::Keys<KeyType> &keys,
vtkm::Id) const
{
VTKM_ASSERT(object.GetNumberOfValues() == keys.GetNumberOfValues());
PermutedArrayType permutedArray(keys.GetSortedValuesMap(), object);
GroupedArrayType groupedArray(permutedArray, keys.GetOffsets());
// There is a bit of an issue here where groupedArray goes out of scope,
// and array portals usually rely on the associated array handle
// maintaining the resources it points to. However, the entire state of the
// portal should be self contained except for the data managed by the
// object argument, which should stay in scope.
return groupedArray.PrepareForInput(Device());
}
};
template<typename ArrayHandleType, typename Device>
struct Transport<
vtkm::cont::arg::TransportTagKeyedValuesInOut, ArrayHandleType, Device>
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
using ContObjectType = ArrayHandleType;
using IdArrayType = vtkm::cont::ArrayHandle<vtkm::Id>;
using PermutedArrayType =
vtkm::cont::ArrayHandlePermutation<IdArrayType,ContObjectType>;
using GroupedArrayType =
vtkm::cont::ArrayHandleGroupVecVariable<PermutedArrayType,IdArrayType>;
using ExecObjectType =
typename GroupedArrayType::template ExecutionTypes<Device>::Portal;
template<typename KeyType>
VTKM_CONT
ExecObjectType operator()(ContObjectType object,
const vtkm::worklet::Keys<KeyType> &keys,
vtkm::Id) const
{
VTKM_ASSERT(object.GetNumberOfValues() == keys.GetNumberOfValues());
PermutedArrayType permutedArray(keys.GetSortedValuesMap(), object);
GroupedArrayType groupedArray(permutedArray, keys.GetOffsets());
// There is a bit of an issue here where groupedArray goes out of scope,
// and array portals usually rely on the associated array handle
// maintaining the resources it points to. However, the entire state of the
// portal should be self contained except for the data managed by the
// object argument, which should stay in scope.
return groupedArray.PrepareForInPlace(Device());
}
};
template<typename ArrayHandleType, typename Device>
struct Transport<
vtkm::cont::arg::TransportTagKeyedValuesOut, ArrayHandleType, Device>
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
using ContObjectType = ArrayHandleType;
using IdArrayType = vtkm::cont::ArrayHandle<vtkm::Id>;
using PermutedArrayType =
vtkm::cont::ArrayHandlePermutation<IdArrayType,ContObjectType>;
using GroupedArrayType =
vtkm::cont::ArrayHandleGroupVecVariable<PermutedArrayType,IdArrayType>;
using ExecObjectType =
typename GroupedArrayType::template ExecutionTypes<Device>::Portal;
template<typename KeyType>
VTKM_CONT
ExecObjectType operator()(ContObjectType object,
const vtkm::worklet::Keys<KeyType> &keys,
vtkm::Id) const
{
// The PrepareForOutput for ArrayHandleGroupVecVariable and
// ArrayHandlePermutation cannot determine the actual size expected for the
// target array (object), so we have to make sure it gets allocated here.
object.PrepareForOutput(keys.GetNumberOfValues(), Device());
PermutedArrayType permutedArray(keys.GetSortedValuesMap(), object);
GroupedArrayType groupedArray(permutedArray, keys.GetOffsets());
// There is a bit of an issue here where groupedArray goes out of scope,
// and array portals usually rely on the associated array handle
// maintaining the resources it points to. However, the entire state of the
// portal should be self contained except for the data managed by the
// object argument, which should stay in scope.
return groupedArray.PrepareForOutput(keys.GetInputRange(), Device());
}
};
}
}
} // namespace vtkm::cont::arg
......
......@@ -22,11 +22,18 @@
#include <vtkm/worklet/internal/WorkletBase.h>
#include <vtkm/cont/arg/TransportTagKeyedValuesIn.h>
#include <vtkm/cont/arg/TransportTagKeyedValuesInOut.h>
#include <vtkm/cont/arg/TransportTagKeyedValuesOut.h>
#include <vtkm/cont/arg/TransportTagKeysIn.h>
#include <vtkm/cont/arg/TypeCheckTagArray.h>
#include <vtkm/cont/arg/TypeCheckTagKeys.h>
#include <vtkm/exec/internal/ReduceByKeyLookup.h>
#include <vtkm/exec/arg/FetchTagArrayDirectIn.h>
#include <vtkm/exec/arg/FetchTagArrayDirectInOut.h>
#include <vtkm/exec/arg/FetchTagArrayDirectOut.h>
#include <vtkm/exec/arg/FetchTagKeysIn.h>
#include <vtkm/exec/arg/ThreadIndicesReduceByKey.h>
......@@ -38,7 +45,7 @@ class WorkletReduceByKey : public vtkm::worklet::internal::WorkletBase
public:
/// \brief A control signature tag for input keys.
///
/// A \c WorkletReduceByKey operates by collected all identical keys and
/// A \c WorkletReduceByKey operates by collecting all identical keys and
/// then executing the worklet on each unique key. This tag specifies a
/// \c Keys object that defines and manages these keys.
///
......@@ -52,6 +59,51 @@ public:
using FetchTag = vtkm::exec::arg::FetchTagKeysIn;
};
/// \brief A control signature tag for input values.
///
/// A \c WorkletReduceByKey operates by collecting all values associated with
/// identical keys and then giving the worklet a Vec-like object containing
/// all values with a matching key. This tag specifies an \c ArrayHandle
/// object that holds the values.
///
template<typename TypeList = AllTypes>
struct ValuesIn : vtkm::cont::arg::ControlSignatureTagBase
{
using TypeCheckTag = vtkm::cont::arg::TypeCheckTagArray<TypeList>;
using TransportTag = vtkm::cont::arg::TransportTagKeyedValuesIn;
using FetchTag = vtkm::exec::arg::FetchTagArrayDirectIn;
};
/// \brief A control signature tag for input/output values.
///
/// A \c WorkletReduceByKey operates by collecting all values associated with
/// identical keys and then giving the worklet a Vec-like object containing
/// all values with a matching key. This tag specifies an \c ArrayHandle
/// object that holds the values.
///
template<typename TypeList = AllTypes>
struct ValuesInOut : vtkm::cont::arg::ControlSignatureTagBase
{
using TypeCheckTag = vtkm::cont::arg::TypeCheckTagArray<TypeList>;
using TransportTag = vtkm::cont::arg::TransportTagKeyedValuesInOut;
using FetchTag = vtkm::exec::arg::FetchTagArrayDirectIn;
};
/// \brief A control signature tag for output values.
///
/// A \c WorkletReduceByKey operates by collecting all values associated with
/// identical keys and then giving the worklet a Vec-like object containing
/// all values with a matching key. This tag specifies an \c ArrayHandle
/// object that holds the values.
///
template<typename TypeList = AllTypes>
struct ValuesOut : vtkm::cont::arg::ControlSignatureTagBase
{
using TypeCheckTag = vtkm::cont::arg::TypeCheckTagArray<TypeList>;
using TransportTag = vtkm::cont::arg::TransportTagKeyedValuesOut;
using FetchTag = vtkm::exec::arg::FetchTagArrayDirectIn;
};
/// Reduce by key worklets use the related thread indices class.
///
VTKM_SUPPRESS_EXEC_WARNINGS
......
......@@ -29,25 +29,69 @@
namespace {
#define STRINGIFY(x) STRINGIFY_IMPL(x)
#define STRINGIFY_IMPL(x) #x
#define IMPL_TEST_ASSERT_WORKLET(condition, file, line) \
this->RaiseError("Test assert failed: " #condition \
"\n" #file ":" #line) \
#define TEST_ASSERT_WORKLET(condition) \
do { \
if (!(condition)) \
{ \
this->RaiseError("Test assert failed: " #condition \
"\n" __FILE__ ":" STRINGIFY(__LINE__)); \
} \
} while (false)
static const vtkm::Id ARRAY_SIZE = 1033;
static const vtkm::Id NUM_UNIQUE = ARRAY_SIZE/10;
static const vtkm::IdComponent GROUP_SIZE = 10;
static const vtkm::Id NUM_UNIQUE = ARRAY_SIZE/GROUP_SIZE;
struct CheckReduceByKeyWorklet : vtkm::worklet::WorkletReduceByKey
{
typedef void ControlSignature(KeysIn);
typedef void ExecutionSignature(_1, WorkIndex);
typedef void ControlSignature(KeysIn keys,
ValuesIn<> keyMirror,
ValuesIn<> indexValues,
ValuesInOut<> valuesToModify,
ValuesOut<> writeKey);
typedef void ExecutionSignature(_1, _2, _3, _4, _5, WorkIndex);
typedef _1 InputDomain;
template<typename T>
template<typename T,
typename KeyMirrorVecType,
typename IndexValuesVecType,
typename ValuesToModifyVecType,
typename WriteKeysVecType>
VTKM_EXEC
void operator()(const T &key, vtkm::Id workIndex) const
void operator()(const T &key,
const KeyMirrorVecType &keyMirror,
const IndexValuesVecType &valueIndices,
ValuesToModifyVecType &valuesToModify,
WriteKeysVecType &writeKey,
vtkm::Id workIndex) const
{
// These tests only work if keys are in sorted order, which is how we group
// them.
if (key != TestValue(workIndex, T()))
TEST_ASSERT_WORKLET(key == TestValue(workIndex, T()));
vtkm::IdComponent numValues = keyMirror.GetNumberOfComponents();
TEST_ASSERT_WORKLET(numValues >= GROUP_SIZE);
TEST_ASSERT_WORKLET(keyMirror.GetNumberOfComponents() ==
valueIndices.GetNumberOfComponents());
for (vtkm::IdComponent iComponent = 0; iComponent < numValues; iComponent++)
{
this->RaiseError("Unexpected key");
TEST_ASSERT_WORKLET(test_equal(keyMirror[iComponent], key));
TEST_ASSERT_WORKLET(valueIndices[iComponent]%NUM_UNIQUE == workIndex);
T value = valuesToModify[iComponent];
valuesToModify[iComponent] = static_cast<T>(key + value);
writeKey[iComponent] = key;
}
}
};
......@@ -67,8 +111,37 @@ void TryKeyType(KeyType)
vtkm::worklet::Keys<KeyType> keys(keyArray,
VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
vtkm::cont::ArrayHandle<KeyType> valuesToModify;
valuesToModify.Allocate(ARRAY_SIZE);
SetPortal(valuesToModify.GetPortalControl());
vtkm::cont::ArrayHandle<KeyType> writeKey;
vtkm::worklet::DispatcherReduceByKey<CheckReduceByKeyWorklet> dispatcher;
dispatcher.Invoke(keys);
dispatcher.Invoke(keys,
keyArray,
vtkm::cont::ArrayHandleIndex(ARRAY_SIZE),
valuesToModify,
writeKey);
VTKM_TEST_ASSERT(valuesToModify.GetNumberOfValues() == ARRAY_SIZE,
"Bad array size.");
VTKM_TEST_ASSERT(writeKey.GetNumberOfValues() == ARRAY_SIZE,
"Bad array size.");
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
KeyType key = TestValue(index%NUM_UNIQUE, KeyType());
KeyType value = TestValue(index, KeyType());
VTKM_TEST_ASSERT(
test_equal(static_cast<KeyType>(key+value),
valuesToModify.GetPortalConstControl().Get(index)),
"Bad in/out value.");
VTKM_TEST_ASSERT(
test_equal(key, writeKey.GetPortalConstControl().Get(index)),
"Bad out value.");
}
}
void TestReduceByKey()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment