mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-10-05 01:49:02 +00:00
a6725b3acd
Unfortunately, this introduces a backward-incompatible change with the filters that use ImplicitFunctions. Before, they would get an ImplicitFunctionHandle. This class is deprecated, and there is no easy way to get back the actual type of implicit function stored in it.
926 lines
28 KiB
C++
926 lines
28 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 <vtkm/ImplicitFunction.h>
|
|
#include <vtkm/Math.h>
|
|
#include <vtkm/VectorAnalysis.h>
|
|
|
|
#include <vtkm/cont/ArrayHandle.h>
|
|
#include <vtkm/cont/ArrayHandleMultiplexer.h>
|
|
#include <vtkm/cont/CellSetStructured.h>
|
|
#include <vtkm/cont/Initialize.h>
|
|
#include <vtkm/cont/Invoker.h>
|
|
#include <vtkm/cont/Timer.h>
|
|
|
|
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
|
|
#include <vtkm/cont/ArrayHandleVirtual.h>
|
|
#endif
|
|
|
|
#include <vtkm/worklet/WorkletMapField.h>
|
|
#include <vtkm/worklet/WorkletMapTopology.h>
|
|
|
|
#include "Benchmarker.h"
|
|
#include <vtkm/cont/testing/Testing.h>
|
|
|
|
#include <cctype>
|
|
#include <random>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
namespace
|
|
{
|
|
|
|
//==============================================================================
|
|
// Benchmark Parameters
|
|
|
|
#define ARRAY_SIZE (1 << 22)
|
|
#define CUBE_SIZE 256
|
|
|
|
using ValueTypes = vtkm::List<vtkm::Float32, vtkm::Float64>;
|
|
using InterpValueTypes = vtkm::List<vtkm::Float32, vtkm::Vec3f_32>;
|
|
|
|
//==============================================================================
|
|
// Worklets and helpers
|
|
|
|
// Hold configuration state (e.g. active device)
|
|
vtkm::cont::InitializeResult Config;
|
|
|
|
template <typename T>
|
|
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<vtkm::Float32>(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<T>(cnd);
|
|
}
|
|
|
|
template <typename U, typename V, typename W>
|
|
VTKM_EXEC void operator()(const U& sp, const V& os, const W& oy, T& callResult, T& putResult)
|
|
const
|
|
{
|
|
const T stockPrice = static_cast<T>(sp);
|
|
const T optionStrike = static_cast<T>(os);
|
|
const T optionYears = static_cast<T>(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 <typename T, typename U>
|
|
VTKM_EXEC void operator()(const vtkm::Vec<T, 3>& vec, U& result) const
|
|
{
|
|
result = static_cast<U>(vtkm::Magnitude(vec));
|
|
}
|
|
};
|
|
|
|
class Square : public vtkm::worklet::WorkletMapField
|
|
{
|
|
public:
|
|
using ControlSignature = void(FieldIn, FieldOut);
|
|
using ExecutionSignature = void(_1, _2);
|
|
|
|
template <typename T, typename U>
|
|
VTKM_EXEC void operator()(T input, U& output) const
|
|
{
|
|
output = static_cast<U>(input * input);
|
|
}
|
|
};
|
|
|
|
class Sin : public vtkm::worklet::WorkletMapField
|
|
{
|
|
public:
|
|
using ControlSignature = void(FieldIn, FieldOut);
|
|
using ExecutionSignature = void(_1, _2);
|
|
|
|
template <typename T, typename U>
|
|
VTKM_EXEC void operator()(T input, U& output) const
|
|
{
|
|
output = static_cast<U>(vtkm::Sin(input));
|
|
}
|
|
};
|
|
|
|
class Cos : public vtkm::worklet::WorkletMapField
|
|
{
|
|
public:
|
|
using ControlSignature = void(FieldIn, FieldOut);
|
|
using ExecutionSignature = void(_1, _2);
|
|
|
|
template <typename T, typename U>
|
|
VTKM_EXEC void operator()(T input, U& output) const
|
|
{
|
|
output = static_cast<U>(vtkm::Cos(input));
|
|
}
|
|
};
|
|
|
|
class FusedMath : public vtkm::worklet::WorkletMapField
|
|
{
|
|
public:
|
|
using ControlSignature = void(FieldIn, FieldOut);
|
|
using ExecutionSignature = void(_1, _2);
|
|
|
|
template <typename T>
|
|
VTKM_EXEC void operator()(const vtkm::Vec<T, 3>& vec, T& result) const
|
|
{
|
|
const T m = vtkm::Magnitude(vec);
|
|
result = vtkm::Cos(vtkm::Sin(m) * vtkm::Sin(m));
|
|
}
|
|
|
|
template <typename T, typename U>
|
|
VTKM_EXEC void operator()(const vtkm::Vec<T, 3>&, U&) const
|
|
{
|
|
this->RaiseError("Mixed types unsupported.");
|
|
}
|
|
};
|
|
|
|
class GenerateEdges : public vtkm::worklet::WorkletVisitCellsWithPoints
|
|
{
|
|
public:
|
|
using ControlSignature = void(CellSetIn cellset, WholeArrayOut edgeIds);
|
|
using ExecutionSignature = void(PointIndices, ThreadIndices, _2);
|
|
using InputDomain = _1;
|
|
|
|
template <typename ConnectivityInVec, typename ThreadIndicesType, typename IdPairTableType>
|
|
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 <typename WeightType, typename T, typename S>
|
|
VTKM_EXEC void operator()(const vtkm::Id2& low_high,
|
|
const WeightType& weight,
|
|
const vtkm::exec::ExecutionWholeArrayConst<T, S>& 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 <typename WeightType, typename T, typename S, typename U>
|
|
VTKM_EXEC void operator()(const vtkm::Id2&,
|
|
const WeightType&,
|
|
const vtkm::exec::ExecutionWholeArrayConst<T, S>&,
|
|
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.");
|
|
}
|
|
};
|
|
|
|
class EvaluateImplicitFunction : public vtkm::worklet::WorkletMapField
|
|
{
|
|
public:
|
|
using ControlSignature = void(FieldIn, FieldOut, ExecObject);
|
|
using ExecutionSignature = void(_1, _2, _3);
|
|
|
|
template <typename VecType, typename ScalarType, typename FunctionType>
|
|
VTKM_EXEC void operator()(const VecType& point,
|
|
ScalarType& val,
|
|
const FunctionType& function) const
|
|
{
|
|
val = function.Value(point);
|
|
}
|
|
};
|
|
|
|
class Evaluate2ImplicitFunctions : public vtkm::worklet::WorkletMapField
|
|
{
|
|
public:
|
|
using ControlSignature = void(FieldIn, FieldOut, ExecObject, ExecObject);
|
|
using ExecutionSignature = void(_1, _2, _3, _4);
|
|
|
|
template <typename VecType, typename ScalarType, typename FType1, typename FType2>
|
|
VTKM_EXEC void operator()(const VecType& point,
|
|
ScalarType& val,
|
|
const FType1& function1,
|
|
const FType2& function2) const
|
|
{
|
|
val = function1.Value(point) + function2.Value(point);
|
|
}
|
|
};
|
|
|
|
struct PassThroughFunctor
|
|
{
|
|
template <typename T>
|
|
VTKM_EXEC_CONT T operator()(const T& x) const
|
|
{
|
|
return x;
|
|
}
|
|
};
|
|
|
|
template <typename ArrayHandleType>
|
|
using ArrayHandlePassThrough =
|
|
vtkm::cont::ArrayHandleTransform<ArrayHandleType, PassThroughFunctor, PassThroughFunctor>;
|
|
|
|
template <typename ValueType, vtkm::IdComponent>
|
|
struct JunkArrayHandle : vtkm::cont::ArrayHandle<ValueType>
|
|
{
|
|
};
|
|
|
|
template <typename ArrayHandleType>
|
|
using BMArrayHandleMultiplexer =
|
|
vtkm::cont::ArrayHandleMultiplexer<ArrayHandleType,
|
|
JunkArrayHandle<typename ArrayHandleType::ValueType, 0>,
|
|
JunkArrayHandle<typename ArrayHandleType::ValueType, 1>,
|
|
JunkArrayHandle<typename ArrayHandleType::ValueType, 2>,
|
|
JunkArrayHandle<typename ArrayHandleType::ValueType, 3>,
|
|
JunkArrayHandle<typename ArrayHandleType::ValueType, 4>,
|
|
JunkArrayHandle<typename ArrayHandleType::ValueType, 5>,
|
|
JunkArrayHandle<typename ArrayHandleType::ValueType, 6>,
|
|
JunkArrayHandle<typename ArrayHandleType::ValueType, 7>,
|
|
JunkArrayHandle<typename ArrayHandleType::ValueType, 8>,
|
|
JunkArrayHandle<typename ArrayHandleType::ValueType, 9>,
|
|
ArrayHandlePassThrough<ArrayHandleType>>;
|
|
|
|
template <typename ArrayHandleType>
|
|
BMArrayHandleMultiplexer<ArrayHandleType> make_ArrayHandleMultiplexer0(const ArrayHandleType& array)
|
|
{
|
|
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
|
|
return BMArrayHandleMultiplexer<ArrayHandleType>(array);
|
|
}
|
|
|
|
template <typename ArrayHandleType>
|
|
BMArrayHandleMultiplexer<ArrayHandleType> make_ArrayHandleMultiplexerN(const ArrayHandleType& array)
|
|
{
|
|
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
|
|
return BMArrayHandleMultiplexer<ArrayHandleType>(ArrayHandlePassThrough<ArrayHandleType>(array));
|
|
}
|
|
|
|
|
|
//==============================================================================
|
|
// Benchmark implementations:
|
|
|
|
template <typename Value>
|
|
struct BenchBlackScholesImpl
|
|
{
|
|
using ValueArrayHandle = vtkm::cont::ArrayHandle<Value>;
|
|
|
|
ValueArrayHandle StockPrice;
|
|
ValueArrayHandle OptionStrike;
|
|
ValueArrayHandle OptionYears;
|
|
|
|
::benchmark::State& State;
|
|
vtkm::Id ArraySize;
|
|
|
|
vtkm::cont::Timer Timer;
|
|
vtkm::cont::Invoker Invoker;
|
|
|
|
VTKM_CONT
|
|
BenchBlackScholesImpl(::benchmark::State& state)
|
|
: State{ state }
|
|
, ArraySize{ ARRAY_SIZE }
|
|
, Timer{ Config.Device }
|
|
, Invoker{ Config.Device }
|
|
{
|
|
|
|
{ // Initialize arrays
|
|
std::mt19937 rng;
|
|
std::uniform_real_distribution<Value> price_range(Value(5.0f), Value(30.0f));
|
|
std::uniform_real_distribution<Value> strike_range(Value(1.0f), Value(100.0f));
|
|
std::uniform_real_distribution<Value> year_range(Value(0.25f), Value(10.0f));
|
|
|
|
this->StockPrice.Allocate(this->ArraySize);
|
|
this->OptionStrike.Allocate(this->ArraySize);
|
|
this->OptionYears.Allocate(this->ArraySize);
|
|
|
|
auto stockPricePortal = this->StockPrice.WritePortal();
|
|
auto optionStrikePortal = this->OptionStrike.WritePortal();
|
|
auto optionYearsPortal = this->OptionYears.WritePortal();
|
|
|
|
for (vtkm::Id i = 0; i < this->ArraySize; ++i)
|
|
{
|
|
stockPricePortal.Set(i, price_range(rng));
|
|
optionStrikePortal.Set(i, strike_range(rng));
|
|
optionYearsPortal.Set(i, year_range(rng));
|
|
}
|
|
}
|
|
|
|
{ // Configure label:
|
|
const vtkm::Id numBytes = this->ArraySize * static_cast<vtkm::Id>(sizeof(Value));
|
|
std::ostringstream desc;
|
|
desc << "NumValues:" << this->ArraySize << " (" << vtkm::cont::GetHumanReadableSize(numBytes)
|
|
<< ")";
|
|
this->State.SetLabel(desc.str());
|
|
}
|
|
}
|
|
|
|
template <typename BenchArrayType>
|
|
VTKM_CONT void Run(const BenchArrayType& stockPrice,
|
|
const BenchArrayType& optionStrike,
|
|
const BenchArrayType& optionYears)
|
|
{
|
|
static constexpr Value RISKFREE = 0.02f;
|
|
static constexpr Value VOLATILITY = 0.30f;
|
|
|
|
BlackScholes<Value> worklet(RISKFREE, VOLATILITY);
|
|
vtkm::cont::ArrayHandle<Value> callResultHandle;
|
|
vtkm::cont::ArrayHandle<Value> putResultHandle;
|
|
|
|
for (auto _ : this->State)
|
|
{
|
|
(void)_;
|
|
this->Timer.Start();
|
|
this->Invoker(
|
|
worklet, stockPrice, optionStrike, optionYears, callResultHandle, putResultHandle);
|
|
this->Timer.Stop();
|
|
|
|
this->State.SetIterationTime(this->Timer.GetElapsedTime());
|
|
}
|
|
|
|
const int64_t iterations = static_cast<int64_t>(this->State.iterations());
|
|
const int64_t numValues = static_cast<int64_t>(this->ArraySize);
|
|
this->State.SetItemsProcessed(numValues * iterations);
|
|
}
|
|
};
|
|
|
|
template <typename ValueType>
|
|
void BenchBlackScholesStatic(::benchmark::State& state)
|
|
{
|
|
BenchBlackScholesImpl<ValueType> impl{ state };
|
|
impl.Run(impl.StockPrice, impl.OptionStrike, impl.OptionYears);
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchBlackScholesStatic, ValueTypes);
|
|
|
|
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
|
|
template <typename ValueType>
|
|
void BenchBlackScholesDynamic(::benchmark::State& state)
|
|
{
|
|
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
|
BenchBlackScholesImpl<ValueType> impl{ state };
|
|
impl.Run(vtkm::cont::make_ArrayHandleVirtual(impl.StockPrice),
|
|
vtkm::cont::make_ArrayHandleVirtual(impl.OptionStrike),
|
|
vtkm::cont::make_ArrayHandleVirtual(impl.OptionYears));
|
|
VTKM_DEPRECATED_SUPPRESS_END
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchBlackScholesDynamic, ValueTypes);
|
|
#endif //VTKM_NO_DEPRECATED_VIRTUAL
|
|
|
|
template <typename ValueType>
|
|
void BenchBlackScholesMultiplexer0(::benchmark::State& state)
|
|
{
|
|
BenchBlackScholesImpl<ValueType> impl{ state };
|
|
impl.Run(make_ArrayHandleMultiplexer0(impl.StockPrice),
|
|
make_ArrayHandleMultiplexer0(impl.OptionStrike),
|
|
make_ArrayHandleMultiplexer0(impl.OptionYears));
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchBlackScholesMultiplexer0, ValueTypes);
|
|
|
|
template <typename ValueType>
|
|
void BenchBlackScholesMultiplexerN(::benchmark::State& state)
|
|
{
|
|
BenchBlackScholesImpl<ValueType> impl{ state };
|
|
impl.Run(make_ArrayHandleMultiplexerN(impl.StockPrice),
|
|
make_ArrayHandleMultiplexerN(impl.OptionStrike),
|
|
make_ArrayHandleMultiplexerN(impl.OptionYears));
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchBlackScholesMultiplexerN, ValueTypes);
|
|
|
|
template <typename Value>
|
|
struct BenchMathImpl
|
|
{
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<Value, 3>> InputHandle;
|
|
vtkm::cont::ArrayHandle<Value> TempHandle1;
|
|
vtkm::cont::ArrayHandle<Value> TempHandle2;
|
|
|
|
::benchmark::State& State;
|
|
vtkm::Id ArraySize;
|
|
|
|
vtkm::cont::Timer Timer;
|
|
vtkm::cont::Invoker Invoker;
|
|
|
|
VTKM_CONT
|
|
BenchMathImpl(::benchmark::State& state)
|
|
: State{ state }
|
|
, ArraySize{ ARRAY_SIZE }
|
|
, Timer{ Config.Device }
|
|
, Invoker{ Config.Device }
|
|
{
|
|
{ // Initialize input
|
|
std::mt19937 rng;
|
|
std::uniform_real_distribution<Value> range;
|
|
|
|
this->InputHandle.Allocate(this->ArraySize);
|
|
auto portal = this->InputHandle.WritePortal();
|
|
for (vtkm::Id i = 0; i < this->ArraySize; ++i)
|
|
{
|
|
portal.Set(i, vtkm::Vec<Value, 3>{ range(rng), range(rng), range(rng) });
|
|
}
|
|
}
|
|
}
|
|
|
|
template <typename InputArrayType, typename BenchArrayType>
|
|
VTKM_CONT void Run(const InputArrayType& inputHandle,
|
|
const BenchArrayType& tempHandle1,
|
|
const BenchArrayType& tempHandle2)
|
|
{
|
|
{ // Configure label:
|
|
const vtkm::Id numBytes = this->ArraySize * static_cast<vtkm::Id>(sizeof(Value));
|
|
std::ostringstream desc;
|
|
desc << "NumValues:" << this->ArraySize << " (" << vtkm::cont::GetHumanReadableSize(numBytes)
|
|
<< ")";
|
|
this->State.SetLabel(desc.str());
|
|
}
|
|
|
|
for (auto _ : this->State)
|
|
{
|
|
(void)_;
|
|
|
|
this->Timer.Start();
|
|
this->Invoker(Mag{}, inputHandle, tempHandle1);
|
|
this->Invoker(Sin{}, tempHandle1, tempHandle2);
|
|
this->Invoker(Square{}, tempHandle2, tempHandle1);
|
|
this->Invoker(Cos{}, tempHandle1, tempHandle2);
|
|
this->Timer.Stop();
|
|
|
|
this->State.SetIterationTime(this->Timer.GetElapsedTime());
|
|
}
|
|
|
|
const int64_t iterations = static_cast<int64_t>(this->State.iterations());
|
|
const int64_t numValues = static_cast<int64_t>(this->ArraySize);
|
|
this->State.SetItemsProcessed(numValues * iterations);
|
|
}
|
|
};
|
|
|
|
template <typename ValueType>
|
|
void BenchMathStatic(::benchmark::State& state)
|
|
{
|
|
BenchMathImpl<ValueType> impl{ state };
|
|
impl.Run(impl.InputHandle, impl.TempHandle1, impl.TempHandle2);
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchMathStatic, ValueTypes);
|
|
|
|
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
|
|
template <typename ValueType>
|
|
void BenchMathDynamic(::benchmark::State& state)
|
|
{
|
|
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
|
BenchMathImpl<ValueType> impl{ state };
|
|
impl.Run(vtkm::cont::make_ArrayHandleVirtual(impl.InputHandle),
|
|
vtkm::cont::make_ArrayHandleVirtual(impl.TempHandle1),
|
|
vtkm::cont::make_ArrayHandleVirtual(impl.TempHandle2));
|
|
VTKM_DEPRECATED_SUPPRESS_END
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchMathDynamic, ValueTypes);
|
|
#endif //VTKM_NO_DEPRECATED_VIRTUAL
|
|
|
|
template <typename ValueType>
|
|
void BenchMathMultiplexer0(::benchmark::State& state)
|
|
{
|
|
BenchMathImpl<ValueType> impl{ state };
|
|
impl.Run(make_ArrayHandleMultiplexer0(impl.InputHandle),
|
|
make_ArrayHandleMultiplexer0(impl.TempHandle1),
|
|
make_ArrayHandleMultiplexer0(impl.TempHandle2));
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchMathMultiplexer0, ValueTypes);
|
|
|
|
template <typename ValueType>
|
|
void BenchMathMultiplexerN(::benchmark::State& state)
|
|
{
|
|
BenchMathImpl<ValueType> impl{ state };
|
|
impl.Run(make_ArrayHandleMultiplexerN(impl.InputHandle),
|
|
make_ArrayHandleMultiplexerN(impl.TempHandle1),
|
|
make_ArrayHandleMultiplexerN(impl.TempHandle2));
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchMathMultiplexerN, ValueTypes);
|
|
|
|
template <typename Value>
|
|
struct BenchFusedMathImpl
|
|
{
|
|
vtkm::cont::ArrayHandle<vtkm::Vec<Value, 3>> InputHandle;
|
|
|
|
::benchmark::State& State;
|
|
vtkm::Id ArraySize;
|
|
|
|
vtkm::cont::Timer Timer;
|
|
vtkm::cont::Invoker Invoker;
|
|
|
|
VTKM_CONT
|
|
BenchFusedMathImpl(::benchmark::State& state)
|
|
: State{ state }
|
|
, ArraySize{ ARRAY_SIZE }
|
|
, Timer{ Config.Device }
|
|
, Invoker{ Config.Device }
|
|
{
|
|
{ // Initialize input
|
|
std::mt19937 rng;
|
|
std::uniform_real_distribution<Value> range;
|
|
|
|
this->InputHandle.Allocate(this->ArraySize);
|
|
auto portal = this->InputHandle.WritePortal();
|
|
for (vtkm::Id i = 0; i < this->ArraySize; ++i)
|
|
{
|
|
portal.Set(i, vtkm::Vec<Value, 3>{ range(rng), range(rng), range(rng) });
|
|
}
|
|
}
|
|
|
|
{ // Configure label:
|
|
const vtkm::Id numBytes = this->ArraySize * static_cast<vtkm::Id>(sizeof(Value));
|
|
std::ostringstream desc;
|
|
desc << "NumValues:" << this->ArraySize << " (" << vtkm::cont::GetHumanReadableSize(numBytes)
|
|
<< ")";
|
|
this->State.SetLabel(desc.str());
|
|
}
|
|
}
|
|
|
|
template <typename BenchArrayType>
|
|
VTKM_CONT void Run(const BenchArrayType& inputHandle)
|
|
{
|
|
vtkm::cont::ArrayHandle<Value> result;
|
|
|
|
for (auto _ : this->State)
|
|
{
|
|
(void)_;
|
|
|
|
this->Timer.Start();
|
|
this->Invoker(FusedMath{}, inputHandle, result);
|
|
this->Timer.Stop();
|
|
|
|
this->State.SetIterationTime(this->Timer.GetElapsedTime());
|
|
}
|
|
|
|
const int64_t iterations = static_cast<int64_t>(this->State.iterations());
|
|
const int64_t numValues = static_cast<int64_t>(this->ArraySize);
|
|
this->State.SetItemsProcessed(numValues * iterations);
|
|
}
|
|
};
|
|
|
|
template <typename ValueType>
|
|
void BenchFusedMathStatic(::benchmark::State& state)
|
|
{
|
|
BenchFusedMathImpl<ValueType> impl{ state };
|
|
impl.Run(impl.InputHandle);
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchFusedMathStatic, ValueTypes);
|
|
|
|
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
|
|
template <typename ValueType>
|
|
void BenchFusedMathDynamic(::benchmark::State& state)
|
|
{
|
|
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
|
BenchFusedMathImpl<ValueType> impl{ state };
|
|
impl.Run(vtkm::cont::make_ArrayHandleVirtual(impl.InputHandle));
|
|
VTKM_DEPRECATED_SUPPRESS_END
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchFusedMathDynamic, ValueTypes);
|
|
#endif //VTKM_NO_DEPRECATED_VIRTUAL
|
|
|
|
template <typename ValueType>
|
|
void BenchFusedMathMultiplexer0(::benchmark::State& state)
|
|
{
|
|
BenchFusedMathImpl<ValueType> impl{ state };
|
|
impl.Run(make_ArrayHandleMultiplexer0(impl.InputHandle));
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchFusedMathMultiplexer0, ValueTypes);
|
|
|
|
template <typename ValueType>
|
|
void BenchFusedMathMultiplexerN(::benchmark::State& state)
|
|
{
|
|
BenchFusedMathImpl<ValueType> impl{ state };
|
|
impl.Run(make_ArrayHandleMultiplexerN(impl.InputHandle));
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchFusedMathMultiplexerN, ValueTypes);
|
|
|
|
template <typename Value>
|
|
struct BenchEdgeInterpImpl
|
|
{
|
|
vtkm::cont::ArrayHandle<vtkm::Float32> WeightHandle;
|
|
vtkm::cont::ArrayHandle<Value> FieldHandle;
|
|
vtkm::cont::ArrayHandle<vtkm::Id2> EdgePairHandle;
|
|
|
|
::benchmark::State& State;
|
|
vtkm::Id CubeSize;
|
|
|
|
vtkm::cont::Timer Timer;
|
|
vtkm::cont::Invoker Invoker;
|
|
|
|
VTKM_CONT
|
|
BenchEdgeInterpImpl(::benchmark::State& state)
|
|
: State{ state }
|
|
, CubeSize{ CUBE_SIZE }
|
|
, Timer{ Config.Device }
|
|
, Invoker{ Config.Device }
|
|
{
|
|
{ // Initialize arrays
|
|
using CT = typename vtkm::VecTraits<Value>::ComponentType;
|
|
|
|
std::mt19937 rng;
|
|
std::uniform_real_distribution<vtkm::Float32> weight_range(0.0f, 1.0f);
|
|
std::uniform_real_distribution<CT> 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{ this->CubeSize, this->CubeSize, this->CubeSize });
|
|
|
|
const vtkm::Id numberOfEdges = cellSet.GetNumberOfCells() * 12;
|
|
|
|
this->EdgePairHandle.Allocate(numberOfEdges);
|
|
this->Invoker(GenerateEdges{}, cellSet, this->EdgePairHandle);
|
|
|
|
{ // Per-edge weights
|
|
this->WeightHandle.Allocate(numberOfEdges);
|
|
auto portal = this->WeightHandle.WritePortal();
|
|
for (vtkm::Id i = 0; i < numberOfEdges; ++i)
|
|
{
|
|
portal.Set(i, weight_range(rng));
|
|
}
|
|
}
|
|
|
|
{ // Point field
|
|
this->FieldHandle.Allocate(cellSet.GetNumberOfPoints());
|
|
auto portal = this->FieldHandle.WritePortal();
|
|
for (vtkm::Id i = 0; i < portal.GetNumberOfValues(); ++i)
|
|
{
|
|
portal.Set(i, field_range(rng));
|
|
}
|
|
}
|
|
}
|
|
|
|
{ // Configure label:
|
|
const vtkm::Id numValues = this->FieldHandle.GetNumberOfValues();
|
|
const vtkm::Id numBytes = numValues * static_cast<vtkm::Id>(sizeof(Value));
|
|
std::ostringstream desc;
|
|
desc << "FieldValues:" << numValues << " (" << vtkm::cont::GetHumanReadableSize(numBytes)
|
|
<< ") | CubeSize: " << this->CubeSize;
|
|
this->State.SetLabel(desc.str());
|
|
}
|
|
}
|
|
|
|
template <typename EdgePairArrayType, typename WeightArrayType, typename FieldArrayType>
|
|
VTKM_CONT void Run(const EdgePairArrayType& edgePairs,
|
|
const WeightArrayType& weights,
|
|
const FieldArrayType& field)
|
|
{
|
|
vtkm::cont::ArrayHandle<Value> result;
|
|
|
|
for (auto _ : this->State)
|
|
{
|
|
(void)_;
|
|
this->Timer.Start();
|
|
this->Invoker(InterpolateField{}, edgePairs, weights, field, result);
|
|
this->Timer.Stop();
|
|
|
|
this->State.SetIterationTime(this->Timer.GetElapsedTime());
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename ValueType>
|
|
void BenchEdgeInterpStatic(::benchmark::State& state)
|
|
{
|
|
BenchEdgeInterpImpl<ValueType> impl{ state };
|
|
impl.Run(impl.EdgePairHandle, impl.WeightHandle, impl.FieldHandle);
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchEdgeInterpStatic, InterpValueTypes);
|
|
|
|
#ifndef VTKM_NO_DEPRECATED_VIRTUAL
|
|
template <typename ValueType>
|
|
void BenchEdgeInterpDynamic(::benchmark::State& state)
|
|
{
|
|
VTKM_DEPRECATED_SUPPRESS_BEGIN
|
|
BenchEdgeInterpImpl<ValueType> impl{ state };
|
|
impl.Run(vtkm::cont::make_ArrayHandleVirtual(impl.EdgePairHandle),
|
|
vtkm::cont::make_ArrayHandleVirtual(impl.WeightHandle),
|
|
vtkm::cont::make_ArrayHandleVirtual(impl.FieldHandle));
|
|
VTKM_DEPRECATED_SUPPRESS_END
|
|
};
|
|
VTKM_BENCHMARK_TEMPLATES(BenchEdgeInterpDynamic, InterpValueTypes);
|
|
#endif //VTKM_NO_DEPRECATED_VIRTUAL
|
|
|
|
struct ImplicitFunctionBenchData
|
|
{
|
|
vtkm::cont::ArrayHandle<vtkm::Vec3f> Points;
|
|
vtkm::cont::ArrayHandle<vtkm::FloatDefault> Result;
|
|
vtkm::Sphere Sphere1;
|
|
vtkm::Sphere 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<vtkm::FloatDefault> distx(bounds[0], bounds[1]);
|
|
std::uniform_real_distribution<vtkm::FloatDefault> disty(bounds[2], bounds[3]);
|
|
std::uniform_real_distribution<vtkm::FloatDefault> distz(bounds[4], bounds[5]);
|
|
|
|
auto portal = data.Points.WritePortal();
|
|
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;
|
|
}
|
|
|
|
void BenchImplicitFunction(::benchmark::State& state)
|
|
{
|
|
using EvalWorklet = EvaluateImplicitFunction;
|
|
|
|
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
|
|
|
auto data = MakeImplicitFunctionBenchData();
|
|
|
|
{
|
|
std::ostringstream desc;
|
|
desc << data.Points.GetNumberOfValues() << " points";
|
|
state.SetLabel(desc.str());
|
|
}
|
|
|
|
EvalWorklet eval;
|
|
|
|
vtkm::cont::Timer timer{ device };
|
|
vtkm::cont::Invoker invoker{ device };
|
|
|
|
for (auto _ : state)
|
|
{
|
|
(void)_;
|
|
timer.Start();
|
|
invoker(eval, data.Points, data.Result, data.Sphere1);
|
|
timer.Stop();
|
|
|
|
state.SetIterationTime(timer.GetElapsedTime());
|
|
}
|
|
}
|
|
VTKM_BENCHMARK(BenchImplicitFunction);
|
|
|
|
void BenchVirtualImplicitFunction(::benchmark::State& state)
|
|
{
|
|
using EvalWorklet = EvaluateImplicitFunction;
|
|
|
|
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
|
|
|
auto data = MakeImplicitFunctionBenchData();
|
|
|
|
{
|
|
std::ostringstream desc;
|
|
desc << data.Points.GetNumberOfValues() << " points";
|
|
state.SetLabel(desc.str());
|
|
}
|
|
|
|
EvalWorklet eval;
|
|
|
|
vtkm::cont::Timer timer{ device };
|
|
vtkm::cont::Invoker invoker{ device };
|
|
|
|
for (auto _ : state)
|
|
{
|
|
(void)_;
|
|
timer.Start();
|
|
invoker(eval, data.Points, data.Result, data.Sphere1);
|
|
timer.Stop();
|
|
|
|
state.SetIterationTime(timer.GetElapsedTime());
|
|
}
|
|
}
|
|
VTKM_BENCHMARK(BenchVirtualImplicitFunction);
|
|
|
|
void Bench2ImplicitFunctions(::benchmark::State& state)
|
|
{
|
|
using EvalWorklet = Evaluate2ImplicitFunctions;
|
|
|
|
const vtkm::cont::DeviceAdapterId device = Config.Device;
|
|
|
|
auto data = MakeImplicitFunctionBenchData();
|
|
|
|
{
|
|
std::ostringstream desc;
|
|
desc << data.Points.GetNumberOfValues() << " points";
|
|
state.SetLabel(desc.str());
|
|
}
|
|
|
|
EvalWorklet eval;
|
|
|
|
vtkm::cont::Timer timer{ device };
|
|
vtkm::cont::Invoker invoker{ device };
|
|
|
|
for (auto _ : state)
|
|
{
|
|
(void)_;
|
|
timer.Start();
|
|
invoker(eval, data.Points, data.Result, data.Sphere1, data.Sphere2);
|
|
timer.Stop();
|
|
|
|
state.SetIterationTime(timer.GetElapsedTime());
|
|
}
|
|
}
|
|
VTKM_BENCHMARK(Bench2ImplicitFunctions);
|
|
|
|
} // 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());
|
|
}
|