vtk-m/vtkm/cont/testing/TestingDeviceAdapter.h
Kenneth Moreland 8b33f2bc79 Fix device adapter algorithms for small arrays
There were some issues for device adapter algorithms (like scan and
reduce) for empty arrays or arrays of size 1. This adds tests for these
short arrays to the device adapter algorithm tests and fixes these
problems.
2017-03-08 19:05:28 -05:00

1954 lines
70 KiB
C++

//============================================================================
// 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 2014 Sandia Corporation.
// Copyright 2014 UT-Battelle, LLC.
// Copyright 2014 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_testing_TestingDeviceAdapter_h
#define vtk_m_cont_testing_TestingDeviceAdapter_h
#include <vtkm/TypeTraits.h>
#include <vtkm/BinaryPredicates.h>
#include <vtkm/BinaryOperators.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleConstant.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ArrayHandlePermutation.h>
#include <vtkm/cont/ArrayHandleZip.h>
#include <vtkm/cont/ArrayPortalToIterators.h>
#include <vtkm/cont/ErrorBadAllocation.h>
#include <vtkm/cont/ErrorExecution.h>
#include <vtkm/cont/RuntimeDeviceInformation.h>
#include <vtkm/cont/StorageBasic.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/internal/DeviceAdapterError.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/exec/AtomicArray.h>
#include <algorithm>
#include <cmath>
#include <utility>
#include <vector>
#include <vtkm/internal/Windows.h>
namespace vtkm {
namespace cont {
namespace testing {
#define ERROR_MESSAGE "Got an error."
#define ARRAY_SIZE 100000
#define OFFSET 1000
#define DIM_SIZE 128
/// This class has a single static member, Run, that tests the templated
/// DeviceAdapter for conformance.
///
template<class DeviceAdapterTag>
struct TestingDeviceAdapter
{
private:
typedef vtkm::cont::StorageTagBasic StorageTag;
typedef vtkm::cont::ArrayHandle<vtkm::Id, StorageTag>
IdArrayHandle;
typedef vtkm::cont::ArrayHandle<vtkm::FloatDefault,StorageTag>
ScalarArrayHandle;
typedef vtkm::cont::internal::ArrayManagerExecution<
vtkm::Id, StorageTag, DeviceAdapterTag>
IdArrayManagerExecution;
typedef vtkm::cont::internal::Storage<vtkm::Id, StorageTag> IdStorage;
typedef typename IdArrayHandle::template ExecutionTypes<DeviceAdapterTag>
::Portal IdPortalType;
typedef typename IdArrayHandle::template ExecutionTypes<DeviceAdapterTag>
::PortalConst IdPortalConstType;
typedef vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapterTag>
Algorithm;
public:
// Cuda kernels have to be public (in Cuda 4.0).
struct CopyArrayKernel
{
VTKM_CONT
CopyArrayKernel(const IdPortalConstType &input,
const IdPortalType &output)
: InputArray(input), OutputArray(output) { }
VTKM_EXEC void operator()(
vtkm::Id index,
const vtkm::exec::internal::ErrorMessageBuffer &) const
{
this->OutputArray.Set(index, this->InputArray.Get(index));
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
IdPortalConstType InputArray;
IdPortalType OutputArray;
};
struct ClearArrayKernel
{
VTKM_CONT
ClearArrayKernel(const IdPortalType &array) : Array(array), Dims() { }
VTKM_CONT
ClearArrayKernel(const IdPortalType &array,
const vtkm::Id3& dims) : Array(array), Dims(dims) { }
VTKM_EXEC void operator()(vtkm::Id index) const
{
this->Array.Set(index, OFFSET);
}
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 &) { }
IdPortalType Array;
vtkm::Id3 Dims;
};
struct ClearArrayMapKernel //: public vtkm::exec::WorkletMapField
{
// typedef void ControlSignature(Field(Out));
// typedef void ExecutionSignature(_1);
template<typename T>
VTKM_EXEC void operator()(T& value) const
{
value = OFFSET;
}
};
struct AddArrayKernel
{
VTKM_CONT
AddArrayKernel(const IdPortalType &array) : Array(array), Dims() { }
VTKM_CONT
AddArrayKernel(const IdPortalType &array,
const vtkm::Id3& dims) : Array(array), Dims(dims) { }
VTKM_EXEC void operator()(vtkm::Id index) const
{
this->Array.Set(index, this->Array.Get(index) + index);
}
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 &) { }
IdPortalType Array;
vtkm::Id3 Dims;
};
struct OneErrorKernel
{
VTKM_EXEC void operator()(vtkm::Id index) const
{
if (index == ARRAY_SIZE/2)
{
this->ErrorMessage.RaiseError(ERROR_MESSAGE);
}
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &errorMessage)
{
this->ErrorMessage = errorMessage;
}
vtkm::exec::internal::ErrorMessageBuffer ErrorMessage;
};
struct AllErrorKernel
{
VTKM_EXEC void operator()(vtkm::Id vtkmNotUsed(index)) const
{
this->ErrorMessage.RaiseError(ERROR_MESSAGE);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &errorMessage)
{
this->ErrorMessage = errorMessage;
}
vtkm::exec::internal::ErrorMessageBuffer ErrorMessage;
};
struct OffsetPlusIndexKernel
{
VTKM_CONT
OffsetPlusIndexKernel(const IdPortalType &array) : Array(array) { }
VTKM_EXEC void operator()(vtkm::Id index) const
{
this->Array.Set(index, OFFSET + index);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
IdPortalType Array;
};
struct MarkOddNumbersKernel
{
VTKM_CONT
MarkOddNumbersKernel(const IdPortalType &array) : Array(array) { }
VTKM_EXEC void operator()(vtkm::Id index) const
{
this->Array.Set(index, index%2);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
IdPortalType Array;
};
struct FuseAll
{
template<typename T>
VTKM_EXEC bool operator()(const T&, const T&) const
{
//binary predicates for unique return true if they are the same
return true;
}
};
template<typename T>
struct AtomicKernel
{
VTKM_CONT
AtomicKernel(const vtkm::exec::AtomicArray<T,DeviceAdapterTag> &array)
: AArray(array)
{ }
VTKM_EXEC void operator()(vtkm::Id index) const
{
T value = (T) index;
this->AArray.Add(0, value);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
vtkm::exec::AtomicArray<T,DeviceAdapterTag> AArray;
};
template<typename T>
struct AtomicCASKernel
{
VTKM_CONT
AtomicCASKernel(const vtkm::exec::AtomicArray<T,DeviceAdapterTag> &array)
: AArray(array)
{ }
VTKM_EXEC void operator()(vtkm::Id index) const
{
T value = (T) index;
//Get the old value from the array with a no-op
T oldValue = this->AArray.Add(0,T(0));
//This creates an atomic add using the CAS operatoin
T assumed = T(0);
do
{
assumed = oldValue;
oldValue = this->AArray.CompareAndSwap(0, (assumed + value) , assumed);
} while (assumed != oldValue);
}
VTKM_CONT void SetErrorMessageBuffer(
const vtkm::exec::internal::ErrorMessageBuffer &) { }
vtkm::exec::AtomicArray<T,DeviceAdapterTag> AArray;
};
private:
static VTKM_CONT void TestDeviceAdapterTag()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing device adapter tag" << std::endl;
typedef vtkm::cont::DeviceAdapterTraits<DeviceAdapterTag> Traits;
typedef vtkm::cont::DeviceAdapterTraits<
vtkm::cont::DeviceAdapterTagError> ErrorTraits;
VTKM_TEST_ASSERT(Traits::GetId() == Traits::GetId(),
"Device adapter Id does not equal itself.");
VTKM_TEST_ASSERT(Traits::GetId() != ErrorTraits::GetId(),
"Device adapter Id not distinguishable from others.");
VTKM_TEST_ASSERT(Traits::GetName() == Traits::GetName(),
"Device adapter Name does not equal itself.");
VTKM_TEST_ASSERT(Traits::GetName() != ErrorTraits::GetName(),
"Device adapter Name not distinguishable from others.");
}
// Note: this test does not actually test to make sure the data is available
// in the execution environment. It tests to make sure data gets to the array
// and back, but it is possible that the data is not available in the
// execution environment.
static VTKM_CONT void TestArrayManagerExecution()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing ArrayManagerExecution" << std::endl;
typedef vtkm::cont::internal::ArrayManagerExecution<
vtkm::Id,StorageTagBasic,DeviceAdapterTag>
ArrayManagerExecution;
typedef vtkm::cont::internal::Storage<vtkm::Id,StorageTagBasic> StorageType;
// Create original input array.
StorageType storage;
storage.Allocate(ARRAY_SIZE*2);
StorageType::PortalType portal = storage.GetPortal();
VTKM_TEST_ASSERT(portal.GetNumberOfValues() == ARRAY_SIZE*2,
"Storage portal has unexpected size.");
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
portal.Set(index, TestValue(index, vtkm::Id()));
}
ArrayManagerExecution manager(&storage);
// Do an operation just so we know the values are placed in the execution
// environment and they change. We are only calling on half the array
// because we are about to shrink.
Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(true)),
ARRAY_SIZE);
// Change size.
manager.Shrink(ARRAY_SIZE);
VTKM_TEST_ASSERT(manager.GetNumberOfValues() == ARRAY_SIZE,
"Shrink did not set size of array manager correctly.");
// Get the array back and check its values. We have to get it back into
// the same storage since some ArrayManagerExecution classes will expect
// that.
manager.RetrieveOutputData(&storage);
VTKM_TEST_ASSERT(storage.GetNumberOfValues() == ARRAY_SIZE,
"Storage has wrong number of values after execution "
"array shrink.");
// Check array.
StorageType::PortalConstType checkPortal = storage.GetPortalConst();
VTKM_TEST_ASSERT(checkPortal.GetNumberOfValues() == ARRAY_SIZE,
"Storage portal wrong size.");
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
VTKM_TEST_ASSERT(
checkPortal.Get(index) == TestValue(index, vtkm::Id()) + index,
"Did not get correct values from array.");
}
}
static VTKM_CONT void TestOutOfMemory()
{
// Only test out of memory with 64 bit ids. If there are 32 bit ids on
// a 64 bit OS (common), it is simply too hard to get a reliable allocation
// that is too much memory.
#ifdef VTKM_USE_64BIT_IDS
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Out of Memory" << std::endl;
try
{
std::cout << "Do array allocation that should fail." << std::endl;
vtkm::cont::internal::Storage<
vtkm::Vec<vtkm::Float32, 4>, StorageTagBasic> supportArray;
vtkm::cont::internal::ArrayManagerExecution<
vtkm::Vec<vtkm::Float32, 4>, StorageTagBasic, DeviceAdapterTag>
bigManager(&supportArray);
const vtkm::Id bigSize = 0x7FFFFFFFFFFFFFFFLL;
bigManager.PrepareForOutput(bigSize);
// It does not seem reasonable to get here. The previous call should fail.
VTKM_TEST_FAIL("A ridiculously sized allocation succeeded. Either there "
"was a failure that was not reported but should have been "
"or the width of vtkm::Id is not large enough to express all "
"array sizes.");
}
catch (vtkm::cont::ErrorBadAllocation &error)
{
std::cout << "Got the expected error: " << error.GetMessage() << std::endl;
}
#else
std::cout << "--------- Skipping out of memory test" << std::endl;
#endif
}
VTKM_CONT
static void TestTimer()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Timer" << std::endl;
vtkm::cont::Timer<DeviceAdapterTag> timer;
std::cout << "Timer started. Sleeping..." << std::endl;
#ifndef _WIN32
sleep(1);
#else
Sleep(1000);
#endif
std::cout << "Woke up. Check time." << std::endl;
vtkm::Float64 elapsedTime = timer.GetElapsedTime();
std::cout << "Elapsed time: " << elapsedTime << std::endl;
VTKM_TEST_ASSERT(elapsedTime > 0.999,
"Timer did not capture full second wait.");
VTKM_TEST_ASSERT(elapsedTime < 2.0,
"Timer counted too far or system really busy.");
}
VTKM_CONT
static void TestRuntime()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing RuntimeDeviceInformation" << std::endl;
vtkm::cont::RuntimeDeviceInformation<DeviceAdapterTag> runtime;
const bool valid_runtime = runtime.Exists();
VTKM_TEST_ASSERT(valid_runtime, "runtime detection failed for device");
}
static VTKM_CONT void TestAlgorithmSchedule()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing single value Scheduling with vtkm::Id" << std::endl;
{
std::cout << "Allocating execution array" << std::endl;
IdStorage storage;
IdArrayManagerExecution manager(&storage);
std::cout << "Running clear." << std::endl;
Algorithm::Schedule(ClearArrayKernel(manager.PrepareForOutput(1)), 1);
std::cout << "Running add." << std::endl;
Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false)), 1);
std::cout << "Checking results." << std::endl;
manager.RetrieveOutputData(&storage);
for (vtkm::Id index = 0; index < 1; index++)
{
vtkm::Id value = storage.GetPortalConst().Get(index);
VTKM_TEST_ASSERT(value == index + OFFSET,
"Got bad value for single value scheduled kernel.");
}
} //release memory
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Schedule with vtkm::Id" << std::endl;
{
std::cout << "Allocating execution array" << std::endl;
IdStorage storage;
IdArrayManagerExecution manager(&storage);
std::cout << "Running clear." << std::endl;
Algorithm::Schedule(ClearArrayKernel(manager.PrepareForOutput(ARRAY_SIZE)),
ARRAY_SIZE);
std::cout << "Running add." << std::endl;
Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false)),
ARRAY_SIZE);
std::cout << "Checking results." << std::endl;
manager.RetrieveOutputData(&storage);
for (vtkm::Id index = 0; index < ARRAY_SIZE; index++)
{
vtkm::Id value = storage.GetPortalConst().Get(index);
VTKM_TEST_ASSERT(value == index + OFFSET,
"Got bad value for scheduled kernels.");
}
} //release memory
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Schedule with a vary large Id value" << std::endl;
{
std::cout << "Allocating execution array" << std::endl;
IdStorage storage;
IdArrayManagerExecution manager(&storage);
std::cout << "Running clear." << std::endl;
//size is selected to be larger than the CUDA backend can launch in a
//single invocation when compiled for SM_2 support
const vtkm::Id size = 8400000;
Algorithm::Schedule(ClearArrayKernel(manager.PrepareForOutput(size)),
size);
std::cout << "Running add." << std::endl;
Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false)),
size);
std::cout << "Checking results." << std::endl;
manager.RetrieveOutputData(&storage);
for (vtkm::Id index = 0; index < size; index+=100)
{
vtkm::Id value = storage.GetPortalConst().Get(index);
VTKM_TEST_ASSERT(value == index + OFFSET,
"Got bad value for scheduled kernels.");
}
} //release memory
//verify that the schedule call works with id3
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Schedule with vtkm::Id3" << std::endl;
{
std::cout << "Allocating execution array" << std::endl;
IdStorage storage;
IdArrayManagerExecution manager(&storage);
vtkm::Id3 maxRange(DIM_SIZE);
std::cout << "Running clear." << std::endl;
Algorithm::Schedule(
ClearArrayKernel(manager.PrepareForOutput(
DIM_SIZE * DIM_SIZE * DIM_SIZE), maxRange),
maxRange);
std::cout << "Running add." << std::endl;
Algorithm::Schedule(AddArrayKernel(manager.PrepareForInPlace(false), maxRange),
maxRange);
std::cout << "Checking results." << std::endl;
manager.RetrieveOutputData(&storage);
const vtkm::Id maxId = DIM_SIZE * DIM_SIZE * DIM_SIZE;
for (vtkm::Id index = 0; index < maxId; index++)
{
vtkm::Id value = storage.GetPortalConst().Get(index);
VTKM_TEST_ASSERT(value == index + OFFSET,
"Got bad value for scheduled vtkm::Id3 kernels.");
}
} //release memory
}
static VTKM_CONT void TestCopyIf()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing CopyIf" << std::endl;
IdArrayHandle array;
IdArrayHandle stencil;
IdArrayHandle result;
std::cout << " Standard call" << std::endl;
//construct the index array
Algorithm::Schedule(
OffsetPlusIndexKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
Algorithm::Schedule(
MarkOddNumbersKernel(stencil.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
Algorithm::CopyIf(array,stencil,result);
VTKM_TEST_ASSERT(result.GetNumberOfValues() == array.GetNumberOfValues()/2,
"result of CopyIf has an incorrect size");
for (vtkm::Id index = 0; index < result.GetNumberOfValues(); index++)
{
const vtkm::Id value = result.GetPortalConstControl().Get(index);
VTKM_TEST_ASSERT(value == (OFFSET + (index*2)+1),
"Incorrect value in CopyIf result.");
}
std::cout << " CopyIf on zero size arrays." << std::endl;
array.Shrink(0);
stencil.Shrink(0);
Algorithm::CopyIf(array, stencil, result);
VTKM_TEST_ASSERT(result.GetNumberOfValues() == 0,
"result of CopyIf has an incorrect size");
}
static VTKM_CONT void TestOrderedUniqueValues()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing Sort, Unique, LowerBounds and UpperBounds" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+(i % 50));
}
IdArrayHandle input = vtkm::cont::make_ArrayHandle(&(*testData.begin()), ARRAY_SIZE);
//make a deep copy of input and place it into temp
IdArrayHandle temp;
Algorithm::Copy(input,temp);
Algorithm::Sort(temp);
Algorithm::Unique(temp);
IdArrayHandle handle;
IdArrayHandle handle1;
//verify lower and upper bounds work
Algorithm::LowerBounds(temp,input,handle);
Algorithm::UpperBounds(temp,input,handle1);
// Check to make sure that temp was resized correctly during Unique.
// (This was a discovered bug at one point.)
temp.GetPortalConstControl(); // Forces copy back to control.
temp.ReleaseResourcesExecution(); // Make sure not counting on execution.
VTKM_TEST_ASSERT(
temp.GetNumberOfValues() == 50,
"Unique did not resize array (or size did not copy to control).");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id value = handle.GetPortalConstControl().Get(i);
vtkm::Id value1 = handle1.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == i % 50, "Got bad value (LowerBounds)");
VTKM_TEST_ASSERT(value1 >= i % 50, "Got bad value (UpperBounds)");
}
std::cout << "Testing Sort, Unique, LowerBounds and UpperBounds with random values"
<< std::endl;
//now test it works when the id are not incrementing
const vtkm::Id RANDOMDATA_SIZE = 6;
vtkm::Id randomData[RANDOMDATA_SIZE];
randomData[0]=500; // 2 (lower), 3 (upper)
randomData[1]=955; // 3 (lower), 4 (upper)
randomData[2]=955; // 3 (lower), 4 (upper)
randomData[3]=120; // 0 (lower), 1 (upper)
randomData[4]=320; // 1 (lower), 2 (upper)
randomData[5]=955; // 3 (lower), 4 (upper)
//change the control structure under the handle
input = vtkm::cont::make_ArrayHandle(randomData, RANDOMDATA_SIZE);
Algorithm::Copy(input,handle);
VTKM_TEST_ASSERT(handle.GetNumberOfValues() == RANDOMDATA_SIZE,
"Handle incorrect size after setting new control data");
Algorithm::Copy(input,handle1);
VTKM_TEST_ASSERT(handle.GetNumberOfValues() == RANDOMDATA_SIZE,
"Handle incorrect size after setting new control data");
Algorithm::Copy(handle,temp);
VTKM_TEST_ASSERT(temp.GetNumberOfValues() == RANDOMDATA_SIZE,
"Copy failed");
Algorithm::Sort(temp);
Algorithm::Unique(temp);
Algorithm::LowerBounds(temp,handle);
Algorithm::UpperBounds(temp,handle1);
VTKM_TEST_ASSERT(handle.GetNumberOfValues() == RANDOMDATA_SIZE,
"LowerBounds returned incorrect size");
std::copy(
vtkm::cont::ArrayPortalToIteratorBegin(handle.GetPortalConstControl()),
vtkm::cont::ArrayPortalToIteratorEnd(handle.GetPortalConstControl()),
randomData);
VTKM_TEST_ASSERT(randomData[0] == 2, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(randomData[1] == 3, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(randomData[2] == 3, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(randomData[3] == 0, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(randomData[4] == 1, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(randomData[5] == 3, "Got bad value - LowerBounds");
VTKM_TEST_ASSERT(handle1.GetNumberOfValues() == RANDOMDATA_SIZE,
"UppererBounds returned incorrect size");
std::copy(
vtkm::cont::ArrayPortalToIteratorBegin(handle1.GetPortalConstControl()),
vtkm::cont::ArrayPortalToIteratorEnd(handle1.GetPortalConstControl()),
randomData);
VTKM_TEST_ASSERT(randomData[0] == 3, "Got bad value - UpperBound");
VTKM_TEST_ASSERT(randomData[1] == 4, "Got bad value - UpperBound");
VTKM_TEST_ASSERT(randomData[2] == 4, "Got bad value - UpperBound");
VTKM_TEST_ASSERT(randomData[3] == 1, "Got bad value - UpperBound");
VTKM_TEST_ASSERT(randomData[4] == 2, "Got bad value - UpperBound");
VTKM_TEST_ASSERT(randomData[5] == 4, "Got bad value - UpperBound");
}
static VTKM_CONT void TestSort()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Sort" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+((ARRAY_SIZE-i) % 50));
}
IdArrayHandle unsorted = vtkm::cont::make_ArrayHandle(testData);
IdArrayHandle sorted;
Algorithm::Copy(unsorted, sorted);
//Validate the standard inplace sort is correct
Algorithm::Sort(sorted);
for (vtkm::Id i = 0; i < ARRAY_SIZE-1; ++i)
{
vtkm::Id sorted1 = sorted.GetPortalConstControl().Get(i);
vtkm::Id sorted2 = sorted.GetPortalConstControl().Get(i+1);
VTKM_TEST_ASSERT(sorted1 <= sorted2, "Values not properly sorted.");
}
//Try zero sized array
sorted.Shrink(0);
Algorithm::Sort(sorted);
}
static VTKM_CONT void TestSortWithComparisonObject()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Sort with comparison object" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+((ARRAY_SIZE-i) % 50));
}
//sort the users memory in-place
IdArrayHandle sorted = vtkm::cont::make_ArrayHandle(testData);
Algorithm::Sort(sorted);
//copy the sorted array into our own memory, if use the same user ptr
//we would also sort the 'sorted' handle
IdArrayHandle comp_sorted;
Algorithm::Copy(sorted, comp_sorted);
Algorithm::Sort(comp_sorted,vtkm::SortGreater());
//Validate that sorted and comp_sorted are sorted in the opposite directions
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id sorted1 = sorted.GetPortalConstControl().Get(i);
vtkm::Id sorted2 = comp_sorted.GetPortalConstControl().Get(ARRAY_SIZE - (i + 1));
VTKM_TEST_ASSERT(sorted1 == sorted2,
"Got bad sort values when using SortGreater");
}
//validate that sorted and comp_sorted are now equal
Algorithm::Sort(comp_sorted,vtkm::SortLess());
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id sorted1 = sorted.GetPortalConstControl().Get(i);
vtkm::Id sorted2 = comp_sorted.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(sorted1 == sorted2,
"Got bad sort values when using SortLess");
}
}
static VTKM_CONT void TestSortWithFancyArrays()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Sort of a ArrayHandleZip" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+((ARRAY_SIZE-i) % 50));
}
IdArrayHandle unsorted = vtkm::cont::make_ArrayHandle(testData);
IdArrayHandle sorted;
Algorithm::Copy(unsorted, sorted);
//verify that we can use ArrayHandleZip inplace
vtkm::cont::ArrayHandleZip< IdArrayHandle, IdArrayHandle> zipped(unsorted, sorted);
//verify we can use sort with zip handle
Algorithm::Sort(zipped, vtkm::SortGreater());
Algorithm::Sort(zipped);
for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i)
{
vtkm::Pair<vtkm::Id,vtkm::Id> kv_sorted = zipped.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(( OFFSET + ( i / (ARRAY_SIZE/50)) ) == kv_sorted.first,
"ArrayZipHandle improperly sorted");
}
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Sort of a ArrayHandlePermutation" << std::endl;
//verify that we can use ArrayHandlePermutation inplace
vtkm::cont::ArrayHandleIndex index(ARRAY_SIZE);
vtkm::cont::ArrayHandlePermutation< vtkm::cont::ArrayHandleIndex,
IdArrayHandle> perm(index, sorted);
//verify we can use a custom operator sort with permutation handle
Algorithm::Sort(perm, vtkm::SortGreater());
for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i)
{
vtkm::Id sorted_value = perm.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(( OFFSET + ( (ARRAY_SIZE-(i+1)) / (ARRAY_SIZE/50)) ) == sorted_value,
"ArrayZipPermutation improperly sorted");
}
//verify we can use the default sort with permutation handle
Algorithm::Sort(perm);
for (vtkm::Id i = 0; i < ARRAY_SIZE; ++i)
{
vtkm::Id sorted_value = perm.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(( OFFSET + ( i / (ARRAY_SIZE/50)) ) == sorted_value,
"ArrayZipPermutation improperly sorted");
}
}
static VTKM_CONT void TestSortByKey()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Sort by keys" << std::endl;
typedef vtkm::Vec<FloatDefault,3> Vec3;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault,3>,StorageTag>
Vec3ArrayHandle;
std::vector<vtkm::Id> testKeys(ARRAY_SIZE);
std::vector<Vec3> testValues(testKeys.size());
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
std::size_t index = static_cast<size_t>(i);
testKeys[index] = ARRAY_SIZE - i;
testValues[index] = TestValue(i, Vec3());
}
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(testKeys);
Vec3ArrayHandle values = vtkm::cont::make_ArrayHandle(testValues);
Algorithm::SortByKey(keys,values);
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
//keys should be sorted from 1 to ARRAY_SIZE
//values should be sorted from (ARRAY_SIZE-1) to 0
Vec3 sorted_value = values.GetPortalConstControl().Get(i);
vtkm::Id sorted_key = keys.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT( (sorted_key == (i+1)) , "Got bad SortByKeys key");
VTKM_TEST_ASSERT( test_equal(sorted_value, TestValue(ARRAY_SIZE-1-i, Vec3())),
"Got bad SortByKeys value");
}
// this will return everything back to what it was before sorting
Algorithm::SortByKey(keys,values,vtkm::SortGreater());
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
//keys should be sorted from ARRAY_SIZE to 1
//values should be sorted from 0 to (ARRAY_SIZE-1)
Vec3 sorted_value = values.GetPortalConstControl().Get(i);
vtkm::Id sorted_key = keys.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT( (sorted_key == (ARRAY_SIZE-i)),
"Got bad SortByKeys key");
VTKM_TEST_ASSERT( test_equal(sorted_value, TestValue(i, Vec3())),
"Got bad SortByKeys value");
}
//this is here to verify we can sort by vtkm::Vec
Algorithm::SortByKey(values,keys);
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
//keys should be sorted from ARRAY_SIZE to 1
//values should be sorted from 0 to (ARRAY_SIZE-1)
Vec3 sorted_value = values.GetPortalConstControl().Get(i);
vtkm::Id sorted_key = keys.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT( (sorted_key == (ARRAY_SIZE-i)),
"Got bad SortByKeys key");
VTKM_TEST_ASSERT( test_equal(sorted_value, TestValue(i, Vec3())),
"Got bad SortByKeys value");
}
}
static VTKM_CONT void TestLowerBoundsWithComparisonObject()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing LowerBounds with comparison object" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+(i % 50));
}
IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData);
//make a deep copy of input and place it into temp
IdArrayHandle temp;
Algorithm::Copy(input,temp);
Algorithm::Sort(temp);
Algorithm::Unique(temp);
IdArrayHandle handle;
//verify lower bounds work
Algorithm::LowerBounds(temp,input,handle,vtkm::SortLess());
// Check to make sure that temp was resized correctly during Unique.
// (This was a discovered bug at one point.)
temp.GetPortalConstControl(); // Forces copy back to control.
temp.ReleaseResourcesExecution(); // Make sure not counting on execution.
VTKM_TEST_ASSERT(
temp.GetNumberOfValues() == 50,
"Unique did not resize array (or size did not copy to control).");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id value = handle.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == i % 50, "Got bad LowerBounds value with SortLess");
}
}
static VTKM_CONT void TestUpperBoundsWithComparisonObject()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing UpperBounds with comparison object" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+(i % 50));
}
IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData);
//make a deep copy of input and place it into temp
IdArrayHandle temp;
Algorithm::Copy(input,temp);
Algorithm::Sort(temp);
Algorithm::Unique(temp);
IdArrayHandle handle;
//verify upper bounds work
Algorithm::UpperBounds(temp,input,handle,vtkm::SortLess());
// Check to make sure that temp was resized correctly during Unique.
// (This was a discovered bug at one point.)
temp.GetPortalConstControl(); // Forces copy back to control.
temp.ReleaseResourcesExecution(); // Make sure not counting on execution.
VTKM_TEST_ASSERT(
temp.GetNumberOfValues() == 50,
"Unique did not resize array (or size did not copy to control).");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id value = handle.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == (i % 50)+1, "Got bad UpperBounds value with SortLess");
}
}
static VTKM_CONT void TestUniqueWithComparisonObject()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing Unique with comparison object" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+(i % 50));
}
IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData);
Algorithm::Sort(input);
Algorithm::Unique(input, FuseAll());
// Check to make sure that input was resized correctly during Unique.
// (This was a discovered bug at one point.)
input.GetPortalConstControl(); // Forces copy back to control.
input.ReleaseResourcesExecution(); // Make sure not counting on execution.
VTKM_TEST_ASSERT(
input.GetNumberOfValues() == 1,
"Unique did not resize array (or size did not copy to control).");
vtkm::Id value = input.GetPortalConstControl().Get(0);
VTKM_TEST_ASSERT(value == OFFSET, "Got bad unique value");
}
static VTKM_CONT void TestReduce()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce" << std::endl;
//construct the index array
IdArrayHandle array;
Algorithm::Schedule(
ClearArrayKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
//the output of reduce and scan inclusive should be the same
std::cout << " Reduce with initial value of 0." << std::endl;
vtkm::Id reduce_sum = Algorithm::Reduce(array, vtkm::Id(0));
std::cout << " Reduce with initial value." << std::endl;
vtkm::Id reduce_sum_with_intial_value = Algorithm::Reduce(array,
vtkm::Id(ARRAY_SIZE));
std::cout << " Inclusive scan to check" << std::endl;
vtkm::Id inclusive_sum = Algorithm::ScanInclusive(array, array);
std::cout << " Reduce with 1 value." << std::endl;
array.Shrink(1);
vtkm::Id reduce_sum_one_value = Algorithm::Reduce(array, vtkm::Id(0));
std::cout << " Reduce with 0 values." << std::endl;
array.Shrink(0);
vtkm::Id reduce_sum_no_values = Algorithm::Reduce(array, vtkm::Id(0));
VTKM_TEST_ASSERT(reduce_sum == OFFSET * ARRAY_SIZE,
"Got bad sum from Reduce");
VTKM_TEST_ASSERT(reduce_sum_with_intial_value == reduce_sum + ARRAY_SIZE,
"Got bad sum from Reduce with initial value");
VTKM_TEST_ASSERT(reduce_sum_one_value == OFFSET,
"Got bad single sum from Reduce");
VTKM_TEST_ASSERT(reduce_sum_no_values == 0,
"Got bad empty sum from Reduce");
VTKM_TEST_ASSERT(reduce_sum == inclusive_sum,
"Got different sums from Reduce and ScanInclusive");
}
static VTKM_CONT void TestReduceWithComparisonObject()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce with comparison object " << std::endl;
//construct the index array. Assign an abnormally large value
//to the middle of the array, that should be what we see as our sum.
std::vector<vtkm::Id> testData(ARRAY_SIZE);
const vtkm::Id maxValue = ARRAY_SIZE*2;
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
vtkm::Id index = static_cast<vtkm::Id>(i);
testData[i]= index;
}
testData[ARRAY_SIZE/2] = maxValue;
IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData);
vtkm::Vec<vtkm::Id,2> range = Algorithm::Reduce(input,
vtkm::Vec<vtkm::Id,2>(0,0),
vtkm::MinAndMax<vtkm::Id>());
VTKM_TEST_ASSERT(maxValue == range[1],
"Got bad value from Reduce with comparison object");
VTKM_TEST_ASSERT(0 == range[0],
"Got bad value from Reduce with comparison object");
}
static VTKM_CONT void TestReduceWithFancyArrays()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce with ArrayHandleZip" << std::endl;
{
IdArrayHandle keys, values;
Algorithm::Schedule(
ClearArrayKernel(keys.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
Algorithm::Schedule(
ClearArrayKernel(values.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
vtkm::cont::ArrayHandleZip< IdArrayHandle,
IdArrayHandle > zipped(keys,values);
//the output of reduce and scan inclusive should be the same
typedef vtkm::Pair<vtkm::Id,vtkm::Id> ResultType;
ResultType reduce_sum_with_intial_value =
Algorithm::Reduce(zipped, ResultType(ARRAY_SIZE,ARRAY_SIZE));
ResultType expectedResult(OFFSET * ARRAY_SIZE + ARRAY_SIZE,
OFFSET * ARRAY_SIZE + ARRAY_SIZE);
VTKM_TEST_ASSERT( ( reduce_sum_with_intial_value == expectedResult),
"Got bad sum from Reduce with initial value");
}
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce with ArrayHandlePermutation" << std::endl;
{
//lastly test with heterogeneous zip values ( vec3, and constant array handle),
//and a custom reduce binary functor
const vtkm::Id indexLength = 30;
const vtkm::Id valuesLength = 10;
typedef vtkm::Float32 ValueType;
vtkm::Id indexs[indexLength] = {0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,
5,5,5,1,4,9,7,7,7,8,8,8,0,1,2};
ValueType values[valuesLength] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f,
6.0f, 7.0f, 8.0f, 9.0f, -2.0f};
const ValueType expectedSum = 125;
IdArrayHandle indexHandle = vtkm::cont::make_ArrayHandle(indexs, indexLength);
vtkm::cont::ArrayHandle<ValueType> valueHandle = vtkm::cont::make_ArrayHandle(values, valuesLength);
vtkm::cont::ArrayHandlePermutation< IdArrayHandle, vtkm::cont::ArrayHandle<ValueType> > perm;
perm = vtkm::cont::make_ArrayHandlePermutation(indexHandle, valueHandle);
const ValueType sum = Algorithm::Reduce(perm, ValueType(0.0f));
std::cout << "sum: " << sum << std::endl;
VTKM_TEST_ASSERT( ( sum == expectedSum),
"Got bad sum from Reduce with permutation handle");
}
}
static VTKM_CONT void TestReduceByKey()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce By Key" << std::endl;
//first test with very basic integer key / values
{
const vtkm::Id inputLength = 12;
const vtkm::Id expectedLength = 6;
vtkm::Id inputKeys[inputLength] = {0, 0, 0,\
1, 1,\
4,\
0,\
2, 2, 2, 2,\
-1}; // input keys
vtkm::Id inputValues[inputLength] = {13, -2, -1,\
1, 1,\
0,\
3,\
1, 2, 3, 4, \
-42}; // input keys
vtkm::Id expectedKeys[expectedLength] = { 0, 1, 4, 0, 2, -1 };
vtkm::Id expectedValues[expectedLength] = {10, 2, 0, 3, 10, -42};
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
IdArrayHandle values = vtkm::cont::make_ArrayHandle(inputValues, inputLength);
IdArrayHandle keysOut, valuesOut;
Algorithm::ReduceByKey( keys,
values,
keysOut,
valuesOut,
vtkm::Add() );
VTKM_TEST_ASSERT(keysOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output keys");
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for(vtkm::Id i=0; i < expectedLength; ++i)
{
const vtkm::Id k = keysOut.GetPortalConstControl().Get(i);
const vtkm::Id v = valuesOut.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT( expectedKeys[i] == k, "Incorrect reduced key");
VTKM_TEST_ASSERT( expectedValues[i] == v, "Incorrect reduced value");
}
}
//next test with a single key across the entire set, using vec3 as the
//value, using a custom reduce binary functor
{
const vtkm::Id inputLength = 3;
const vtkm::Id expectedLength = 1;
vtkm::Id inputKeys[inputLength] = {0, 0, 0}; // input keys
vtkm::Vec<vtkm::Float64, 3> inputValues[inputLength];
inputValues[0] = vtkm::make_Vec(13.1, 13.3, 13.5);
inputValues[1] = vtkm::make_Vec(-2.1, -2.3, -2.5);
inputValues[2] = vtkm::make_Vec(-1.0, -1.0, 1.0); // input keys
vtkm::Id expectedKeys[expectedLength] = { 0};
vtkm::Vec<vtkm::Float64, 3> expectedValues[expectedLength];
expectedValues[0] = vtkm::make_Vec(27.51, 30.59, -33.75);
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float64, 3>, StorageTag> values = vtkm::cont::make_ArrayHandle(inputValues, inputLength);
IdArrayHandle keysOut;
vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float64, 3>, StorageTag> valuesOut;
Algorithm::ReduceByKey( keys,
values,
keysOut,
valuesOut,
vtkm::Multiply() );
VTKM_TEST_ASSERT(keysOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output keys");
VTKM_TEST_ASSERT(valuesOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for(vtkm::Id i=0; i < expectedLength; ++i)
{
const vtkm::Id k = keysOut.GetPortalConstControl().Get(i);
const vtkm::Vec<vtkm::Float64, 3> v = valuesOut.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT( expectedKeys[i] == k, "Incorrect reduced key");
VTKM_TEST_ASSERT( expectedValues[i] == v, "Incorrect reduced vale");
}
}
}
static VTKM_CONT void TestReduceByKeyWithFancyArrays()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Reduce By Key with Fancy Arrays" << std::endl;
//lastly test with heterogeneous zip values ( vec3, and constant array handle),
//and a custom reduce binary functor
const vtkm::Id inputLength = 30;
const vtkm::Id expectedLength = 10;
typedef vtkm::Float32 ValueType;
vtkm::Id inputKeys[inputLength] = {0,0,0,1,1,1,2,2,2,3,3,3,4,4,4,
5,5,5,6,6,6,7,7,7,8,8,8,9,9,9}; // input keys
ValueType inputValues1[inputLength] = {13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f,
13.1f, -2.1f, -1.0f}; // input values array1
vtkm::Id expectedKeys[expectedLength] = {0,1,2,3,4,5,6,7,8,9};
ValueType expectedValues1[expectedLength] = {10.f,10.f,10.f,10.f,10.f,10.f,10.f,10.f,10.f,10.f}; // output values 1
ValueType expectedValues2[expectedLength] = {3.f,3.f,3.f,3.f,3.f,3.f,3.f,3.f,3.f,3.f}; // output values 2
IdArrayHandle keys = vtkm::cont::make_ArrayHandle(inputKeys, inputLength);
typedef vtkm::cont::ArrayHandle<ValueType, StorageTag> ValueArrayType;
ValueArrayType values1 = vtkm::cont::make_ArrayHandle(inputValues1, inputLength);
typedef vtkm::cont::ArrayHandleConstant<ValueType> ConstValueArrayType;
ConstValueArrayType constOneArray(1.f, inputLength);
vtkm::cont::ArrayHandleZip<ValueArrayType, ConstValueArrayType> valuesZip;
valuesZip = make_ArrayHandleZip(values1, constOneArray); // values in zip
IdArrayHandle keysOut;
ValueArrayType valuesOut1;
ValueArrayType valuesOut2;
vtkm::cont::ArrayHandleZip<ValueArrayType, ValueArrayType> valuesOutZip(valuesOut1, valuesOut2);
Algorithm::ReduceByKey( keys,
valuesZip,
keysOut,
valuesOutZip,
vtkm::Add() );
VTKM_TEST_ASSERT(keysOut.GetNumberOfValues() == expectedLength,
"Got wrong number of output keys");
VTKM_TEST_ASSERT(valuesOutZip.GetNumberOfValues() == expectedLength,
"Got wrong number of output values");
for(vtkm::Id i=0; i < expectedLength; ++i)
{
const vtkm::Id k = keysOut.GetPortalConstControl().Get(i);
const vtkm::Pair<ValueType, ValueType> v = valuesOutZip.GetPortalConstControl().Get(i);
std::cout << "key=" << k << "," << "expectedValues1[i] = " << expectedValues1[i] << "," << "computed value1 = " << v.first << std::endl;
VTKM_TEST_ASSERT( expectedKeys[i] == k, "Incorrect reduced key");
VTKM_TEST_ASSERT( expectedValues1[i] == v.first, "Incorrect reduced value1");
VTKM_TEST_ASSERT( expectedValues2[i] == v.second, "Incorrect reduced value2");
}
}
static VTKM_CONT void TestScanInclusive()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Inclusive Scan" << std::endl;
{
std::cout << " size " << ARRAY_SIZE << std::endl;
//construct the index array
IdArrayHandle array;
Algorithm::Schedule(
ClearArrayKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
//we know have an array whose sum is equal to OFFSET * ARRAY_SIZE,
//let's validate that
vtkm::Id sum = Algorithm::ScanInclusive(array, array);
VTKM_TEST_ASSERT(sum == OFFSET * ARRAY_SIZE,
"Got bad sum from Inclusive Scan");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
const vtkm::Id value = array.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == (i+1) * OFFSET,
"Incorrect partial sum");
}
std::cout << " size 1" << std::endl;
array.Shrink(1);
sum = Algorithm::ScanInclusive(array, array);
VTKM_TEST_ASSERT(sum == OFFSET, "Incorrect partial sum");
const vtkm::Id value = array.GetPortalConstControl().Get(0);
VTKM_TEST_ASSERT(value == OFFSET, "Incorrect partial sum");
std::cout << " size 0" << std::endl;
array.Shrink(0);
sum = Algorithm::ScanInclusive(array, array);
VTKM_TEST_ASSERT(sum == 0, "Incorrect partial sum");
}
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Inclusive Scan with multiplication operator" << std::endl;
{
std::vector<vtkm::Float64> inputValues(ARRAY_SIZE);
for (std::size_t i = 0; i < ARRAY_SIZE; ++i)
{
inputValues[i] = 1.01;
}
std::size_t mid = ARRAY_SIZE/2;
inputValues[mid] = 0.0;
vtkm::cont::ArrayHandle<vtkm::Float64> array =
vtkm::cont::make_ArrayHandle(&inputValues[0], ARRAY_SIZE);
vtkm::Float64 product = Algorithm::ScanInclusive(array, array,
vtkm::Multiply());
VTKM_TEST_ASSERT(product == 0.0f, "ScanInclusive product result not 0.0");
for (std::size_t i = 0; i < mid; ++i)
{
vtkm::Id index = static_cast<vtkm::Id>(i);
vtkm::Float64 expected = pow(1.01, static_cast<vtkm::Float64>(i + 1));
vtkm::Float64 got = array.GetPortalConstControl().Get(index);
VTKM_TEST_ASSERT(test_equal(got, expected),
"Incorrect results for ScanInclusive");
}
for (std::size_t i = mid; i < ARRAY_SIZE; ++i)
{
vtkm::Id index = static_cast<vtkm::Id>(i);
VTKM_TEST_ASSERT(array.GetPortalConstControl().Get(index) == 0.0f,
"Incorrect results for ScanInclusive");
}
}
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Inclusive Scan with a vtkm::Vec" << std::endl;
{
typedef vtkm::Vec<Float64,3> Vec3;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float64,3>,StorageTag>
Vec3ArrayHandle;
std::vector<Vec3> testValues(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testValues[i] = TestValue(1, Vec3());
}
Vec3ArrayHandle values = vtkm::cont::make_ArrayHandle(testValues);
Vec3 sum = Algorithm::ScanInclusive(values, values);
std::cout << "Sum that was returned " << sum << std::endl;
VTKM_TEST_ASSERT( test_equal(sum, TestValue(1, Vec3()) * ARRAY_SIZE ),
"Got bad sum from Inclusive Scan");
}
}
static VTKM_CONT void TestScanInclusiveWithComparisonObject()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Inclusive Scan with comparison object " << std::endl;
//construct the index array
IdArrayHandle array;
Algorithm::Schedule(
ClearArrayKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
Algorithm::Schedule(
AddArrayKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
//we know have an array whose sum is equal to OFFSET * ARRAY_SIZE,
//let's validate that
IdArrayHandle result;
vtkm::Id sum = Algorithm::ScanInclusive(array,
result,
vtkm::Maximum());
VTKM_TEST_ASSERT(sum == OFFSET + (ARRAY_SIZE-1),
"Got bad sum from Inclusive Scan with comparison object");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
const vtkm::Id input_value = array.GetPortalConstControl().Get(i);
const vtkm::Id result_value = result.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(input_value == result_value, "Incorrect partial sum");
}
//now try it inline
sum = Algorithm::ScanInclusive(array,
array,
vtkm::Maximum());
VTKM_TEST_ASSERT(sum == OFFSET + (ARRAY_SIZE-1),
"Got bad sum from Inclusive Scan with comparison object");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
const vtkm::Id input_value = array.GetPortalConstControl().Get(i);
const vtkm::Id result_value = result.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(input_value == result_value, "Incorrect partial sum");
}
}
static VTKM_CONT void TestScanExclusive()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Exclusive Scan" << std::endl;
{
std::cout << " size " << ARRAY_SIZE << std::endl;
//construct the index array
IdArrayHandle array;
Algorithm::Schedule(
ClearArrayKernel(array.PrepareForOutput(ARRAY_SIZE,
DeviceAdapterTag())),
ARRAY_SIZE);
// we know have an array whose sum = (OFFSET * ARRAY_SIZE),
// let's validate that
vtkm::Id sum = Algorithm::ScanExclusive(array, array);
std::cout << " Sum that was returned " << sum << std::endl;
VTKM_TEST_ASSERT(sum == (OFFSET * ARRAY_SIZE),
"Got bad sum from Exclusive Scan");
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i)
{
const vtkm::Id value = array.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == i * OFFSET,
"Incorrect partial sum");
}
std::cout << " size 1" << std::endl;
array.Shrink(1);
array.GetPortalControl().Set(0, OFFSET);
sum = Algorithm::ScanExclusive(array, array);
VTKM_TEST_ASSERT(sum == OFFSET, "Incorrect partial sum");
const vtkm::Id value = array.GetPortalConstControl().Get(0);
VTKM_TEST_ASSERT(value == 0, "Incorrect partial sum");
std::cout << " size 0" << std::endl;
array.Shrink(0);
sum = Algorithm::ScanExclusive(array, array);
VTKM_TEST_ASSERT(sum == 0, "Incorrect partial sum");
}
// Enable when Exclusive Scan with custom operator is implemented for all
// device adaptors
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Exclusive Scan with multiplication operator" << std::endl;
{
std::vector<vtkm::Float64> inputValues(ARRAY_SIZE);
for (std::size_t i = 0; i < ARRAY_SIZE; ++i)
{
inputValues[i] = 1.01;
}
std::size_t mid = ARRAY_SIZE/2;
inputValues[mid] = 0.0;
vtkm::cont::ArrayHandle<vtkm::Float64> array = vtkm::cont::make_ArrayHandle(inputValues);
vtkm::Float64 initialValue = 2.00;
vtkm::Float64 product = Algorithm::ScanExclusive(array, array,
vtkm::Multiply(), initialValue);
VTKM_TEST_ASSERT(product == 0.0f, "ScanExclusive product result not 0.0");
VTKM_TEST_ASSERT(array.GetPortalConstControl().Get(0) == initialValue,
"ScanExclusive result's first value != initialValue");
for (std::size_t i = 1; i <= mid; ++i)
{
vtkm::Id index = static_cast<vtkm::Id>(i);
vtkm::Float64 expected = pow(1.01, static_cast<vtkm::Float64>(i)) *
initialValue;
vtkm::Float64 got = array.GetPortalConstControl().Get(index);
VTKM_TEST_ASSERT(test_equal(got, expected),
"Incorrect results for ScanExclusive");
}
for (std::size_t i = mid + 1; i < ARRAY_SIZE; ++i)
{
vtkm::Id index = static_cast<vtkm::Id>(i);
VTKM_TEST_ASSERT(array.GetPortalConstControl().Get(index) == 0.0f,
"Incorrect results for ScanExclusive");
}
}
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Exclusive Scan with a vtkm::Vec" << std::endl;
{
typedef vtkm::Vec<Float64,3> Vec3;
typedef vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float64,3>,StorageTag>
Vec3ArrayHandle;
std::vector<Vec3> testValues(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testValues[i] = TestValue(1, Vec3());
}
Vec3ArrayHandle values = vtkm::cont::make_ArrayHandle(testValues);
Vec3 sum = Algorithm::ScanExclusive(values, values);
std::cout << "Sum that was returned " << sum << std::endl;
VTKM_TEST_ASSERT( test_equal(sum, (TestValue(1, Vec3()) * ARRAY_SIZE) ),
"Got bad sum from Exclusive Scan");
}
}
static VTKM_CONT void TestErrorExecution()
{
std::cout << "-------------------------------------------" << std::endl;
std::cout << "Testing Exceptions in Execution Environment" << std::endl;
std::cout << "Generating one error." << std::endl;
std::string message;
try
{
Algorithm::Schedule(OneErrorKernel(), ARRAY_SIZE);
}
catch (vtkm::cont::ErrorExecution &error)
{
std::cout << "Got expected error: " << error.GetMessage() << std::endl;
message = error.GetMessage();
}
VTKM_TEST_ASSERT(message == ERROR_MESSAGE,
"Did not get expected error message.");
std::cout << "Generating lots of errors." << std::endl;
message = "";
try
{
Algorithm::Schedule(AllErrorKernel(), ARRAY_SIZE);
}
catch (vtkm::cont::ErrorExecution &error)
{
std::cout << "Got expected error: " << error.GetMessage() << std::endl;
message = error.GetMessage();
}
VTKM_TEST_ASSERT(message == ERROR_MESSAGE,
"Did not get expected error message.");
}
template <typename T, int N=0>
struct TestCopy {};
template <typename T>
struct TestCopy<T> {
static T get(vtkm::Id i) { return static_cast<T>(i); }
};
template <typename T, int N>
struct TestCopy<vtkm::Vec<T, N> > {
static vtkm::Vec<T, N> get(vtkm::Id i) {
vtkm::Vec<T, N> temp;
for (int j=0; j<N; ++j) {
temp[j] = static_cast<T>( OFFSET+(i % 50) );
}
return temp;
}
};
template <typename T>
static VTKM_CONT void TestCopyArrays()
{
#define COPY_ARRAY_SIZE 10000
std::vector<T> testData(COPY_ARRAY_SIZE);
vtkm::Id index = 0;
for(std::size_t i=0; i < COPY_ARRAY_SIZE; ++i, ++index)
{
testData[i]= TestCopy<T>::get(index);
}
vtkm::cont::ArrayHandle<T> input = vtkm::cont::make_ArrayHandle(&testData[0],
COPY_ARRAY_SIZE);
//make a deep copy of input and place it into temp
{
vtkm::cont::ArrayHandle<T> temp;
temp.Allocate( COPY_ARRAY_SIZE * 2 );
Algorithm::Copy(input,temp);
VTKM_TEST_ASSERT(temp.GetNumberOfValues() == COPY_ARRAY_SIZE,
"Copy Needs to Resize Array");
typename std::vector<T>::const_iterator c = testData.begin();
for(vtkm::Id i=0; i < COPY_ARRAY_SIZE; i+=50,c+=50)
{
T value = temp.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (Copy)");
}
}
//Verify copy of empty array works
{
vtkm::cont::ArrayHandle<T> tempIn;
vtkm::cont::ArrayHandle<T> tempOut;
tempOut.Allocate(COPY_ARRAY_SIZE);
Algorithm::Copy(tempIn, tempOut);
VTKM_TEST_ASSERT(tempIn.GetNumberOfValues() == tempOut.GetNumberOfValues(),
"Copy sized wrong");
// Actually allocate input array to 0 in case that makes a difference.
tempIn.Allocate(0);
tempOut.Allocate(COPY_ARRAY_SIZE);
Algorithm::Copy(tempIn, tempOut);
VTKM_TEST_ASSERT(tempIn.GetNumberOfValues() == tempOut.GetNumberOfValues(),
"Copy sized wrong");
}
//CopySubRange tests:
//1. Verify invalid input start position fails
{
vtkm::cont::ArrayHandle<T> output;
bool result = Algorithm::CopySubRange(input, COPY_ARRAY_SIZE*4, 1, output);
VTKM_TEST_ASSERT(result == false, "CopySubRange when given bad input offset");
}
//2. Verify unallocated output gets allocated
{
vtkm::cont::ArrayHandle<T> output;
bool result = Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output);
VTKM_TEST_ASSERT(result == true, "CopySubRange should succeed");
VTKM_TEST_ASSERT(output.GetNumberOfValues() == COPY_ARRAY_SIZE,
"CopySubRange needs to allocate output");
}
//3. Verify under allocated output gets resized properly
{
vtkm::cont::ArrayHandle<T> output;
output.Allocate(2);
bool result = Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output);
VTKM_TEST_ASSERT(result == true, "CopySubRange should succeed");
VTKM_TEST_ASSERT(output.GetNumberOfValues() == COPY_ARRAY_SIZE,
"CopySubRange needs to re-allocate output");
}
//4. Verify invalid input length gets shortened
{
vtkm::cont::ArrayHandle<T> output;
bool result = Algorithm::CopySubRange(input, 100, COPY_ARRAY_SIZE, output);
VTKM_TEST_ASSERT(result == true, "CopySubRange needs to shorten input range");
VTKM_TEST_ASSERT(output.GetNumberOfValues() == (COPY_ARRAY_SIZE-100),
"CopySubRange needs to shorten input range");
typename std::vector<T>::const_iterator c = testData.begin() + 100;
for(vtkm::Id i=0; i < (COPY_ARRAY_SIZE-100); i+=100,c+=100)
{
T value = output.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (CopySubRange 2)");
}
}
//5. Verify sub range copy works when copying into a larger output
{
vtkm::cont::ArrayHandle<T> output;
output.Allocate( COPY_ARRAY_SIZE * 2 );
Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output);
Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output, COPY_ARRAY_SIZE);
VTKM_TEST_ASSERT(output.GetNumberOfValues() == (COPY_ARRAY_SIZE*2),
"CopySubRange needs to not resize array");
typename std::vector<T>::const_iterator c = testData.begin();
for(vtkm::Id i=0; i < COPY_ARRAY_SIZE; i+=50,c+=50)
{
T value = output.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (CopySubRange 5)");
value = output.GetPortalConstControl().Get(COPY_ARRAY_SIZE + i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (CopySubRange 5)");
}
}
//6. Verify that whey sub range needs to reallocate the output it
// properly copies the original data instead of clearing it
{
vtkm::cont::ArrayHandle<T> output;
output.Allocate( COPY_ARRAY_SIZE );
Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output);
Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output, COPY_ARRAY_SIZE);
VTKM_TEST_ASSERT(output.GetNumberOfValues() == (COPY_ARRAY_SIZE*2),
"CopySubRange needs too resize Array");
typename std::vector<T>::const_iterator c = testData.begin();
for(vtkm::Id i=0; i < COPY_ARRAY_SIZE; i+=50,c+=50)
{
T value = output.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (CopySubRange 6)");
value = output.GetPortalConstControl().Get(COPY_ARRAY_SIZE + i);
VTKM_TEST_ASSERT(value == *c, "Got bad value (CopySubRange 6)");
}
}
{
vtkm::cont::ArrayHandle<T> output;
//7. Verify negative input index returns false
bool result = Algorithm::CopySubRange(input, -1, COPY_ARRAY_SIZE, output);
VTKM_TEST_ASSERT(result == false, "CopySubRange negative index should fail");
//8. Verify negative input numberOfElementsToCopy returns false
result = Algorithm::CopySubRange(input, 0, -COPY_ARRAY_SIZE, output);
VTKM_TEST_ASSERT(result == false, "CopySubRange negative number elements should fail");
//9. Verify negative output index return false
result = Algorithm::CopySubRange(input, 0, COPY_ARRAY_SIZE, output, -2);
VTKM_TEST_ASSERT(result == false, "CopySubRange negative output index should fail");
}
#undef COPY_ARRAY_SIZE
}
static VTKM_CONT void TestCopyArraysMany()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing Copy to same array type" << std::endl;
TestCopyArrays< vtkm::Vec<vtkm::Float32,4> >();
TestCopyArrays< vtkm::Vec<vtkm::Float64,4> >();
//
TestCopyArrays< vtkm::Vec<vtkm::UInt8,2> >();
TestCopyArrays< vtkm::Vec<vtkm::UInt16,2> >();
TestCopyArrays< vtkm::Vec<vtkm::UInt32,2> >();
TestCopyArrays< vtkm::Vec<vtkm::UInt64,2> >();
//
TestCopyArrays< vtkm::Float32 >();
TestCopyArrays< vtkm::Float64 >();
//
TestCopyArrays< vtkm::Int8 >();
TestCopyArrays< vtkm::Int16 >();
TestCopyArrays< vtkm::Int32 >();
TestCopyArrays< vtkm::Int64 >();
//
TestCopyArrays< vtkm::UInt8 >();
TestCopyArrays< vtkm::UInt16 >();
TestCopyArrays< vtkm::UInt32 >();
TestCopyArrays< vtkm::UInt64 >();
//
TestCopyArrays<vtkm::Id>();
}
static VTKM_CONT void TestCopyArraysInDiffTypes()
{
std::cout << "-------------------------------------------------" << std::endl;
std::cout << "Testing Copy to a different array type" << std::endl;
std::vector<vtkm::Id> testData(ARRAY_SIZE);
for(std::size_t i=0; i < ARRAY_SIZE; ++i)
{
testData[i]= static_cast<vtkm::Id>(OFFSET+(i % 50));
}
IdArrayHandle input = vtkm::cont::make_ArrayHandle(testData);
//make a deep copy of input and place it into temp
vtkm::cont::ArrayHandle<vtkm::Float64> temp;
Algorithm::Copy(input,temp);
std::vector<vtkm::Id>::const_iterator c = testData.begin();
for(vtkm::Id i=0; i < ARRAY_SIZE; ++i, ++c)
{
vtkm::Float64 value = temp.GetPortalConstControl().Get(i);
VTKM_TEST_ASSERT(value == static_cast<vtkm::Float64>(*c),
"Got bad value (Copy)");
}
}
static VTKM_CONT void TestAtomicArray()
{
//we can't use ARRAY_SIZE as that would cause a overflow
vtkm::Int32 SHORT_ARRAY_SIZE = 10000;
vtkm::Int32 atomicCount = 0;
for(vtkm::Int32 i = 0; i < SHORT_ARRAY_SIZE; i++) atomicCount += i;
std::cout << "-------------------------------------------" << std::endl;
// To test the atomics, SHORT_ARRAY_SIZE number of threads will all increment
// a single atomic value.
std::cout << "Testing Atomic Add with vtkm::Int32" << std::endl;
{
std::vector<vtkm::Int32> singleElement;
singleElement.push_back(0);
vtkm::cont::ArrayHandle<vtkm::Int32> atomicElement = vtkm::cont::make_ArrayHandle(singleElement);
vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapterTag> atomic(atomicElement);
Algorithm::Schedule(AtomicKernel<vtkm::Int32>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int32 expected = vtkm::Int32(atomicCount);
vtkm::Int32 actual= atomicElement.GetPortalControl().Get(0);
VTKM_TEST_ASSERT(expected == actual, "Did not get expected value: Atomic add Int32");
}
std::cout << "Testing Atomic Add with vtkm::Int64" << std::endl;
{
std::vector<vtkm::Int64> singleElement;
singleElement.push_back(0);
vtkm::cont::ArrayHandle<vtkm::Int64> atomicElement = vtkm::cont::make_ArrayHandle(singleElement);
vtkm::exec::AtomicArray<vtkm::Int64, DeviceAdapterTag> atomic(atomicElement);
Algorithm::Schedule(AtomicKernel<vtkm::Int64>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int64 expected = vtkm::Int64(atomicCount);
vtkm::Int64 actual= atomicElement.GetPortalControl().Get(0);
VTKM_TEST_ASSERT(expected == actual, "Did not get expected value: Atomic add Int64");
}
std::cout << "Testing Atomic CAS with vtkm::Int32" << std::endl;
{
std::vector<vtkm::Int32> singleElement;
singleElement.push_back(0);
vtkm::cont::ArrayHandle<vtkm::Int32> atomicElement = vtkm::cont::make_ArrayHandle(singleElement);
vtkm::exec::AtomicArray<vtkm::Int32, DeviceAdapterTag> atomic(atomicElement);
Algorithm::Schedule(AtomicCASKernel<vtkm::Int32>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int32 expected = vtkm::Int32(atomicCount);
vtkm::Int32 actual= atomicElement.GetPortalControl().Get(0);
VTKM_TEST_ASSERT(expected == actual, "Did not get expected value: Atomic CAS Int32");
}
std::cout << "Testing Atomic CAS with vtkm::Int64" << std::endl;
{
std::vector<vtkm::Int64> singleElement;
singleElement.push_back(0);
vtkm::cont::ArrayHandle<vtkm::Int64> atomicElement = vtkm::cont::make_ArrayHandle(singleElement);
vtkm::exec::AtomicArray<vtkm::Int64, DeviceAdapterTag> atomic(atomicElement);
Algorithm::Schedule(AtomicCASKernel<vtkm::Int64>(atomic), SHORT_ARRAY_SIZE);
vtkm::Int64 expected = vtkm::Int64(atomicCount);
vtkm::Int64 actual= atomicElement.GetPortalControl().Get(0);
VTKM_TEST_ASSERT(expected == actual, "Did not get expected value: Atomic CAS Int64");
}
}
struct TestAll
{
VTKM_CONT void operator()() const
{
std::cout << "Doing DeviceAdapter tests" << std::endl;
TestArrayManagerExecution();
TestOutOfMemory();
TestTimer();
TestRuntime();
TestAlgorithmSchedule();
TestErrorExecution();
TestReduce();
TestReduceWithComparisonObject();
TestReduceWithFancyArrays();
TestReduceByKey();
TestReduceByKeyWithFancyArrays();
TestScanExclusive();
TestScanInclusive();
TestScanInclusiveWithComparisonObject();
TestSort();
TestSortWithComparisonObject();
TestSortWithFancyArrays();
TestSortByKey();
TestLowerBoundsWithComparisonObject();
TestUpperBoundsWithComparisonObject();
TestUniqueWithComparisonObject();
TestOrderedUniqueValues(); //tests Copy, LowerBounds, Sort, Unique
TestCopyIf();
TestCopyArraysMany();
TestCopyArraysInDiffTypes();
TestAtomicArray();
}
};
public:
/// Run a suite of tests to check to see if a DeviceAdapter properly supports
/// all members and classes required for driving vtkm algorithms. Returns an
/// error code that can be returned from the main function of a test.
///
static VTKM_CONT int Run()
{
return vtkm::cont::testing::Testing::Run(TestAll());
}
};
#undef ERROR_MESSAGE
#undef ARRAY_SIZE
#undef OFFSET
#undef DIM
}
}
} // namespace vtkm::cont::testing
#endif //vtk_m_cont_testing_TestingDeviceAdapter_h