vtk-m/vtkm/benchmarking/BenchmarkTopologyAlgorithms.cxx
2017-03-09 14:51:45 -07:00

503 lines
15 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.
//============================================================================
#include <vtkm/Math.h>
#include <vtkm/VectorAnalysis.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/CellSetStructured.h>
#include <vtkm/cont/Timer.h>
#include <vtkm/worklet/WorkletMapField.h>
#include <vtkm/worklet/WorkletMapTopology.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
#include <vtkm/cont/testing/Testing.h>
#include <vtkm/benchmarking/Benchmarker.h>
#include <random>
#include <string>
namespace vtkm {
namespace benchmarking {
#define CUBE_SIZE 256
const static std::string DIVIDER(40, '-');
enum BenchmarkName {
CELL_TO_POINT = 1 << 1,
POINT_TO_CELL = 1 << 2,
MC_CLASSIFY = 1 << 3,
ALL = CELL_TO_POINT |
POINT_TO_CELL |
MC_CLASSIFY
};
class AveragePointToCell : public vtkm::worklet::WorkletMapPointToCell
{
public:
typedef void ControlSignature(FieldInPoint<> inPoints,
CellSetIn cellset,
FieldOutCell<> outCells);
typedef void ExecutionSignature(_1, PointCount, _3);
typedef _2 InputDomain;
template<typename PointValueVecType, typename OutType>
VTKM_EXEC
void operator()(const PointValueVecType &pointValues,
const vtkm::IdComponent &numPoints,
OutType &average) const
{
OutType sum = static_cast<OutType>(pointValues[0]);
for (vtkm::IdComponent pointIndex = 1; pointIndex < numPoints; ++pointIndex)
{
sum = sum + static_cast<OutType>(pointValues[pointIndex]);
}
average = sum / static_cast<OutType>(numPoints);
}
};
class AverageCellToPoint : public vtkm::worklet::WorkletMapCellToPoint
{
public:
typedef void ControlSignature(FieldInCell<> inCells,
CellSetIn topology,
FieldOut<> outPoints);
typedef void ExecutionSignature(_1, _3, CellCount);
typedef _2 InputDomain;
template<typename CellVecType, typename OutType>
VTKM_EXEC
void operator()(const CellVecType &cellValues,
OutType &avgVal,
const vtkm::IdComponent &numCellIDs) const
{
//simple functor that returns the average cell Value.
avgVal = static_cast<OutType>(cellValues[0]);
for (vtkm::IdComponent cellIndex = 1; cellIndex < numCellIDs; ++cellIndex)
{
avgVal += static_cast<OutType>(cellValues[cellIndex]);
}
avgVal = avgVal / static_cast<OutType>(numCellIDs);
}
};
// -----------------------------------------------------------------------------
template<typename T>
class Classification : public vtkm::worklet::WorkletMapPointToCell
{
public:
typedef void ControlSignature(
FieldInPoint<> inNodes,
CellSetIn cellset,
FieldOutCell< IdComponentType > outCaseId);
typedef void ExecutionSignature(_1, _3);
typedef _2 InputDomain;
T IsoValue;
VTKM_CONT
Classification(T isovalue) :
IsoValue(isovalue)
{
}
template<typename FieldInType>
VTKM_EXEC
void operator()(const FieldInType &fieldIn,
vtkm::IdComponent &caseNumber) const
{
typedef typename vtkm::VecTraits<FieldInType>::ComponentType FieldType;
const FieldType iso = static_cast<FieldType>(this->IsoValue);
caseNumber= ((fieldIn[0] > iso) |
(fieldIn[1] > iso) << 1 |
(fieldIn[2] > iso) << 2 |
(fieldIn[3] > iso) << 3 |
(fieldIn[4] > iso) << 4 |
(fieldIn[5] > iso) << 5 |
(fieldIn[6] > iso) << 6 |
(fieldIn[7] > iso) << 7);
}
};
struct ValueTypes : vtkm::ListTagBase<vtkm::UInt32, vtkm::Int32, vtkm::Int64,
vtkm::Float32, vtkm::Float64 >{};
using StorageListTag = ::vtkm::cont::StorageListTagBasic;
/// This class runs a series of micro-benchmarks to measure
/// performance of different field operations
template<class DeviceAdapterTag>
class BenchmarkTopologyAlgorithms {
typedef vtkm::cont::StorageTagBasic StorageTag;
typedef vtkm::cont::DeviceAdapterAlgorithm<DeviceAdapterTag> Algorithm;
typedef vtkm::cont::Timer<DeviceAdapterTag> Timer;
using ValueDynamicHandle =
vtkm::cont::DynamicArrayHandleBase<ValueTypes, StorageListTag>;
private:
template<typename T, typename Enable= void> struct NumberGenerator {};
template<typename T>
struct NumberGenerator<T,
typename std::enable_if<
std::is_floating_point<T>::value
>::type
>
{
std::mt19937 rng;
std::uniform_real_distribution<T> distribution;
NumberGenerator(T low, T high): rng(), distribution(low,high) {}
T next() { return distribution(rng); }
};
template<typename T>
struct NumberGenerator<T,
typename std::enable_if<
!std::is_floating_point<T>::value
>::type
>
{
std::mt19937 rng;
std::uniform_int_distribution<T> distribution;
NumberGenerator(T low, T high): rng(), distribution(low,high) {}
T next() { return distribution(rng); }
};
template<typename Value>
struct BenchCellToPointAvg {
std::vector< Value > input;
vtkm::cont::ArrayHandle< Value, StorageTag> InputHandle;
std::size_t DomainSize;
VTKM_CONT
BenchCellToPointAvg()
{
NumberGenerator<Value> generator(static_cast<Value>(1.0),
static_cast<Value>(100.0));
//cube size is points in each dim
this->DomainSize = (CUBE_SIZE-1)*(CUBE_SIZE-1)*(CUBE_SIZE-1);
this->input.resize( DomainSize );
for(std::size_t i=0; i < DomainSize; ++i )
{
this->input[i] = generator.next();
}
this->InputHandle = vtkm::cont::make_ArrayHandle(this->input);
}
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions( vtkm::Id3(CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) );
vtkm::cont::ArrayHandle<Value,StorageTag> result;
Timer timer;
vtkm::worklet::DispatcherMapTopology< AverageCellToPoint > dispatcher;
dispatcher.Invoke( this->InputHandle,
cellSet,
result);
//result.SyncControlArray();
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Static"); }
VTKM_CONT
std::string Description() const {
std::stringstream description;
description << "Computing Cell To Point Average "
<< "[" << this->Type() << "] "
<< "with a domain size of: " << this->DomainSize;
return description.str();
}
};
template<typename Value>
struct BenchCellToPointAvgDynamic : public BenchCellToPointAvg<Value> {
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions( vtkm::Id3(CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) );
ValueDynamicHandle dinput(this->InputHandle);
vtkm::cont::ArrayHandle<Value,StorageTag> result;
Timer timer;
vtkm::worklet::DispatcherMapTopology< AverageCellToPoint > dispatcher;
dispatcher.Invoke( dinput,
cellSet,
result);
//result.SyncControlArray();
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Dynamic"); }
};
VTKM_MAKE_BENCHMARK(CellToPointAvg, BenchCellToPointAvg);
VTKM_MAKE_BENCHMARK(CellToPointAvgDynamic, BenchCellToPointAvgDynamic);
template<typename Value>
struct BenchPointToCellAvg {
std::vector< Value > input;
vtkm::cont::ArrayHandle< Value, StorageTag> InputHandle;
std::size_t DomainSize;
VTKM_CONT
BenchPointToCellAvg()
{
NumberGenerator<Value> generator(static_cast<Value>(1.0),
static_cast<Value>(100.0));
this->DomainSize = (CUBE_SIZE)*(CUBE_SIZE)*(CUBE_SIZE);
this->input.resize( DomainSize );
for(std::size_t i=0; i < DomainSize; ++i )
{
this->input[i] = generator.next();
}
this->InputHandle = vtkm::cont::make_ArrayHandle(this->input);
}
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions( vtkm::Id3(CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) );
vtkm::cont::ArrayHandle<Value,StorageTag> result;
Timer timer;
vtkm::worklet::DispatcherMapTopology< AveragePointToCell > dispatcher;
dispatcher.Invoke( this->InputHandle,
cellSet,
result);
//result.SyncControlArray();
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Static"); }
VTKM_CONT
std::string Description() const {
std::stringstream description;
description << "Computing Point To Cell Average "
<< "[" << this->Type() << "] "
<< "with a domain size of: " << this->DomainSize;
return description.str();
}
};
template<typename Value>
struct BenchPointToCellAvgDynamic : public BenchPointToCellAvg<Value> {
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions( vtkm::Id3(CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) );
ValueDynamicHandle dinput(this->InputHandle);
vtkm::cont::ArrayHandle<Value,StorageTag> result;
Timer timer;
vtkm::worklet::DispatcherMapTopology< AveragePointToCell > dispatcher;
dispatcher.Invoke( dinput,
cellSet,
result);
//result.SyncControlArray();
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Dynamic"); }
};
VTKM_MAKE_BENCHMARK(PointToCellAvg, BenchPointToCellAvg);
VTKM_MAKE_BENCHMARK(PointToCellAvgDynamic, BenchPointToCellAvgDynamic);
template<typename Value>
struct BenchClassification {
std::vector< Value > input;
vtkm::cont::ArrayHandle< Value, StorageTag> InputHandle;
Value IsoValue;
size_t DomainSize;
VTKM_CONT
BenchClassification()
{
NumberGenerator<Value> generator(static_cast<Value>(1.0),
static_cast<Value>(100.0));
this->DomainSize = (CUBE_SIZE)*(CUBE_SIZE)*(CUBE_SIZE);
this->input.resize( DomainSize );
for(std::size_t i=0; i < DomainSize; ++i )
{
this->input[i] = generator.next();
}
this->InputHandle = vtkm::cont::make_ArrayHandle(this->input);
this->IsoValue = generator.next();
}
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions( vtkm::Id3(CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) );
vtkm::cont::ArrayHandle< vtkm::IdComponent, StorageTag> result;
ValueDynamicHandle dinput(this->InputHandle);
Timer timer;
Classification<Value> worklet(this->IsoValue);
vtkm::worklet::DispatcherMapTopology< Classification<Value> > dispatcher(worklet);
dispatcher.Invoke( dinput,
cellSet,
result);
//result.SyncControlArray();
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Static"); }
VTKM_CONT
std::string Description() const {
std::stringstream description;
description << "Computing Marching Cubes Classification "
<< "[" << this->Type() << "] "
<< "with a domain size of: " << this->DomainSize;
return description.str();
}
};
template<typename Value>
struct BenchClassificationDynamic : public BenchClassification<Value> {
VTKM_CONT
vtkm::Float64 operator()()
{
vtkm::cont::CellSetStructured<3> cellSet;
cellSet.SetPointDimensions( vtkm::Id3(CUBE_SIZE,CUBE_SIZE,CUBE_SIZE) );
vtkm::cont::ArrayHandle< vtkm::IdComponent, StorageTag> result;
Timer timer;
Classification<Value> worklet(this->IsoValue);
vtkm::worklet::DispatcherMapTopology< Classification<Value> > dispatcher(worklet);
dispatcher.Invoke( this->InputHandle,
cellSet,
result);
//result.SyncControlArray();
return timer.GetElapsedTime();
}
virtual std::string Type() const { return std::string("Dynamic"); }
};
VTKM_MAKE_BENCHMARK(Classification, BenchClassification);
VTKM_MAKE_BENCHMARK(ClassificationDynamic, BenchClassificationDynamic);
public:
static VTKM_CONT int Run(int benchmarks){
std::cout << DIVIDER << "\nRunning Topology Algorithm benchmarks\n";
if (benchmarks & CELL_TO_POINT) {
std::cout << DIVIDER << "\nBenchmarking Cell To Point Average\n";
VTKM_RUN_BENCHMARK(CellToPointAvg, ValueTypes());
VTKM_RUN_BENCHMARK(CellToPointAvgDynamic, ValueTypes());
}
if (benchmarks & POINT_TO_CELL){
std::cout << DIVIDER << "\nBenchmarking Point to Cell Average\n";
VTKM_RUN_BENCHMARK(PointToCellAvg, ValueTypes());
VTKM_RUN_BENCHMARK(PointToCellAvgDynamic, ValueTypes());
}
if (benchmarks & MC_CLASSIFY){
std::cout << DIVIDER << "\nBenchmarking Hex/Voxel MC Classification\n";
VTKM_RUN_BENCHMARK(Classification, ValueTypes());
VTKM_RUN_BENCHMARK(ClassificationDynamic, ValueTypes());
}
return 0;
}
};
#undef ARRAY_SIZE
}
} // namespace vtkm::benchmarking
int main(int argc, char *argv[])
{
int benchmarks = 0;
if (argc < 2){
benchmarks = vtkm::benchmarking::ALL;
}
else {
for (int i = 1; i < argc; ++i){
std::string arg = argv[i];
std::transform(arg.begin(), arg.end(), arg.begin(), ::tolower);
if (arg == "celltopoint")
{
benchmarks |= vtkm::benchmarking::CELL_TO_POINT;
}
else if (arg == "pointtocell")
{
benchmarks |= vtkm::benchmarking::POINT_TO_CELL;
}
else if (arg == "classify")
{
benchmarks |= vtkm::benchmarking::MC_CLASSIFY;
}
else {
std::cout << "Unrecognized benchmark: " << argv[i] << std::endl;
return 1;
}
}
}
//now actually execute the benchmarks
return vtkm::benchmarking::BenchmarkTopologyAlgorithms
<VTKM_DEFAULT_DEVICE_ADAPTER_TAG>::Run(benchmarks);
}