Remove ability to pass a runtime device tracker to TryExecute

Since runtime device trackers are single instance per thread
the ability to pass them around to other functions is unneeded.
This commit is contained in:
Robert Maynard 2019-04-01 17:25:44 -04:00
parent 9f55c5efcc
commit 2d477fd531
8 changed files with 71 additions and 258 deletions

@ -374,11 +374,21 @@ struct Algorithm
{
template <typename T, typename U, class CIn, class COut>
VTKM_CONT static void Copy(vtkm::cont::DeviceAdapterId devId,
VTKM_CONT static bool Copy(vtkm::cont::DeviceAdapterId devId,
const vtkm::cont::ArrayHandle<T, CIn>& input,
vtkm::cont::ArrayHandle<U, COut>& output)
{
vtkm::cont::TryExecuteOnDevice(devId, detail::CopyFunctor(), input, output);
// If we can use any device, prefer to use source's already loaded device.
if (devId == vtkm::cont::DeviceAdapterTagAny())
{
bool isCopied = vtkm::cont::TryExecuteOnDevice(
input.GetDeviceAdapterId(), detail::CopyFunctor(), input, output);
if (isCopied)
{
return true;
}
}
return vtkm::cont::TryExecuteOnDevice(devId, detail::CopyFunctor(), input, output);
}
template <typename T, typename U, class CIn, class COut>
VTKM_CONT static void Copy(const vtkm::cont::ArrayHandle<T, CIn>& input,

@ -20,10 +20,9 @@
#ifndef vtk_m_cont_ArrayCopy_h
#define vtk_m_cont_ArrayCopy_h
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleCast.h>
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/TryExecute.h>
// TODO: When virtual arrays are available, compile the implementation in a .cxx/.cu file. Common
@ -33,68 +32,18 @@ namespace vtkm
{
namespace cont
{
/// \brief Does a deep copy from one array to another array.
///
/// Given a source \c ArrayHandle and a destination \c ArrayHandle, this function allocates the
/// destination \c ArrayHandle to the correct size and deeply copies all the values from the source
/// to the destination.
///
/// This version of the method takes a device adapter on which to perform the copy. If you do not
/// have a device adapter handy, use a version of \c ArrayCopy that uses a \c RuntimeDeviceTracker
/// (or no device at all) to choose a good option for you.
///
template <typename InValueType,
typename InStorage,
typename OutValueType,
typename OutStorage,
typename Device>
VTKM_CONT void ArrayCopy(const vtkm::cont::ArrayHandle<InValueType, InStorage>& source,
vtkm::cont::ArrayHandle<OutValueType, OutStorage>& destination,
Device)
{
vtkm::cont::DeviceAdapterAlgorithm<Device>::Copy(
vtkm::cont::make_ArrayHandleCast<OutValueType>(source), destination);
}
namespace detail
{
struct ArrayCopyFunctor
{
template <typename Device, typename InArray, typename OutArray>
VTKM_CONT bool operator()(Device, const InArray& input, OutArray& output)
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::ArrayCopy(input, output, Device());
return true;
}
};
} // namespace detail
/// \brief Does a deep copy from one array to another array.
///
/// Given a source \c ArrayHandle and a destination \c ArrayHandle, this function allocates the
/// destination \c ArrayHandle to the correct size and deeply copies all the values from the source
/// to the destination.
///
/// This method optionally takes a \c RuntimeDeviceTracker to control which devices to try.
///
template <typename InValueType, typename InStorage, typename OutValueType, typename OutStorage>
VTKM_CONT void ArrayCopy(
const vtkm::cont::ArrayHandle<InValueType, InStorage>& source,
vtkm::cont::ArrayHandle<OutValueType, OutStorage>& destination,
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetRuntimeDeviceTracker())
VTKM_CONT inline void ArrayCopy(const vtkm::cont::ArrayHandle<InValueType, InStorage>& source,
vtkm::cont::ArrayHandle<OutValueType, OutStorage>& destination)
{
detail::ArrayCopyFunctor functor;
// First pass, only use source's already loaded device.
bool isCopied = vtkm::cont::TryExecuteOnDevice(
source.GetDeviceAdapterId(), functor, tracker, source, destination);
if (!isCopied)
{ // Second pass, use any available device.
isCopied = vtkm::cont::TryExecute(functor, tracker, source, destination);
}
bool isCopied =
vtkm::cont::Algorithm::Copy(vtkm::cont::DeviceAdapterTagAny(), source, destination);
if (!isCopied)
{ // If after the second pass, still not valid through an exception
throw vtkm::cont::ErrorExecution("Failed to run ArrayCopy on any device.");

@ -33,18 +33,18 @@ void ThrowArrayRangeComputeFailed()
#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_T(T, Storage) \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<T, Storage>& input, vtkm::cont::RuntimeDeviceTracker tracker) \
const vtkm::cont::ArrayHandle<T, Storage>& input, vtkm::cont::DeviceAdapterId device) \
{ \
return detail::ArrayRangeComputeImpl(input, tracker); \
return detail::ArrayRangeComputeImpl(input, device); \
} \
struct SwallowSemicolon
#define VTKM_ARRAY_RANGE_COMPUTE_IMPL_VEC(T, N, Storage) \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, Storage>& input, \
vtkm::cont::RuntimeDeviceTracker tracker) \
vtkm::cont::DeviceAdapterId device) \
{ \
return detail::ArrayRangeComputeImpl(input, tracker); \
return detail::ArrayRangeComputeImpl(input, device); \
} \
struct SwallowSemicolon
@ -85,7 +85,7 @@ VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault, 3>,
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>& array,
vtkm::cont::RuntimeDeviceTracker)
vtkm::cont::DeviceAdapterId)
{
vtkm::internal::ArrayPortalUniformPointCoordinates portal = array.GetPortalConstControl();

@ -27,7 +27,7 @@
#include <vtkm/cont/ArrayHandleCompositeVector.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/ArrayHandleVirtualCoordinates.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/internal/DeviceAdapterTag.h>
namespace vtkm
{
@ -40,7 +40,7 @@ namespace cont
/// the values in the array. For arrays containing Vec values, the range is
/// computed for each component.
///
/// This method optionally takes a \c RuntimeDeviceTracker to control which
/// This method optionally takes a \c vtkm::cont::DeviceAdapterId to control which
/// devices to try.
///
/// The result is returned in an \c ArrayHandle of \c Range objects. There is
@ -50,7 +50,7 @@ namespace cont
template <typename ArrayHandleType>
VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const ArrayHandleType& input,
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetRuntimeDeviceTracker());
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny());
// Precompiled versions of ArrayRangeCompute
#define VTKM_ARRAY_RANGE_COMPUTE_EXPORT_T(T, Storage) \
@ -58,13 +58,13 @@ VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<T, Storage>& input, \
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetRuntimeDeviceTracker())
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
#define VTKM_ARRAY_RANGE_COMPUTE_EXPORT_VEC(T, N, Storage) \
VTKM_CONT_EXPORT \
VTKM_CONT \
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute( \
const vtkm::cont::ArrayHandle<vtkm::Vec<T, N>, Storage>& input, \
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetRuntimeDeviceTracker())
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
VTKM_ARRAY_RANGE_COMPUTE_EXPORT_T(char, vtkm::cont::StorageTagBasic);
VTKM_ARRAY_RANGE_COMPUTE_EXPORT_T(vtkm::Int8, vtkm::cont::StorageTagBasic);
@ -100,14 +100,12 @@ VTKM_ARRAY_RANGE_COMPUTE_EXPORT_VEC(vtkm::Float64, 4, vtkm::cont::StorageTagBasi
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandleVirtual<vtkm::Vec<vtkm::FloatDefault, 3>>& input,
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetRuntimeDeviceTracker());
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny());
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::FloatDefault, 3>,
vtkm::cont::ArrayHandleUniformPointCoordinates::StorageTag>& array,
vtkm::cont::RuntimeDeviceTracker = vtkm::cont::GetRuntimeDeviceTracker());
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny());
// Implementation of composite vectors
VTKM_CONT_EXPORT
@ -118,17 +116,15 @@ vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>,
vtkm::cont::ArrayHandle<vtkm::Float32>>::StorageTag>& input,
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetRuntimeDeviceTracker());
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny());
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
VTKM_CONT_EXPORT VTKM_CONT vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::Float64, 3>,
typename vtkm::cont::ArrayHandleCompositeVector<
vtkm::cont::ArrayHandle<vtkm::Float64>,
vtkm::cont::ArrayHandle<vtkm::Float64>,
vtkm::cont::ArrayHandle<vtkm::Float64>>::StorageTag>& input,
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetRuntimeDeviceTracker());
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny());
// Implementation of cartesian products
template <typename T, typename ArrayType1, typename ArrayType2, typename ArrayType3>
@ -136,7 +132,7 @@ VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandle<
T,
vtkm::cont::internal::StorageTagCartesianProduct<ArrayType1, ArrayType2, ArrayType3>>& input,
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetRuntimeDeviceTracker())
vtkm::cont::DeviceAdapterId device = vtkm::cont::DeviceAdapterTagAny())
{
vtkm::cont::ArrayHandle<vtkm::Range> result;
result.Allocate(3);
@ -145,17 +141,17 @@ VTKM_CONT inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
vtkm::Range componentRange;
ArrayType1 firstArray = input.GetStorage().GetFirstArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(firstArray, tracker);
componentRangeArray = vtkm::cont::ArrayRangeCompute(firstArray, device);
componentRange = componentRangeArray.GetPortalConstControl().Get(0);
result.GetPortalControl().Set(0, componentRange);
ArrayType2 secondArray = input.GetStorage().GetSecondArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(secondArray, tracker);
componentRangeArray = vtkm::cont::ArrayRangeCompute(secondArray, device);
componentRange = componentRangeArray.GetPortalConstControl().Get(0);
result.GetPortalControl().Set(1, componentRange);
ArrayType3 thirdArray = input.GetStorage().GetThirdArray();
componentRangeArray = vtkm::cont::ArrayRangeCompute(thirdArray, tracker);
componentRangeArray = vtkm::cont::ArrayRangeCompute(thirdArray, device);
componentRange = componentRangeArray.GetPortalConstControl().Get(0);
result.GetPortalControl().Set(2, componentRange);

@ -55,7 +55,7 @@ struct ArrayRangeComputeFunctor
template <typename T, typename S>
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
const vtkm::cont::ArrayHandle<T, S>& input,
vtkm::cont::RuntimeDeviceTracker tracker)
vtkm::cont::DeviceAdapterId device)
{
using VecTraits = vtkm::VecTraits<T>;
using CT = typename VecTraits::ComponentType;
@ -81,8 +81,8 @@ inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
initial[0] = T(std::numeric_limits<CT>::max());
initial[1] = T(std::numeric_limits<CT>::lowest());
const bool rangeComputed =
vtkm::cont::TryExecute(detail::ArrayRangeComputeFunctor{}, tracker, input, initial, result);
const bool rangeComputed = vtkm::cont::TryExecuteOnDevice(
device, detail::ArrayRangeComputeFunctor{}, input, initial, result);
if (!rangeComputed)
{
ThrowArrayRangeComputeFailed();
@ -107,7 +107,7 @@ inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeComputeImpl(
VTKM_CONT
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const vtkm::cont::ArrayHandleVirtual<vtkm::Vec<vtkm::FloatDefault, 3>>& input,
vtkm::cont::RuntimeDeviceTracker tracker)
vtkm::cont::DeviceAdapterId device)
{
using UniformHandleType = ArrayHandleUniformPointCoordinates;
using RectilinearHandleType =
@ -124,7 +124,7 @@ inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const auto* castStorage =
storage->Cast<vtkm::cont::internal::detail::StorageVirtualImpl<T, S>>();
return ArrayRangeCompute(castStorage->GetHandle(), tracker);
return ArrayRangeCompute(castStorage->GetHandle(), device);
}
else if (input.IsType<RectilinearHandleType>())
{
@ -135,21 +135,20 @@ inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const auto* castStorage =
storage->Cast<vtkm::cont::internal::detail::StorageVirtualImpl<T, S>>();
return ArrayRangeCompute(castStorage->GetHandle(), tracker);
return ArrayRangeCompute(castStorage->GetHandle(), device);
}
else
{
return detail::ArrayRangeComputeImpl(input, tracker);
return detail::ArrayRangeComputeImpl(input, device);
}
}
template <typename ArrayHandleType>
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(
const ArrayHandleType& input,
vtkm::cont::RuntimeDeviceTracker tracker)
inline vtkm::cont::ArrayHandle<vtkm::Range> ArrayRangeCompute(const ArrayHandleType& input,
vtkm::cont::DeviceAdapterId device)
{
VTKM_IS_ARRAY_HANDLE(ArrayHandleType);
return detail::ArrayRangeComputeImpl(input, tracker);
return detail::ArrayRangeComputeImpl(input, device);
}
}
} // namespace vtkm::cont

@ -327,7 +327,7 @@ vtkm::Float64 Timer::GetElapsedTime(vtkm::cont::DeviceAdapterId device) const
}
// If we have specified a specific device, make sure we can run on it.
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetRuntimeDeviceTracker();
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
if ((deviceToTime != vtkm::cont::DeviceAdapterTagAny()) && !tracker.CanRunOn(deviceToTime))
{
VTKM_LOG_S(vtkm::cont::LogLevel::Error,

@ -42,7 +42,7 @@ inline bool TryExecuteIfValid(std::true_type,
DeviceTag tag,
Functor&& f,
vtkm::cont::DeviceAdapterId devId,
vtkm::cont::RuntimeDeviceTracker tracker,
vtkm::cont::RuntimeDeviceTracker& tracker,
Args&&... args)
{
if ((tag == devId || devId == DeviceAdapterTagAny()) && tracker.CanRunOn(tag))
@ -66,7 +66,7 @@ inline bool TryExecuteIfValid(std::false_type,
DeviceTag,
Functor&&,
vtkm::cont::DeviceAdapterId,
vtkm::cont::RuntimeDeviceTracker,
vtkm::cont::RuntimeDeviceTracker&,
Args&&...)
{
return false;
@ -78,7 +78,7 @@ struct TryExecuteWrapper
inline void operator()(DeviceTag tag,
Functor&& f,
vtkm::cont::DeviceAdapterId devId,
vtkm::cont::RuntimeDeviceTracker tracker,
vtkm::cont::RuntimeDeviceTracker& tracker,
bool& ran,
Args&&... args) const
{
@ -98,12 +98,11 @@ template <typename Functor, typename DeviceList, typename... Args>
inline bool TryExecuteImpl(vtkm::cont::DeviceAdapterId devId,
Functor&& functor,
std::true_type,
std::true_type,
vtkm::cont::RuntimeDeviceTracker tracker,
DeviceList list,
Args&&... args)
{
bool success = false;
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
TryExecuteWrapper task;
vtkm::ListForEach(task,
list,
@ -119,11 +118,10 @@ template <typename Functor, typename... Args>
inline bool TryExecuteImpl(vtkm::cont::DeviceAdapterId devId,
Functor&& functor,
std::false_type,
std::false_type,
Args&&... args)
{
bool success = false;
auto tracker = vtkm::cont::GetRuntimeDeviceTracker();
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
TryExecuteWrapper task;
vtkm::ListForEach(task,
VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG(),
@ -134,42 +132,6 @@ inline bool TryExecuteImpl(vtkm::cont::DeviceAdapterId devId,
std::forward<Args>(args)...);
return success;
}
template <typename Functor, typename Arg1, typename... Args>
inline bool TryExecuteImpl(vtkm::cont::DeviceAdapterId devId,
Functor&& functor,
std::true_type t,
std::false_type,
Arg1&& arg1,
Args&&... args)
{
return TryExecuteImpl(devId,
std::forward<Functor>(functor),
t,
t,
std::forward<Arg1>(arg1),
VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG(),
std::forward<Args>(args)...);
}
template <typename Functor, typename Arg1, typename... Args>
inline bool TryExecuteImpl(vtkm::cont::DeviceAdapterId devId,
Functor&& functor,
std::false_type,
std::true_type t,
Arg1&& arg1,
Args&&... args)
{
auto tracker = vtkm::cont::GetRuntimeDeviceTracker();
return TryExecuteImpl(devId,
std::forward<Functor>(functor),
t,
t,
tracker,
std::forward<Arg1>(arg1),
std::forward<Args>(args)...);
}
} // namespace detail
///@{
@ -177,20 +139,15 @@ inline bool TryExecuteImpl(vtkm::cont::DeviceAdapterId devId,
///
/// This function takes a functor and a \c DeviceAdapterId which represents a
/// specific device to attempt to run on at runtime. It also optionally accepts
/// the following parameters:
/// - A set of devices to compile support for
/// - \c RuntimeDeviceTracker which holds which devices have been enabled at runtime, and
/// records any functor execution failures
/// a set of devices to compile support for.
///
/// It then iterates over the set of devices finding which one matches the provided
/// adapter Id and is also enabled in the runtime. The function will return true
/// only if the device adapter was valid, and the task was successfully run.
/// The optional \c RuntimeDeviceTracker allows for monitoring for certain
/// failures across calls to TryExecute and skip trying devices with a history of failure.
///
/// The TryExecuteOnDevice is also able to perfectly forward arbitrary arguments onto the functor.
/// These arguments must be placed after the optional \c RuntimeDeviceTracker, and device adapter
/// list and will passed to the functor in the same order as listed.
/// These arguments must be placed after the optional device adapter list and will passed to
/// the functor in the same order as listed.
///
/// The functor must implement the function call operator ( \c operator() ) with a return type of
/// \c bool and that is \c true if the execution succeeds, \c false if it fails. If an exception
@ -212,10 +169,6 @@ inline bool TryExecuteImpl(vtkm::cont::DeviceAdapterId devId,
/// // Will not execute all if devId is
/// vtkm::cont::TryExecuteOnDevice(devId, TryCallExample(), int{42});
///
/// // Executing on a specific deviceID with a runtime tracker
/// auto tracker = vtkm::cont::GetRuntimeDeviceTracker();
/// vtkm::cont::TryExecute(devId, TryCallExample(), tracker, int{42});
///
/// \endcode
///
/// This function returns \c true if the functor succeeded on a device,
@ -224,81 +177,40 @@ inline bool TryExecuteImpl(vtkm::cont::DeviceAdapterId devId,
/// If no device list is specified, then \c VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG
/// is used.
///
/// If no \c RuntimeDeviceTracker specified, then \c GetRuntimeDeviceTracker()
/// is used.
template <typename Functor>
VTKM_CONT bool TryExecuteOnDevice(vtkm::cont::DeviceAdapterId devId, Functor&& functor)
{
//we haven't been passed either a runtime tracker or a device list
return detail::TryExecuteImpl(
devId, std::forward<Functor>(functor), std::false_type{}, std::false_type{});
return detail::TryExecuteImpl(devId, std::forward<Functor>(functor), std::false_type{});
}
template <typename Functor, typename Arg1>
VTKM_CONT bool TryExecuteOnDevice(vtkm::cont::DeviceAdapterId devId, Functor&& functor, Arg1&& arg1)
{
//determine if we are being passed a device adapter or runtime tracker as our argument
using is_deviceAdapter = typename std::is_base_of<vtkm::detail::ListRoot, Arg1>::type;
using is_tracker = typename std::is_base_of<vtkm::cont::RuntimeDeviceTracker,
typename std::remove_reference<Arg1>::type>::type;
return detail::TryExecuteImpl(devId,
std::forward<Functor>(functor),
is_tracker{},
is_deviceAdapter{},
std::forward<Arg1>(arg1));
}
template <typename Functor, typename Arg1, typename Arg2, typename... Args>
template <typename Functor, typename Arg1, typename... Args>
VTKM_CONT bool TryExecuteOnDevice(vtkm::cont::DeviceAdapterId devId,
Functor&& functor,
Arg1&& arg1,
Arg2&& arg2,
Args&&... args)
{
//So arg1 can be runtime or device adapter
//if arg1 is runtime, we need to see if arg2 is device adapter
using is_arg1_tracker =
typename std::is_base_of<vtkm::cont::RuntimeDeviceTracker,
typename std::remove_reference<Arg1>::type>::type;
using is_arg2_devicelist = typename std::is_base_of<vtkm::detail::ListRoot, Arg2>::type;
//We now know what of three states we are currently at
using has_runtime_and_deviceAdapter =
brigand::bool_<is_arg1_tracker::value && is_arg2_devicelist::value>;
using has_just_runtime = brigand::bool_<is_arg1_tracker::value && !is_arg2_devicelist::value>;
using has_just_devicelist = typename std::is_base_of<vtkm::detail::ListRoot, Arg1>::type;
//With this information we can now compute if we have a runtime tracker and/or
//the device adapter and enable the correct flags
using first_true =
brigand::bool_<has_runtime_and_deviceAdapter::value || has_just_runtime::value>;
using second_true =
brigand::bool_<has_runtime_and_deviceAdapter::value || has_just_devicelist::value>;
//determine if we are being passed a device adapter or runtime tracker as our argument
using is_deviceAdapter = typename std::is_base_of<vtkm::detail::ListRoot, Arg1>::type;
return detail::TryExecuteImpl(devId,
functor,
first_true{},
second_true{},
std::forward<Functor>(functor),
is_deviceAdapter{},
std::forward<Arg1>(arg1),
std::forward<Arg2>(arg2),
std::forward<Args>(args)...);
}
//@} //block doxygen all TryExecuteOnDevice functions
///@{
/// \brief Try to execute a functor on a set of devices until one succeeds.
///
/// This function takes a functor and optionally the following:
/// - A set of devices to compile support for
/// - \c RuntimeDeviceTracker which holds which devices have been enabled at runtime, and
/// records any functor execution failures
///
/// This function takes a functor and optionally a set of devices to compile support.
/// It then tries to run the functor for each device (in the order given in the list) until the
/// execution succeeds. The optional \c RuntimeDeviceTracker allows for monitoring for certain
/// failures across calls to TryExecute and skip trying devices with a history of failure.
/// execution succeeds.
///
/// The TryExecute is also able to perfectly forward arbitrary arguments onto the functor.
/// These arguments must be placed after the optional \c RuntimeDeviceTracker, and device adapter
/// list and will passed to the functor in the same order as listed.
/// These arguments must be placed after the optional device adapter list and will passed
/// to the functor in the same order as listed.
///
/// The functor must implement the function call operator ( \c operator() ) with a return type of
/// \c bool and that is \c true if the execution succeeds, \c false if it fails. If an exception
@ -316,20 +228,13 @@ VTKM_CONT bool TryExecuteOnDevice(vtkm::cont::DeviceAdapterId devId,
/// };
///
///
/// // Executing without a runtime tracker, deviceId, or device list
/// // Executing without a deviceId, or device list
/// vtkm::cont::TryExecute(TryCallExample(), int{42});
///
/// // Executing with a runtime tracker
/// auto tracker = vtkm::cont::GetRuntimeDeviceTracker();
/// vtkm::cont::TryExecute(TryCallExample(), tracker, int{42});
///
/// // Executing with a device list
/// using DeviceList = vtkm::ListTagBase<vtkm::cont::DeviceAdapterTagSerial>;
/// vtkm::cont::TryExecute(TryCallExample(), DeviceList(), int{42});
///
/// // Executing with a runtime tracker and device list
/// vtkm::cont::TryExecute(EdgeCaseFunctor(), tracker, DeviceList(), int{42});
///
/// \endcode
///
/// This function returns \c true if the functor succeeded on a device,
@ -338,8 +243,6 @@ VTKM_CONT bool TryExecuteOnDevice(vtkm::cont::DeviceAdapterId devId,
/// If no device list is specified, then \c VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG
/// is used.
///
/// If no \c RuntimeDeviceTracker specified, then \c GetRuntimeDeviceTracker()
/// is used.
template <typename Functor, typename... Args>
VTKM_CONT bool TryExecute(Functor&& functor, Args&&... args)
{

@ -26,7 +26,6 @@
#include <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/cont/ErrorBadType.h>
#include <vtkm/cont/ErrorBadValue.h>
#include <vtkm/cont/RuntimeDeviceTracker.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/cont/serial/DeviceAdapterSerial.h>
@ -92,7 +91,7 @@ struct TryExecuteTestErrorFunctor
};
template <typename DeviceList>
void TryExecuteWithDevice(DeviceList, bool expectSuccess)
void TryExecuteTests(DeviceList, bool expectSuccess)
{
vtkm::cont::ArrayHandle<vtkm::FloatDefault> inArray;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> outArray;
@ -129,29 +128,6 @@ void TryExecuteWithDevice(DeviceList, bool expectSuccess)
}
}
template <typename DeviceList>
void TryExecuteAllExplicit(DeviceList, bool expectSuccess)
{
auto tracker = vtkm::cont::GetRuntimeDeviceTracker();
vtkm::cont::ArrayHandle<vtkm::FloatDefault> inArray;
vtkm::cont::ArrayHandle<vtkm::FloatDefault> outArray;
inArray.Allocate(ARRAY_SIZE);
SetPortal(inArray.GetPortalControl());
bool result =
vtkm::cont::TryExecute(TryExecuteTestFunctor(), tracker, DeviceList(), inArray, outArray);
if (expectSuccess)
{
VTKM_TEST_ASSERT(result, "Call returned failure when expected success.");
CheckPortal(outArray.GetPortalConstControl());
}
else
{
VTKM_TEST_ASSERT(!result, "Call returned true when expected failure.");
}
}
struct EdgeCaseFunctor
{
template <typename DeviceList>
@ -178,32 +154,12 @@ void TryExecuteAllEdgeCases()
std::cout << "TryExecute no Runtime, no Device, with parameters." << std::endl;
vtkm::cont::TryExecute(EdgeCaseFunctor(), int{ 42 }, float{ 3.14f }, bool{ true });
std::cout << "TryExecute with Runtime, no Device, no parameters." << std::endl;
vtkm::cont::TryExecute(EdgeCaseFunctor(), tracker);
std::cout << "TryExecute with Runtime, no Device, with parameters." << std::endl;
vtkm::cont::TryExecute(EdgeCaseFunctor(), tracker, int{ 42 }, float{ 3.14f }, bool{ true });
std::cout << "TryExecute no Runtime, with Device, no parameters." << std::endl;
std::cout << "TryExecute with Device, no parameters." << std::endl;
vtkm::cont::TryExecute(EdgeCaseFunctor(), SingleValidList());
std::cout << "TryExecute no Runtime, with Device, with parameters." << std::endl;
std::cout << "TryExecute with Device, with parameters." << std::endl;
vtkm::cont::TryExecute(
EdgeCaseFunctor(), SingleValidList(), int{ 42 }, float{ 3.14f }, bool{ true });
std::cout << "TryExecute with Runtime, with Device, no parameters." << std::endl;
vtkm::cont::TryExecute(EdgeCaseFunctor(), tracker, SingleValidList());
std::cout << "TryExecute with Runtime, with Device, with parameters." << std::endl;
vtkm::cont::TryExecute(
EdgeCaseFunctor(), tracker, SingleValidList(), int{ 42 }, float{ 3.14f }, bool{ true });
}
template <typename DeviceList>
void TryExecuteTests(DeviceList list, bool expectSuccess)
{
TryExecuteAllExplicit(list, expectSuccess);
TryExecuteWithDevice(list, expectSuccess);
}
template <typename ExceptionType>