Make Keys class do in-place sort

Previously, the Keys class constructor took an array of keys, made a
copy of it, and sorted the copy. This was to protect the caller in case
it needed the original keys array again. However, this copy takes a
significant chunk of time and it is probably rare in practice to ever
need the original keys array again. So instead just do an in-place sort.
This commit is contained in:
Kenneth Moreland 2017-01-23 13:44:09 -07:00
parent 059c7f6db0
commit 0703139a3d
3 changed files with 29 additions and 17 deletions

@ -70,10 +70,18 @@ public:
Keys()
{ }
template<typename OriginalKeyStorage, typename Device>
/// \b Construct a Keys class from an array of keys.
///
/// Given an array of keys, construct a \c Keys class that will manage
/// using these keys to perform reduce-by-key operations.
///
/// WARNING: This constructor will sort the keys array! If you need the
/// keys in the original order after calling this constructor, then make
/// a deep copy of the keys first.
///
template<typename KeyStorage, typename Device>
VTKM_CONT
Keys(const vtkm::cont::ArrayHandle<KeyType,OriginalKeyStorage> &keys,
Device)
Keys(vtkm::cont::ArrayHandle<KeyType,KeyStorage> keys, Device)
{
this->BuildArrays(keys, Device());
}
@ -150,28 +158,24 @@ private:
vtkm::cont::ArrayHandle<vtkm::Id> Offsets;
vtkm::cont::ArrayHandle<vtkm::IdComponent> Counts;
template<typename OriginalKeyArrayType, typename Device>
template<typename KeyArrayType, typename Device>
VTKM_CONT
void BuildArrays(const OriginalKeyArrayType &originalKeys, Device)
void BuildArrays(KeyArrayType &keys, Device)
{
using Algorithm = vtkm::cont::DeviceAdapterAlgorithm<Device>;
vtkm::Id numOriginalKeys = originalKeys.GetNumberOfValues();
vtkm::Id numKeys = keys.GetNumberOfValues();
// Copy and sort the keys. (Copy is in place.)
KeyArrayHandleType sortedKeys;
Algorithm::Copy(originalKeys, sortedKeys);
Algorithm::Copy(vtkm::cont::ArrayHandleIndex(numOriginalKeys),
Algorithm::Copy(vtkm::cont::ArrayHandleIndex(numKeys),
this->SortedValuesMap);
// TODO: Do we need the ability to specify a comparison functor for sort?
Algorithm::SortByKey(sortedKeys, this->SortedValuesMap);
Algorithm::SortByKey(keys, this->SortedValuesMap);
// Find the unique keys and the number of values per key.
Algorithm::ReduceByKey(
sortedKeys,
vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>(1, numOriginalKeys),
keys,
vtkm::cont::ArrayHandleConstant<vtkm::IdComponent>(1, numKeys),
this->UniqueKeys,
this->Counts,
vtkm::Sum());
@ -181,7 +185,7 @@ private:
Algorithm::ScanExclusive(
vtkm::cont::make_ArrayHandleCast(this->Counts, vtkm::Id()),
this->Offsets);
VTKM_ASSERT(offsetsTotal == numOriginalKeys); // Sanity check
VTKM_ASSERT(offsetsTotal == numKeys); // Sanity check
(void)offsetsTotal; // Shut up, compiler
}
};

@ -74,7 +74,11 @@ void TryKeyType(KeyType)
vtkm::cont::ArrayHandle<KeyType> keyArray =
vtkm::cont::make_ArrayHandle(keyBuffer, ARRAY_SIZE);
vtkm::worklet::Keys<KeyType> keys(keyArray,
vtkm::cont::ArrayHandle<KeyType> sortedKeys;
vtkm::cont::DeviceAdapterAlgorithm<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>::
Copy(keyArray, sortedKeys);
vtkm::worklet::Keys<KeyType> keys(sortedKeys,
VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
VTKM_TEST_ASSERT(keys.GetInputRange() == NUM_UNIQUE,
"Keys has bad input range.");

@ -136,7 +136,11 @@ void TryKeyType(KeyType)
vtkm::cont::ArrayHandle<KeyType> keyArray =
vtkm::cont::make_ArrayHandle(keyBuffer, ARRAY_SIZE);
vtkm::worklet::Keys<KeyType> keys(keyArray,
vtkm::cont::ArrayHandle<KeyType> sortedKeys;
vtkm::cont::DeviceAdapterAlgorithm<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>::
Copy(keyArray, sortedKeys);
vtkm::worklet::Keys<KeyType> keys(sortedKeys,
VTKM_DEFAULT_DEVICE_ADAPTER_TAG());
vtkm::cont::ArrayHandle<KeyType> valuesToModify;