Deprecate ArrayHandle::GetDeviceAdapterId

This method is a remenant of when `ArrayHandle` could only store data on
one device at a time. It is now capable of storing data on any number of
devices (as well as the host), so asking for "the" device no longer
makes sense. Thus, this method is deprecated in favor of
`ArrayHandle::IsOnDevice`.

This deprecation leads to fixing some older functionality that still
assumed data could only be on one device at a time.

Fixes #592.
This commit is contained in:
Kenneth Moreland 2021-07-19 13:21:07 -06:00
parent f34b432832
commit 34615a9858
4 changed files with 61 additions and 51 deletions

@ -69,14 +69,29 @@ struct BitFieldToUnorderedSetFunctor
struct CopyFunctor
{
template <typename T, typename S, typename... Args>
VTKM_CONT bool InputArrayOnDevice(vtkm::cont::DeviceAdapterId device,
const vtkm::cont::ArrayHandle<T, S>& input,
Args&&...) const
{
return input.IsOnDevice(device);
}
template <typename Device, typename... Args>
VTKM_CONT bool operator()(Device, Args&&... args) const
VTKM_CONT bool operator()(Device device, bool useExistingDevice, Args&&... args) const
{
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::Copy(
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
if (!useExistingDevice || this->InputArrayOnDevice(device, std::forward<Args>(args)...))
{
vtkm::cont::Token token;
vtkm::cont::DeviceAdapterAlgorithm<Device>::Copy(
PrepareArgForExec<Device>(std::forward<Args>(args), token)...);
return true;
}
else
{
return false;
}
}
};
@ -399,14 +414,14 @@ struct Algorithm
// 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);
bool isCopied =
vtkm::cont::TryExecuteOnDevice(devId, detail::CopyFunctor(), true, input, output);
if (isCopied)
{
return true;
}
}
return vtkm::cont::TryExecuteOnDevice(devId, detail::CopyFunctor(), input, output);
return vtkm::cont::TryExecuteOnDevice(devId, detail::CopyFunctor(), false, input, output);
}
template <typename T, typename U, class CIn, class COut>
VTKM_CONT static void Copy(const vtkm::cont::ArrayHandle<T, CIn>& input,

@ -33,34 +33,12 @@ namespace detail
{
// Element-wise copy.
// TODO: Remove last argument once ArryHandleNewStyle becomes ArrayHandle
template <typename InArrayType, typename OutArrayType>
void ArrayCopyWithAlgorithm(const InArrayType& source, OutArrayType& destination)
{
// Find the device that already has a copy of the data:
vtkm::cont::DeviceAdapterId devId = source.GetDeviceAdapterId();
// If the data is not on any device, let the runtime tracker pick an available
// parallel copy algorithm.
if (devId.GetValue() == VTKM_DEVICE_ADAPTER_UNDEFINED)
{
devId = vtkm::cont::make_DeviceAdapterId(VTKM_DEVICE_ADAPTER_ANY);
}
bool success = vtkm::cont::Algorithm::Copy(devId, source, destination);
if (!success && devId.GetValue() != VTKM_DEVICE_ADAPTER_ANY)
{ // Retry on any device if the first attempt failed.
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
"Failed to run ArrayCopy on device '" << devId.GetName()
<< "'. Retrying on any device.");
success = vtkm::cont::Algorithm::Copy(vtkm::cont::DeviceAdapterTagAny{}, source, destination);
}
if (!success)
{
throw vtkm::cont::ErrorExecution("Failed to run ArrayCopy on any device.");
}
// Current implementation of Algorithm::Copy will first try to copy on devices where the
// data is already available.
vtkm::cont::Algorithm::Copy(source, destination);
}
// TODO: Remove last argument once ArryHandleNewStyle becomes ArrayHandle

@ -26,6 +26,33 @@ namespace vtkm
namespace cont
{
namespace detail
{
struct ArrayGetValuesFunctor
{
template <typename Device, typename IdsArray, typename DataArray, typename OutputArray>
VTKM_CONT bool operator()(Device,
const IdsArray& ids,
const DataArray& data,
OutputArray& output) const
{
// Only get data on a device the data are already on.
if (data.IsOnDevice(Device{}))
{
const auto input = vtkm::cont::make_ArrayHandlePermutation(ids, data);
vtkm::cont::DeviceAdapterAlgorithm<Device>::Copy(input, output);
return true;
}
else
{
return false;
}
}
};
} // namespace detail
/// \brief Obtain a small set of values from an ArrayHandle with minimal device
/// transfers.
///
@ -90,25 +117,17 @@ VTKM_CONT void ArrayGetValues(const vtkm::cont::ArrayHandle<vtkm::Id, SIds>& ids
{
bool copyComplete = false;
// Find the device that already has a copy of the data:
vtkm::cont::DeviceAdapterId devId = data.GetDeviceAdapterId();
if (devId.GetValue() != VTKM_DEVICE_ADAPTER_UNDEFINED)
{ // Data exists on some device -- use it:
const auto input = vtkm::cont::make_ArrayHandlePermutation(ids, data);
copyComplete = vtkm::cont::Algorithm::Copy(devId, input, output);
if (!copyComplete)
{ // Retry on any device if the first attempt failed.
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
"Failed to run ArrayGetValues on device '"
<< devId.GetName() << "'. Falling back to control-side copy.");
copyComplete = vtkm::cont::Algorithm::Copy(vtkm::cont::DeviceAdapterTagAny{}, input, output);
}
// If the data are not already on the host, attempt to copy on the device.
if (!data.IsOnHost())
{
copyComplete = vtkm::cont::TryExecute(detail::ArrayGetValuesFunctor{}, ids, data, output);
}
if (!copyComplete)
{ // Fallback to a control-side copy if the device copy fails or if the device
// is undefined:
// is undefined or if the data were already on the host. In this case, the
// best we can do is grab the portals and copy one at a time on the host with
// a for loop.
const vtkm::Id numVals = ids.GetNumberOfValues();
auto idPortal = ids.ReadPortal();
auto dataPortal = data.ReadPortal();

@ -647,10 +647,8 @@ public:
/// Note that in a multithreaded environment the validity of this result can
/// change.
///
/// TODO: Deprecate this method in favor of IsOnDevice since the data can be on multiple
/// devices at once.
VTKM_CONT
DeviceAdapterId GetDeviceAdapterId() const
VTKM_DEPRECATED(1.7, "Use ArrayHandle::IsOnDevice.") DeviceAdapterId GetDeviceAdapterId() const
{
return detail::ArrayHandleGetDeviceAdapterId(this->Buffers);
}