2019-01-09 16:11:49 +00:00
|
|
|
//============================================================================
|
|
|
|
// Copyright (c) Kitware, Inc.
|
|
|
|
// All rights reserved.
|
|
|
|
// See LICENSE.txt for details.
|
2019-04-15 23:24:21 +00:00
|
|
|
//
|
2019-01-09 16:11:49 +00:00
|
|
|
// 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.
|
|
|
|
//============================================================================
|
2022-07-12 14:52:12 +00:00
|
|
|
#include <vtkm/cont/Algorithm.h>
|
2021-10-13 18:11:23 +00:00
|
|
|
#include <vtkm/cont/DeviceAdapter.h>
|
|
|
|
#include <vtkm/cont/DeviceAdapterList.h>
|
2019-01-09 16:11:49 +00:00
|
|
|
#include <vtkm/cont/Logging.h>
|
|
|
|
#include <vtkm/cont/RuntimeDeviceTracker.h>
|
|
|
|
#include <vtkm/cont/Timer.h>
|
|
|
|
|
2019-12-05 21:38:41 +00:00
|
|
|
#include <tuple>
|
2019-01-09 16:11:49 +00:00
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
namespace
|
2019-01-09 16:11:49 +00:00
|
|
|
{
|
2019-12-05 21:38:41 +00:00
|
|
|
template <typename Device>
|
|
|
|
using DeviceInvalid = std::integral_constant<bool, !Device::IsEnabled>;
|
|
|
|
using EnabledDeviceList = vtkm::ListRemoveIf<vtkm::cont::DeviceAdapterListCommon, DeviceInvalid>;
|
2019-01-09 16:11:49 +00:00
|
|
|
|
2019-12-11 22:59:32 +00:00
|
|
|
template <typename Device>
|
|
|
|
using DeviceTimerPtr = std::unique_ptr<vtkm::cont::DeviceAdapterTimerImplementation<Device>>;
|
2019-01-09 16:11:49 +00:00
|
|
|
|
2019-12-11 22:59:32 +00:00
|
|
|
using EnabledTimerImpls = vtkm::ListTransform<EnabledDeviceList, DeviceTimerPtr>;
|
|
|
|
using EnabledTimerImplTuple = vtkm::ListApply<EnabledTimerImpls, std::tuple>;
|
2019-02-28 18:32:09 +00:00
|
|
|
|
2019-01-09 16:11:49 +00:00
|
|
|
// C++11 does not support get tuple element by type. C++14 does support that.
|
|
|
|
// Get the index of a type in tuple elements
|
|
|
|
template <class T, class Tuple>
|
|
|
|
struct Index;
|
|
|
|
|
|
|
|
template <class T, template <typename...> class Container, class... Types>
|
|
|
|
struct Index<T, Container<T, Types...>>
|
|
|
|
{
|
|
|
|
static const std::size_t value = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class T, class U, template <typename...> class Container, class... Types>
|
|
|
|
struct Index<T, Container<U, Types...>>
|
|
|
|
{
|
|
|
|
static const std::size_t value = 1 + Index<T, Container<Types...>>::value;
|
|
|
|
};
|
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
template <typename Device>
|
2019-02-28 22:36:55 +00:00
|
|
|
VTKM_CONT inline
|
|
|
|
typename std::tuple_element<Index<Device, EnabledDeviceList>::value, EnabledTimerImplTuple>::type&
|
2019-12-11 22:59:32 +00:00
|
|
|
GetUniqueTimerPtr(Device, EnabledTimerImplTuple& enabledTimers)
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
return std::get<Index<Device, EnabledDeviceList>::value>(enabledTimers);
|
2019-02-28 18:32:09 +00:00
|
|
|
}
|
|
|
|
|
2019-12-11 22:59:32 +00:00
|
|
|
struct InitFunctor
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
template <typename Device>
|
|
|
|
VTKM_CONT void operator()(Device, EnabledTimerImplTuple& timerImpls)
|
|
|
|
{
|
|
|
|
//We don't use the runtime device tracker to very initializtion support
|
|
|
|
//so that the following use case is supported:
|
|
|
|
//
|
|
|
|
// GetRuntimeDeviceTracker().Disable( openMP );
|
|
|
|
// vtkm::cont::Timer timer; //tracks all active devices
|
|
|
|
// GetRuntimeDeviceTracker().Enable( openMP );
|
|
|
|
// timer.Start() //want to test openmp
|
|
|
|
//
|
|
|
|
// timer.GetElapsedTime()
|
|
|
|
//
|
|
|
|
// When `GetElapsedTime` is called we need to make sure that the OpenMP
|
|
|
|
// device timer is safe to call. At the same time we still need to make
|
|
|
|
// sure that we have the required runtime and not just compile time support
|
|
|
|
// this is why we use `DeviceAdapterRuntimeDetector`
|
|
|
|
bool haveRequiredRuntimeSupport = vtkm::cont::DeviceAdapterRuntimeDetector<Device>{}.Exists();
|
|
|
|
if (haveRequiredRuntimeSupport)
|
|
|
|
{
|
|
|
|
std::get<Index<Device, EnabledDeviceList>::value>(timerImpls)
|
|
|
|
.reset(new vtkm::cont::DeviceAdapterTimerImplementation<Device>());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2019-02-28 18:32:09 +00:00
|
|
|
|
|
|
|
struct ResetFunctor
|
|
|
|
{
|
|
|
|
template <typename Device>
|
|
|
|
VTKM_CONT void operator()(Device device,
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::cont::DeviceAdapterId deviceToRunOn,
|
|
|
|
const vtkm::cont::RuntimeDeviceTracker& tracker,
|
|
|
|
EnabledTimerImplTuple& timerImpls)
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
if ((deviceToRunOn == device || deviceToRunOn == vtkm::cont::DeviceAdapterTagAny()) &&
|
|
|
|
tracker.CanRunOn(device))
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
GetUniqueTimerPtr(device, timerImpls)->Reset();
|
2019-02-28 18:32:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct StartFunctor
|
2019-01-09 16:11:49 +00:00
|
|
|
{
|
2019-02-28 18:32:09 +00:00
|
|
|
template <typename Device>
|
|
|
|
VTKM_CONT void operator()(Device device,
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::cont::DeviceAdapterId deviceToRunOn,
|
|
|
|
const vtkm::cont::RuntimeDeviceTracker& tracker,
|
|
|
|
EnabledTimerImplTuple& timerImpls)
|
2019-01-09 16:11:49 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
if ((deviceToRunOn == device || deviceToRunOn == vtkm::cont::DeviceAdapterTagAny()) &&
|
|
|
|
tracker.CanRunOn(device))
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
GetUniqueTimerPtr(device, timerImpls)->Start();
|
2019-02-28 18:32:09 +00:00
|
|
|
}
|
2019-01-09 16:11:49 +00:00
|
|
|
}
|
2019-02-28 18:32:09 +00:00
|
|
|
};
|
2019-01-09 16:11:49 +00:00
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
struct StopFunctor
|
|
|
|
{
|
|
|
|
template <typename Device>
|
|
|
|
VTKM_CONT void operator()(Device device,
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::cont::DeviceAdapterId deviceToRunOn,
|
|
|
|
const vtkm::cont::RuntimeDeviceTracker& tracker,
|
|
|
|
EnabledTimerImplTuple& timerImpls)
|
2019-01-09 16:11:49 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
if ((deviceToRunOn == device || deviceToRunOn == vtkm::cont::DeviceAdapterTagAny()) &&
|
|
|
|
tracker.CanRunOn(device))
|
2019-01-09 16:11:49 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
GetUniqueTimerPtr(device, timerImpls)->Stop();
|
2019-01-09 16:11:49 +00:00
|
|
|
}
|
|
|
|
}
|
2019-02-28 18:32:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct StartedFunctor
|
|
|
|
{
|
|
|
|
bool Value = true;
|
2019-01-09 16:11:49 +00:00
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
template <typename Device>
|
|
|
|
VTKM_CONT void operator()(Device device,
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::cont::DeviceAdapterId deviceToRunOn,
|
|
|
|
const vtkm::cont::RuntimeDeviceTracker& tracker,
|
|
|
|
EnabledTimerImplTuple& timerImpls)
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
if ((deviceToRunOn == device || deviceToRunOn == vtkm::cont::DeviceAdapterTagAny()) &&
|
|
|
|
tracker.CanRunOn(device))
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
this->Value &= GetUniqueTimerPtr(device, timerImpls)->Started();
|
2019-02-28 18:32:09 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-09 16:11:49 +00:00
|
|
|
};
|
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
struct StoppedFunctor
|
|
|
|
{
|
|
|
|
bool Value = true;
|
|
|
|
|
|
|
|
template <typename Device>
|
|
|
|
VTKM_CONT void operator()(Device device,
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::cont::DeviceAdapterId deviceToRunOn,
|
|
|
|
const vtkm::cont::RuntimeDeviceTracker& tracker,
|
|
|
|
EnabledTimerImplTuple& timerImpls)
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
if ((deviceToRunOn == device || deviceToRunOn == vtkm::cont::DeviceAdapterTagAny()) &&
|
|
|
|
tracker.CanRunOn(device))
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
this->Value &= GetUniqueTimerPtr(device, timerImpls)->Stopped();
|
2019-02-28 18:32:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ReadyFunctor
|
|
|
|
{
|
|
|
|
bool Value = true;
|
|
|
|
|
|
|
|
template <typename Device>
|
|
|
|
VTKM_CONT void operator()(Device device,
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::cont::DeviceAdapterId deviceToRunOn,
|
|
|
|
const vtkm::cont::RuntimeDeviceTracker& tracker,
|
|
|
|
EnabledTimerImplTuple& timerImpls)
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
if ((deviceToRunOn == device || deviceToRunOn == vtkm::cont::DeviceAdapterTagAny()) &&
|
|
|
|
tracker.CanRunOn(device))
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
this->Value &= GetUniqueTimerPtr(device, timerImpls)->Ready();
|
2019-02-28 18:32:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ElapsedTimeFunctor
|
|
|
|
{
|
|
|
|
vtkm::Float64 ElapsedTime = 0.0;
|
|
|
|
|
|
|
|
template <typename Device>
|
2019-12-11 22:59:32 +00:00
|
|
|
VTKM_CONT void operator()(Device device,
|
2019-02-28 18:32:09 +00:00
|
|
|
vtkm::cont::DeviceAdapterId deviceToRunOn,
|
2019-12-11 22:59:32 +00:00
|
|
|
const vtkm::cont::RuntimeDeviceTracker& tracker,
|
|
|
|
EnabledTimerImplTuple& timerImpls)
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
if ((deviceToRunOn == device || deviceToRunOn == vtkm::cont::DeviceAdapterTagAny()) &&
|
|
|
|
tracker.CanRunOn(device))
|
2019-02-28 18:32:09 +00:00
|
|
|
{
|
|
|
|
this->ElapsedTime =
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::Max(this->ElapsedTime, GetUniqueTimerPtr(device, timerImpls)->GetElapsedTime());
|
2019-02-28 18:32:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2019-12-11 22:59:32 +00:00
|
|
|
|
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace cont
|
|
|
|
{
|
|
|
|
namespace detail
|
|
|
|
{
|
|
|
|
|
|
|
|
struct EnabledDeviceTimerImpls
|
|
|
|
{
|
|
|
|
EnabledDeviceTimerImpls()
|
|
|
|
{
|
|
|
|
vtkm::ListForEach(InitFunctor(), EnabledDeviceList(), this->EnabledTimers);
|
|
|
|
}
|
|
|
|
~EnabledDeviceTimerImpls() {}
|
|
|
|
// A tuple of enabled timer implementations
|
|
|
|
EnabledTimerImplTuple EnabledTimers;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} // namespace vtkm::cont::detail
|
|
|
|
|
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
namespace vtkm
|
|
|
|
{
|
|
|
|
namespace cont
|
|
|
|
{
|
2019-01-09 16:11:49 +00:00
|
|
|
|
|
|
|
Timer::Timer()
|
|
|
|
: Device(vtkm::cont::DeviceAdapterTagAny())
|
2019-12-11 22:59:32 +00:00
|
|
|
, Internal(new detail::EnabledDeviceTimerImpls)
|
2019-01-09 16:11:49 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-02-27 22:15:18 +00:00
|
|
|
Timer::Timer(vtkm::cont::DeviceAdapterId device)
|
|
|
|
: Device(device)
|
2019-12-11 22:59:32 +00:00
|
|
|
, Internal(new detail::EnabledDeviceTimerImpls)
|
2019-02-27 22:15:18 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
const auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
2019-06-19 14:50:44 +00:00
|
|
|
if (!tracker.CanRunOn(device))
|
2019-02-27 22:15:18 +00:00
|
|
|
{
|
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
|
2020-08-17 14:18:24 +00:00
|
|
|
"Device '" << device.GetName()
|
|
|
|
<< "' can not run on current Device."
|
|
|
|
"Thus timer is not usable");
|
2019-02-27 22:15:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
Timer::~Timer() = default;
|
2019-01-09 16:11:49 +00:00
|
|
|
|
|
|
|
void Timer::Reset()
|
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
const auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
|
|
|
vtkm::ListForEach(
|
|
|
|
ResetFunctor(), EnabledDeviceList(), this->Device, tracker, this->Internal->EnabledTimers);
|
2019-01-09 16:11:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-27 22:23:44 +00:00
|
|
|
void Timer::Reset(vtkm::cont::DeviceAdapterId device)
|
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
const auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
2019-06-19 14:50:44 +00:00
|
|
|
if (!tracker.CanRunOn(device))
|
2019-02-27 22:23:44 +00:00
|
|
|
{
|
|
|
|
VTKM_LOG_S(vtkm::cont::LogLevel::Error,
|
2020-08-17 14:18:24 +00:00
|
|
|
"Device '" << device.GetName()
|
|
|
|
<< "' can not run on current Device."
|
|
|
|
"Thus timer is not usable");
|
2019-02-27 22:23:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
this->Device = device;
|
|
|
|
this->Reset();
|
|
|
|
}
|
|
|
|
|
2019-01-09 16:11:49 +00:00
|
|
|
void Timer::Start()
|
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
const auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
|
|
|
vtkm::ListForEach(
|
|
|
|
StartFunctor(), EnabledDeviceList(), this->Device, tracker, this->Internal->EnabledTimers);
|
2019-01-09 16:11:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Timer::Stop()
|
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
const auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
|
|
|
vtkm::ListForEach(
|
|
|
|
StopFunctor(), EnabledDeviceList(), this->Device, tracker, this->Internal->EnabledTimers);
|
2019-01-09 16:11:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
bool Timer::Started() const
|
2019-01-09 16:11:49 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
const auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
2019-02-28 18:32:09 +00:00
|
|
|
StartedFunctor functor;
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::ListForEach(
|
|
|
|
functor, EnabledDeviceList(), this->Device, tracker, this->Internal->EnabledTimers);
|
2019-02-28 18:32:09 +00:00
|
|
|
return functor.Value;
|
2019-01-09 16:11:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
bool Timer::Stopped() const
|
2019-01-09 16:11:49 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
const auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
2019-02-28 18:32:09 +00:00
|
|
|
StoppedFunctor functor;
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::ListForEach(
|
|
|
|
functor, EnabledDeviceList(), this->Device, tracker, this->Internal->EnabledTimers);
|
2019-02-28 18:32:09 +00:00
|
|
|
return functor.Value;
|
2019-01-09 16:11:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
bool Timer::Ready() const
|
2019-01-09 16:11:49 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
const auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
2019-02-28 18:32:09 +00:00
|
|
|
ReadyFunctor functor;
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::ListForEach(
|
|
|
|
functor, EnabledDeviceList(), this->Device, tracker, this->Internal->EnabledTimers);
|
2019-02-28 18:32:09 +00:00
|
|
|
return functor.Value;
|
2019-01-09 16:11:49 +00:00
|
|
|
}
|
|
|
|
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::Float64 Timer::GetElapsedTime() const
|
2019-01-09 16:11:49 +00:00
|
|
|
{
|
2019-12-11 22:59:32 +00:00
|
|
|
//Throw an exception if a timer bound device now can't be used
|
2019-04-01 21:25:44 +00:00
|
|
|
auto& tracker = vtkm::cont::GetRuntimeDeviceTracker();
|
2019-01-09 16:11:49 +00:00
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
ElapsedTimeFunctor functor;
|
2019-12-11 22:59:32 +00:00
|
|
|
vtkm::ListForEach(
|
|
|
|
functor, EnabledDeviceList(), this->Device, tracker, this->Internal->EnabledTimers);
|
2019-01-09 16:11:49 +00:00
|
|
|
|
2019-02-28 18:32:09 +00:00
|
|
|
return functor.ElapsedTime;
|
2019-01-09 16:11:49 +00:00
|
|
|
}
|
2022-07-12 14:52:12 +00:00
|
|
|
|
|
|
|
void Timer::Synchronize() const
|
|
|
|
{
|
|
|
|
vtkm::cont::Algorithm::Synchronize(this->Device);
|
|
|
|
}
|
|
|
|
|
2019-01-09 16:11:49 +00:00
|
|
|
}
|
|
|
|
} // namespace vtkm::cont
|