From 28e0eb9da665a5cac449cb29e4662289a13bdf90 Mon Sep 17 00:00:00 2001 From: Robert Maynard Date: Wed, 8 Aug 2018 14:53:28 -0400 Subject: [PATCH] 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. --- vtkm/cont/ArrayHandleVirtualCoordinates.h | 36 ++++++--- vtkm/cont/BoundingIntervalHierarchy.hxx | 13 +-- vtkm/cont/CMakeLists.txt | 1 + vtkm/cont/ColorTable.cxx | 15 ++-- vtkm/cont/ErrorBadDevice.cxx | 42 ++++++++++ vtkm/cont/ErrorBadDevice.h | 13 +++ vtkm/cont/PointLocator.h | 1 - vtkm/cont/PointLocatorUniformGrid.h | 24 ++---- vtkm/cont/VirtualObjectHandle.h | 15 +--- vtkm/cont/internal/DeviceAdapterListHelpers.h | 79 +++---------------- 10 files changed, 121 insertions(+), 118 deletions(-) create mode 100644 vtkm/cont/ErrorBadDevice.cxx diff --git a/vtkm/cont/ArrayHandleVirtualCoordinates.h b/vtkm/cont/ArrayHandleVirtualCoordinates.h index 9ae1b7910..997f5c0e0 100644 --- a/vtkm/cont/ArrayHandleVirtualCoordinates.h +++ b/vtkm/cont/ArrayHandleVirtualCoordinates.h @@ -22,8 +22,8 @@ #include #include +#include #include -#include #include #include @@ -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 - VTKM_CONT void operator()(DeviceAdapter device, + VTKM_CONT bool operator()(DeviceAdapter device, CoordinatesArrayHandle* instance, PortalConst& ret) const { @@ -283,13 +296,14 @@ private: vtkm::ListTagBase()); ret = PortalConst(portal.GetNumberOfValues(), instance->DevicePortalHandle.PrepareForExecution(device)); + return true; } }; struct PrepareForOutputFunctor { template - 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(portal), true, vtkm::ListTagBase()); ret = Portal(numberOfValues, instance->DevicePortalHandle.PrepareForExecution(device)); + return true; } }; struct PrepareForInPlaceFunctor { template - VTKM_CONT void operator()(DeviceAdapter device, + VTKM_CONT bool operator()(DeviceAdapter device, CoordinatesArrayHandle* instance, Portal& ret) const { @@ -313,6 +328,7 @@ private: new CoordinatesPortal(portal), true, vtkm::ListTagBase()); ret = Portal(instance->Array.GetNumberOfValues(), instance->DevicePortalHandle.PrepareForExecution(device)); + return true; } }; diff --git a/vtkm/cont/BoundingIntervalHierarchy.hxx b/vtkm/cont/BoundingIntervalHierarchy.hxx index feb191627..ab32ecfca 100644 --- a/vtkm/cont/BoundingIntervalHierarchy.hxx +++ b/vtkm/cont/BoundingIntervalHierarchy.hxx @@ -31,7 +31,6 @@ #include #include #include -#include #include #include #include @@ -455,7 +454,7 @@ class BoundingIntervalHierarchy::PrepareForExecutionFunctor { public: template - 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; } diff --git a/vtkm/cont/CMakeLists.txt b/vtkm/cont/CMakeLists.txt index c05540620..3e907c258 100644 --- a/vtkm/cont/CMakeLists.txt +++ b/vtkm/cont/CMakeLists.txt @@ -126,6 +126,7 @@ set(sources DataSetBuilderUniform.cxx DynamicArrayHandle.cxx EnvironmentTracker.cxx + ErrorBadDevice.cxx Field.cxx FieldRangeCompute.cxx FieldRangeGlobalCompute.cxx diff --git a/vtkm/cont/ColorTable.cxx b/vtkm/cont/ColorTable.cxx index 2273029a3..50275bd37 100644 --- a/vtkm/cont/ColorTable.cxx +++ b/vtkm/cont/ColorTable.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; diff --git a/vtkm/cont/ErrorBadDevice.cxx b/vtkm/cont/ErrorBadDevice.cxx new file mode 100644 index 000000000..5f09e0dc1 --- /dev/null +++ b/vtkm/cont/ErrorBadDevice.cxx @@ -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 +#include + +#include + +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); +} +} +} diff --git a/vtkm/cont/ErrorBadDevice.h b/vtkm/cont/ErrorBadDevice.h index a3128c75e..cc2168bdb 100644 --- a/vtkm/cont/ErrorBadDevice.h +++ b/vtkm/cont/ErrorBadDevice.h @@ -22,11 +22,15 @@ #include +#include +#include + 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 diff --git a/vtkm/cont/PointLocator.h b/vtkm/cont/PointLocator.h index c7e29475f..cf5eff06e 100644 --- a/vtkm/cont/PointLocator.h +++ b/vtkm/cont/PointLocator.h @@ -60,7 +60,6 @@ public: return PrepareForExecutionImp(device).PrepareForExecution(device); } - //VTKM_CONT virtual const vtkm::exec::PointLocator* using HandleType = vtkm::cont::VirtualObjectHandle; VTKM_CONT virtual const HandleType PrepareForExecutionImp( vtkm::cont::DeviceAdapterId deviceId) const = 0; diff --git a/vtkm/cont/PointLocatorUniformGrid.h b/vtkm/cont/PointLocatorUniformGrid.h index c41ddeb82..57b0fd585 100644 --- a/vtkm/cont/PointLocatorUniformGrid.h +++ b/vtkm/cont/PointLocatorUniformGrid.h @@ -140,11 +140,10 @@ public: struct PrepareForExecutionFunctor { template - 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* h = new vtkm::exec::PointLocatorUniformGrid( 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; - - 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: diff --git a/vtkm/cont/VirtualObjectHandle.h b/vtkm/cont/VirtualObjectHandle.h index cfc2f2544..4c3b22a9f 100644 --- a/vtkm/cont/VirtualObjectHandle.h +++ b/vtkm/cont/VirtualObjectHandle.h @@ -130,11 +130,12 @@ public: { if (!this->Internals->Transfers[static_cast(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* transfers, const VirtualDerivedType* virtualObject) const { - using DeviceInfo = vtkm::cont::DeviceAdapterTraits; 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; transfers[device.GetValue()].reset(new TransferImpl(virtualObject)); diff --git a/vtkm/cont/internal/DeviceAdapterListHelpers.h b/vtkm/cont/internal/DeviceAdapterListHelpers.h index 1f7fd11c1..40fa061e0 100644 --- a/vtkm/cont/internal/DeviceAdapterListHelpers.h +++ b/vtkm/cont/internal/DeviceAdapterListHelpers.h @@ -32,104 +32,43 @@ namespace internal { //============================================================================ -template -class ExecuteIfValidDeviceTag +struct ExecuteIfValidDeviceTag { -private: + template using EnableIfValid = std::enable_if; template using EnableIfInvalid = std::enable_if; -public: - explicit ExecuteIfValidDeviceTag(const FunctorType& functor) - : Functor(functor) - { - } - - template + template typename EnableIfValid::type operator()( DeviceAdapter device, + Functor&& f, const vtkm::cont::RuntimeDeviceTracker& tracker, Args&&... args) const { if (tracker.CanRunOn(device)) { - this->Functor(device, std::forward(args)...); + f(device, std::forward(args)...); } } // do not generate code for invalid devices template - typename EnableIfInvalid::type operator()(DeviceAdapter, - const vtkm::cont::RuntimeDeviceTracker&, - Args&&...) const + typename EnableIfInvalid::type operator()(DeviceAdapter, Args&&...) const { } - -private: - FunctorType Functor; }; /// Execute the given functor on each valid device in \c DeviceList. /// template -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 wrapped(functor); - vtkm::ListForEach(wrapped, devices, tracker, std::forward(args)...); -} - -//============================================================================ -template -class ExecuteIfSameDeviceId -{ -public: - ExecuteIfSameDeviceId(FunctorType functor) - : Functor(functor) - { - } - - template - 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)...); - 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 -VTKM_CONT void FindDeviceAdapterTagAndCall(vtkm::cont::DeviceAdapterId deviceId, - DeviceList devices, - const Functor& functor, - Args&&... args) -{ - bool status = false; - ExecuteIfSameDeviceId wrapped(functor); - ForEachValidDevice(devices, wrapped, deviceId, status, std::forward(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)...); } } }