//============================================================================ // 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 #include #include #include #include #include #include #include #include #include #include #include namespace { #define CUBE_SIZE 256 using ValueTypes = vtkm::List; using ValueUncertainHandle = vtkm::cont::UncertainArrayHandle; // 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 VTKM_EXEC void operator()(const PointValueVecType& pointValues, const vtkm::IdComponent& numPoints, OutType& average) const { OutType sum = static_cast(pointValues[0]); for (vtkm::IdComponent pointIndex = 1; pointIndex < numPoints; ++pointIndex) { sum = sum + static_cast(pointValues[pointIndex]); } average = sum / static_cast(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 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::ZeroInitialization(); if (numCellIDs != 0) { for (vtkm::IdComponent cellIndex = 0; cellIndex < numCellIDs; ++cellIndex) { avgVal += static_cast(cellValues[cellIndex]); } avgVal = avgVal / static_cast(numCellIDs); } } }; // ----------------------------------------------------------------------------- template 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 VTKM_EXEC void operator()(const FieldInType& fieldIn, vtkm::IdComponent& caseNumber) const { using FieldType = typename vtkm::VecTraits::ComponentType; const FieldType iso = static_cast(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 struct NumberGenerator { }; template struct NumberGenerator::value>::type> { std::mt19937 rng; std::uniform_real_distribution distribution; NumberGenerator(T low, T high) : rng() , distribution(low, high) { } T next() { return distribution(rng); } }; template struct NumberGenerator::value>::type> { std::mt19937 rng; std::uniform_int_distribution 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 VTKM_CONT typename ArrayT::ValueType FillRandomValues(ArrayT& array, vtkm::Id size, vtkm::Float64 min, vtkm::Float64 max) { using ValueType = typename ArrayT::ValueType; NumberGenerator generator{ static_cast(min), static_cast(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 struct BenchCellToPointAvgImpl { vtkm::cont::ArrayHandle 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 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 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(this->State.iterations()); this->State.SetItemsProcessed(static_cast(cellSet.GetNumberOfPoints()) * iterations); } }; template void BenchCellToPointAvgStatic(::benchmark::State& state) { BenchCellToPointAvgImpl impl{ state }; impl.Run(impl.Input); }; VTKM_BENCHMARK_TEMPLATES(BenchCellToPointAvgStatic, ValueTypes); template void BenchCellToPointAvgDynamic(::benchmark::State& state) { BenchCellToPointAvgImpl impl{ state }; impl.Run(ValueUncertainHandle{ impl.Input }); }; VTKM_BENCHMARK_TEMPLATES(BenchCellToPointAvgDynamic, ValueTypes); template struct BenchPointToCellAvgImpl { vtkm::cont::ArrayHandle 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 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 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(this->State.iterations()); this->State.SetItemsProcessed(static_cast(cellSet.GetNumberOfCells()) * iterations); } }; template void BenchPointToCellAvgStatic(::benchmark::State& state) { BenchPointToCellAvgImpl impl{ state }; impl.Run(impl.Input); }; VTKM_BENCHMARK_TEMPLATES(BenchPointToCellAvgStatic, ValueTypes); template void BenchPointToCellAvgDynamic(::benchmark::State& state) { BenchPointToCellAvgImpl impl{ state }; impl.Run(ValueUncertainHandle{ impl.Input }); }; VTKM_BENCHMARK_TEMPLATES(BenchPointToCellAvgDynamic, ValueTypes); template struct BenchClassificationImpl { vtkm::cont::ArrayHandle 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 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 result; Classification 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(this->State.iterations()); this->State.SetItemsProcessed(static_cast(cellSet.GetNumberOfCells()) * iterations); } }; template void BenchClassificationStatic(::benchmark::State& state) { BenchClassificationImpl impl{ state }; impl.Run(impl.Input); }; VTKM_BENCHMARK_TEMPLATES(BenchClassificationStatic, ValueTypes); template void BenchClassificationDynamic(::benchmark::State& state) { BenchClassificationImpl 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 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()); }