mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-08 13:23:51 +00:00
The code in `vtkm/cont/Testing.h` now requires a library, which is not built if testing is not built. Thus, the benchmarking code was giving a compile error if benchmarking was on but testing was off. Change the benchmarking to not rely on anything in the Testing framework. This means using classes in `vtkm/source` instead of `MakeTestData`. Also avoid using the `TestValue` defined for the tests. (In one case, we have a simple replacement.) Also had to fix a problem with a header file not defining everything it needed to compile.
404 lines
12 KiB
C++
404 lines
12 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.
|
|
//============================================================================
|
|
|
|
#include "Benchmarker.h"
|
|
|
|
#include <vtkm/Math.h>
|
|
#include <vtkm/VectorAnalysis.h>
|
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
|
#include <vtkm/cont/CellSetStructured.h>
|
|
#include <vtkm/cont/Invoker.h>
|
|
#include <vtkm/cont/Timer.h>
|
|
#include <vtkm/cont/UncertainArrayHandle.h>
|
|
|
|
#include <vtkm/worklet/WorkletMapField.h>
|
|
#include <vtkm/worklet/WorkletMapTopology.h>
|
|
|
|
#include <cctype>
|
|
#include <random>
|
|
#include <string>
|
|
|
|
namespace
|
|
{
|
|
|
|
#define CUBE_SIZE 256
|
|
|
|
using ValueTypes = vtkm::List<vtkm::UInt32, vtkm::Int32, vtkm::Int64, vtkm::Float32, vtkm::Float64>;
|
|
|
|
using ValueUncertainHandle =
|
|
vtkm::cont::UncertainArrayHandle<ValueTypes, vtkm::cont::StorageListBasic>;
|
|
|
|
// Hold configuration state (e.g. active device)
|
|
vtkm::cont::InitializeResult Config;
|
|
|
|
class AveragePointToCell : public vtkm::worklet::WorkletVisitCellsWithPoints
|
|
{
|
|
public:
|
|
using ControlSignature = void(FieldInPoint inPoints, CellSetIn cellset, FieldOutCell outCells);
|
|
using ExecutionSignature = void(_1, PointCount, _3);
|
|
using InputDomain = _2;
|
|
|
|
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::WorkletVisitPointsWithCells
|
|
{
|
|
public:
|
|
using ControlSignature = void(FieldInCell inCells, CellSetIn topology, FieldOut outPoints);
|
|
using ExecutionSignature = void(_1, _3, CellCount);
|
|
using InputDomain = _2;
|
|
|
|
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 = vtkm::TypeTraits<OutType>::ZeroInitialization();
|
|
if (numCellIDs != 0)
|
|
{
|
|
for (vtkm::IdComponent cellIndex = 0; cellIndex < numCellIDs; ++cellIndex)
|
|
{
|
|
avgVal += static_cast<OutType>(cellValues[cellIndex]);
|
|
}
|
|
avgVal = avgVal / static_cast<OutType>(numCellIDs);
|
|
}
|
|
}
|
|
};
|
|
|
|
// -----------------------------------------------------------------------------
|
|
template <typename T>
|
|
class Classification : public vtkm::worklet::WorkletVisitCellsWithPoints
|
|
{
|
|
public:
|
|
using ControlSignature = void(FieldInPoint inNodes, CellSetIn cellset, FieldOutCell outCaseId);
|
|
using ExecutionSignature = void(_1, _3);
|
|
using InputDomain = _2;
|
|
|
|
T IsoValue;
|
|
|
|
VTKM_CONT
|
|
Classification(T isovalue)
|
|
: IsoValue(isovalue)
|
|
{
|
|
}
|
|
|
|
template <typename FieldInType>
|
|
VTKM_EXEC void operator()(const FieldInType& fieldIn, vtkm::IdComponent& caseNumber) const
|
|
{
|
|
using FieldType = typename vtkm::VecTraits<FieldInType>::ComponentType;
|
|
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);
|
|
}
|
|
};
|
|
|
|
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); }
|
|
};
|
|
|
|
// Returns an extra random value.
|
|
// Like, an additional random value.
|
|
// Not a random value that's somehow "extra random".
|
|
template <typename ArrayT>
|
|
VTKM_CONT typename ArrayT::ValueType FillRandomValues(ArrayT& array,
|
|
vtkm::Id size,
|
|
vtkm::Float64 min,
|
|
vtkm::Float64 max)
|
|
{
|
|
using ValueType = typename ArrayT::ValueType;
|
|
|
|
NumberGenerator<ValueType> generator{ static_cast<ValueType>(min), static_cast<ValueType>(max) };
|
|
array.Allocate(size);
|
|
auto portal = array.WritePortal();
|
|
for (vtkm::Id i = 0; i < size; ++i)
|
|
{
|
|
portal.Set(i, generator.next());
|
|
}
|
|
return generator.next();
|
|
}
|
|
|
|
template <typename Value>
|
|
struct BenchCellToPointAvgImpl
|
|
{
|
|
vtkm::cont::ArrayHandle<Value> Input;
|
|
|
|
::benchmark::State& State;
|
|
vtkm::Id CubeSize;
|
|
vtkm::Id NumCells;
|
|
|
|
vtkm::cont::Timer Timer;
|
|
vtkm::cont::Invoker Invoker;
|
|
|
|
VTKM_CONT
|
|
BenchCellToPointAvgImpl(::benchmark::State& state)
|
|
: State{ state }
|
|
, CubeSize{ CUBE_SIZE }
|
|
, NumCells{ (this->CubeSize - 1) * (this->CubeSize - 1) * (this->CubeSize - 1) }
|
|
, Timer{ Config.Device }
|
|
, Invoker{ Config.Device }
|
|
{
|
|
FillRandomValues(this->Input, this->NumCells, 1., 100.);
|
|
|
|
{ // Configure label:
|
|
std::ostringstream desc;
|
|
desc << "CubeSize:" << this->CubeSize;
|
|
this->State.SetLabel(desc.str());
|
|
}
|
|
}
|
|
|
|
template <typename BenchArrayType>
|
|
VTKM_CONT void Run(const BenchArrayType& input)
|
|
{
|
|
vtkm::cont::CellSetStructured<3> cellSet;
|
|
cellSet.SetPointDimensions(vtkm::Id3{ this->CubeSize, this->CubeSize, this->CubeSize });
|
|
vtkm::cont::ArrayHandle<Value> result;
|
|
|
|
for (auto _ : this->State)
|
|
{
|
|
(void)_;
|
|
this->Timer.Start();
|
|
this->Invoker(AverageCellToPoint{}, input, cellSet, result);
|
|
this->Timer.Stop();
|
|
|
|
this->State.SetIterationTime(this->Timer.GetElapsedTime());
|
|
}
|
|
|
|
// #items = #points
|
|
const int64_t iterations = static_cast<int64_t>(this->State.iterations());
|
|
this->State.SetItemsProcessed(static_cast<int64_t>(cellSet.GetNumberOfPoints()) * iterations);
|
|
}
|
|
};
|
|
|
|
template <typename ValueType>
|
|
void BenchCellToPointAvgStatic(::benchmark::State& state)
|
|
{
|
|
BenchCellToPointAvgImpl<ValueType> impl{ state };
|
|
impl.Run(impl.Input);
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchCellToPointAvgStatic, ValueTypes);
|
|
|
|
template <typename ValueType>
|
|
void BenchCellToPointAvgDynamic(::benchmark::State& state)
|
|
{
|
|
BenchCellToPointAvgImpl<ValueType> impl{ state };
|
|
impl.Run(ValueUncertainHandle{ impl.Input });
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchCellToPointAvgDynamic, ValueTypes);
|
|
|
|
template <typename Value>
|
|
struct BenchPointToCellAvgImpl
|
|
{
|
|
vtkm::cont::ArrayHandle<Value> Input;
|
|
|
|
::benchmark::State& State;
|
|
vtkm::Id CubeSize;
|
|
vtkm::Id NumPoints;
|
|
|
|
vtkm::cont::Timer Timer;
|
|
vtkm::cont::Invoker Invoker;
|
|
|
|
VTKM_CONT
|
|
BenchPointToCellAvgImpl(::benchmark::State& state)
|
|
: State{ state }
|
|
, CubeSize{ CUBE_SIZE }
|
|
, NumPoints{ (this->CubeSize) * (this->CubeSize) * (this->CubeSize) }
|
|
, Timer{ Config.Device }
|
|
, Invoker{ Config.Device }
|
|
{
|
|
FillRandomValues(this->Input, this->NumPoints, 1., 100.);
|
|
|
|
{ // Configure label:
|
|
std::ostringstream desc;
|
|
desc << "CubeSize:" << this->CubeSize;
|
|
this->State.SetLabel(desc.str());
|
|
}
|
|
}
|
|
|
|
template <typename BenchArrayType>
|
|
VTKM_CONT void Run(const BenchArrayType& input)
|
|
{
|
|
vtkm::cont::CellSetStructured<3> cellSet;
|
|
cellSet.SetPointDimensions(vtkm::Id3{ this->CubeSize, this->CubeSize, this->CubeSize });
|
|
vtkm::cont::ArrayHandle<Value> result;
|
|
|
|
for (auto _ : this->State)
|
|
{
|
|
(void)_;
|
|
this->Timer.Start();
|
|
this->Invoker(AveragePointToCell{}, input, cellSet, result);
|
|
this->Timer.Stop();
|
|
|
|
this->State.SetIterationTime(this->Timer.GetElapsedTime());
|
|
}
|
|
|
|
// #items = #cells
|
|
const int64_t iterations = static_cast<int64_t>(this->State.iterations());
|
|
this->State.SetItemsProcessed(static_cast<int64_t>(cellSet.GetNumberOfCells()) * iterations);
|
|
}
|
|
};
|
|
|
|
template <typename ValueType>
|
|
void BenchPointToCellAvgStatic(::benchmark::State& state)
|
|
{
|
|
BenchPointToCellAvgImpl<ValueType> impl{ state };
|
|
impl.Run(impl.Input);
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchPointToCellAvgStatic, ValueTypes);
|
|
|
|
template <typename ValueType>
|
|
void BenchPointToCellAvgDynamic(::benchmark::State& state)
|
|
{
|
|
BenchPointToCellAvgImpl<ValueType> impl{ state };
|
|
impl.Run(ValueUncertainHandle{ impl.Input });
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchPointToCellAvgDynamic, ValueTypes);
|
|
|
|
template <typename Value>
|
|
struct BenchClassificationImpl
|
|
{
|
|
vtkm::cont::ArrayHandle<Value> Input;
|
|
|
|
::benchmark::State& State;
|
|
vtkm::Id CubeSize;
|
|
vtkm::Id DomainSize;
|
|
Value IsoValue;
|
|
|
|
vtkm::cont::Timer Timer;
|
|
vtkm::cont::Invoker Invoker;
|
|
|
|
VTKM_CONT
|
|
BenchClassificationImpl(::benchmark::State& state)
|
|
: State{ state }
|
|
, CubeSize{ CUBE_SIZE }
|
|
, DomainSize{ this->CubeSize * this->CubeSize * this->CubeSize }
|
|
, Timer{ Config.Device }
|
|
, Invoker{ Config.Device }
|
|
{
|
|
this->IsoValue = FillRandomValues(this->Input, this->DomainSize, 1., 100.);
|
|
|
|
{ // Configure label:
|
|
std::ostringstream desc;
|
|
desc << "CubeSize:" << this->CubeSize;
|
|
this->State.SetLabel(desc.str());
|
|
}
|
|
}
|
|
|
|
template <typename BenchArrayType>
|
|
VTKM_CONT void Run(const BenchArrayType& input)
|
|
{
|
|
vtkm::cont::CellSetStructured<3> cellSet;
|
|
cellSet.SetPointDimensions(vtkm::Id3{ this->CubeSize, this->CubeSize, this->CubeSize });
|
|
vtkm::cont::ArrayHandle<vtkm::IdComponent> result;
|
|
|
|
Classification<Value> worklet(this->IsoValue);
|
|
|
|
for (auto _ : this->State)
|
|
{
|
|
(void)_;
|
|
this->Timer.Start();
|
|
this->Invoker(worklet, input, cellSet, result);
|
|
this->Timer.Stop();
|
|
|
|
this->State.SetIterationTime(this->Timer.GetElapsedTime());
|
|
}
|
|
|
|
// #items = #cells
|
|
const int64_t iterations = static_cast<int64_t>(this->State.iterations());
|
|
this->State.SetItemsProcessed(static_cast<int64_t>(cellSet.GetNumberOfCells()) * iterations);
|
|
}
|
|
};
|
|
|
|
template <typename ValueType>
|
|
void BenchClassificationStatic(::benchmark::State& state)
|
|
{
|
|
BenchClassificationImpl<ValueType> impl{ state };
|
|
impl.Run(impl.Input);
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchClassificationStatic, ValueTypes);
|
|
|
|
template <typename ValueType>
|
|
void BenchClassificationDynamic(::benchmark::State& state)
|
|
{
|
|
BenchClassificationImpl<ValueType> impl{ state };
|
|
impl.Run(ValueUncertainHandle{ impl.Input });
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchClassificationDynamic, ValueTypes);
|
|
|
|
} // end anon namespace
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
// Parse VTK-m options:
|
|
auto opts = vtkm::cont::InitializeOptions::RequireDevice;
|
|
|
|
std::vector<char*> args(argv, argv + argc);
|
|
vtkm::bench::detail::InitializeArgs(&argc, args, opts);
|
|
|
|
// Parse VTK-m options:
|
|
Config = vtkm::cont::Initialize(argc, args.data(), opts);
|
|
|
|
// This occurs when it is help
|
|
if (opts == vtkm::cont::InitializeOptions::None)
|
|
{
|
|
std::cout << Config.Usage << std::endl;
|
|
}
|
|
else
|
|
{
|
|
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(Config.Device);
|
|
}
|
|
|
|
// handle benchmarking related args and run benchmarks:
|
|
VTKM_EXECUTE_BENCHMARKS(argc, args.data());
|
|
}
|