Profiler: listen to OnSystemTick instead of OnFrameBegin (#1977)

* Profiler: move to OnSystemTick polling

Migrates from implementing FrameEventBus::Handler to SystemTickBus::Handler.
When we were collecting data from threads on the start of a frame, it
turns out that the event only fired once the RHI began working, which
would exclude any events before that (ex. RPI, some AuxGeom regions)
from the next GetTimeRegionMap call.

Signed-off-by: Jacob Hilliard <jhlliar@amazon.com>

* Visualizer: update logic to avoid dangling frame

Signed-off-by: Jacob Hilliard <jhlliar@amazon.com>
This commit is contained in:
Jacob Hilliard
2021-07-12 09:57:45 -07:00
committed by GitHub
parent c4f2ee7881
commit 37e3b02269
3 changed files with 20 additions and 11 deletions
@@ -9,13 +9,13 @@
#include <Atom/RHI/CpuProfiler.h>
#include <Atom/RHI.Reflect/Base.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/Memory/OSAllocator.h>
#include <AzCore/std/containers/map.h>
#include <AzCore/std/parallel/mutex.h>
#include <AzCore/std/parallel/shared_mutex.h>
#include <AzCore/std/smart_ptr/intrusive_refcount.h>
#include <Atom/RHI/FrameEventBus.h>
namespace AZ
{
@@ -83,7 +83,7 @@ namespace AZ
//! cached regions, which are stored on a per thread frequency.
class CpuProfilerImpl final
: public CpuProfiler
, public FrameEventBus::Handler
, public SystemTickBus::Handler
{
friend class CpuTimingLocalStorage;
@@ -99,7 +99,10 @@ namespace AZ
//! Unregisters the CpuProfilerImpl instance from the interface
void Shutdown();
void OnFrameBegin();
// SystemTickBus::Handler overrides
// When fired, the profiler collects all profiling data from registered threads and updates
// m_timeRegionMap so that the next frame has up-to-date profiling data.
void OnSystemTick() final override;
//! CpuProfiler overrides...
void BeginTimeRegion(TimeRegion& timeRegion) final;
@@ -79,8 +79,7 @@ namespace AZ
{
Interface<CpuProfiler>::Register(this);
m_initialized = true;
Device* rhiDevice = GetRHIDevice().get();
FrameEventBus::Handler::BusConnect(rhiDevice);
SystemTickBus::Handler::BusConnect();
}
void CpuProfilerImpl::Shutdown()
@@ -101,7 +100,7 @@ namespace AZ
m_registeredThreads.clear();
m_timeRegionMap.clear();
m_initialized = false;
FrameEventBus::Handler::BusDisconnect();
SystemTickBus::Handler::BusDisconnect();
}
void CpuProfilerImpl::BeginTimeRegion(TimeRegion& timeRegion)
@@ -173,7 +172,7 @@ namespace AZ
return m_enabled;
}
void CpuProfilerImpl::OnFrameBegin()
void CpuProfilerImpl::OnSystemTick()
{
if (!m_enabled)
{
@@ -199,7 +198,6 @@ namespace AZ
m_timeRegionMap = AZStd::move(newMap);
}
void CpuProfilerImpl::RegisterThreadStorage()
{
AZStd::unique_lock<AZStd::mutex> lock(m_threadRegisterMutex);
@@ -649,7 +649,10 @@ namespace AZ
// End ticks are sorted in increasing order, find the first frame bound to draw
auto endTickItr = AZStd::lower_bound(m_frameEndTicks.begin(), m_frameEndTicks.end(), m_viewportStartTick);
while (endTickItr != m_frameEndTicks.end() && *endTickItr < m_viewportEndTick)
// Draw to one element before the last collected boundary if possible to avoid empty frame at the end
auto drawToItr = m_frameEndTicks.size() > 1 ? m_frameEndTicks.end() - 1 : m_frameEndTicks.end();
while (endTickItr != drawToItr && *endTickItr < m_viewportEndTick)
{
const float horizontalPixel = ConvertTickToPixelSpace(*endTickItr);
drawList->AddLine({ horizontalPixel, wy }, { horizontalPixel, wy + windowHeight }, red);
@@ -670,7 +673,9 @@ namespace AZ
const auto [wx, wy] = ImGui::GetWindowPos();
ImDrawList* drawList = ImGui::GetWindowDrawList();
while (nextFrameBoundaryItr != m_frameEndTicks.end())
auto drawToItr = m_frameEndTicks.size() > 1 ? m_frameEndTicks.end() - 1 : m_frameEndTicks.end();
while (nextFrameBoundaryItr != drawToItr && *lastFrameBoundaryItr <= m_viewportEndTick)
{
const AZStd::sys_time_t lastFrameBoundaryTick = *lastFrameBoundaryItr;
const AZStd::sys_time_t nextFrameBoundaryTick = *nextFrameBoundaryItr;
@@ -750,7 +755,10 @@ namespace AZ
// System tick bus overrides
inline void ImGuiCpuProfiler::OnSystemTick()
{
m_frameEndTicks.push_back(AZStd::GetTimeNowTicks());
if (!m_paused)
{
m_frameEndTicks.push_back(AZStd::GetTimeNowTicks());
}
if (!m_showVisualizer || m_paused)
{