From a20f48915e11af993f6a6e5d7f51d92d4d927379 Mon Sep 17 00:00:00 2001 From: Scott Romero <24445312+AMZN-ScottR@users.noreply.github.com> Date: Thu, 17 Feb 2022 14:00:49 -0800 Subject: [PATCH] [development] Profiler gem cleanup (#7533) Consolidated the contents of CpuProfilerImp.h into CpuProfiler.h Renamed CpuProfilerImpl.cpp to CpuProfiler.cpp Collapsed the CpuProfilerImpl class into the intermediary CpuProfiler interface class, removing that interface type Replaced all calls to the old CpuProfiler interface with AZ::Debug::ProfilerSystemInterface Added accessor to see if a continuous capture is in progress to AZ::Debug::ProfilerRequests Signed-off-by: AMZN-ScottR 24445312+AMZN-ScottR@users.noreply.github.com --- .../AzCore/AzCore/Debug/ProfilerBus.h | 4 + .../{CpuProfilerImpl.cpp => CpuProfiler.cpp} | 44 ++-- Gems/Profiler/Code/Source/CpuProfiler.h | 183 +++++++++++++++-- Gems/Profiler/Code/Source/CpuProfilerImpl.h | 189 ------------------ .../Profiler/Code/Source/ImGuiCpuProfiler.cpp | 17 +- .../Source/ProfilerImGuiSystemComponent.cpp | 3 +- .../Code/Source/ProfilerSystemComponent.cpp | 13 +- .../Code/Source/ProfilerSystemComponent.h | 5 +- Gems/Profiler/Code/profiler_files.cmake | 3 +- 9 files changed, 213 insertions(+), 248 deletions(-) rename Gems/Profiler/Code/Source/{CpuProfilerImpl.cpp => CpuProfiler.cpp} (91%) delete mode 100644 Gems/Profiler/Code/Source/CpuProfilerImpl.h diff --git a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h index 322bfb60c2..8c5c6de902 100644 --- a/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h +++ b/Code/Framework/AzCore/AzCore/Debug/ProfilerBus.h @@ -58,6 +58,10 @@ namespace AZ //! Starting/ending a multi-frame capture of profiling data virtual bool StartCapture(AZStd::string outputFilePath) = 0; virtual bool EndCapture() = 0; + + //! Check to see if a programmatic capture is currently in progress, implies + //! that the profiler is active if returns True. + virtual bool IsCaptureInProgress() const = 0; }; using ProfilerSystemInterface = AZ::Interface; diff --git a/Gems/Profiler/Code/Source/CpuProfilerImpl.cpp b/Gems/Profiler/Code/Source/CpuProfiler.cpp similarity index 91% rename from Gems/Profiler/Code/Source/CpuProfilerImpl.cpp rename to Gems/Profiler/Code/Source/CpuProfiler.cpp index b0082bd046..7fa1277019 100644 --- a/Gems/Profiler/Code/Source/CpuProfilerImpl.cpp +++ b/Gems/Profiler/Code/Source/CpuProfiler.cpp @@ -6,7 +6,7 @@ * */ -#include +#include #include #include @@ -15,14 +15,7 @@ namespace Profiler { - thread_local CpuTimingLocalStorage* CpuProfilerImpl::ms_threadLocalStorage = nullptr; - - // --- CpuProfiler --- - - CpuProfiler* CpuProfiler::Get() - { - return AZ::Interface::Get(); - } + thread_local CpuTimingLocalStorage* CpuProfiler::ms_threadLocalStorage = nullptr; // --- CachedTimeRegion --- @@ -61,25 +54,24 @@ namespace Profiler } - // --- CpuProfilerImpl --- + // --- CpuProfiler --- - void CpuProfilerImpl::Init() + void CpuProfiler::Init() { AZ::Interface::Register(this); - AZ::Interface::Register(this); m_initialized = true; AZ::SystemTickBus::Handler::BusConnect(); m_continuousCaptureData.set_capacity(10); } - void CpuProfilerImpl::Shutdown() + void CpuProfiler::Shutdown() { if (!m_initialized) { return; } + // When this call is made, no more thread profiling calls can be performed anymore - AZ::Interface::Unregister(this); AZ::Interface::Unregister(this); // Wait for the remaining threads that might still be processing its profiling calls @@ -96,7 +88,7 @@ namespace Profiler AZ::SystemTickBus::Handler::BusDisconnect(); } - void CpuProfilerImpl::BeginRegion(const AZ::Debug::Budget* budget, const char* eventName, [[maybe_unused]] size_t eventNameArgCount, ...) + void CpuProfiler::BeginRegion(const AZ::Debug::Budget* budget, const char* eventName, [[maybe_unused]] size_t eventNameArgCount, ...) { // Try to lock here, the shutdownMutex will only be contested when the CpuProfiler is shutting down. if (m_shutdownMutex.try_lock_shared()) @@ -115,7 +107,7 @@ namespace Profiler } } - void CpuProfilerImpl::EndRegion([[maybe_unused]] const AZ::Debug::Budget* budget) + void CpuProfiler::EndRegion([[maybe_unused]] const AZ::Debug::Budget* budget) { // Try to lock here, the shutdownMutex will only be contested when the CpuProfiler is shutting down. if (m_shutdownMutex.try_lock_shared()) @@ -130,12 +122,12 @@ namespace Profiler } } - const CpuProfiler::TimeRegionMap& CpuProfilerImpl::GetTimeRegionMap() const + const TimeRegionMap& CpuProfiler::GetTimeRegionMap() const { return m_timeRegionMap; } - bool CpuProfilerImpl::BeginContinuousCapture() + bool CpuProfiler::BeginContinuousCapture() { bool expected = false; if (m_continuousCaptureInProgress.compare_exchange_strong(expected, true)) @@ -149,7 +141,7 @@ namespace Profiler return false; } - bool CpuProfilerImpl::EndContinuousCapture(AZStd::ring_buffer& flushTarget) + bool CpuProfiler::EndContinuousCapture(AZStd::ring_buffer& flushTarget) { if (!m_continuousCaptureInProgress.load()) { @@ -172,12 +164,12 @@ namespace Profiler return false; } - bool CpuProfilerImpl::IsContinuousCaptureInProgress() const + bool CpuProfiler::IsContinuousCaptureInProgress() const { return m_continuousCaptureInProgress.load(); } - void CpuProfilerImpl::SetProfilerEnabled(bool enabled) + void CpuProfiler::SetProfilerEnabled(bool enabled) { AZStd::unique_lock lock(m_threadRegisterMutex); @@ -204,12 +196,12 @@ namespace Profiler } } - bool CpuProfilerImpl::IsProfilerEnabled() const + bool CpuProfiler::IsProfilerEnabled() const { return m_enabled; } - void CpuProfilerImpl::OnSystemTick() + void CpuProfiler::OnSystemTick() { if (!m_enabled) { @@ -249,7 +241,7 @@ namespace Profiler m_timeRegionMap = AZStd::move(newMap); } - void CpuProfilerImpl::RegisterThreadStorage() + void CpuProfiler::RegisterThreadStorage() { AZStd::unique_lock lock(m_threadRegisterMutex); if (!ms_threadLocalStorage) @@ -371,7 +363,7 @@ namespace Profiler } } - void CpuTimingLocalStorage::TryFlushCachedMap(CpuProfiler::ThreadTimeRegionMap& cachedTimeRegionMap) + void CpuTimingLocalStorage::TryFlushCachedMap(ThreadTimeRegionMap& cachedTimeRegionMap) { // Try to lock, if it's already in use (the cached regions in the array are being copied to the map) // it'll show up in the next iteration when the user requests it. @@ -397,7 +389,7 @@ namespace Profiler // --- CpuProfilingStatisticsSerializer --- - CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializer(const AZStd::ring_buffer& continuousData) + CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializer(const AZStd::ring_buffer& continuousData) { // Create serializable entries for (const auto& timeRegionMap : continuousData) diff --git a/Gems/Profiler/Code/Source/CpuProfiler.h b/Gems/Profiler/Code/Source/CpuProfiler.h index 9235ac7da9..2595516ef6 100644 --- a/Gems/Profiler/Code/Source/CpuProfiler.h +++ b/Gems/Profiler/Code/Source/CpuProfiler.h @@ -8,10 +8,17 @@ #pragma once +#include #include +#include +#include #include +#include #include #include +#include +#include +#include #include namespace Profiler @@ -47,36 +54,178 @@ namespace Profiler AZStd::sys_time_t m_endTick = 0; }; - //! Interface class of the CpuProfiler - class CpuProfiler + using ThreadTimeRegionMap = AZStd::unordered_map>; + using TimeRegionMap = AZStd::unordered_map; + + //! Thread local class to keep track of the thread's cached time regions. + //! Each thread keeps track of its own time regions, which is communicated from the CpuProfiler. + //! The CpuProfiler is able to request the cached time regions from the CpuTimingLocalStorage. + class CpuTimingLocalStorage + : public AZStd::intrusive_refcount { + friend class CpuProfiler; + public: - using ThreadTimeRegionMap = AZStd::unordered_map>; - using TimeRegionMap = AZStd::unordered_map; + AZ_CLASS_ALLOCATOR(CpuTimingLocalStorage, AZ::SystemAllocator, 0); + + CpuTimingLocalStorage(); + ~CpuTimingLocalStorage(); + + private: + // Maximum stack size + static constexpr uint32_t TimeRegionStackSize = 2048u; + + // Adds a region to the stack, gets called each time a region begins + void RegionStackPushBack(CachedTimeRegion& timeRegion); + + // Pops a region from the stack, gets called each time a region ends + void RegionStackPopBack(); + + // Add a new cached time region. If the stack is empty, flush all entries to the cached map + void AddCachedRegion(const CachedTimeRegion& timeRegionCached); + + // Tries to flush the map to the passed parameter, only if the thread's mutex is unlocked + void TryFlushCachedMap(ThreadTimeRegionMap& cachedRegionMap); + + // Clears m_cachedTimeRegions and resets m_cachedDataLimitReached flag. + void ResetCachedData(); + + AZStd::thread_id m_executingThreadId; + // Keeps track of the current thread's stack depth + uint32_t m_stackLevel = 0u; + + // Cached region map, will be flushed to the system's map when the system requests it + ThreadTimeRegionMap m_cachedTimeRegionMap; + + // Use fixed vectors to avoid re-allocating new elements + // Keeps track of the regions that added and removed using the macro + AZStd::fixed_vector m_timeRegionStack; + + // Keeps track of regions that completed (i.e regions that was pushed and popped from the stack) + // Intermediate storage point for the CachedTimeRegions, when the stack is empty, all entries will be + // copied to the map. + AZStd::fixed_vector m_cachedTimeRegions; + AZStd::mutex m_cachedTimeRegionMutex; + + // Dirty flag which is set when the CpuProfiler's enabled state is set from false to true + AZStd::atomic_bool m_clearContainers = false; + + // When the thread is terminated, it will flag itself for deletion + AZStd::atomic_bool m_deleteFlag = false; + + // Keep track of the regions that have hit the size limit so we don't have to lock to check + AZStd::map m_hitSizeLimitMap; + + // Keeps track of the first time cached data limit was reached. + bool m_cachedDataLimitReached = false; + }; + + //! CpuProfiler will keep track of the registered threads, and + //! forwards the request to profile a region to the appropriate thread. The user is able to request all + //! cached regions, which are stored on a per thread frequency. + class CpuProfiler final + : public AZ::Debug::Profiler + , public AZ::SystemTickBus::Handler + { + friend class CpuTimingLocalStorage; - AZ_RTTI(CpuProfiler, "{127C1D0B-BE05-4E18-A8F6-24F3EED2ECA6}"); + public: + AZ_RTTI(CpuProfiler, "{10E9D394-FC83-4B45-B2B8-807C6BF07BF0}", AZ::Debug::Profiler); + AZ_CLASS_ALLOCATOR(CpuProfiler, AZ::SystemAllocator, 0); CpuProfiler() = default; - virtual ~CpuProfiler() = default; + ~CpuProfiler() = default; - AZ_DISABLE_COPY_MOVE(CpuProfiler); + //! Registers/un-registers the AZ::Debug::Profiler instance to the interface + void Init(); + void Shutdown(); - static CpuProfiler* Get(); + //! AZ::Debug::Profiler overrides... + void BeginRegion(const AZ::Debug::Budget* budget, const char* eventName, size_t eventNameArgCount, ...) final override; + void EndRegion(const AZ::Debug::Budget* budget) final override; //! Get the last frame's TimeRegionMap - virtual const TimeRegionMap& GetTimeRegionMap() const = 0; + const TimeRegionMap& GetTimeRegionMap() const; + + //! Starting/ending a multi-frame capture of profiling data + bool BeginContinuousCapture(); + bool EndContinuousCapture(AZStd::ring_buffer& flushTarget); + + //! Check to see if a programmatic capture is currently in progress, implies + //! that the profiler is active if returns True. + bool IsContinuousCaptureInProgress() const; + + //! Getter/setter for the profiler active state + void SetProfilerEnabled(bool enabled); + bool IsProfilerEnabled() const; + + //! AZ::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; + + private: + static constexpr AZStd::size_t MaxFramesToSave = 2 * 60 * 120; // 2 minutes of 120fps + static constexpr AZStd::size_t MaxRegionStringPoolSize = 16384; // Max amount of unique strings to save in the pool before throwing warnings. + + // Lazily create and register the local thread data + void RegisterThreadStorage(); + + // ThreadId -> ThreadTimeRegionMap + // On the start of each frame, this map will be updated with the last frame's profiling data. + TimeRegionMap m_timeRegionMap; + + // Set of registered threads when created + AZStd::vector, AZ::OSStdAllocator> m_registeredThreads; + AZStd::mutex m_threadRegisterMutex; + + // Thread local storage, gets lazily allocated when a thread is created + static thread_local CpuTimingLocalStorage* ms_threadLocalStorage; - //! Begin a continuous capture. Blocks the profiler from being toggled off until EndContinuousCapture is called. - [[nodiscard]] virtual bool BeginContinuousCapture() = 0; + // Enable/Disables the threads from profiling + AZStd::atomic_bool m_enabled = false; - //! Flush the CPU Profiler's saved data into the passed ring buffer . - [[nodiscard]] virtual bool EndContinuousCapture(AZStd::ring_buffer& flushTarget) = 0; + // This lock will only be contested when the CpuProfiler's Shutdown() method has been called + AZStd::shared_mutex m_shutdownMutex; + + bool m_initialized = false; + + AZStd::mutex m_continuousCaptureEndingMutex; + + AZStd::atomic_bool m_continuousCaptureInProgress = false; + + // Stores multiple frames of profiling data, size is controlled by MaxFramesToSave. Flushed when EndContinuousCapture is called. + // Ring buffer so that we can have fast append of new data + removal of old profiling data with good cache locality. + AZStd::ring_buffer m_continuousCaptureData; + }; + + // Intermediate class to serialize Cpu TimedRegion data. + class CpuProfilingStatisticsSerializer + { + public: + class CpuProfilingStatisticsSerializerEntry + { + public: + AZ_TYPE_INFO(CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry, "{26B78F65-EB96-46E2-BE7E-A1233880B225}"); + static void Reflect(AZ::ReflectContext* context); + + CpuProfilingStatisticsSerializerEntry() = default; + CpuProfilingStatisticsSerializerEntry(const CachedTimeRegion& cachedTimeRegion, AZStd::thread_id threadId); + + AZ::Name m_groupName; + AZ::Name m_regionName; + uint16_t m_stackDepth; + AZStd::sys_time_t m_startTick; + AZStd::sys_time_t m_endTick; + size_t m_threadId; + }; - virtual bool IsContinuousCaptureInProgress() const = 0; + AZ_TYPE_INFO(CpuProfilingStatisticsSerializer, "{D5B02946-0D27-474F-9A44-364C2706DD41}"); + static void Reflect(AZ::ReflectContext* context); - //! Enable/Disable the CpuProfiler - virtual void SetProfilerEnabled(bool enabled) = 0; + CpuProfilingStatisticsSerializer() = default; + CpuProfilingStatisticsSerializer(const AZStd::ring_buffer& continuousData); - virtual bool IsProfilerEnabled() const = 0 ; + AZStd::vector m_cpuProfilingStatisticsSerializerEntries; }; } // namespace Profiler diff --git a/Gems/Profiler/Code/Source/CpuProfilerImpl.h b/Gems/Profiler/Code/Source/CpuProfilerImpl.h deleted file mode 100644 index 48b972bc49..0000000000 --- a/Gems/Profiler/Code/Source/CpuProfilerImpl.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) Contributors to the Open 3D Engine Project. - * For complete copyright and license terms please see the LICENSE at the root of this distribution. - * - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - */ -#pragma once - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Profiler -{ - //! Thread local class to keep track of the thread's cached time regions. - //! Each thread keeps track of its own time regions, which is communicated from the CpuProfilerImpl. - //! The CpuProfilerImpl is able to request the cached time regions from the CpuTimingLocalStorage. - class CpuTimingLocalStorage - : public AZStd::intrusive_refcount - { - friend class CpuProfilerImpl; - - public: - AZ_CLASS_ALLOCATOR(CpuTimingLocalStorage, AZ::OSAllocator, 0); - - CpuTimingLocalStorage(); - ~CpuTimingLocalStorage(); - - private: - // Maximum stack size - static constexpr uint32_t TimeRegionStackSize = 2048u; - - // Adds a region to the stack, gets called each time a region begins - void RegionStackPushBack(CachedTimeRegion& timeRegion); - - // Pops a region from the stack, gets called each time a region ends - void RegionStackPopBack(); - - // Add a new cached time region. If the stack is empty, flush all entries to the cached map - void AddCachedRegion(const CachedTimeRegion& timeRegionCached); - - // Tries to flush the map to the passed parameter, only if the thread's mutex is unlocked - void TryFlushCachedMap(CpuProfiler::ThreadTimeRegionMap& cachedRegionMap); - - // Clears m_cachedTimeRegions and resets m_cachedDataLimitReached flag. - void ResetCachedData(); - - AZStd::thread_id m_executingThreadId; - // Keeps track of the current thread's stack depth - uint32_t m_stackLevel = 0u; - - // Cached region map, will be flushed to the system's map when the system requests it - CpuProfiler::ThreadTimeRegionMap m_cachedTimeRegionMap; - - // Use fixed vectors to avoid re-allocating new elements - // Keeps track of the regions that added and removed using the macro - AZStd::fixed_vector m_timeRegionStack; - - // Keeps track of regions that completed (i.e regions that was pushed and popped from the stack) - // Intermediate storage point for the CachedTimeRegions, when the stack is empty, all entries will be - // copied to the map. - AZStd::fixed_vector m_cachedTimeRegions; - AZStd::mutex m_cachedTimeRegionMutex; - - // Dirty flag which is set when the CpuProfiler's enabled state is set from false to true - AZStd::atomic_bool m_clearContainers = false; - - // When the thread is terminated, it will flag itself for deletion - AZStd::atomic_bool m_deleteFlag = false; - - // Keep track of the regions that have hit the size limit so we don't have to lock to check - AZStd::map m_hitSizeLimitMap; - - // Keeps track of the first time cached data limit was reached. - bool m_cachedDataLimitReached = false; - }; - - //! CpuProfiler will keep track of the registered threads, and - //! forwards the request to profile a region to the appropriate thread. The user is able to request all - //! cached regions, which are stored on a per thread frequency. - class CpuProfilerImpl final - : public AZ::Debug::Profiler - , public CpuProfiler - , public AZ::SystemTickBus::Handler - { - friend class CpuTimingLocalStorage; - - public: - AZ_TYPE_INFO(CpuProfilerImpl, "{10E9D394-FC83-4B45-B2B8-807C6BF07BF0}"); - AZ_CLASS_ALLOCATOR(CpuProfilerImpl, AZ::OSAllocator, 0); - - CpuProfilerImpl() = default; - ~CpuProfilerImpl() = default; - - //! Registers the CpuProfilerImpl instance to the interface - void Init(); - //! Unregisters the CpuProfilerImpl instance from the interface - void Shutdown(); - - // AZ::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; - - //! AZ::Debug::Profiler overrides... - void BeginRegion(const AZ::Debug::Budget* budget, const char* eventName, size_t eventNameArgCount, ...) final override; - void EndRegion(const AZ::Debug::Budget* budget) final override; - - //! CpuProfiler overrides... - const TimeRegionMap& GetTimeRegionMap() const final override; - bool BeginContinuousCapture() final override; - bool EndContinuousCapture(AZStd::ring_buffer& flushTarget) final override; - bool IsContinuousCaptureInProgress() const final override; - void SetProfilerEnabled(bool enabled) final override; - bool IsProfilerEnabled() const final override; - - private: - static constexpr AZStd::size_t MaxFramesToSave = 2 * 60 * 120; // 2 minutes of 120fps - static constexpr AZStd::size_t MaxRegionStringPoolSize = 16384; // Max amount of unique strings to save in the pool before throwing warnings. - - // Lazily create and register the local thread data - void RegisterThreadStorage(); - - // ThreadId -> ThreadTimeRegionMap - // On the start of each frame, this map will be updated with the last frame's profiling data. - TimeRegionMap m_timeRegionMap; - - // Set of registered threads when created - AZStd::vector, AZ::OSStdAllocator> m_registeredThreads; - AZStd::mutex m_threadRegisterMutex; - - // Thread local storage, gets lazily allocated when a thread is created - static thread_local CpuTimingLocalStorage* ms_threadLocalStorage; - - // Enable/Disables the threads from profiling - AZStd::atomic_bool m_enabled = false; - - // This lock will only be contested when the CpuProfiler's Shutdown() method has been called - AZStd::shared_mutex m_shutdownMutex; - - bool m_initialized = false; - - AZStd::mutex m_continuousCaptureEndingMutex; - - AZStd::atomic_bool m_continuousCaptureInProgress = false; - - // Stores multiple frames of profiling data, size is controlled by MaxFramesToSave. Flushed when EndContinuousCapture is called. - // Ring buffer so that we can have fast append of new data + removal of old profiling data with good cache locality. - AZStd::ring_buffer m_continuousCaptureData; - }; - - // Intermediate class to serialize Cpu TimedRegion data. - class CpuProfilingStatisticsSerializer - { - public: - class CpuProfilingStatisticsSerializerEntry - { - public: - AZ_TYPE_INFO(CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry, "{26B78F65-EB96-46E2-BE7E-A1233880B225}"); - static void Reflect(AZ::ReflectContext* context); - - CpuProfilingStatisticsSerializerEntry() = default; - CpuProfilingStatisticsSerializerEntry(const CachedTimeRegion& cachedTimeRegion, AZStd::thread_id threadId); - - AZ::Name m_groupName; - AZ::Name m_regionName; - uint16_t m_stackDepth; - AZStd::sys_time_t m_startTick; - AZStd::sys_time_t m_endTick; - size_t m_threadId; - }; - - AZ_TYPE_INFO(CpuProfilingStatisticsSerializer, "{D5B02946-0D27-474F-9A44-364C2706DD41}"); - static void Reflect(AZ::ReflectContext* context); - - CpuProfilingStatisticsSerializer() = default; - CpuProfilingStatisticsSerializer(const AZStd::ring_buffer& continuousData); - - AZStd::vector m_cpuProfilingStatisticsSerializerEntries; - }; -}; // namespace Profiler diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index c4da3ab45a..c2cf705015 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -10,7 +10,7 @@ #include -#include +#include #include #include @@ -176,7 +176,7 @@ namespace Profiler // Toggle if the bool isn't the same as the cached value if (cachedShowCpuProfiler != keepDrawing) { - CpuProfiler::Get()->SetProfilerEnabled(keepDrawing); + AZ::Debug::ProfilerSystemInterface::Get()->SetActive(keepDrawing); } } @@ -193,11 +193,11 @@ namespace Profiler } ImGui::SameLine(); - m_paused = !CpuProfiler::Get()->IsProfilerEnabled(); + m_paused = !AZ::Debug::ProfilerSystemInterface::Get()->IsActive(); if (ImGui::Button(m_paused ? "Resume" : "Pause")) { m_paused = !m_paused; - CpuProfiler::Get()->SetProfilerEnabled(!m_paused); + AZ::Debug::ProfilerSystemInterface::Get()->SetActive(!m_paused); } ImGui::SameLine(); @@ -207,7 +207,7 @@ namespace Profiler } ImGui::SameLine(); - bool isInProgress = CpuProfiler::Get()->IsContinuousCaptureInProgress(); + bool isInProgress = AZ::Debug::ProfilerSystemInterface::Get()->IsCaptureInProgress(); if (ImGui::Button(isInProgress ? "End" : "Begin")) { auto profilerSystem = AZ::Debug::ProfilerSystemInterface::Get(); @@ -445,7 +445,7 @@ namespace Profiler m_savedData.clear(); m_paused = true; - CpuProfiler::Get()->SetProfilerEnabled(false); + AZ::Debug::ProfilerSystemInterface::Get()->SetActive(false); m_frameEndTicks.clear(); m_tableData.clear(); @@ -708,7 +708,10 @@ namespace Profiler // compared to if we needed to transform the visualizer's data into the statistical format every frame. // Get the latest TimeRegionMap - const CpuProfiler::TimeRegionMap& timeRegionMap = CpuProfiler::Get()->GetTimeRegionMap(); + auto profilerInterface = AZ::Interface::Get(); + auto cpuProfiler = azrtti_cast(profilerInterface); + + const TimeRegionMap& timeRegionMap = cpuProfiler->GetTimeRegionMap(); AZ::s64 viewportStartTick = AZStd::numeric_limits::max(); AZ::s64 viewportEndTick = AZStd::numeric_limits::lowest(); diff --git a/Gems/Profiler/Code/Source/ProfilerImGuiSystemComponent.cpp b/Gems/Profiler/Code/Source/ProfilerImGuiSystemComponent.cpp index 62d27a1806..0fb37c7634 100644 --- a/Gems/Profiler/Code/Source/ProfilerImGuiSystemComponent.cpp +++ b/Gems/Profiler/Code/Source/ProfilerImGuiSystemComponent.cpp @@ -8,6 +8,7 @@ #include +#include #include #include #include @@ -107,7 +108,7 @@ namespace Profiler { if (ImGui::MenuItem("CPU", "", &m_showCpuProfiler)) { - CpuProfiler::Get()->SetProfilerEnabled(m_showCpuProfiler); + AZ::Debug::ProfilerSystemInterface::Get()->SetActive(m_showCpuProfiler); } ImGui::EndMenu(); } diff --git a/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp b/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp index 24da9e050e..975109935d 100644 --- a/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp +++ b/Gems/Profiler/Code/Source/ProfilerSystemComponent.cpp @@ -51,7 +51,7 @@ namespace Profiler int m_framesLeft{ 0 }; }; - bool SerializeCpuProfilingData(const AZStd::ring_buffer& data, AZStd::string outputFilePath, bool wasEnabled) + bool SerializeCpuProfilingData(const AZStd::ring_buffer& data, AZStd::string outputFilePath, bool wasEnabled) { AZ_TracePrintf("ProfilerSystemComponent", "Beginning serialization of %zu frames of profiling data\n", data.size()); AZ::JsonSerializerSettings serializationSettings; @@ -78,7 +78,7 @@ namespace Profiler // Disable the profiler again if (!wasEnabled) { - CpuProfiler::Get()->SetProfilerEnabled(false); + AZ::Debug::ProfilerSystemInterface::Get()->SetActive(false); } // Notify listeners that the profiler capture has finished. @@ -188,7 +188,7 @@ namespace Profiler [this, outputFilePath, wasEnabled]() { // Blocking call for a single frame of data, avoid thread overhead - AZStd::ring_buffer singleFrameData(1); + AZStd::ring_buffer singleFrameData(1); singleFrameData.push_back(m_cpuProfiler.GetTimeRegionMap()); SerializeCpuProfilingData(singleFrameData, outputFilePath, wasEnabled); m_cpuCaptureInProgress.store(false); @@ -216,7 +216,7 @@ namespace Profiler return false; } - AZStd::ring_buffer captureResult; + AZStd::ring_buffer captureResult; const bool captureEnded = m_cpuProfiler.EndContinuousCapture(captureResult); if (!captureEnded) { @@ -245,4 +245,9 @@ namespace Profiler return true; } + + bool ProfilerSystemComponent::IsCaptureInProgress() const + { + return m_cpuProfiler.IsContinuousCaptureInProgress(); + } } // namespace Profiler diff --git a/Gems/Profiler/Code/Source/ProfilerSystemComponent.h b/Gems/Profiler/Code/Source/ProfilerSystemComponent.h index a1c8c47479..b435dec013 100644 --- a/Gems/Profiler/Code/Source/ProfilerSystemComponent.h +++ b/Gems/Profiler/Code/Source/ProfilerSystemComponent.h @@ -8,7 +8,7 @@ #pragma once -#include +#include #include #include @@ -44,6 +44,7 @@ namespace Profiler bool CaptureFrame(const AZStd::string& outputFilePath) override; bool StartCapture(AZStd::string outputFilePath) override; bool EndCapture() override; + bool IsCaptureInProgress() const override; AZStd::thread m_cpuDataSerializationThread; @@ -51,7 +52,7 @@ namespace Profiler AZStd::atomic_bool m_cpuCaptureInProgress{ false }; - CpuProfilerImpl m_cpuProfiler; + CpuProfiler m_cpuProfiler; AZStd::string m_captureFile; }; diff --git a/Gems/Profiler/Code/profiler_files.cmake b/Gems/Profiler/Code/profiler_files.cmake index ebbca1cd78..c5aaac0d24 100644 --- a/Gems/Profiler/Code/profiler_files.cmake +++ b/Gems/Profiler/Code/profiler_files.cmake @@ -9,8 +9,7 @@ set(FILES Include/Profiler/ProfilerImGuiBus.h Source/CpuProfiler.h - Source/CpuProfilerImpl.cpp - Source/CpuProfilerImpl.h + Source/CpuProfiler.cpp Source/ProfilerSystemComponent.cpp Source/ProfilerSystemComponent.h )