//============================================================================ // 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 National Technology & Engineering Solutions of Sandia, LLC (NTESS). // Copyright 2014 UT-Battelle, LLC. // Copyright 2014 Los Alamos National Security. // // Under the terms of Contract DE-NA0003525 with NTESS, // 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "Benchmarker.h" #include #include #include #include namespace vtkm { namespace benchmarking { #define ARRAY_SIZE (1 << 22) #define CUBE_SIZE 256 static const std::string DIVIDER(40, '-'); enum BenchmarkName { BLACK_SCHOLES = 1, MATH = 1 << 1, FUSED_MATH = 1 << 2, INTERPOLATE_FIELD = 1 << 3, IMPLICIT_FUNCTION = 1 << 4, ALL = BLACK_SCHOLES | MATH | FUSED_MATH | INTERPOLATE_FIELD | IMPLICIT_FUNCTION }; template class BlackScholes : public vtkm::worklet::WorkletMapField { T Riskfree; T Volatility; public: using ControlSignature = void(FieldIn, FieldIn, FieldIn, FieldOut, FieldOut); using ExecutionSignature = void(_1, _2, _3, _4, _5); BlackScholes(T risk, T volatility) : Riskfree(risk) , Volatility(volatility) { } VTKM_EXEC T CumulativeNormalDistribution(T d) const { const vtkm::Float32 A1 = 0.31938153f; const vtkm::Float32 A2 = -0.356563782f; const vtkm::Float32 A3 = 1.781477937f; const vtkm::Float32 A4 = -1.821255978f; const vtkm::Float32 A5 = 1.330274429f; const vtkm::Float32 RSQRT2PI = 0.39894228040143267793994605993438f; const vtkm::Float32 df = static_cast(d); const vtkm::Float32 K = 1.0f / (1.0f + 0.2316419f * vtkm::Abs(df)); vtkm::Float32 cnd = RSQRT2PI * vtkm::Exp(-0.5f * df * df) * (K * (A1 + K * (A2 + K * (A3 + K * (A4 + K * A5))))); if (df > 0.0f) { cnd = 1.0f - cnd; } return static_cast(cnd); } template VTKM_EXEC void operator()(const U& sp, const V& os, const W& oy, T& callResult, T& putResult) const { const T stockPrice = static_cast(sp); const T optionStrike = static_cast(os); const T optionYears = static_cast(oy); // Black-Scholes formula for both call and put const T sqrtYears = vtkm::Sqrt(optionYears); const T volMultSqY = this->Volatility * sqrtYears; const T d1 = (vtkm::Log(stockPrice / optionStrike) + (this->Riskfree + 0.5f * Volatility * Volatility) * optionYears) / (volMultSqY); const T d2 = d1 - volMultSqY; const T CNDD1 = CumulativeNormalDistribution(d1); const T CNDD2 = CumulativeNormalDistribution(d2); //Calculate Call and Put simultaneously T expRT = vtkm::Exp(-this->Riskfree * optionYears); callResult = stockPrice * CNDD1 - optionStrike * expRT * CNDD2; putResult = optionStrike * expRT * (1.0f - CNDD2) - stockPrice * (1.0f - CNDD1); } }; class Mag : public vtkm::worklet::WorkletMapField { public: using ControlSignature = void(FieldIn, FieldOut); using ExecutionSignature = void(_1, _2); template VTKM_EXEC void operator()(const vtkm::Vec& vec, U& result) const { result = static_cast(vtkm::Magnitude(vec)); } }; class Square : public vtkm::worklet::WorkletMapField { public: using ControlSignature = void(FieldIn, FieldOut); using ExecutionSignature = void(_1, _2); template VTKM_EXEC void operator()(T input, U& output) const { output = static_cast(input * input); } }; class Sin : public vtkm::worklet::WorkletMapField { public: using ControlSignature = void(FieldIn, FieldOut); using ExecutionSignature = void(_1, _2); template VTKM_EXEC void operator()(T input, U& output) const { output = static_cast(vtkm::Sin(input)); } }; class Cos : public vtkm::worklet::WorkletMapField { public: using ControlSignature = void(FieldIn, FieldOut); using ExecutionSignature = void(_1, _2); template VTKM_EXEC void operator()(T input, U& output) const { output = static_cast(vtkm::Cos(input)); } }; class FusedMath : public vtkm::worklet::WorkletMapField { public: using ControlSignature = void(FieldIn, FieldOut); using ExecutionSignature = void(_1, _2); template VTKM_EXEC void operator()(const vtkm::Vec& vec, T& result) const { const T m = vtkm::Magnitude(vec); result = vtkm::Cos(vtkm::Sin(m) * vtkm::Sin(m)); } template VTKM_EXEC void operator()(const vtkm::Vec&, U&) const { this->RaiseError("Mixed types unsupported."); } }; class GenerateEdges : public vtkm::worklet::WorkletMapPointToCell { public: using ControlSignature = void(CellSetIn cellset, WholeArrayOut edgeIds); using ExecutionSignature = void(PointIndices, ThreadIndices, _2); using InputDomain = _1; template VTKM_EXEC void operator()(const ConnectivityInVec& connectivity, const ThreadIndicesType threadIndices, const IdPairTableType& edgeIds) const { const vtkm::Id writeOffset = (threadIndices.GetInputIndex() * 12); const vtkm::IdComponent edgeTable[24] = { 0, 1, 1, 2, 3, 2, 0, 3, 4, 5, 5, 6, 7, 6, 4, 7, 0, 4, 1, 5, 2, 6, 3, 7 }; for (vtkm::Id i = 0; i < 12; ++i) { const vtkm::Id offset = (i * 2); const vtkm::Id2 edge(connectivity[edgeTable[offset]], connectivity[edgeTable[offset + 1]]); edgeIds.Set(writeOffset + i, edge); } } }; class InterpolateField : public vtkm::worklet::WorkletMapField { public: using ControlSignature = void(FieldIn interpolation_ids, FieldIn interpolation_weights, WholeArrayIn inputField, FieldOut output); using ExecutionSignature = void(_1, _2, _3, _4); using InputDomain = _1; template VTKM_EXEC void operator()(const vtkm::Id2& low_high, const WeightType& weight, const vtkm::exec::ExecutionWholeArrayConst& inPortal, T& result) const { //fetch the low / high values from inPortal result = vtkm::Lerp(inPortal.Get(low_high[0]), inPortal.Get(low_high[1]), weight); } template VTKM_EXEC void operator()(const vtkm::Id2&, const WeightType&, const vtkm::exec::ExecutionWholeArrayConst&, U&) const { //the inPortal and result need to be the same type so this version only //exists to generate code when using dynamic arrays this->RaiseError("Mixed types unsupported."); } }; template class EvaluateImplicitFunction : public vtkm::worklet::WorkletMapField { public: using ControlSignature = void(FieldIn, FieldOut); using ExecutionSignature = void(_1, _2); EvaluateImplicitFunction(const ImplicitFunction* function) : Function(function) { } template VTKM_EXEC void operator()(const VecType& point, ScalarType& val) const { val = this->Function->Value(point); } private: const ImplicitFunction* Function; }; template class Evaluate2ImplicitFunctions : public vtkm::worklet::WorkletMapField { public: using ControlSignature = void(FieldIn, FieldOut); using ExecutionSignature = void(_1, _2); Evaluate2ImplicitFunctions(const T1* f1, const T2* f2) : Function1(f1) , Function2(f2) { } template VTKM_EXEC void operator()(const VecType& point, ScalarType& val) const { val = this->Function1->Value(point) + this->Function2->Value(point); } private: const T1* Function1; const T2* Function2; }; struct ValueTypes : vtkm::ListTagBase { }; struct InterpValueTypes : vtkm::ListTagBase> { }; /// This class runs a series of micro-benchmarks to measure /// performance of different field operations class BenchmarkFieldAlgorithms { using StorageTag = vtkm::cont::StorageTagBasic; using Timer = vtkm::cont::Timer; using ValueVariantHandle = vtkm::cont::VariantArrayHandleBase; using InterpVariantHandle = vtkm::cont::VariantArrayHandleBase; using EdgeIdVariantHandle = vtkm::cont::VariantArrayHandleBase; private: template struct BenchBlackScholes { using ValueArrayHandle = vtkm::cont::ArrayHandle; ValueArrayHandle StockPrice; ValueArrayHandle OptionStrike; ValueArrayHandle OptionYears; std::vector price; std::vector strike; std::vector years; VTKM_CONT BenchBlackScholes() { std::mt19937 rng; std::uniform_real_distribution price_range(Value(5.0f), Value(30.0f)); std::uniform_real_distribution strike_range(Value(1.0f), Value(100.0f)); std::uniform_real_distribution year_range(Value(0.25f), Value(10.0f)); this->price.resize(ARRAY_SIZE); this->strike.resize(ARRAY_SIZE); this->years.resize(ARRAY_SIZE); for (std::size_t i = 0; i < ARRAY_SIZE; ++i) { this->price[i] = price_range(rng); this->strike[i] = strike_range(rng); this->years[i] = year_range(rng); } this->StockPrice = vtkm::cont::make_ArrayHandle(this->price); this->OptionStrike = vtkm::cont::make_ArrayHandle(this->strike); this->OptionYears = vtkm::cont::make_ArrayHandle(this->years); } VTKM_CONT vtkm::Float64 operator()() { vtkm::cont::ArrayHandle callResultHandle, putResultHandle; const Value RISKFREE = 0.02f; const Value VOLATILITY = 0.30f; Timer timer{ DeviceAdapter() }; timer.Start(); BlackScholes worklet(RISKFREE, VOLATILITY); vtkm::worklet::DispatcherMapField> dispatcher(worklet); dispatcher.Invoke( this->StockPrice, this->OptionStrike, this->OptionYears, callResultHandle, putResultHandle); return timer.GetElapsedTime(); } virtual std::string Type() const { return std::string("Static"); } VTKM_CONT std::string Description() const { std::stringstream description; description << "BlackScholes " << "[" << this->Type() << "] " << " with a domain size of: " << ARRAY_SIZE; return description.str(); } }; template struct BenchBlackScholesDynamic : public BenchBlackScholes { VTKM_CONT vtkm::Float64 operator()() { ValueVariantHandle dstocks(this->StockPrice); ValueVariantHandle dstrikes(this->OptionStrike); ValueVariantHandle doptions(this->OptionYears); vtkm::cont::ArrayHandle callResultHandle, putResultHandle; const Value RISKFREE = 0.02f; const Value VOLATILITY = 0.30f; Timer timer{ DeviceAdapter() }; timer.Start(); BlackScholes worklet(RISKFREE, VOLATILITY); vtkm::worklet::DispatcherMapField> dispatcher(worklet); dispatcher.Invoke(dstocks, dstrikes, doptions, callResultHandle, putResultHandle); return timer.GetElapsedTime(); } virtual std::string Type() const { return std::string("Dynamic"); } }; VTKM_MAKE_BENCHMARK(BlackScholes, BenchBlackScholes); VTKM_MAKE_BENCHMARK(BlackScholesDynamic, BenchBlackScholesDynamic); template struct BenchMath { std::vector> input; vtkm::cont::ArrayHandle, StorageTag> InputHandle; VTKM_CONT BenchMath() { std::mt19937 rng; std::uniform_real_distribution range; this->input.resize(ARRAY_SIZE); for (std::size_t i = 0; i < ARRAY_SIZE; ++i) { this->input[i] = vtkm::Vec(range(rng), range(rng), range(rng)); } this->InputHandle = vtkm::cont::make_ArrayHandle(this->input); } VTKM_CONT vtkm::Float64 operator()() { vtkm::cont::ArrayHandle tempHandle1; vtkm::cont::ArrayHandle tempHandle2; Timer timer{ DeviceAdapter() }; timer.Start(); vtkm::worklet::Invoker invoke(DeviceAdapter{}); invoke(Mag{}, this->InputHandle, tempHandle1); invoke(Sin{}, tempHandle1, tempHandle2); invoke(Square{}, tempHandle2, tempHandle1); invoke(Cos{}, tempHandle1, tempHandle2); return timer.GetElapsedTime(); } virtual std::string Type() const { return std::string("Static"); } VTKM_CONT std::string Description() const { std::stringstream description; description << "Magnitude -> Sine -> Square -> Cosine " << "[" << this->Type() << "] " << "with a domain size of: " << ARRAY_SIZE; return description.str(); } }; template struct BenchMathDynamic : public BenchMath { VTKM_CONT vtkm::Float64 operator()() { using MathTypes = vtkm::ListTagBase, vtkm::Vec>; vtkm::cont::ArrayHandle temp1; vtkm::cont::ArrayHandle temp2; vtkm::cont::VariantArrayHandleBase dinput(this->InputHandle); ValueVariantHandle dtemp1(temp1); ValueVariantHandle dtemp2(temp2); Timer timer{ DeviceAdapter() }; timer.Start(); vtkm::worklet::Invoker invoke(DeviceAdapter{}); invoke(Mag{}, dinput, dtemp1); invoke(Sin{}, dtemp1, dtemp2); invoke(Square{}, dtemp2, dtemp1); invoke(Cos{}, dtemp1, dtemp2); return timer.GetElapsedTime(); } virtual std::string Type() const { return std::string("Dynamic"); } }; VTKM_MAKE_BENCHMARK(Math, BenchMath); VTKM_MAKE_BENCHMARK(MathDynamic, BenchMathDynamic); template struct BenchFusedMath { std::vector> input; vtkm::cont::ArrayHandle, StorageTag> InputHandle; VTKM_CONT BenchFusedMath() { std::mt19937 rng; std::uniform_real_distribution range; this->input.resize(ARRAY_SIZE); for (std::size_t i = 0; i < ARRAY_SIZE; ++i) { this->input[i] = vtkm::Vec(range(rng), range(rng), range(rng)); } this->InputHandle = vtkm::cont::make_ArrayHandle(this->input); } VTKM_CONT vtkm::Float64 operator()() { vtkm::cont::ArrayHandle result; Timer timer{ DeviceAdapter() }; timer.Start(); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(this->InputHandle, result); return timer.GetElapsedTime(); } virtual std::string Type() const { return std::string("Static"); } VTKM_CONT std::string Description() const { std::stringstream description; description << "Fused Magnitude -> Sine -> Square -> Cosine " << "[" << this->Type() << "] " << "with a domain size of: " << ARRAY_SIZE; return description.str(); } }; template struct BenchFusedMathDynamic : public BenchFusedMath { VTKM_CONT vtkm::Float64 operator()() { using MathTypes = vtkm::ListTagBase, vtkm::Vec>; vtkm::cont::VariantArrayHandleBase dinput(this->InputHandle); vtkm::cont::ArrayHandle result; Timer timer{ DeviceAdapter() }; timer.Start(); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(dinput, result); return timer.GetElapsedTime(); } virtual std::string Type() const { return std::string("Dynamic"); } }; VTKM_MAKE_BENCHMARK(FusedMath, BenchFusedMath); VTKM_MAKE_BENCHMARK(FusedMathDynamic, BenchFusedMathDynamic); template struct BenchEdgeInterp { std::vector weight; std::vector field; vtkm::cont::ArrayHandle WeightHandle; vtkm::cont::ArrayHandle FieldHandle; vtkm::cont::ArrayHandle EdgePairHandle; VTKM_CONT BenchEdgeInterp() { using CT = typename vtkm::VecTraits::ComponentType; std::mt19937 rng; std::uniform_real_distribution weight_range(0.0f, 1.0f); std::uniform_real_distribution field_range; //basically the core challenge is to generate an array whose //indexing pattern matches that of a edge based algorithm. // //So for this kind of problem we generate the 12 edges of each //cell and place them into array. // vtkm::cont::CellSetStructured<3> cellSet; cellSet.SetPointDimensions(vtkm::Id3(CUBE_SIZE, CUBE_SIZE, CUBE_SIZE)); const vtkm::Id numberOfEdges = cellSet.GetNumberOfCells() * 12; const std::size_t esize = static_cast(numberOfEdges); const std::size_t psize = static_cast(cellSet.GetNumberOfPoints()); this->EdgePairHandle.Allocate(numberOfEdges); vtkm::worklet::DispatcherMapTopology dispatcher; dispatcher.Invoke(cellSet, this->EdgePairHandle); this->weight.resize(esize); for (std::size_t i = 0; i < esize; ++i) { this->weight[i] = weight_range(rng); } this->field.resize(psize); for (std::size_t i = 0; i < psize; ++i) { this->field[i] = Value(field_range(rng)); } this->FieldHandle = vtkm::cont::make_ArrayHandle(this->field); this->WeightHandle = vtkm::cont::make_ArrayHandle(this->weight); } VTKM_CONT vtkm::Float64 operator()() { vtkm::cont::ArrayHandle result; Timer timer{ DeviceAdapter() }; timer.Start(); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(this->EdgePairHandle, this->WeightHandle, this->FieldHandle, result); return timer.GetElapsedTime(); } virtual std::string Type() const { return std::string("Static"); } VTKM_CONT std::string Description() const { std::stringstream description; const std::size_t size = (CUBE_SIZE - 1) * (CUBE_SIZE - 1) * (CUBE_SIZE - 1) * 12; description << "Edge Interpolation " << "[" << this->Type() << "] " << "with a domain size of: " << size; return description.str(); } }; template struct BenchEdgeInterpDynamic : public BenchEdgeInterp { VTKM_CONT vtkm::Float64 operator()() { InterpVariantHandle dfield(this->FieldHandle); ValueVariantHandle dweight(this->WeightHandle); EdgeIdVariantHandle dedges(this->EdgePairHandle); vtkm::cont::ArrayHandle result; Timer timer{ DeviceAdapter() }; timer.Start(); vtkm::worklet::DispatcherMapField dispatcher; dispatcher.Invoke(dedges, dweight, dfield, result); return timer.GetElapsedTime(); } virtual std::string Type() const { return std::string("Dynamic"); } }; VTKM_MAKE_BENCHMARK(EdgeInterp, BenchEdgeInterp); VTKM_MAKE_BENCHMARK(EdgeInterpDynamic, BenchEdgeInterpDynamic); struct ImplicitFunctionBenchData { vtkm::cont::ArrayHandle> Points; vtkm::cont::ArrayHandle Result; vtkm::Sphere Sphere1, Sphere2; }; static ImplicitFunctionBenchData MakeImplicitFunctionBenchData() { vtkm::Id count = ARRAY_SIZE; vtkm::FloatDefault bounds[6] = { -2.0f, 2.0f, -2.0f, 2.0f, -2.0f, 2.0f }; ImplicitFunctionBenchData data; data.Points.Allocate(count); data.Result.Allocate(count); std::default_random_engine rangen; std::uniform_real_distribution distx(bounds[0], bounds[1]); std::uniform_real_distribution disty(bounds[2], bounds[3]); std::uniform_real_distribution distz(bounds[4], bounds[5]); auto portal = data.Points.GetPortalControl(); for (vtkm::Id i = 0; i < count; ++i) { portal.Set(i, vtkm::make_Vec(distx(rangen), disty(rangen), distz(rangen))); } data.Sphere1 = vtkm::Sphere({ 0.22f, 0.33f, 0.44f }, 0.55f); data.Sphere2 = vtkm::Sphere({ 0.22f, 0.33f, 0.11f }, 0.77f); return data; } template struct BenchImplicitFunction { BenchImplicitFunction() : Internal(MakeImplicitFunctionBenchData()) { } VTKM_CONT vtkm::Float64 operator()() { using EvalWorklet = EvaluateImplicitFunction; using EvalDispatcher = vtkm::worklet::DispatcherMapField; auto handle = vtkm::cont::make_ImplicitFunctionHandle(Internal.Sphere1); auto function = static_cast(handle.PrepareForExecution(DeviceAdapter())); EvalWorklet eval(function); Timer timer{ DeviceAdapter() }; timer.Start(); EvalDispatcher dispatcher(eval); dispatcher.Invoke(this->Internal.Points, this->Internal.Result); return timer.GetElapsedTime(); } VTKM_CONT std::string Description() const { std::stringstream description; description << "Implicit Function (vtkm::Sphere) on " << Internal.Points.GetNumberOfValues() << " points"; return description.str(); } ImplicitFunctionBenchData Internal; }; template struct BenchVirtualImplicitFunction { BenchVirtualImplicitFunction() : Internal(MakeImplicitFunctionBenchData()) { } VTKM_CONT vtkm::Float64 operator()() { using EvalWorklet = EvaluateImplicitFunction; using EvalDispatcher = vtkm::worklet::DispatcherMapField; auto sphere = vtkm::cont::make_ImplicitFunctionHandle(Internal.Sphere1); EvalWorklet eval(sphere.PrepareForExecution(DeviceAdapter())); Timer timer{ DeviceAdapter() }; timer.Start(); EvalDispatcher dispatcher(eval); dispatcher.Invoke(this->Internal.Points, this->Internal.Result); return timer.GetElapsedTime(); } VTKM_CONT std::string Description() const { std::stringstream description; description << "Implicit Function (VirtualImplicitFunction) on " << Internal.Points.GetNumberOfValues() << " points"; return description.str(); } ImplicitFunctionBenchData Internal; }; template struct Bench2ImplicitFunctions { Bench2ImplicitFunctions() : Internal(MakeImplicitFunctionBenchData()) { } VTKM_CONT vtkm::Float64 operator()() { using EvalWorklet = Evaluate2ImplicitFunctions; using EvalDispatcher = vtkm::worklet::DispatcherMapField; auto h1 = vtkm::cont::make_ImplicitFunctionHandle(Internal.Sphere1); auto h2 = vtkm::cont::make_ImplicitFunctionHandle(Internal.Sphere2); auto f1 = static_cast(h1.PrepareForExecution(DeviceAdapter())); auto f2 = static_cast(h2.PrepareForExecution(DeviceAdapter())); EvalWorklet eval(f1, f2); Timer timer{ DeviceAdapter() }; timer.Start(); EvalDispatcher dispatcher(eval); dispatcher.Invoke(this->Internal.Points, this->Internal.Result); return timer.GetElapsedTime(); } VTKM_CONT std::string Description() const { std::stringstream description; description << "Implicit Function 2x(vtkm::Sphere) on " << Internal.Points.GetNumberOfValues() << " points"; return description.str(); } ImplicitFunctionBenchData Internal; }; template struct Bench2VirtualImplicitFunctions { Bench2VirtualImplicitFunctions() : Internal(MakeImplicitFunctionBenchData()) { } VTKM_CONT vtkm::Float64 operator()() { using EvalWorklet = Evaluate2ImplicitFunctions; using EvalDispatcher = vtkm::worklet::DispatcherMapField; auto s1 = vtkm::cont::make_ImplicitFunctionHandle(Internal.Sphere1); auto s2 = vtkm::cont::make_ImplicitFunctionHandle(Internal.Sphere2); EvalWorklet eval(s1.PrepareForExecution(DeviceAdapter()), s2.PrepareForExecution(DeviceAdapter())); Timer timer{ DeviceAdapter() }; timer.Start(); EvalDispatcher dispatcher(eval); dispatcher.Invoke(this->Internal.Points, this->Internal.Result); return timer.GetElapsedTime(); } VTKM_CONT std::string Description() const { std::stringstream description; description << "Implicit Function 2x(VirtualImplicitFunction) on " << Internal.Points.GetNumberOfValues() << " points"; return description.str(); } ImplicitFunctionBenchData Internal; }; VTKM_MAKE_BENCHMARK(ImplicitFunction, BenchImplicitFunction); VTKM_MAKE_BENCHMARK(ImplicitFunctionVirtual, BenchVirtualImplicitFunction); VTKM_MAKE_BENCHMARK(ImplicitFunction2, Bench2ImplicitFunctions); VTKM_MAKE_BENCHMARK(ImplicitFunctionVirtual2, Bench2VirtualImplicitFunctions); public: static VTKM_CONT int Run(int benchmarks, vtkm::cont::DeviceAdapterId id) { std::cout << DIVIDER << "\nRunning Field Algorithm benchmarks\n"; if (benchmarks & BLACK_SCHOLES) { std::cout << DIVIDER << "\nBenchmarking BlackScholes\n"; VTKM_RUN_BENCHMARK(BlackScholes, ValueTypes(), id); VTKM_RUN_BENCHMARK(BlackScholesDynamic, ValueTypes(), id); } if (benchmarks & MATH) { std::cout << DIVIDER << "\nBenchmarking Multiple Math Worklets\n"; VTKM_RUN_BENCHMARK(Math, ValueTypes(), id); VTKM_RUN_BENCHMARK(MathDynamic, ValueTypes(), id); } if (benchmarks & FUSED_MATH) { std::cout << DIVIDER << "\nBenchmarking Single Fused Math Worklet\n"; VTKM_RUN_BENCHMARK(FusedMath, ValueTypes(), id); VTKM_RUN_BENCHMARK(FusedMathDynamic, ValueTypes(), id); } if (benchmarks & INTERPOLATE_FIELD) { std::cout << DIVIDER << "\nBenchmarking Edge Based Field InterpolationWorklet\n"; VTKM_RUN_BENCHMARK(EdgeInterp, InterpValueTypes(), id); VTKM_RUN_BENCHMARK(EdgeInterpDynamic, InterpValueTypes(), id); } if (benchmarks & IMPLICIT_FUNCTION) { using FloatDefaultType = vtkm::ListTagBase; std::cout << "\nBenchmarking Implicit Function\n"; VTKM_RUN_BENCHMARK(ImplicitFunction, FloatDefaultType(), id); VTKM_RUN_BENCHMARK(ImplicitFunctionVirtual, FloatDefaultType(), id); VTKM_RUN_BENCHMARK(ImplicitFunction2, FloatDefaultType(), id); VTKM_RUN_BENCHMARK(ImplicitFunctionVirtual2, FloatDefaultType(), id); } return 0; } }; #undef ARRAY_SIZE } } // namespace vtkm::benchmarking int main(int argc, char* argv[]) { auto opts = vtkm::cont::InitializeOptions::DefaultAnyDevice; auto config = vtkm::cont::Initialize(argc, argv, opts); 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(), [](char c) { return static_cast(std::tolower(static_cast(c))); }); if (arg == "blackscholes") { benchmarks |= vtkm::benchmarking::BLACK_SCHOLES; } else if (arg == "math") { benchmarks |= vtkm::benchmarking::MATH; } else if (arg == "fusedmath") { benchmarks |= vtkm::benchmarking::FUSED_MATH; } else if (arg == "interpolate") { benchmarks |= vtkm::benchmarking::INTERPOLATE_FIELD; } else if (arg == "implicit_function") { benchmarks |= vtkm::benchmarking::IMPLICIT_FUNCTION; } else { std::cerr << "Unrecognized benchmark: " << argv[i] << std::endl; std::cerr << "Usage: " << argv[0] << " [options] [benchmarks]" << std::endl; std::cerr << "options are:" << std::endl; std::cerr << config.Usage; std::cerr << "available benchmarks are:" << std::endl; std::cerr << " blackscholes, math, fusedmath, interpolate, implicit_function" << std::endl; std::cerr << "If no benchmarks are specified, all are run." << std::endl; return 1; } } } //now actually execute the benchmarks return vtkm::benchmarking::BenchmarkFieldAlgorithms::Run(benchmarks, config.Device); }