mirror of
https://gitlab.kitware.com/vtk/vtk-m
synced 2024-09-16 17:22:55 +00:00
Rework TryExecute to leverage perfect forwarding.
By using perfect forwarding we can reduce not only the amount of TryExecute signatures, but we can enable the ability to pass temporary functors to TryExecute. At the same time we have optimized TryExecute by moving the string generation code into a single function that is compiled into the vtkm_cont library. The end result is that the vtkm_rendering library size has been reduced from 12MB to 11MB, and we shave off about 5% of our build time.
This commit is contained in:
parent
cc71e8ec6e
commit
68381d9fe5
@ -110,6 +110,7 @@ set(device_sources
|
|||||||
ArrayRangeCompute.cxx
|
ArrayRangeCompute.cxx
|
||||||
CellSetExplicit.cxx
|
CellSetExplicit.cxx
|
||||||
RuntimeDeviceTracker.cxx
|
RuntimeDeviceTracker.cxx
|
||||||
|
TryExecute.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
vtkm_declare_headers(${headers})
|
vtkm_declare_headers(${headers})
|
||||||
|
@ -74,6 +74,17 @@ public:
|
|||||||
this->SetDeviceState(Traits::GetId(), Traits::GetName(), false);
|
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
|
/// Reset the tracker for the given device. This will discard any updates
|
||||||
/// caused by reported failures
|
/// 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
|
#define vtk_m_cont_TryExecute_h
|
||||||
|
|
||||||
#include <vtkm/cont/DeviceAdapterListTag.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>
|
#include <vtkm/cont/RuntimeDeviceTracker.h>
|
||||||
|
|
||||||
namespace vtkm
|
namespace vtkm
|
||||||
@ -35,105 +31,56 @@ namespace cont
|
|||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
|
|
||||||
template <typename Functor, typename Device, bool DeviceAdapterValid>
|
VTKM_CONT_EXPORT void HandleTryExecuteException(vtkm::Int8,
|
||||||
struct TryExecuteRunIfValid;
|
const std::string&,
|
||||||
|
vtkm::cont::RuntimeDeviceTracker&);
|
||||||
|
|
||||||
template <typename Functor, typename Device>
|
template <typename DeviceTag, typename Functor>
|
||||||
struct TryExecuteRunIfValid<Functor, Device, false>
|
bool TryExecuteIfValid(std::true_type,
|
||||||
|
DeviceTag tag,
|
||||||
|
Functor&& f,
|
||||||
|
vtkm::cont::RuntimeDeviceTracker& tracker)
|
||||||
{
|
{
|
||||||
VTKM_CONT
|
if (tracker.CanRunOn(tag))
|
||||||
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(Device()))
|
try
|
||||||
{
|
{
|
||||||
try
|
return f(tag);
|
||||||
{
|
}
|
||||||
return functor(Device());
|
catch (...)
|
||||||
}
|
{
|
||||||
catch (vtkm::cont::ErrorBadAllocation& e)
|
using Traits = vtkm::cont::DeviceAdapterTraits<DeviceTag>;
|
||||||
{
|
HandleTryExecuteException(Traits::GetId(), Traits::GetName(), tracker);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
struct TryExecuteImpl
|
||||||
{
|
{
|
||||||
// Warning, these are a references. Make sure referenced objects do not go
|
template <typename DeviceTag, typename Functor>
|
||||||
// out of scope.
|
void operator()(DeviceTag tag,
|
||||||
FunctorType& Functor;
|
Functor&& f,
|
||||||
vtkm::cont::RuntimeDeviceTracker Tracker;
|
vtkm::cont::RuntimeDeviceTracker& tracker,
|
||||||
|
bool& ran) const
|
||||||
bool Success;
|
|
||||||
|
|
||||||
VTKM_CONT
|
|
||||||
TryExecuteImpl(
|
|
||||||
FunctorType& functor,
|
|
||||||
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetGlobalRuntimeDeviceTracker())
|
|
||||||
: Functor(functor)
|
|
||||||
, Tracker(tracker)
|
|
||||||
, Success(false)
|
|
||||||
{
|
{
|
||||||
}
|
if (!ran)
|
||||||
|
|
||||||
template <typename Device>
|
|
||||||
VTKM_CONT bool operator()(Device)
|
|
||||||
{
|
|
||||||
if (!this->Success)
|
|
||||||
{
|
{
|
||||||
using DeviceTraits = vtkm::cont::DeviceAdapterTraits<Device>;
|
using DeviceTraits = vtkm::cont::DeviceAdapterTraits<DeviceTag>;
|
||||||
|
ran = TryExecuteIfValid(std::integral_constant<bool, DeviceTraits::Valid>(),
|
||||||
this->Success = detail::TryExecuteRunIfValid<FunctorType, Device, DeviceTraits::Valid>::Run(
|
tag,
|
||||||
this->Functor, this->Tracker);
|
std::forward<Functor>(f),
|
||||||
|
tracker);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->Success;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
void operator=(const TryExecuteImpl<FunctorType>&) = delete;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -160,44 +107,25 @@ private:
|
|||||||
/// is used.
|
/// is used.
|
||||||
///
|
///
|
||||||
template <typename Functor, typename DeviceList>
|
template <typename Functor, typename DeviceList>
|
||||||
VTKM_CONT bool TryExecute(const Functor& functor,
|
VTKM_CONT bool TryExecute(Functor&& functor, vtkm::cont::RuntimeDeviceTracker tracker, DeviceList)
|
||||||
vtkm::cont::RuntimeDeviceTracker tracker,
|
|
||||||
DeviceList)
|
|
||||||
{
|
{
|
||||||
detail::TryExecuteImpl<const Functor> internals(functor, tracker);
|
bool success = false;
|
||||||
vtkm::ListForEach(internals, DeviceList());
|
detail::TryExecuteImpl task;
|
||||||
return internals.Success;
|
vtkm::ListForEach(task, DeviceList(), std::forward<Functor>(functor), tracker, success);
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
template <typename Functor, typename DeviceList>
|
template <typename Functor, typename DeviceList>
|
||||||
VTKM_CONT bool TryExecute(Functor& functor, vtkm::cont::RuntimeDeviceTracker tracker, DeviceList)
|
VTKM_CONT bool TryExecute(Functor&& functor, 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)
|
|
||||||
{
|
{
|
||||||
return vtkm::cont::TryExecute(functor, vtkm::cont::GetGlobalRuntimeDeviceTracker(), DeviceList());
|
return vtkm::cont::TryExecute(functor, vtkm::cont::GetGlobalRuntimeDeviceTracker(), DeviceList());
|
||||||
}
|
}
|
||||||
template <typename Functor>
|
template <typename Functor>
|
||||||
VTKM_CONT bool TryExecute(
|
VTKM_CONT bool TryExecute(
|
||||||
const Functor& functor,
|
Functor&& functor,
|
||||||
vtkm::cont::RuntimeDeviceTracker tracker = vtkm::cont::GetGlobalRuntimeDeviceTracker())
|
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());
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // namespace vtkm::cont
|
} // namespace vtkm::cont
|
||||||
|
@ -81,6 +81,19 @@ void TryExecuteWithList(DeviceList, bool expectSuccess)
|
|||||||
{
|
{
|
||||||
VTKM_TEST_ASSERT(!result, "Call returned true when expected failure.");
|
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()
|
static void Run()
|
||||||
|
Loading…
Reference in New Issue
Block a user