Commit 095e2883 authored by Robert Maynard's avatar Robert Maynard Committed by Kitware Robot

Merge topic 'better_scoped_rt_dt'

bcaf7d9b ScopedRuntimeDeviceTracker have better controls of setting devices.
4212d0c0 RuntimeDeviceInformation now says the AnyTag exists.
fa03dc66 ScopedRuntimeDeviceTracker requires a device to execute on when constructed.
4020f519 RuntimeDeviceTracker can't be copied and is only accessible via reference.
e9482018 ScopedRuntimeDeviceTracker has the same API as RuntimeDeviceTracker
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Acked-by: Kenneth Moreland's avatarKenneth Moreland <kmorel@sandia.gov>
Merge-request: !1676
parents 425fcd89 bcaf7d9b
......@@ -8,7 +8,7 @@ vtkm::cont::DeviceAdapterId id1 = vtkm::cont::make_DeviceAdapterId("cuda");
vtkm::cont::DeviceAdapterId id2 = vtkm::cont::make_DeviceAdapterId("CUDA");
vtkm::cont::DeviceAdapterId id3 = vtkm::cont::make_DeviceAdapterId("Cuda");
auto tracker = vtkm::cont::GetGlobalRuntimeDeviceTracker();
auto& tracker = vtkm::cont::GetGlobalRuntimeDeviceTracker();
vtkm::cont::DeviceAdapterId id4 = tracker.GetDeviceAdapterId("cuda");
vtkm::cont::DeviceAdapterId id5 = tracker.GetDeviceAdapterId("CUDA");
vtkm::cont::DeviceAdapterId id6 = tracker.GetDeviceAdapterId("Cuda");
......@@ -4,3 +4,87 @@ The device tracking infrastructure in VTK-m has been redesigned to
remove multiple redundant codes paths and to simplify reasoning
about around what an instance of RuntimeDeviceTracker will modify.
`vtkm::cont::RuntimeDeviceTracker` tracks runtime information on
a per-user thread basis. This is done to allow multiple calling
threads to use different vtk-m backends such as seen in this
example:
```cpp
vtkm::cont::DeviceAdapterTagCuda cuda;
vtkm::cont::DeviceAdapterTagOpenMP openmp;
{ // thread 1
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
tracker->ForceDevice(cuda);
vtkm::worklet::Invoker invoke;
invoke(LightTask{}, input, output);
vtkm::cont::Algorithm::Sort(output);
invoke(HeavyTask{}, output);
}
{ // thread 2
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
tracker->ForceDevice(openmp);
vtkm::worklet::Invoker invoke;
invoke(LightTask{}, input, output);
vtkm::cont::Algorithm::Sort(output);
invoke(HeavyTask{}, output);
}
```
While this address the ability for threads to specify what
device they should run on. It doesn't make it easy to toggle
the status of a device in a programmatic way, for example
the following block forces execution to only occur on
`cuda` and doesn't restore previous active devices after
```cpp
{
vtkm::cont::DeviceAdapterTagCuda cuda;
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
tracker->ForceDevice(cuda);
vtkm::worklet::Invoker invoke;
invoke(LightTask{}, input, output);
}
//openmp/tbb/... still inactive
```
To resolve those issues we have `vtkm::cont::ScopedRuntimeDeviceTracker` which
has the same interface as `vtkm::cont::RuntimeDeviceTracker` but additionally
resets any per-user thread modifications when it goes out of scope. So by
switching over the previous example to use `ScopedRuntimeDeviceTracker` we
correctly restore the threads `RuntimeDeviceTracker` state when `tracker`
goes out of scope.
```cpp
{
vtkm::cont::DeviceAdapterTagCuda cuda;
vtkm::cont::ScopedRuntimeDeviceTracker tracker(cuda);
vtkm::worklet::Invoker invoke;
invoke(LightTask{}, input, output);
}
//openmp/tbb/... are now again active
```
The `vtkm::cont::ScopedRuntimeDeviceTracker` is not limited to forcing
execution to occur on a single device. When constructed it can either force
execution to a device, disable a device or enable a device. These options
also work with the `DeviceAdapterTagAny`.
```cpp
{
//enable all devices
vtkm::cont::DeviceAdapterTagAny any;
vtkm::cont::ScopedRuntimeDeviceTracker tracker(any,
vtkm::cont::RuntimeDeviceTrackerMode::Enable);
...
}
{
//disable only cuda
vtkm::cont::DeviceAdapterTagCuda cuda;
vtkm::cont::ScopedRuntimeDeviceTracker tracker(cuda,
vtkm::cont::RuntimeDeviceTrackerMode::Disable);
...
}
```
......@@ -126,7 +126,7 @@ VTKM_CONT MultiDeviceGradient::MultiDeviceGradient()
, Workers()
{
//Step 1. Determine the number of workers we want
auto tracker = vtkm::cont::GetRuntimeDeviceTracker();
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
const bool runOnCuda = tracker.CanRunOn(vtkm::cont::DeviceAdapterTagCuda{});
const bool runOnOpenMP = tracker.CanRunOn(vtkm::cont::DeviceAdapterTagOpenMP{});
const bool runOnTbb = tracker.CanRunOn(vtkm::cont::DeviceAdapterTagTBB{});
......
......@@ -312,8 +312,7 @@ public:
PortalConstType GetPortalConst() const
{
VTKM_ASSERT(this->Valid);
vtkm::cont::ScopedRuntimeDeviceTracker trackerScope;
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial());
vtkm::cont::ScopedRuntimeDeviceTracker trackerScope(vtkm::cont::DeviceAdapterTagSerial{});
return PortalConstType(this->Array.GetPortalConstControl(), this->Functor.PrepareForControl());
}
......@@ -404,8 +403,7 @@ public:
PortalType GetPortal()
{
VTKM_ASSERT(this->Valid);
vtkm::cont::ScopedRuntimeDeviceTracker trackerScope;
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial());
vtkm::cont::ScopedRuntimeDeviceTracker trackerScope(vtkm::cont::DeviceAdapterTagSerial{});
return PortalType(this->Array.GetPortalControl(),
this->Functor.PrepareForControl(),
this->InverseFunctor.PrepareForControl());
......@@ -415,8 +413,7 @@ public:
PortalConstType GetPortalConst() const
{
VTKM_ASSERT(this->Valid);
vtkm::cont::ScopedRuntimeDeviceTracker trackerScope;
vtkm::cont::GetRuntimeDeviceTracker().ForceDevice(vtkm::cont::DeviceAdapterTagSerial());
vtkm::cont::ScopedRuntimeDeviceTracker trackerScope(vtkm::cont::DeviceAdapterTagSerial{});
return PortalConstType(this->Array.GetPortalConstControl(),
this->Functor.PrepareForControl(),
this->InverseFunctor.PrepareForControl());
......
......@@ -169,6 +169,11 @@ DeviceAdapterId RuntimeDeviceInformation::GetId(DeviceAdapterNameType name) cons
VTKM_CONT
bool RuntimeDeviceInformation::Exists(DeviceAdapterId id) const
{
if (id == vtkm::cont::DeviceAdapterTagAny{})
{
return true;
}
RuntimeDeviceInformationFunctor functor;
vtkm::ListForEach(functor, VTKM_DEFAULT_DEVICE_ADAPTER_LIST_TAG(), id);
return functor.Exists;
......
......@@ -33,10 +33,14 @@ struct RuntimeDeviceTrackerInternals
}
VTKM_CONT
RuntimeDeviceTracker::RuntimeDeviceTracker()
: Internals(std::make_shared<detail::RuntimeDeviceTrackerInternals>())
RuntimeDeviceTracker::RuntimeDeviceTracker(detail::RuntimeDeviceTrackerInternals* details,
bool reset)
: Internals(details)
{
this->Reset();
if (reset)
{
this->Reset();
}
}
VTKM_CONT
......@@ -57,10 +61,24 @@ void RuntimeDeviceTracker::CheckDevice(vtkm::cont::DeviceAdapterId deviceId) con
}
VTKM_CONT
bool RuntimeDeviceTracker::CanRunOnImpl(vtkm::cont::DeviceAdapterId deviceId) const
bool RuntimeDeviceTracker::CanRunOn(vtkm::cont::DeviceAdapterId deviceId) const
{
this->CheckDevice(deviceId);
return this->Internals->RuntimeAllowed[deviceId.GetValue()];
if (deviceId == vtkm::cont::DeviceAdapterTagAny{})
{ //If at least a single device is enabled, than any device is enabled
for (vtkm::Int8 i = 1; i < VTKM_MAX_DEVICE_ADAPTER_ID; ++i)
{
if (this->Internals->RuntimeAllowed[static_cast<std::size_t>(i)])
{
return true;
}
}
return false;
}
else
{
this->CheckDevice(deviceId);
return this->Internals->RuntimeAllowed[deviceId.GetValue()];
}
}
VTKM_CONT
......@@ -73,6 +91,21 @@ void RuntimeDeviceTracker::SetDeviceState(vtkm::cont::DeviceAdapterId deviceId,
this->Internals->RuntimeAllowed[deviceId.GetValue()] = state;
}
VTKM_CONT void RuntimeDeviceTracker::ResetDevice(vtkm::cont::DeviceAdapterId deviceId)
{
if (deviceId == vtkm::cont::DeviceAdapterTagAny{})
{
this->Reset();
}
else
{
vtkm::cont::RuntimeDeviceInformation runtimeDevice;
this->SetDeviceState(deviceId, runtimeDevice.Exists(deviceId));
}
}
VTKM_CONT
void RuntimeDeviceTracker::Reset()
{
......@@ -82,7 +115,7 @@ void RuntimeDeviceTracker::Reset()
// when we use logging we get better messages stating we are reseting
// the devices.
vtkm::cont::RuntimeDeviceInformation runtimeDevice;
for (vtkm::Int8 i = 0; i < VTKM_MAX_DEVICE_ADAPTER_ID; ++i)
for (vtkm::Int8 i = 1; i < VTKM_MAX_DEVICE_ADAPTER_ID; ++i)
{
vtkm::cont::DeviceAdapterId device = vtkm::cont::make_DeviceAdapterId(i);
if (device.IsValueValid())
......@@ -95,53 +128,109 @@ void RuntimeDeviceTracker::Reset()
}
}
VTKM_CONT
vtkm::cont::RuntimeDeviceTracker RuntimeDeviceTracker::DeepCopy() const
VTKM_CONT void RuntimeDeviceTracker::DisableDevice(vtkm::cont::DeviceAdapterId deviceId)
{
return vtkm::cont::RuntimeDeviceTracker(this->Internals);
if (deviceId == vtkm::cont::DeviceAdapterTagAny{})
{
std::fill_n(this->Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, false);
}
else
{
this->SetDeviceState(deviceId, false);
}
}
VTKM_CONT
void RuntimeDeviceTracker::DeepCopy(const vtkm::cont::RuntimeDeviceTracker& src)
void RuntimeDeviceTracker::ForceDevice(DeviceAdapterId deviceId)
{
std::copy_n(
src.Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, this->Internals->RuntimeAllowed);
if (deviceId == vtkm::cont::DeviceAdapterTagAny{})
{
this->Reset();
}
else
{
this->CheckDevice(deviceId);
vtkm::cont::RuntimeDeviceInformation runtimeDevice;
const bool runtimeExists = runtimeDevice.Exists(deviceId);
if (!runtimeExists)
{
std::stringstream message;
message << "Cannot force to device '" << deviceId.GetName()
<< "' because that device is not available on this system";
throw vtkm::cont::ErrorBadValue(message.str());
}
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Forcing execution to occur on device '" << deviceId.GetName() << "'");
std::fill_n(this->Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, false);
this->Internals->RuntimeAllowed[deviceId.GetValue()] = runtimeExists;
}
}
VTKM_CONT
RuntimeDeviceTracker::RuntimeDeviceTracker(
const std::shared_ptr<detail::RuntimeDeviceTrackerInternals>& internals)
: Internals(std::make_shared<detail::RuntimeDeviceTrackerInternals>())
ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(vtkm::cont::DeviceAdapterId device,
RuntimeDeviceTrackerMode mode)
: RuntimeDeviceTracker(GetRuntimeDeviceTracker().Internals, false)
, SavedState(new detail::RuntimeDeviceTrackerInternals())
{
std::copy_n(
internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, this->Internals->RuntimeAllowed);
this->Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, this->SavedState->RuntimeAllowed);
if (mode == RuntimeDeviceTrackerMode::Force)
{
this->ForceDevice(device);
}
else if (mode == RuntimeDeviceTrackerMode::Enable)
{
this->ResetDevice(device);
}
else if (mode == RuntimeDeviceTrackerMode::Disable)
{
this->DisableDevice(device);
}
}
VTKM_CONT
void RuntimeDeviceTracker::ForceDeviceImpl(vtkm::cont::DeviceAdapterId deviceId, bool runtimeExists)
ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(
vtkm::cont::DeviceAdapterId device,
RuntimeDeviceTrackerMode mode,
const vtkm::cont::RuntimeDeviceTracker& tracker)
: RuntimeDeviceTracker(tracker.Internals, false)
, SavedState(new detail::RuntimeDeviceTrackerInternals())
{
if (!runtimeExists)
std::copy_n(
this->Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, this->SavedState->RuntimeAllowed);
if (mode == RuntimeDeviceTrackerMode::Force)
{
std::stringstream message;
message << "Cannot force to device '" << deviceId.GetName()
<< "' because that device is not available on this system";
throw vtkm::cont::ErrorBadValue(message.str());
this->ForceDevice(device);
}
this->CheckDevice(deviceId);
VTKM_LOG_S(vtkm::cont::LogLevel::Info,
"Forcing execution to occur on device '" << deviceId.GetName() << "'");
std::fill_n(this->Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, false);
else if (mode == RuntimeDeviceTrackerMode::Enable)
{
this->ResetDevice(device);
}
else if (mode == RuntimeDeviceTrackerMode::Disable)
{
this->DisableDevice(device);
}
}
this->Internals->RuntimeAllowed[deviceId.GetValue()] = runtimeExists;
VTKM_CONT
ScopedRuntimeDeviceTracker::ScopedRuntimeDeviceTracker(
const vtkm::cont::RuntimeDeviceTracker& tracker)
: RuntimeDeviceTracker(tracker.Internals, false)
, SavedState(new detail::RuntimeDeviceTrackerInternals())
{
std::copy_n(
this->Internals->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, this->SavedState->RuntimeAllowed);
}
VTKM_CONT
void RuntimeDeviceTracker::ForceDevice(DeviceAdapterId deviceId)
ScopedRuntimeDeviceTracker::~ScopedRuntimeDeviceTracker()
{
vtkm::cont::RuntimeDeviceInformation runtimeDevice;
this->ForceDeviceImpl(deviceId, runtimeDevice.Exists(deviceId));
std::copy_n(
this->SavedState->RuntimeAllowed, VTKM_MAX_DEVICE_ADAPTER_ID, this->Internals->RuntimeAllowed);
}
VTKM_CONT
......@@ -150,6 +239,8 @@ vtkm::cont::RuntimeDeviceTracker& GetRuntimeDeviceTracker()
#if defined(VTKM_CLANG) && defined(__apple_build_version__) && (__apple_build_version__ < 8000000)
static std::mutex mtx;
static std::map<std::thread::id, vtkm::cont::RuntimeDeviceTracker*> globalTrackers;
static std::map<std::thread::id, vtkm::cont::detail::RuntimeDeviceTrackerInternals*>
globalTrackerInternals;
std::thread::id this_id = std::this_thread::get_id();
std::unique_lock<std::mutex> lock(mtx);
......@@ -160,12 +251,15 @@ vtkm::cont::RuntimeDeviceTracker& GetRuntimeDeviceTracker()
}
else
{
vtkm::cont::RuntimeDeviceTracker* tracker = new vtkm::cont::RuntimeDeviceTracker();
auto* details = new vtkm::cont::detail::RuntimeDeviceTrackerInternals();
vtkm::cont::RuntimeDeviceTracker* tracker = new vtkm::cont::RuntimeDeviceTracker(details, true);
globalTrackers[this_id] = tracker;
globalTrackerInternals[this_id] = details;
return *tracker;
}
#else
static thread_local vtkm::cont::RuntimeDeviceTracker runtimeDeviceTracker;
static thread_local vtkm::cont::detail::RuntimeDeviceTrackerInternals details;
static thread_local vtkm::cont::RuntimeDeviceTracker runtimeDeviceTracker(&details, true);
return runtimeDeviceTracker;
#endif
}
......
......@@ -28,11 +28,18 @@ namespace detail
struct RuntimeDeviceTrackerInternals;
}
struct ScopedRuntimeDeviceTracker;
/// A class that can be used to determine if a given device adapter
/// is supported on the current machine at runtime. This is a more
/// complex version of vtkm::cont::RunimeDeviceInformation, as this can
/// also track when worklets fail, why the fail, and will update the list
/// RuntimeDeviceTracker is the central location for determining
/// which device adapter will be active for algorithm execution.
/// Many features in VTK-m will attempt to run algorithms on the "best
/// available device." This generally is determined at runtime as some
/// backends require specific hardware, or failures in one device are
/// recorded and that device is disabled.
///
/// While vtkm::cont::RunimeDeviceInformation reports on the existence
/// of a device being supported, this tracks on a per-thread basis
/// when worklets fail, why the fail, and will update the list
/// of valid runtime devices based on that information.
///
///
......@@ -47,11 +54,10 @@ public:
/// Returns true if the given device adapter is supported on the current
/// machine.
///
VTKM_CONT bool CanRunOn(DeviceAdapterId device) const { return this->CanRunOnImpl(device); }
VTKM_CONT bool CanRunOn(DeviceAdapterId deviceId) const;
/// 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.
/// device as being unusable for all future invocations.
///
VTKM_CONT void ReportAllocationFailure(vtkm::cont::DeviceAdapterId deviceId,
const vtkm::cont::ErrorBadAllocation&)
......@@ -68,13 +74,10 @@ public:
}
/// Reset the tracker for the given device. This will discard any updates
/// caused by reported failures
/// caused by reported failures. Passing DeviceAdapterTagAny to this will
/// reset all devices ( same as \c Reset ).
///
VTKM_CONT void ResetDevice(vtkm::cont::DeviceAdapterId device)
{
vtkm::cont::RuntimeDeviceInformation runtimeDevice;
this->SetDeviceState(device, runtimeDevice.Exists(device));
}
VTKM_CONT void ResetDevice(vtkm::cont::DeviceAdapterId deviceId);
/// Reset the tracker to its default state for default devices.
/// Will discard any updates caused by reported failures.
......@@ -82,48 +85,6 @@ public:
VTKM_CONT
void Reset();
/// \brief Perform a deep copy of the \c RuntimeDeviceTracker state.
///
/// Normally when you assign or copy a \c RuntimeDeviceTracker, they share
/// state so that when you change the state of one (for example, find a
/// device that does not work), the other is also implicitly updated. This
/// important so that when you use the global runtime device tracker the
/// state is synchronized across all the units using it.
///
/// If you want a \c RuntimeDeviceTracker with independent state, just create
/// one independently. If you want to start with the state of a source
/// \c RuntimeDeviceTracker but update the state independently, you can use
/// \c DeepCopy method to get the initial state. Further changes will
/// not be shared.
///
/// This version of \c DeepCopy creates a whole new \c RuntimeDeviceTracker
/// with a state that is not shared with any other object.
///
VTKM_CONT
vtkm::cont::RuntimeDeviceTracker DeepCopy() const;
/// \brief Perform a deep copy of the \c RuntimeDeviceTracker state.
///
/// Normally when you assign or copy a \c RuntimeDeviceTracker, they share
/// state so that when you change the state of one (for example, find a
/// device that does not work), the other is also implicitly updated. This
/// important so that when you use the global runtime device tracker the
/// state is synchronized across all the units using it.
///
/// If you want a \c RuntimeDeviceTracker with independent state, just create
/// one independently. If you want to start with the state of a source
/// \c RuntimeDeviceTracker but update the state independently, you can use
/// \c DeepCopy method to get the initial state. Further changes will
/// not be shared.
///
/// This version of \c DeepCopy sets the state of the current object to
/// the one given in the argument. Any other \c RuntimeDeviceTrackers sharing
/// state with this object will also get updated. This method is good for
/// restoring a state that was previously saved.
///
VTKM_CONT
void DeepCopy(const vtkm::cont::RuntimeDeviceTracker& src);
/// \brief Disable the given device
///
/// The main intention of \c RuntimeDeviceTracker is to keep track of what
......@@ -131,43 +92,119 @@ public:
/// devices on and off. Use this method to disable (turn off) a given device.
/// Use \c ResetDevice to turn the device back on (if it is supported).
///
VTKM_CONT void DisableDevice(DeviceAdapterId device) { this->SetDeviceState(device, false); }
/// Passing DeviceAdapterTagAny to this will disable all devices
///
VTKM_CONT void DisableDevice(DeviceAdapterId deviceId);
/// \brief Disable all devices except the specified one.
///
/// The main intention of \c RuntimeDeviceTracker is to keep track of what
/// devices are working for VTK-m. However, it can also be used to turn
/// devices on and off. Use this method to disable all devices except one
/// to effectively force VTK-m to use that device. Use \c Reset restore
/// all devices to their default values. You can also use the \c DeepCopy
/// methods to save and restore the state.
/// to effectively force VTK-m to use that device. Either pass the
/// DeviceAdapterTagAny to this function or call \c Reset to restore
/// all devices to their default state.
///
/// This method will throw a \c ErrorBadValue if the given device does not
/// exist on the system.
///
VTKM_CONT void ForceDevice(DeviceAdapterId id);
VTKM_CONT void ForceDevice(DeviceAdapterId deviceId);
private:
std::shared_ptr<detail::RuntimeDeviceTrackerInternals> Internals;
friend struct ScopedRuntimeDeviceTracker;
detail::RuntimeDeviceTrackerInternals* Internals;
VTKM_CONT
RuntimeDeviceTracker();
RuntimeDeviceTracker(detail::RuntimeDeviceTrackerInternals* details, bool reset);
// Deep Copy constructor.
VTKM_CONT
RuntimeDeviceTracker(const std::shared_ptr<detail::RuntimeDeviceTrackerInternals>& internals);
RuntimeDeviceTracker(const RuntimeDeviceTracker&) = delete;
VTKM_CONT
void CheckDevice(vtkm::cont::DeviceAdapterId deviceId) const;
RuntimeDeviceTracker& operator=(const RuntimeDeviceTracker&) = delete;
VTKM_CONT
bool CanRunOnImpl(vtkm::cont::DeviceAdapterId deviceId) const;
void CheckDevice(vtkm::cont::DeviceAdapterId deviceId) const;
VTKM_CONT
void SetDeviceState(vtkm::cont::DeviceAdapterId deviceId, bool state);
};
VTKM_CONT
void ForceDeviceImpl(vtkm::cont::DeviceAdapterId deviceId, bool runtimeExists);
enum struct RuntimeDeviceTrackerMode
{
Force,
Enable,
Disable
};
/// A class that can be used to determine or modify which device adapter
/// VTK-m algorithms should be run on. This class captures the state
/// of the per-thread device adapter and will revert any changes applied
/// during its lifetime on destruction.
///
///
struct VTKM_CONT_EXPORT ScopedRuntimeDeviceTracker : public vtkm::cont::RuntimeDeviceTracker
{
/// Construct a ScopedRuntimeDeviceTracker where the state of the active devices
/// for the current thread are determined by the parameters to the constructor.
///
/// 'Force'
/// - Force-Enable the provided single device adapter
/// - Force-Enable all device adapters when using vtkm::cont::DeviceAdaterTagAny
/// 'Enable'
/// - Enable the provided single device adapter if it was previously disabled
/// - Enable all device adapters that are currently disabled when using
/// vtkm::cont::DeviceAdaterTagAny
/// 'Disable'
/// - Disable the provided single device adapter
/// - Disable all device adapters when using vtkm::cont::DeviceAdaterTagAny
///
/// Constructor is not thread safe
VTKM_CONT ScopedRuntimeDeviceTracker(
vtkm::cont::DeviceAdapterId device,
RuntimeDeviceTrackerMode mode = RuntimeDeviceTrackerMode::Force);
/// Construct a ScopedRuntimeDeviceTracker associated with the thread
/// associated with the provided tracker. The active devices
/// for the current thread are determined by the parameters to the constructor.
///
/// 'Force'
/// - Force-Enable the provided single device adapter
/// - Force-Enable all device adapters when using vtkm::cont::DeviceAdaterTagAny
/// 'Enable'
/// - Enable the provided single device adapter if it was previously disabled
/// - Enable all device adapters that are currently disabled when using
/// vtkm::cont::DeviceAdaterTagAny
/// 'Disable'
/// - Disable the provided single device adapter
/// - Disable all device adapters when using vtkm::cont::DeviceAdaterTagAny
///
/// Any modifications to the ScopedRuntimeDeviceTracker will effect what
/// ever thread the \c tracker is associated with, which might not be
/// the thread which ScopedRuntimeDeviceTracker was constructed on.
///
/// Constructor is not thread safe
VTKM_CONT ScopedRuntimeDeviceTracker(vtkm::cont::DeviceAdapterId device,
RuntimeDeviceTrackerMode mode,
const vtkm::cont::RuntimeDeviceTracker& tracker);
/// Construct a ScopedRuntimeDeviceTracker associated with the thread
/// associated with the provided tracker.
///
/// Any modifications to the ScopedRuntimeDeviceTracker will effect what
/// ever thread the \c tracker is associated with, which might not be
/// the thread which ScopedRuntimeDeviceTracker was constructed on.
///
/// Constructor is not thread safe
VTKM_CONT ScopedRuntimeDeviceTracker(const vtkm::cont::RuntimeDeviceTracker& tracker);
/// Destructor is not thread safe
VTKM_CONT ~ScopedRuntimeDeviceTracker();
private:
std::unique_ptr<detail::RuntimeDeviceTrackerInternals> SavedState;
};
/// \brief Get the \c RuntimeDeviceTracker for the current thread.
......@@ -178,33 +215,9 @@ private:
/// to check over and over again, VTK-m uses per thread runtime device tracker
/// so that these choices are marked and shared.
///
/// Xcode's clang only supports thread_local from version 8
VTKM_CONT_EXPORT
VTKM_CONT
vtkm::cont::RuntimeDeviceTracker& GetRuntimeDeviceTracker();
struct ScopedRuntimeDeviceTracker
{
vtkm::cont::RuntimeDeviceTracker SavedTracker;
VTKM_CONT ScopedRuntimeDeviceTracker()
: SavedTracker(vtkm::cont::GetRuntimeDeviceTracker().DeepCopy())
{
}
VTKM_CONT ScopedRuntimeDeviceTracker(vtkm::cont::RuntimeDeviceTracker tracker)
: SavedTracker(vtkm::cont::GetRuntimeDeviceTracker().DeepCopy())
{
vtkm::cont::GetRuntimeDeviceTracker().DeepCopy(tracker);
}
VTKM_CONT ~ScopedRuntimeDeviceTracker()
{
vtkm::cont::GetRuntimeDeviceTracker().DeepCopy(this->SavedTracker);
}
ScopedRuntimeDeviceTracker(const ScopedRuntimeDeviceTracker&) = delete;
};
}
} // namespace vtkm::cont
......
......@@ -22,7 +22,7 @@ namespace detail
{
VTKM_CONT_EXPORT void HandleTryExecuteException(vtkm::cont::DeviceAdapterId deviceId,
vtkm::cont::RuntimeDeviceTracker tracker,
vtkm::cont::RuntimeDeviceTracker& tracker,
const std::string& functorName)
{
try
......
......@@ -25,7 +25,7 @@ namespace detail
{
VTKM_CONT_EXPORT void HandleTryExecuteException(vtkm::cont::DeviceAdapterId,
vtkm::cont::RuntimeDeviceTracker,
vtkm::cont::RuntimeDeviceTracker&,
const std::string& functorName);
template <typename DeviceTag, typename Functor, typename... Args>
......
......@@ -13,7 +13,7 @@
int UnitTestCudaArrayHandle(int argc, char* argv[])
{
auto tracker = vtkm::cont::GetRuntimeDeviceTracker();
auto& tracker<