Replace FindDeviceAdapterTagAndCall with TryExecuteOnDevice

Also add a throwFailedRuntimeDeviceTransfer that throws a nicely
detailed message on why a something couldn't be transfered to
the requested device adapter.
This commit is contained in:
Robert Maynard 2018-08-08 14:53:28 -04:00
parent 554bc3d369
commit 28e0eb9da6
10 changed files with 121 additions and 118 deletions

@ -22,8 +22,8 @@
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleUniformPointCoordinates.h>
#include <vtkm/cont/TryExecute.h>
#include <vtkm/cont/VirtualObjectHandle.h>
#include <vtkm/cont/internal/DeviceAdapterListHelpers.h>
#include <vtkm/cont/internal/DynamicTransform.h>
#include <vtkm/VecTraits.h>
@ -246,9 +246,14 @@ public:
VTKM_CONT PortalConst PrepareForInput(vtkm::cont::DeviceAdapterId deviceId) override
{
PortalConst portal;
vtkm::cont::internal::FindDeviceAdapterTagAndCall(
deviceId, DeviceList(), PrepareForInputFunctor(), this, portal);
bool success = vtkm::cont::TryExecuteOnDevice(
deviceId, PrepareForInputFunctor(), DeviceList(), this, portal);
if (!success)
{
throwFailedRuntimeDeviceTransfer("ArrayHandleVirtualCoordinates", deviceId);
}
return portal;
}
@ -256,16 +261,24 @@ public:
vtkm::cont::DeviceAdapterId deviceId) override
{
Portal portal;
vtkm::cont::internal::FindDeviceAdapterTagAndCall(
deviceId, DeviceList(), PrepareForOutputFunctor(), this, numberOfValues, portal);
bool success = vtkm::cont::TryExecuteOnDevice(
deviceId, PrepareForOutputFunctor(), DeviceList(), this, numberOfValues, portal);
if (!success)
{
throwFailedRuntimeDeviceTransfer("ArrayHandleVirtualCoordinates", deviceId);
}
return portal;
}
VTKM_CONT Portal PrepareForInPlace(vtkm::cont::DeviceAdapterId deviceId) override
{
Portal portal;
vtkm::cont::internal::FindDeviceAdapterTagAndCall(
deviceId, DeviceList(), PrepareForInPlaceFunctor(), this, portal);
bool success = vtkm::cont::TryExecuteOnDevice(
deviceId, PrepareForInPlaceFunctor(), DeviceList(), this, portal);
if (!success)
{
throwFailedRuntimeDeviceTransfer("ArrayHandleVirtualCoordinates", deviceId);
}
return portal;
}
@ -273,7 +286,7 @@ private:
struct PrepareForInputFunctor
{
template <typename DeviceAdapter>
VTKM_CONT void operator()(DeviceAdapter device,
VTKM_CONT bool operator()(DeviceAdapter device,
CoordinatesArrayHandle* instance,
PortalConst& ret) const
{
@ -283,13 +296,14 @@ private:
vtkm::ListTagBase<DeviceAdapter>());
ret = PortalConst(portal.GetNumberOfValues(),
instance->DevicePortalHandle.PrepareForExecution(device));
return true;
}
};
struct PrepareForOutputFunctor
{
template <typename DeviceAdapter>
VTKM_CONT void operator()(DeviceAdapter device,
VTKM_CONT bool operator()(DeviceAdapter device,
CoordinatesArrayHandle* instance,
vtkm::Id numberOfValues,
Portal& ret) const
@ -298,13 +312,14 @@ private:
instance->DevicePortalHandle.Reset(
new CoordinatesPortal<decltype(portal)>(portal), true, vtkm::ListTagBase<DeviceAdapter>());
ret = Portal(numberOfValues, instance->DevicePortalHandle.PrepareForExecution(device));
return true;
}
};
struct PrepareForInPlaceFunctor
{
template <typename DeviceAdapter>
VTKM_CONT void operator()(DeviceAdapter device,
VTKM_CONT bool operator()(DeviceAdapter device,
CoordinatesArrayHandle* instance,
Portal& ret) const
{
@ -313,6 +328,7 @@ private:
new CoordinatesPortal<decltype(portal)>(portal), true, vtkm::ListTagBase<DeviceAdapter>());
ret = Portal(instance->Array.GetNumberOfValues(),
instance->DevicePortalHandle.PrepareForExecution(device));
return true;
}
};

@ -31,7 +31,6 @@
#include <vtkm/cont/DeviceAdapterAlgorithm.h>
#include <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/cont/cuda/DeviceAdapterCuda.h>
#include <vtkm/cont/internal/DeviceAdapterListHelpers.h>
#include <vtkm/exec/BoundingIntervalHierarchyExec.h>
#include <vtkm/worklet/DispatcherMapField.h>
#include <vtkm/worklet/DispatcherMapTopology.h>
@ -455,7 +454,7 @@ class BoundingIntervalHierarchy::PrepareForExecutionFunctor
{
public:
template <typename DeviceAdapter>
VTKM_CONT void operator()(DeviceAdapter,
VTKM_CONT bool operator()(DeviceAdapter,
const vtkm::cont::BoundingIntervalHierarchy& bih,
HandleType& bihExec) const
{
@ -508,6 +507,7 @@ public:
{
throw vtkm::cont::ErrorBadType("Could not determine type to write out.");
}
return true;
}
};
@ -522,9 +522,12 @@ VTKM_CONT
const HandleType BoundingIntervalHierarchy::PrepareForExecutionImpl(
const vtkm::cont::DeviceAdapterId deviceId) const
{
using DeviceList = VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG;
vtkm::cont::internal::FindDeviceAdapterTagAndCall(
deviceId, DeviceList(), PrepareForExecutionFunctor(), *this, this->ExecHandle);
const bool success =
vtkm::cont::TryExecuteOnDevice(deviceId, PrepareForExecutionFunctor(), *this, this->ExecHandle);
if (!success)
{
throwFailedRuntimeDeviceTransfer("BoundingIntervalHierarchy", deviceId);
}
return this->ExecHandle;
}

@ -126,6 +126,7 @@ set(sources
DataSetBuilderUniform.cxx
DynamicArrayHandle.cxx
EnvironmentTracker.cxx
ErrorBadDevice.cxx
Field.cxx
FieldRangeCompute.cxx
FieldRangeGlobalCompute.cxx

@ -860,15 +860,20 @@ const vtkm::exec::ColorTableBase* ColorTable::PrepareForExecution(
this->Impl->OpacityMidSharpHandle = vtkm::cont::make_ArrayHandle(this->Impl->OpacityMidSharp);
}
bool transfered = true;
if (this->Impl->ColorArraysChanged || this->Impl->OpacityArraysChanged ||
this->Impl->HostSideCacheChanged)
{
vtkm::cont::internal::FindDeviceAdapterTagAndCall(deviceId,
VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG(),
detail::transfer_color_table_to_device{},
this->Impl->HostSideCache.get(),
this->Impl.get());
transfered = vtkm::cont::TryExecuteOnDevice(deviceId,
detail::transfer_color_table_to_device{},
this->Impl->HostSideCache.get(),
this->Impl.get());
}
if (!transfered)
{
throwFailedRuntimeDeviceTransfer("ColorTable", deviceId);
}
this->Impl->ColorArraysChanged = false;
this->Impl->OpacityArraysChanged = false;

@ -0,0 +1,42 @@
//============================================================================
// 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 2016 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2016 UT-Battelle, LLC.
// Copyright 2016 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 <vtkm/cont/ErrorBadDevice.h>
#include <vtkm/cont/internal/DeviceAdapterTag.h>
#include <string>
namespace vtkm
{
namespace cont
{
void throwFailedRuntimeDeviceTransfer(const std::string& className,
vtkm::cont::DeviceAdapterId deviceId)
{ //Should we support typeid() instead of className?
const std::string msg = "VTK-m was unable to transfer " + className + " to DeviceAdapter[id=" +
std::to_string(deviceId.GetValue()) +
"]. This is generally caused by asking for execution on a DeviceAdapter that "
"isn't compiled into VTK-m. In the case of CUDA it can also be caused by accidentally "
"compiling source files as C++ files instead of CUDA.";
throw vtkm::cont::ErrorBadDevice(msg);
}
}
}

@ -22,11 +22,15 @@
#include <vtkm/cont/Error.h>
#include <vtkm/cont/internal/DeviceAdapterTag.h>
#include <vtkm/cont/vtkm_cont_export.h>
namespace vtkm
{
namespace cont
{
VTKM_SILENCE_WEAK_VTABLE_WARNING_START
/// This class is thrown when VTK-m performs an operation that is not supported
@ -42,6 +46,15 @@ public:
};
VTKM_SILENCE_WEAK_VTABLE_WARNING_END
/// Throws an ErrorBadeDevice exception with the following message:
/// "VTK-m was unable to transfer \c className to DeviceAdapter[id=\c device].
/// This is generally caused by asking for execution on a DeviceAdapter that
/// isn't compiled into VTK-m. In the case of CUDA it can also be caused by accidentally
/// compiling source files as C++ files instead of CUDA."
//
VTKM_CONT_EXPORT void throwFailedRuntimeDeviceTransfer(const std::string& className,
vtkm::cont::DeviceAdapterId device);
}
} // namespace vtkm::cont

@ -60,7 +60,6 @@ public:
return PrepareForExecutionImp(device).PrepareForExecution(device);
}
//VTKM_CONT virtual const vtkm::exec::PointLocator*
using HandleType = vtkm::cont::VirtualObjectHandle<vtkm::exec::PointLocator>;
VTKM_CONT virtual const HandleType PrepareForExecutionImp(
vtkm::cont::DeviceAdapterId deviceId) const = 0;

@ -140,11 +140,10 @@ public:
struct PrepareForExecutionFunctor
{
template <typename DeviceAdapter>
VTKM_CONT void operator()(DeviceAdapter,
VTKM_CONT bool operator()(DeviceAdapter,
const vtkm::cont::PointLocatorUniformGrid& self,
HandleType& handle) const
{
//vtkm::exec::PointLocatorUniformGrid* locator =
vtkm::exec::PointLocatorUniformGrid<DeviceAdapter>* h =
new vtkm::exec::PointLocatorUniformGrid<DeviceAdapter>(
self.Min,
@ -155,27 +154,20 @@ public:
self.cellLower.PrepareForInput(DeviceAdapter()),
self.cellUpper.PrepareForInput(DeviceAdapter()));
handle.Reset(h);
//return handle.PrepareForExecution(DeviceAdapter());
return true;
}
};
VTKM_CONT
//const vtkm::exec::PointLocator *
const HandleType PrepareForExecutionImp(vtkm::cont::DeviceAdapterId deviceId) const override
{
// TODO: call VirtualObjectHandle::PrepareForExecution() and return vtkm::exec::PointLocator
// TODO: how to convert deviceId back to DeviceAdapter tag?
//using DeviceList = vtkm::ListTagBase<vtkm::cont::DeviceAdapterTagCuda,
// vtkm::cont::DeviceAdapterTagTBB,
// vtkm::cont::DeviceAdapterTagSerial>;
using DeviceList = VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG;
//HandleType ExecHandle; // = new HandleType(locator, false);
vtkm::cont::internal::FindDeviceAdapterTagAndCall(
deviceId, DeviceList(), PrepareForExecutionFunctor(), *this, ExecHandle);
const bool success =
vtkm::cont::TryExecuteOnDevice(deviceId, PrepareForExecutionFunctor(), *this, ExecHandle);
if (!success)
{
throwFailedRuntimeDeviceTransfer("PointLocatorUniformGrid", deviceId);
}
return ExecHandle;
//return ExecHandle.PrepareForExecution(DeviceAdapter());
}
private:

@ -130,11 +130,12 @@ public:
{
if (!this->Internals->Transfers[static_cast<std::size_t>(deviceId.GetValue())])
{
std::string msg = "VTK-m was asked to transfer an object for execution on DeviceAdapter " +
std::string msg =
"VTK-m was asked to transfer a VirtualObjectHandle for execution on DeviceAdapter " +
std::to_string(deviceId.GetValue()) +
". It can't as this VirtualObjectHandle was not constructed/bound with this "
"DeviceAdapter in the list of valid DeviceAdapters.";
throw vtkm::cont::ErrorBadType(msg);
throw vtkm::cont::ErrorBadDevice(msg);
}
if (this->Internals->Current)
@ -198,17 +199,9 @@ private:
std::unique_ptr<TransferInterface>* transfers,
const VirtualDerivedType* virtualObject) const
{
using DeviceInfo = vtkm::cont::DeviceAdapterTraits<DeviceAdapter>;
if (!device.IsValueValid())
{
std::string msg =
"VTK-m is unable to construct a VirtualObjectHandle for execution on DeviceAdapter" +
DeviceInfo::GetName() + "[id=" + std::to_string(device.GetValue()) +
"]. This is generally caused by either asking for execution on a DeviceAdapter that "
"wasn't compiled into VTK-m. In the case of CUDA it can also be caused by accidentally "
"compiling source files as C++ files instead of CUDA.";
throw vtkm::cont::ErrorBadType(msg);
throwFailedRuntimeDeviceTransfer("VirtualObjectHandle", device);
}
using TransferImpl = TransferInterfaceImpl<VirtualDerivedType, DeviceAdapter>;
transfers[device.GetValue()].reset(new TransferImpl(virtualObject));

@ -32,104 +32,43 @@ namespace internal
{
//============================================================================
template <typename FunctorType>
class ExecuteIfValidDeviceTag
struct ExecuteIfValidDeviceTag
{
private:
template <typename DeviceAdapter>
using EnableIfValid = std::enable_if<DeviceAdapter::IsEnabled>;
template <typename DeviceAdapter>
using EnableIfInvalid = std::enable_if<!DeviceAdapter::IsEnabled>;
public:
explicit ExecuteIfValidDeviceTag(const FunctorType& functor)
: Functor(functor)
{
}
template <typename DeviceAdapter, typename... Args>
template <typename DeviceAdapter, typename Functor, typename... Args>
typename EnableIfValid<DeviceAdapter>::type operator()(
DeviceAdapter device,
Functor&& f,
const vtkm::cont::RuntimeDeviceTracker& tracker,
Args&&... args) const
{
if (tracker.CanRunOn(device))
{
this->Functor(device, std::forward<Args>(args)...);
f(device, std::forward<Args>(args)...);
}
}
// do not generate code for invalid devices
template <typename DeviceAdapter, typename... Args>
typename EnableIfInvalid<DeviceAdapter>::type operator()(DeviceAdapter,
const vtkm::cont::RuntimeDeviceTracker&,
Args&&...) const
typename EnableIfInvalid<DeviceAdapter>::type operator()(DeviceAdapter, Args&&...) const
{
}
private:
FunctorType Functor;
};
/// Execute the given functor on each valid device in \c DeviceList.
///
template <typename DeviceList, typename Functor, typename... Args>
VTKM_CONT void ForEachValidDevice(DeviceList devices, const Functor& functor, Args&&... args)
VTKM_CONT void ForEachValidDevice(DeviceList devices, Functor&& functor, Args&&... args)
{
auto tracker = vtkm::cont::GetGlobalRuntimeDeviceTracker();
ExecuteIfValidDeviceTag<Functor> wrapped(functor);
vtkm::ListForEach(wrapped, devices, tracker, std::forward<Args>(args)...);
}
//============================================================================
template <typename FunctorType>
class ExecuteIfSameDeviceId
{
public:
ExecuteIfSameDeviceId(FunctorType functor)
: Functor(functor)
{
}
template <typename DeviceAdapter, typename... Args>
void operator()(DeviceAdapter device,
vtkm::cont::DeviceAdapterId deviceId,
bool& status,
Args&&... args) const
{
if (device == deviceId)
{
VTKM_ASSERT(status == false);
this->Functor(device, std::forward<Args>(args)...);
status = true;
}
}
private:
FunctorType Functor;
};
/// Finds the \c DeviceAdapterTag in \c DeviceList with id equal to deviceId
/// and executes the functor with the tag. Throws \c ErrorBadDevice if a valid
/// \c DeviceAdapterTag is not found.
///
template <typename DeviceList, typename Functor, typename... Args>
VTKM_CONT void FindDeviceAdapterTagAndCall(vtkm::cont::DeviceAdapterId deviceId,
DeviceList devices,
const Functor& functor,
Args&&... args)
{
bool status = false;
ExecuteIfSameDeviceId<Functor> wrapped(functor);
ForEachValidDevice(devices, wrapped, deviceId, status, std::forward<Args>(args)...);
if (!status)
{
std::string msg = "Device with id " + std::to_string(deviceId.GetValue()) +
" is either not in the list or is invalid";
throw vtkm::cont::ErrorBadDevice(msg);
}
vtkm::ListForEach(
ExecuteIfValidDeviceTag{}, devices, functor, tracker, std::forward<Args>(args)...);
}
}
}