Merge topic 'internally_improve_CastAndCall_TryExecute'
dd25c5c2 DynamicCellSet CastAndCall refactored to use the new vtkm::ForEach c9f1d192 DynamicArrayHandle CastAndCall refactored to use the new vtkm::ForEach 68381d9f Rework TryExecute to leverage perfect forwarding. Acked-by: Kitware Robot <kwrobot@kitware.com> Acked-by: Kenneth Moreland <kmorel@sandia.gov> Merge-request: !1003
This commit is contained in:
commit
713e428abf
@ -110,6 +110,7 @@ set(device_sources
|
||||
ArrayRangeCompute.cxx
|
||||
CellSetExplicit.cxx
|
||||
RuntimeDeviceTracker.cxx
|
||||
TryExecute.cxx
|
||||
)
|
||||
|
||||
vtkm_declare_headers(${headers})
|
||||
|
@ -132,9 +132,8 @@ template <typename Type, typename Storage>
|
||||
VTKM_CONT vtkm::cont::ArrayHandle<Type, Storage>* DynamicArrayHandleTryCast(
|
||||
vtkm::cont::detail::PolymorphicArrayHandleContainerBase* arrayContainer)
|
||||
{
|
||||
vtkm::cont::detail::PolymorphicArrayHandleContainer<Type, Storage>* downcastContainer =
|
||||
dynamic_cast<vtkm::cont::detail::PolymorphicArrayHandleContainer<Type, Storage>*>(
|
||||
arrayContainer);
|
||||
vtkm::cont::detail::PolymorphicArrayHandleContainer<Type, Storage>* downcastContainer = nullptr;
|
||||
downcastContainer = dynamic_cast<decltype(downcastContainer)>(arrayContainer);
|
||||
if (downcastContainer != nullptr)
|
||||
{
|
||||
return &downcastContainer->Array;
|
||||
@ -407,13 +406,10 @@ using DynamicArrayHandle =
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename Functor>
|
||||
struct ListFunctorWrapper
|
||||
struct DynamicArrayHandleTry
|
||||
{
|
||||
ListFunctorWrapper(bool& called, const Functor& f, PolymorphicArrayHandleContainerBase* c)
|
||||
: Called(called)
|
||||
, Container(c)
|
||||
, Function(f)
|
||||
DynamicArrayHandleTry(const PolymorphicArrayHandleContainerBase* const c)
|
||||
: Container(c)
|
||||
{
|
||||
}
|
||||
|
||||
@ -425,16 +421,17 @@ struct ListFunctorWrapper
|
||||
this->run(std::forward<decltype(p)>(p), invalid{}, args...);
|
||||
}
|
||||
|
||||
template <typename T, typename U, typename... Args>
|
||||
void run(std::pair<T, U>&&, std::false_type, Args&&... args) const
|
||||
template <typename T, typename U, typename Functor, typename... Args>
|
||||
void run(std::pair<T, U>&&, std::false_type, Functor&& f, bool& called, Args&&... args) const
|
||||
{
|
||||
if (!this->Called)
|
||||
if (!called)
|
||||
{
|
||||
vtkm::cont::ArrayHandle<T, U>* handle = DynamicArrayHandleTryCast<T, U>(this->Container);
|
||||
if (handle)
|
||||
using downcastType = const vtkm::cont::detail::PolymorphicArrayHandleContainer<T, U>* const;
|
||||
downcastType downcastContainer = dynamic_cast<downcastType>(this->Container);
|
||||
if (downcastContainer)
|
||||
{
|
||||
this->Function(*handle, std::forward<Args>(args)...);
|
||||
this->Called = true;
|
||||
f(downcastContainer->Array, std::forward<Args>(args)...);
|
||||
called = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -444,9 +441,7 @@ struct ListFunctorWrapper
|
||||
{
|
||||
}
|
||||
|
||||
bool& Called;
|
||||
PolymorphicArrayHandleContainerBase* Container;
|
||||
const Functor& Function;
|
||||
const PolymorphicArrayHandleContainerBase* const Container;
|
||||
};
|
||||
|
||||
VTKM_CONT_EXPORT void ThrowCastAndCallException(PolymorphicArrayHandleContainerBase*,
|
||||
@ -462,11 +457,9 @@ VTKM_CONT void DynamicArrayHandleBase<TypeList, StorageList>::CastAndCall(const
|
||||
//and make it extern
|
||||
using crossProduct = typename vtkm::ListCrossProduct<TypeList, StorageList>;
|
||||
|
||||
auto* ptr = this->ArrayContainer.get();
|
||||
bool called = false;
|
||||
auto task = detail::ListFunctorWrapper<Functor>(called, f, ptr);
|
||||
|
||||
vtkm::ListForEach(task, crossProduct{});
|
||||
auto* ptr = this->ArrayContainer.get();
|
||||
vtkm::ListForEach(detail::DynamicArrayHandleTry(ptr), crossProduct{}, f, called);
|
||||
if (!called)
|
||||
{
|
||||
// throw an exception
|
||||
|
@ -272,38 +272,30 @@ private:
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename Functor>
|
||||
struct DynamicCellSetTryCellSet
|
||||
struct DynamicCellSetTry
|
||||
{
|
||||
vtkm::cont::internal::SimplePolymorphicContainerBase* CellSetContainer;
|
||||
const Functor& Function;
|
||||
bool FoundCast;
|
||||
|
||||
VTKM_CONT
|
||||
DynamicCellSetTryCellSet(vtkm::cont::internal::SimplePolymorphicContainerBase* cellSetContainer,
|
||||
const Functor& f)
|
||||
: CellSetContainer(cellSetContainer)
|
||||
, Function(f)
|
||||
, FoundCast(false)
|
||||
DynamicCellSetTry(
|
||||
const vtkm::cont::internal::SimplePolymorphicContainerBase* const cellSetContainer)
|
||||
: Container(cellSetContainer)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename CellSetType>
|
||||
VTKM_CONT void operator()(CellSetType)
|
||||
template <typename CellSetType, typename Functor>
|
||||
void operator()(CellSetType, Functor&& f, bool& called) const
|
||||
{
|
||||
if (!this->FoundCast)
|
||||
using downcastType = const vtkm::cont::internal::SimplePolymorphicContainer<CellSetType>* const;
|
||||
if (!called)
|
||||
{
|
||||
CellSetType* cellSet = detail::DynamicCellSetTryCast<CellSetType>(this->CellSetContainer);
|
||||
if (cellSet != nullptr)
|
||||
downcastType downcastContainer = dynamic_cast<downcastType>(this->Container);
|
||||
if (downcastContainer)
|
||||
{
|
||||
this->Function(*cellSet);
|
||||
this->FoundCast = true;
|
||||
f(downcastContainer->Item);
|
||||
called = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void operator=(const DynamicCellSetTryCellSet<Functor>&) = delete;
|
||||
const vtkm::cont::internal::SimplePolymorphicContainerBase* const Container;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@ -312,11 +304,10 @@ template <typename CellSetList>
|
||||
template <typename Functor>
|
||||
VTKM_CONT void DynamicCellSetBase<CellSetList>::CastAndCall(const Functor& f) const
|
||||
{
|
||||
using TryCellSetType = detail::DynamicCellSetTryCellSet<Functor>;
|
||||
TryCellSetType tryCellSet = TryCellSetType(this->CellSetContainer.get(), f);
|
||||
|
||||
vtkm::ListForEach(tryCellSet, CellSetList());
|
||||
if (!tryCellSet.FoundCast)
|
||||
bool called = false;
|
||||
detail::DynamicCellSetTry tryCellSet(this->CellSetContainer.get());
|
||||
vtkm::ListForEach(tryCellSet, CellSetList{}, f, called);
|
||||
if (!called)
|
||||
{
|
||||
throw vtkm::cont::ErrorBadValue("Could not find appropriate cast for cell set.");
|
||||
}
|
||||
|
@ -74,6 +74,17 @@ public:
|
||||
this->SetDeviceState(Traits::GetId(), Traits::GetName(), false);
|
||||
}
|
||||
|
||||
/// Report a failure to allocate memory on a device, this will flag the
|
||||
/// device as being unusable for all future invocations of the instance of
|
||||
/// the filter.
|
||||
///
|
||||
VTKM_CONT void ReportAllocationFailure(vtkm::Int8 deviceId,
|
||||
const std::string& name,
|
||||
const vtkm::cont::ErrorBadAllocation&)
|
||||
{
|
||||
this->SetDeviceState(deviceId, name, false);
|
||||
}
|
||||
|
||||
/// Reset the tracker for the given device. This will discard any updates
|
||||
/// caused by reported failures
|
||||
///
|
||||
|
77
vtkm/cont/TryExecute.cxx
Normal file
77
vtkm/cont/TryExecute.cxx
Normal file
@ -0,0 +1,77 @@
|
||||
//============================================================================
|
||||
// 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/ErrorBadAllocation.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
#include <vtkm/cont/ErrorBadValue.h>
|
||||
#include <vtkm/cont/TryExecute.h>
|
||||
|
||||
namespace vtkm
|
||||
{
|
||||
namespace cont
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
void HandleTryExecuteException(vtkm::Int8 deviceId,
|
||||
const std::string& name,
|
||||
vtkm::cont::RuntimeDeviceTracker& tracker)
|
||||
{
|
||||
try
|
||||
{
|
||||
//re-throw the last exception
|
||||
throw;
|
||||
}
|
||||
catch (vtkm::cont::ErrorBadAllocation& e)
|
||||
{
|
||||
std::cerr << "caught ErrorBadAllocation " << e.GetMessage() << std::endl;
|
||||
//currently we only consider OOM errors worth disabling a device for
|
||||
//than we fallback to another device
|
||||
tracker.ReportAllocationFailure(deviceId, name, e);
|
||||
}
|
||||
catch (vtkm::cont::ErrorBadType& e)
|
||||
{
|
||||
//should bad type errors should stop the execution, instead of
|
||||
//deferring to another device adapter?
|
||||
std::cerr << "caught ErrorBadType : " << e.GetMessage() << std::endl;
|
||||
}
|
||||
catch (vtkm::cont::ErrorBadValue& e)
|
||||
{
|
||||
//should bad value errors should stop the filter, instead of deferring
|
||||
//to another device adapter?
|
||||
std::cerr << "caught ErrorBadValue : " << e.GetMessage() << std::endl;
|
||||
}
|
||||
catch (vtkm::cont::Error& e)
|
||||
{
|
||||
//general errors should be caught and let us try the next device adapter.
|
||||
std::cerr << "exception is: " << e.GetMessage() << std::endl;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "caught standard exception: " << e.what() << std::endl;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "unknown exception caught" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -21,10 +21,6 @@
|
||||
#define vtk_m_cont_TryExecute_h
|
||||
|
||||
#include <vtkm/cont/DeviceAdapterListTag.h>
|
||||
#include <vtkm/cont/ErrorBadAllocation.h>
|
||||
#include <vtkm/cont/ErrorBadType.h>
|
||||
#include <vtkm/cont/ErrorBadValue.h>
|
||||
|
||||
#include <vtkm/cont/RuntimeDeviceTracker.h>
|
||||
|
||||
namespace vtkm
|
||||
@ -35,105 +31,56 @@ namespace cont
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename Functor, typename Device, bool DeviceAdapterValid>
|
||||
struct TryExecuteRunIfValid;
|
||||
VTKM_CONT_EXPORT void HandleTryExecuteException(vtkm::Int8,
|
||||
const std::string&,
|
||||
vtkm::cont::RuntimeDeviceTracker&);
|
||||
|
||||
template <typename Functor, typename Device>
|
||||
struct TryExecuteRunIfValid<Functor, Device, false>
|
||||
template <typename DeviceTag, typename Functor>
|
||||
bool TryExecuteIfValid(std::true_type,
|
||||
DeviceTag tag,
|
||||
Functor&& f,
|
||||
vtkm::cont::RuntimeDeviceTracker& tracker)
|
||||
{
|
||||
VTKM_CONT
|
||||
static bool Run(Functor&, const vtkm::cont::RuntimeDeviceTracker&) { return false; }
|
||||
};
|
||||
|
||||
template <typename Functor, typename Device>
|
||||
struct TryExecuteRunIfValid<Functor, Device, true>
|
||||
{
|
||||
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
|
||||
|
||||
VTKM_CONT
|
||||
static bool Run(Functor& functor, vtkm::cont::RuntimeDeviceTracker tracker)
|
||||
if (tracker.CanRunOn(tag))
|
||||
{
|
||||
if (tracker.CanRunOn(Device()))
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
return functor(Device());
|
||||
}
|
||||
catch (vtkm::cont::ErrorBadAllocation& e)
|
||||
{
|
||||
std::cerr << "caught ErrorBadAllocation " << e.GetMessage() << std::endl;
|
||||
//currently we only consider OOM errors worth disabling a device for
|
||||
//than we fallback to another device
|
||||
tracker.ReportAllocationFailure(Device(), e);
|
||||
}
|
||||
catch (vtkm::cont::ErrorBadType& e)
|
||||
{
|
||||
//should bad type errors should stop the execution, instead of
|
||||
//deferring to another device adapter?
|
||||
std::cerr << "caught ErrorBadType : " << e.GetMessage() << std::endl;
|
||||
}
|
||||
catch (vtkm::cont::ErrorBadValue& e)
|
||||
{
|
||||
//should bad value errors should stop the filter, instead of deferring
|
||||
//to another device adapter?
|
||||
std::cerr << "caught ErrorBadValue : " << e.GetMessage() << std::endl;
|
||||
}
|
||||
catch (vtkm::cont::Error& e)
|
||||
{
|
||||
//general errors should be caught and let us try the next device adapter.
|
||||
std::cerr << "exception is: " << e.GetMessage() << std::endl;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cerr << "caught standard exception: " << e.what() << std::endl;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cerr << "unknown exception caught" << std::endl;
|
||||
}
|
||||
return f(tag);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
using Traits = vtkm::cont::DeviceAdapterTraits<DeviceTag>;
|
||||
HandleTryExecuteException(Traits::GetId(), Traits::GetName(), tracker);
|
||||
}
|
||||
|
||||
// If we are here, then the functor was either never run or failed.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename FunctorType>
|
||||
// If we are here, then the functor was either never run or failed.
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename DeviceTag, typename Functor>
|
||||
bool TryExecuteIfValid(std::false_type, DeviceTag, Functor&&, vtkm::cont::RuntimeDeviceTracker&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
struct TryExecuteImpl
|
||||
{
|
||||
// Warning, these are a references. Make sure referenced objects do not go
|
||||
// out of scope.
|
||||
FunctorType& Functor;
|
||||
vtkm::cont::RuntimeDeviceTracker Tracker;
|
||||
|
||||
bool Success;
|
||||
|
||||
VTKM_CONT
|
||||
TryExecuteImpl(
|
||||
FunctorType& functor,
|
||||
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetGlobalRuntimeDeviceTracker())
|
||||
: Functor(functor)
|
||||
, Tracker(tracker)
|
||||
, Success(false)
|
||||
template <typename DeviceTag, typename Functor>
|
||||
void operator()(DeviceTag tag,
|
||||
Functor&& f,
|
||||
vtkm::cont::RuntimeDeviceTracker& tracker,
|
||||
bool& ran) const
|
||||
{
|
||||
}
|
||||
|
||||
template <typename Device>
|
||||
VTKM_CONT bool operator()(Device)
|
||||
{
|
||||
if (!this->Success)
|
||||
if (!ran)
|
||||
{
|
||||
using DeviceTraits = vtkm::cont::DeviceAdapterTraits<Device>;
|
||||
|
||||
this->Success = detail::TryExecuteRunIfValid<FunctorType, Device, DeviceTraits::Valid>::Run(
|
||||
this->Functor, this->Tracker);
|
||||
using DeviceTraits = vtkm::cont::DeviceAdapterTraits<DeviceTag>;
|
||||
ran = TryExecuteIfValid(std::integral_constant<bool, DeviceTraits::Valid>(),
|
||||
tag,
|
||||
std::forward<Functor>(f),
|
||||
tracker);
|
||||
}
|
||||
|
||||
return this->Success;
|
||||
}
|
||||
|
||||
private:
|
||||
void operator=(const TryExecuteImpl<FunctorType>&) = delete;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@ -160,44 +107,25 @@ private:
|
||||
/// is used.
|
||||
///
|
||||
template <typename Functor, typename DeviceList>
|
||||
VTKM_CONT bool TryExecute(const Functor& functor,
|
||||
vtkm::cont::RuntimeDeviceTracker tracker,
|
||||
DeviceList)
|
||||
VTKM_CONT bool TryExecute(Functor&& functor, vtkm::cont::RuntimeDeviceTracker tracker, DeviceList)
|
||||
{
|
||||
detail::TryExecuteImpl<const Functor> internals(functor, tracker);
|
||||
vtkm::ListForEach(internals, DeviceList());
|
||||
return internals.Success;
|
||||
bool success = false;
|
||||
detail::TryExecuteImpl task;
|
||||
vtkm::ListForEach(task, DeviceList(), std::forward<Functor>(functor), tracker, success);
|
||||
return success;
|
||||
}
|
||||
template <typename Functor, typename DeviceList>
|
||||
VTKM_CONT bool TryExecute(Functor& functor, vtkm::cont::RuntimeDeviceTracker tracker, DeviceList)
|
||||
{
|
||||
detail::TryExecuteImpl<Functor> internals(functor, tracker);
|
||||
vtkm::ListForEach(internals, DeviceList());
|
||||
return internals.Success;
|
||||
}
|
||||
template <typename Functor, typename DeviceList>
|
||||
VTKM_CONT bool TryExecute(const Functor& functor, DeviceList)
|
||||
{
|
||||
return vtkm::cont::TryExecute(functor, vtkm::cont::GetGlobalRuntimeDeviceTracker(), DeviceList());
|
||||
}
|
||||
template <typename Functor, typename DeviceList>
|
||||
VTKM_CONT bool TryExecute(Functor& functor, DeviceList)
|
||||
VTKM_CONT bool TryExecute(Functor&& functor, DeviceList)
|
||||
{
|
||||
return vtkm::cont::TryExecute(functor, vtkm::cont::GetGlobalRuntimeDeviceTracker(), DeviceList());
|
||||
}
|
||||
template <typename Functor>
|
||||
VTKM_CONT bool TryExecute(
|
||||
const Functor& functor,
|
||||
Functor&& functor,
|
||||
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetGlobalRuntimeDeviceTracker())
|
||||
{
|
||||
return vtkm::cont::TryExecute(functor, tracker, VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG());
|
||||
}
|
||||
template <typename Functor>
|
||||
VTKM_CONT bool TryExecute(
|
||||
Functor& functor,
|
||||
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetGlobalRuntimeDeviceTracker())
|
||||
{
|
||||
return vtkm::cont::TryExecute(functor, tracker, VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG());
|
||||
return vtkm::cont::TryExecute(
|
||||
functor, std::forward<decltype(tracker)>(tracker), VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG());
|
||||
}
|
||||
}
|
||||
} // namespace vtkm::cont
|
||||
|
@ -81,6 +81,19 @@ void TryExecuteWithList(DeviceList, bool expectSuccess)
|
||||
{
|
||||
VTKM_TEST_ASSERT(!result, "Call returned true when expected failure.");
|
||||
}
|
||||
|
||||
//verify the ability to pass rvalue functors
|
||||
vtkm::cont::ArrayHandle<vtkm::FloatDefault> outArray2;
|
||||
result = vtkm::cont::TryExecute(TryExecuteTestFunctor(inArray, outArray2), DeviceList());
|
||||
if (expectSuccess)
|
||||
{
|
||||
VTKM_TEST_ASSERT(result, "Call returned failure when expected success.");
|
||||
CheckPortal(outArray2.GetPortalConstControl());
|
||||
}
|
||||
else
|
||||
{
|
||||
VTKM_TEST_ASSERT(!result, "Call returned true when expected failure.");
|
||||
}
|
||||
}
|
||||
|
||||
static void Run()
|
||||
|
Loading…
Reference in New Issue
Block a user