From ead3a4b9aef795dd291382ef6182f6ce73cb7f7a Mon Sep 17 00:00:00 2001 From: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> Date: Mon, 11 Oct 2021 18:33:52 -0700 Subject: [PATCH] [atom_cpu_profiler_gem_promotion] included moved files in compilation and fixed compiler errors Signed-off-by: AMZN-ScottR <24445312+AMZN-ScottR@users.noreply.github.com> --- Gems/Profiler/Code/CMakeLists.txt | 3 + Gems/Profiler/Code/Source/CpuProfilerImpl.cpp | 35 ++-- Gems/Profiler/Code/Source/CpuProfilerImpl.h | 22 +-- .../Profiler/Code/Source/ImGuiCpuProfiler.cpp | 182 +++++++++--------- Gems/Profiler/Code/Source/ImGuiCpuProfiler.h | 40 ++-- Gems/Profiler/Code/profiler_files.cmake | 5 + 6 files changed, 146 insertions(+), 141 deletions(-) diff --git a/Gems/Profiler/Code/CMakeLists.txt b/Gems/Profiler/Code/CMakeLists.txt index 899cdee3e7..15b5fca358 100644 --- a/Gems/Profiler/Code/CMakeLists.txt +++ b/Gems/Profiler/Code/CMakeLists.txt @@ -21,6 +21,7 @@ ly_add_target( PUBLIC AZ::AzCore AZ::AzFramework + Gem::ImGui.Static ) # Here add Profiler target, it depends on the Profiler.Static @@ -37,6 +38,8 @@ ly_add_target( BUILD_DEPENDENCIES PRIVATE Gem::Profiler.Static + RUNTIME_DEPENDENCIES + Gem::ImGui ) # By default, we will specify that the above target Profiler would be used by diff --git a/Gems/Profiler/Code/Source/CpuProfilerImpl.cpp b/Gems/Profiler/Code/Source/CpuProfilerImpl.cpp index 15713e647a..253f8576a6 100644 --- a/Gems/Profiler/Code/Source/CpuProfilerImpl.cpp +++ b/Gems/Profiler/Code/Source/CpuProfilerImpl.cpp @@ -6,14 +6,13 @@ * */ -#include - -#include -#include +#include #include +#include +#include #include -#include +#include namespace Profiler { @@ -23,7 +22,7 @@ namespace Profiler CpuProfiler* CpuProfiler::Get() { - return Interface::Get(); + return AZ::Interface::Get(); } // --- CachedTimeRegion --- @@ -67,10 +66,10 @@ namespace Profiler void CpuProfilerImpl::Init() { - Interface::Register(this); - Interface::Register(this); + AZ::Interface::Register(this); + AZ::Interface::Register(this); m_initialized = true; - SystemTickBus::Handler::BusConnect(); + AZ::SystemTickBus::Handler::BusConnect(); m_continuousCaptureData.set_capacity(10); if (auto statsProfiler = AZ::Interface::Get(); statsProfiler) @@ -86,8 +85,8 @@ namespace Profiler return; } // When this call is made, no more thread profiling calls can be performed anymore - Interface::Unregister(this); - Interface::Unregister(this); + AZ::Interface::Unregister(this); + AZ::Interface::Unregister(this); // Wait for the remaining threads that might still be processing its profiling calls AZStd::unique_lock shutdownLock(m_shutdownMutex); @@ -100,7 +99,7 @@ namespace Profiler m_initialized = false; m_continuousCaptureInProgress.store(false); m_continuousCaptureData.clear(); - SystemTickBus::Handler::BusDisconnect(); + AZ::SystemTickBus::Handler::BusDisconnect(); } void CpuProfilerImpl::BeginRegion(const AZ::Debug::Budget* budget, const char* eventName) @@ -247,7 +246,7 @@ namespace Profiler } // Clear all TLS that flagged themselves to be deleted, meaning that the thread is already terminated - AZStd::remove_if(m_registeredThreads.begin(), m_registeredThreads.end(), [](const RHI::Ptr& thread) + AZStd::remove_if(m_registeredThreads.begin(), m_registeredThreads.end(), [](const AZStd::intrusive_ptr& thread) { return thread->m_deleteFlag.load(); }); @@ -383,7 +382,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) @@ -407,8 +406,7 @@ namespace Profiler { serializeContext->Class() ->Version(1) - ->Field("cpuProfilingStatisticsSerializerEntries", &CpuProfilingStatisticsSerializer::m_cpuProfilingStatisticsSerializerEntries) - ; + ->Field("cpuProfilingStatisticsSerializerEntries", &CpuProfilingStatisticsSerializer::m_cpuProfilingStatisticsSerializerEntries); } CpuProfilingStatisticsSerializerEntry::Reflect(context); @@ -417,7 +415,7 @@ namespace Profiler // --- CpuProfilingStatisticsSerializerEntry --- CpuProfilingStatisticsSerializer::CpuProfilingStatisticsSerializerEntry::CpuProfilingStatisticsSerializerEntry( - const RHI::CachedTimeRegion& cachedTimeRegion, AZStd::thread_id threadId) + const CachedTimeRegion& cachedTimeRegion, AZStd::thread_id threadId) { m_groupName = cachedTimeRegion.m_groupRegionName.m_groupName; m_regionName = cachedTimeRegion.m_groupRegionName.m_regionName; @@ -438,8 +436,7 @@ namespace Profiler ->Field("stackDepth", &CpuProfilingStatisticsSerializerEntry::m_stackDepth) ->Field("startTick", &CpuProfilingStatisticsSerializerEntry::m_startTick) ->Field("endTick", &CpuProfilingStatisticsSerializerEntry::m_endTick) - ->Field("threadId", &CpuProfilingStatisticsSerializerEntry::m_threadId) - ; + ->Field("threadId", &CpuProfilingStatisticsSerializerEntry::m_threadId); } } } // namespace Profiler diff --git a/Gems/Profiler/Code/Source/CpuProfilerImpl.h b/Gems/Profiler/Code/Source/CpuProfilerImpl.h index b36494952f..1046b72cff 100644 --- a/Gems/Profiler/Code/Source/CpuProfilerImpl.h +++ b/Gems/Profiler/Code/Source/CpuProfilerImpl.h @@ -7,8 +7,7 @@ */ #pragma once -#include -#include +#include #include #include @@ -19,14 +18,13 @@ #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 + class CpuTimingLocalStorage + : public AZStd::intrusive_refcount { friend class CpuProfilerImpl; @@ -85,7 +83,7 @@ namespace Profiler class CpuProfilerImpl final : public AZ::Debug::Profiler , public CpuProfiler - , public SystemTickBus::Handler + , public AZ::SystemTickBus::Handler { friend class CpuTimingLocalStorage; @@ -101,7 +99,7 @@ namespace Profiler //! Unregisters the CpuProfilerImpl instance from the interface void Shutdown(); - // SystemTickBus::Handler overrides + // 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; @@ -130,7 +128,7 @@ namespace Profiler TimeRegionMap m_timeRegionMap; // Set of registered threads when created - AZStd::vector, AZ::OSStdAllocator> m_registeredThreads; + AZStd::vector, AZ::OSStdAllocator> m_registeredThreads; AZStd::mutex m_threadRegisterMutex; // Thread local storage, gets lazily allocated when a thread is created @@ -164,10 +162,10 @@ namespace Profiler static void Reflect(AZ::ReflectContext* context); CpuProfilingStatisticsSerializerEntry() = default; - CpuProfilingStatisticsSerializerEntry(const RHI::CachedTimeRegion& cachedTimeRegion, AZStd::thread_id threadId); + CpuProfilingStatisticsSerializerEntry(const CachedTimeRegion& cachedTimeRegion, AZStd::thread_id threadId); - Name m_groupName; - Name m_regionName; + AZ::Name m_groupName; + AZ::Name m_regionName; uint16_t m_stackDepth; AZStd::sys_time_t m_startTick; AZStd::sys_time_t m_endTick; @@ -178,7 +176,7 @@ namespace Profiler static void Reflect(AZ::ReflectContext* context); CpuProfilingStatisticsSerializer() = default; - CpuProfilingStatisticsSerializer(const AZStd::ring_buffer& continuousData); + CpuProfilingStatisticsSerializer(const AZStd::ring_buffer& continuousData); AZStd::vector m_cpuProfilingStatisticsSerializerEntries; }; diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index c9471157a0..f048691a7d 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -6,30 +6,28 @@ * */ -#include -#include -#include -#include -#include +#if defined(IMGUI_ENABLED) + +#include + +#include -#include #include #include -#include +#include #include #include -#include -#include +#include #include #include +#include #include - namespace Profiler { namespace CpuProfilerImGuiHelper { - inline float TicksToMs(double ticks) + float TicksToMs(double ticks) { // Note: converting to microseconds integer before converting to milliseconds float const AZStd::sys_time_t ticksPerSecond = AZStd::GetTimeTicksPerSecond(); @@ -37,27 +35,28 @@ namespace Profiler return static_cast((ticks * 1000) / (ticksPerSecond / 1000)) / 1000.0f; } - inline float TicksToMs(AZStd::sys_time_t ticks) + float TicksToMs(AZStd::sys_time_t ticks) { return TicksToMs(static_cast(ticks)); } - using DeserializedCpuData = AZStd::vector; - inline Outcome LoadSavedCpuProfilingStatistics(const AZStd::string& capturePath) - { - auto* base = IO::FileIOBase::GetInstance(); + using DeserializedCpuData = AZStd::vector; - char resolvedPath[IO::MaxPathLength]; - if (!base->ResolvePath(capturePath.c_str(), resolvedPath, IO::MaxPathLength)) + AZ::Outcome LoadSavedCpuProfilingStatistics(const AZStd::string& capturePath) + { + auto* base = AZ::IO::FileIOBase::GetInstance(); + + char resolvedPath[AZ::IO::MaxPathLength]; + if (!base->ResolvePath(capturePath.c_str(), resolvedPath, AZ::IO::MaxPathLength)) { - return Failure(AZStd::string::format("Could not resolve the path to file %s, is the path correct?", resolvedPath)); + return AZ::Failure(AZStd::string::format("Could not resolve the path to file %s, is the path correct?", resolvedPath)); } - u64 captureSizeBytes; - const IO::Result fileSizeResult = base->Size(resolvedPath, captureSizeBytes); + AZ::u64 captureSizeBytes; + const AZ::IO::Result fileSizeResult = base->Size(resolvedPath, captureSizeBytes); if (!fileSizeResult) { - return Failure(AZStd::string::format("Could not read the size of file %s, is the path correct?", resolvedPath)); + return AZ::Failure(AZStd::string::format("Could not read the size of file %s, is the path correct?", resolvedPath)); } // NOTE: this uses raw file pointers over the abstractions and utility functions provided by AZ::JsonSerializationUtils because @@ -66,7 +65,7 @@ namespace Profiler azfopen(&fp, resolvedPath, "rb"); if (!fp) { - return Failure(AZStd::string::format("Could not fopen file %s, is the path correct?\n", resolvedPath)); + return AZ::Failure(AZStd::string::format("Could not fopen file %s, is the path correct?\n", resolvedPath)); } constexpr AZStd::size_t MaxBufSize = 65536; @@ -83,37 +82,35 @@ namespace Profiler if (document.HasParseError()) { const auto pe = document.GetParseError(); - return Failure(AZStd::string::format( + return AZ::Failure(AZStd::string::format( "Rapidjson could not parse the document with ParseErrorCode %u. See 3rdParty/rapidjson/error.h for definitions.\n", pe)); } if (!document.IsObject() || !document.HasMember("ClassData")) { - return Failure(AZStd::string::format( + return AZ::Failure(AZStd::string::format( "Error in loading saved capture: top-level object does not have a ClassData field. Did the serialization format change recently?\n")); } AZ_TracePrintf("JsonUtils", "Successfully loaded JSON into memory.\n"); const auto& root = document["ClassData"]; - RHI::CpuProfilingStatisticsSerializer serializer; - const JsonSerializationResult::ResultCode deserializationResult = JsonSerialization::Load(serializer, root); - if (deserializationResult.GetProcessing() == JsonSerializationResult::Processing::Halted + CpuProfilingStatisticsSerializer serializer; + const AZ::JsonSerializationResult::ResultCode deserializationResult = AZ::JsonSerialization::Load(serializer, root); + if (deserializationResult.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted || serializer.m_cpuProfilingStatisticsSerializerEntries.empty()) { - return Failure(AZStd::string::format("Error in deserializing document: %s\n", deserializationResult.ToString(capturePath.c_str()).c_str())); + return AZ::Failure(AZStd::string::format("Error in deserializing document: %s\n", deserializationResult.ToString(capturePath.c_str()).c_str())); } AZ_TracePrintf("JsonUtils", "Successfully loaded CPU profiling data with %zu profiling entries.\n", serializer.m_cpuProfilingStatisticsSerializerEntries.size()); - return Success(AZStd::move(serializer.m_cpuProfilingStatisticsSerializerEntries)); + return AZ::Success(AZStd::move(serializer.m_cpuProfilingStatisticsSerializerEntries)); } } // namespace CpuProfilerImGuiHelper - - - inline void ImGuiCpuProfiler::Draw(bool& keepDrawing) + void ImGuiCpuProfiler::Draw(bool& keepDrawing) { // Cache the value to detect if it was changed by ImGui(user pressed 'x') const bool cachedShowCpuProfiler = keepDrawing; @@ -132,9 +129,9 @@ namespace Profiler CullFrameData(); // Only listen to system ticks when the profiler is active - if (!SystemTickBus::Handler::BusIsConnected()) + if (!AZ::SystemTickBus::Handler::BusIsConnected()) { - SystemTickBus::Handler::BusConnect(); + AZ::SystemTickBus::Handler::BusConnect(); } } @@ -159,27 +156,25 @@ namespace Profiler AZStd::sys_time_t timeNow = AZStd::GetTimeNowSecond(); AZStd::string timeString; AZStd::to_string(timeString, timeNow); - u64 currentTick = AZ::RPI::RPISystemInterface::Get()->GetCurrentTick(); const AZStd::string frameDataFilePath = AZStd::string::format( - "@user@/CpuProfiler/%s_%llu.json", - timeString.c_str(), - currentTick); + "@user@/CpuProfiler/%s.json", + timeString.c_str()); char resolvedPath[AZ::IO::MaxPathLength]; AZ::IO::FileIOBase::GetInstance()->ResolvePath(frameDataFilePath.c_str(), resolvedPath, AZ::IO::MaxPathLength); m_lastCapturedFilePath = resolvedPath; - AZ::Render::ProfilingCaptureRequestBus::Broadcast( - &AZ::Render::ProfilingCaptureRequestBus::Events::CaptureCpuProfilingStatistics, frameDataFilePath); + //AZ::Render::ProfilingCaptureRequestBus::Broadcast( + // &AZ::Render::ProfilingCaptureRequestBus::Events::CaptureCpuProfilingStatistics, frameDataFilePath); } m_captureToFile = false; // Toggle if the bool isn't the same as the cached value if (cachedShowCpuProfiler != keepDrawing) { - AZ::RHI::CpuProfiler::Get()->SetProfilerEnabled(keepDrawing); + CpuProfiler::Get()->SetProfilerEnabled(keepDrawing); } } - inline void ImGuiCpuProfiler::DrawCommonHeader() + void ImGuiCpuProfiler::DrawCommonHeader() { if (!m_lastCapturedFilePath.empty()) { @@ -192,11 +187,11 @@ namespace Profiler } ImGui::SameLine(); - m_paused = !AZ::RHI::CpuProfiler::Get()->IsProfilerEnabled(); + m_paused = !CpuProfiler::Get()->IsProfilerEnabled(); if (ImGui::Button(m_paused ? "Resume" : "Pause")) { m_paused = !m_paused; - AZ::RHI::CpuProfiler::Get()->SetProfilerEnabled(!m_paused); + CpuProfiler::Get()->SetProfilerEnabled(!m_paused); } ImGui::SameLine(); @@ -206,7 +201,7 @@ namespace Profiler } ImGui::SameLine(); - bool isInProgress = RHI::CpuProfiler::Get()->IsContinuousCaptureInProgress(); + bool isInProgress = CpuProfiler::Get()->IsContinuousCaptureInProgress(); if (ImGui::Button(isInProgress ? "End" : "Begin")) { if (isInProgress) @@ -214,23 +209,21 @@ namespace Profiler AZStd::sys_time_t timeNow = AZStd::GetTimeNowSecond(); AZStd::string timeString; AZStd::to_string(timeString, timeNow); - u64 currentTick = AZ::RPI::RPISystemInterface::Get()->GetCurrentTick(); const AZStd::string frameDataFilePath = AZStd::string::format( - "@user@/CpuProfiler/%s_%llu.json", - timeString.c_str(), - currentTick); + "@user@/CpuProfiler/%s.json", + timeString.c_str()); char resolvedPath[AZ::IO::MaxPathLength]; AZ::IO::FileIOBase::GetInstance()->ResolvePath(frameDataFilePath.c_str(), resolvedPath, AZ::IO::MaxPathLength); m_lastCapturedFilePath = resolvedPath; - AZ::Render::ProfilingCaptureRequestBus::Broadcast( - &AZ::Render::ProfilingCaptureRequestBus::Events::EndContinuousCpuProfilingCapture, frameDataFilePath); + //AZ::Render::ProfilingCaptureRequestBus::Broadcast( + // &AZ::Render::ProfilingCaptureRequestBus::Events::EndContinuousCpuProfilingCapture, frameDataFilePath); m_paused = true; } else { - AZ::Render::ProfilingCaptureRequestBus::Broadcast( - &AZ::Render::ProfilingCaptureRequestBus::Events::BeginContinuousCpuProfilingCapture); + //AZ::Render::ProfilingCaptureRequestBus::Broadcast( + // &AZ::Render::ProfilingCaptureRequestBus::Events::BeginContinuousCpuProfilingCapture); } } @@ -248,21 +241,21 @@ namespace Profiler defaultSavedCapturePath.c_str(), "*.json", [&paths = m_cachedCapturePaths](const char* path) -> bool { - auto foundPath = IO::Path(path); + auto foundPath = AZ::IO::Path(path); paths.push_back(foundPath); return true; }); // Sort by decreasing modification time (most recent at the top) AZStd::sort(m_cachedCapturePaths.begin(), m_cachedCapturePaths.end(), - [&base](const IO::Path& lhs, const IO::Path& rhs) + [&base](const AZ::IO::Path& lhs, const AZ::IO::Path& rhs) { return base->ModificationTime(lhs.c_str()) > base->ModificationTime(rhs.c_str()); }); } } - inline void ImGuiCpuProfiler::DrawTable() + void ImGuiCpuProfiler::DrawTable() { const auto flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Sortable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable; @@ -326,7 +319,7 @@ namespace Profiler ImGui::EndTable(); } - inline void ImGuiCpuProfiler::SortTable(ImGuiTableSortSpecs* sortSpecs) + void ImGuiCpuProfiler::SortTable(ImGuiTableSortSpecs* sortSpecs) { const bool ascending = sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending; const ImS16 columnToSort = sortSpecs->Specs->ColumnIndex; @@ -355,7 +348,7 @@ namespace Profiler sortSpecs->SpecsDirty = false; } - inline void ImGuiCpuProfiler::DrawStatisticsView() + void ImGuiCpuProfiler::DrawStatisticsView() { DrawCommonHeader(); @@ -400,7 +393,7 @@ namespace Profiler } } - inline void ImGuiCpuProfiler::DrawFilePicker() + void ImGuiCpuProfiler::DrawFilePicker() { ImGui::SetNextWindowSize({ 500, 200 }, ImGuiCond_Once); if (ImGui::Begin("File Picker", &m_showFilePicker)) @@ -412,7 +405,7 @@ namespace Profiler auto getter = [](void* vectorPointer, int idx, const char** out_text) -> bool { - const auto& pathVec = *static_cast*>(vectorPointer); + const auto& pathVec = *static_cast*>(vectorPointer); if (idx < 0 || idx >= pathVec.size()) { return false; @@ -427,9 +420,9 @@ namespace Profiler ImGui::End(); } - inline void ImGuiCpuProfiler::LoadFile() + void ImGuiCpuProfiler::LoadFile() { - const IO::Path& pathToLoad = m_cachedCapturePaths[m_currentFileIndex]; + const AZ::IO::Path& pathToLoad = m_cachedCapturePaths[m_currentFileIndex]; auto loadResult = CpuProfilerImGuiHelper::LoadSavedCpuProfilingStatistics(pathToLoad.String()); if (!loadResult.IsSuccess()) { @@ -437,13 +430,14 @@ namespace Profiler return; } - AZStd::vector deserializedData = loadResult.TakeValue(); + AZStd::vector deserializedData = loadResult.TakeValue(); // Clear visualizer and statistics view state m_savedRegionCount = deserializedData.size(); m_savedData.clear(); m_paused = true; - AZ::RHI::CpuProfiler::Get()->SetProfilerEnabled(false); + + CpuProfiler::Get()->SetProfilerEnabled(false); m_frameEndTicks.clear(); m_tableData.clear(); @@ -456,11 +450,11 @@ namespace Profiler const auto [groupRegionNameItr, wasGroupRegionNameInserted] = m_deserializedGroupRegionNamePool.emplace(groupNameItr->c_str(), regionNameItr->c_str()); - const RHI::CachedTimeRegion newRegion(*groupRegionNameItr, entry.m_stackDepth, entry.m_startTick, entry.m_endTick); + const CachedTimeRegion newRegion(*groupRegionNameItr, entry.m_stackDepth, entry.m_startTick, entry.m_endTick); m_savedData[entry.m_threadId].push_back(newRegion); // Since we don't serialize the frame boundaries, we need to use the RPI's OnSystemTick event as a heuristic. - const static Name frameBoundaryName = Name("RPISystem: OnSystemTick"); + const static AZ::Name frameBoundaryName = AZ::Name("RPISystem: OnSystemTick"); if (entry.m_regionName == frameBoundaryName) { m_frameEndTicks.push_back(entry.m_endTick); @@ -492,7 +486,7 @@ namespace Profiler } // -- CPU Visualizer -- - inline void ImGuiCpuProfiler::DrawVisualizer() + void ImGuiCpuProfiler::DrawVisualizer() { DrawCommonHeader(); @@ -556,7 +550,7 @@ namespace Profiler } // Main draw loop - u64 baseRow = 0; + AZ::u64 baseRow = 0; for (const auto& [currentThreadId, singleThreadData] : m_savedData) { // Find the first TimeRegion that we should draw @@ -573,7 +567,7 @@ namespace Profiler } // Draw all of the blocks for a given thread/row - u64 maxDepth = 0; + AZ::u64 maxDepth = 0; while (regionItr != singleThreadData.end()) { const TimeRegion& region = *regionItr; @@ -583,8 +577,8 @@ namespace Profiler { break; } - u64 targetRow = region.m_stackDepth + baseRow; - maxDepth = AZStd::max(aznumeric_cast(region.m_stackDepth), maxDepth); + AZ::u64 targetRow = region.m_stackDepth + baseRow; + maxDepth = AZStd::max(aznumeric_cast(region.m_stackDepth), maxDepth); DrawBlock(region, targetRow); @@ -649,7 +643,7 @@ namespace Profiler ImGui::EndChild(); } - inline void ImGuiCpuProfiler::CacheCpuTimingStatistics() + void ImGuiCpuProfiler::CacheCpuTimingStatistics() { using namespace AZ::Statistics; @@ -675,7 +669,7 @@ namespace Profiler } } - inline void ImGuiCpuProfiler::CollectFrameData() + void ImGuiCpuProfiler::CollectFrameData() { // We maintain separate datastores for the visualizer and the statistical view because they require different // data formats - one grouped by thread ID versus the other organized by group + region. Since the statistical @@ -683,10 +677,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 RHI::CpuProfiler::TimeRegionMap& timeRegionMap = RHI::CpuProfiler::Get()->GetTimeRegionMap(); + const CpuProfiler::TimeRegionMap& timeRegionMap = CpuProfiler::Get()->GetTimeRegionMap(); - m_viewportStartTick = AZStd::numeric_limits::max(); - m_viewportEndTick = AZStd::numeric_limits::lowest(); + m_viewportStartTick = AZStd::numeric_limits::max(); + m_viewportEndTick = AZStd::numeric_limits::lowest(); // Iterate through the entire TimeRegionMap and copy the data since it will get deleted on the next frame for (const auto& [threadId, singleThreadRegionMap] : timeRegionMap) @@ -743,7 +737,7 @@ namespace Profiler } } - inline void ImGuiCpuProfiler::CullFrameData() + void ImGuiCpuProfiler::CullFrameData() { const AZStd::sys_time_t deleteBeforeTick = AZStd::GetTimeNowTicks() - m_frameToFrameTime * m_framesToCollect; @@ -783,7 +777,7 @@ namespace Profiler }); } - inline void ImGuiCpuProfiler::DrawBlock(const TimeRegion& block, u64 targetRow) + void ImGuiCpuProfiler::DrawBlock(const TimeRegion& block, AZ::u64 targetRow) { // Don't draw anything if the user is searching for regions and this block doesn't pass the filter if (!m_visualizerHighlightFilter.PassFilter(block.m_groupRegionName.m_regionName)) @@ -864,7 +858,7 @@ namespace Profiler } } - inline ImU32 ImGuiCpuProfiler::GetBlockColor(const TimeRegion& block) + ImU32 ImGuiCpuProfiler::GetBlockColor(const TimeRegion& block) { // Use the GroupRegionName pointer a key into the cache, equal regions will have equal pointers const GroupRegionName& key = block.m_groupRegionName; @@ -874,7 +868,7 @@ namespace Profiler } // Cache miss, generate a new random color - AZ::SimpleLcgRandom rand(aznumeric_cast(AZStd::GetTimeNowTicks())); + AZ::SimpleLcgRandom rand(aznumeric_cast(AZStd::GetTimeNowTicks())); const float r = AZStd::clamp(rand.GetRandomFloat(), .1f, .9f); const float g = AZStd::clamp(rand.GetRandomFloat(), .1f, .9f); const float b = AZStd::clamp(rand.GetRandomFloat(), .1f, .9f); @@ -883,7 +877,7 @@ namespace Profiler return ImGui::GetColorU32(randomColor); } - inline void ImGuiCpuProfiler::DrawThreadSeparator(u64 baseRow, u64 maxDepth) + void ImGuiCpuProfiler::DrawThreadSeparator(AZ::u64 baseRow, AZ::u64 maxDepth) { const ImU32 red = ImGui::GetColorU32({ 1, 0, 0, 1 }); @@ -895,7 +889,7 @@ namespace Profiler ImGui::GetWindowDrawList()->AddLine({ wx, boundaryY }, { wx + windowWidth, boundaryY }, red, 1.0f); } - inline void ImGuiCpuProfiler::DrawThreadLabel(u64 baseRow, size_t threadId) + void ImGuiCpuProfiler::DrawThreadLabel(AZ::u64 baseRow, size_t threadId) { auto [wx, wy] = ImGui::GetWindowPos(); wy -= ImGui::GetScrollY(); @@ -904,7 +898,7 @@ namespace Profiler ImGui::GetWindowDrawList()->AddText({ wx + 10, wy + baseRow * RowHeight}, IM_COL32_WHITE, threadIdText.c_str()); } - inline void ImGuiCpuProfiler::DrawFrameBoundaries() + void ImGuiCpuProfiler::DrawFrameBoundaries() { ImDrawList* drawList = ImGui::GetWindowDrawList(); @@ -923,7 +917,7 @@ namespace Profiler } } - inline void ImGuiCpuProfiler::DrawRuler() + void ImGuiCpuProfiler::DrawRuler() { // Use a pair of iterators to go through all saved frame boundaries and draw ruler lines auto lastFrameBoundaryItr = AZStd::lower_bound(m_frameEndTicks.begin(), m_frameEndTicks.end(), m_viewportStartTick); @@ -1001,7 +995,7 @@ namespace Profiler } } - inline void ImGuiCpuProfiler::DrawFrameTimeHistogram() + void ImGuiCpuProfiler::DrawFrameTimeHistogram() { ImDrawList* drawList = ImGui::GetWindowDrawList(); const auto [wx, wy] = ImGui::GetWindowPos(); @@ -1083,12 +1077,12 @@ namespace Profiler } } - inline AZStd::sys_time_t ImGuiCpuProfiler::GetViewportTickWidth() const + AZStd::sys_time_t ImGuiCpuProfiler::GetViewportTickWidth() const { return m_viewportEndTick - m_viewportStartTick; } - inline float ImGuiCpuProfiler::ConvertTickToPixelSpace(AZStd::sys_time_t tick, AZStd::sys_time_t leftBound, AZStd::sys_time_t rightBound) const + float ImGuiCpuProfiler::ConvertTickToPixelSpace(AZStd::sys_time_t tick, AZStd::sys_time_t leftBound, AZStd::sys_time_t rightBound) const { const float wx = ImGui::GetWindowPos().x; const float tickSpaceShifted = aznumeric_cast(tick - leftBound); // This will be close to zero, so FP inaccuracy should not be too bad @@ -1098,11 +1092,11 @@ namespace Profiler } // System tick bus overrides - inline void ImGuiCpuProfiler::OnSystemTick() + void ImGuiCpuProfiler::OnSystemTick() { if (m_paused) { - SystemTickBus::Handler::BusDisconnect(); + AZ::SystemTickBus::Handler::BusDisconnect(); } else { @@ -1120,7 +1114,7 @@ namespace Profiler // ---- TableRow impl ---- - inline void TableRow::RecordRegion(const AZ::RHI::CachedTimeRegion& region, size_t threadId) + void TableRow::RecordRegion(const CachedTimeRegion& region, size_t threadId) { const AZStd::sys_time_t deltaTime = region.m_endTick - region.m_startTick; @@ -1136,7 +1130,7 @@ namespace Profiler ++m_invocationsTotal; } - inline void TableRow::ResetPerFrameStatistics() + void TableRow::ResetPerFrameStatistics() { m_invocationsLastFrame = 0; m_executingThreads.clear(); @@ -1144,7 +1138,7 @@ namespace Profiler m_maxTicks = 0; } - inline AZStd::string TableRow::GetExecutingThreadsLabel() const + AZStd::string TableRow::GetExecutingThreadsLabel() const { auto threadString = AZStd::string::format("Executed in %zu threads\n", m_executingThreads.size()); for (const auto& threadId : m_executingThreads) @@ -1154,3 +1148,5 @@ namespace Profiler return threadString; } } // namespace Profiler + +#endif // defined(IMGUI_ENABLED) diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h index 69de0b578a..4529c7a3b2 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.h @@ -8,12 +8,18 @@ #pragma once +#if defined(IMGUI_ENABLED) + +#include + #include #include #include +#include +#include +#include -#include - +#include namespace Profiler { @@ -35,7 +41,7 @@ namespace Profiler }; // Update running statistics with new region data - void RecordRegion(const AZ::RHI::CachedTimeRegion& region, size_t threadId); + void RecordRegion(const CachedTimeRegion& region, size_t threadId); void ResetPerFrameStatistics(); @@ -47,7 +53,7 @@ namespace Profiler // --- Per frame statistics --- - u64 m_invocationsLastFrame = 0; + AZ::u64 m_invocationsLastFrame = 0; // NOTE: set over unordered_set so the threads can be shown in increasing order in tooltip. AZStd::set m_executingThreads; @@ -59,7 +65,7 @@ namespace Profiler // --- Aggregate statistics --- - u64 m_invocationsTotal = 0; + AZ::u64 m_invocationsTotal = 0; // Running average of Mean Time Per Call AZStd::sys_time_t m_runningAverageTicks = 0; @@ -69,15 +75,15 @@ namespace Profiler //! Offers both a statistical view (with sorting and searching capability) and a visualizer //! similar to RAD and other profiling tools. class ImGuiCpuProfiler - : SystemTickBus::Handler + : public AZ::SystemTickBus::Handler { // Region Name -> statistical view row data using RegionRowMap = AZStd::map; // Group Name -> RegionRowMap using GroupRegionMap = AZStd::map; - using TimeRegion = AZ::RHI::CachedTimeRegion; - using GroupRegionName = AZ::RHI::CachedTimeRegion::GroupRegionName; + using TimeRegion = CachedTimeRegion; + using GroupRegionName = CachedTimeRegion::GroupRegionName; public: struct CpuTimingEntry @@ -129,13 +135,13 @@ namespace Profiler void CullFrameData(); // Draws a single block onto the timeline into the specified row - void DrawBlock(const TimeRegion& block, u64 targetRow); + void DrawBlock(const TimeRegion& block, AZ::u64 targetRow); // Draw horizontal lines between threads in the timeline - void DrawThreadSeparator(u64 threadBoundary, u64 maxDepth); + void DrawThreadSeparator(AZ::u64 threadBoundary, AZ::u64 maxDepth); // Draw the "Thread XXXXX" label onto the viewport - void DrawThreadLabel(u64 baseRow, size_t threadId); + void DrawThreadLabel(AZ::u64 baseRow, size_t threadId); // Draw the vertical lines separating frames in the timeline void DrawFrameBoundaries(); @@ -156,14 +162,14 @@ namespace Profiler ImU32 GetBlockColor(const TimeRegion& block); // System tick bus overrides - virtual void OnSystemTick() override; + void OnSystemTick() override; // --- Visualizer Members --- int m_framesToCollect = DefaultFramesToCollect; // Tally of the number of saved profiling events so far - u64 m_savedRegionCount = 0; + AZ::u64 m_savedRegionCount = 0; // Viewport tick bounds, these are used to convert tick space -> screen space and cull so we only draw onscreen objects AZStd::sys_time_t m_viewportStartTick; @@ -175,7 +181,7 @@ namespace Profiler AZStd::unordered_map> m_savedData; // Region color cache - AZStd::unordered_map m_regionColorMap; + AZStd::unordered_map m_regionColorMap; // Tracks the frame boundaries AZStd::vector m_frameEndTicks = { INT64_MIN }; @@ -213,7 +219,7 @@ namespace Profiler bool m_showFilePicker = false; // Cached file paths to previous traces on disk, sorted with the most recent trace at the front. - AZStd::vector m_cachedCapturePaths; + AZStd::vector m_cachedCapturePaths; // Index into the file picker, used to determine which file to load when "Load File" is pressed. int m_currentFileIndex = 0; @@ -221,8 +227,8 @@ namespace Profiler // --- Loading capture state --- AZStd::unordered_set m_deserializedStringPool; - AZStd::unordered_set m_deserializedGroupRegionNamePool; + AZStd::unordered_set m_deserializedGroupRegionNamePool; }; } // namespace Profiler -#include "ImGuiCpuProfiler.inl" +#endif // defined(IMGUI_ENABLED) diff --git a/Gems/Profiler/Code/profiler_files.cmake b/Gems/Profiler/Code/profiler_files.cmake index 4f774fd024..f50329b8dc 100644 --- a/Gems/Profiler/Code/profiler_files.cmake +++ b/Gems/Profiler/Code/profiler_files.cmake @@ -8,6 +8,11 @@ set(FILES Include/Profiler/ProfilerBus.h + Source/CpuProfiler.h + Source/CpuProfilerImpl.cpp + Source/CpuProfilerImpl.h + Source/ImGuiCpuProfiler.cpp + Source/ImGuiCpuProfiler.h Source/ProfilerModuleInterface.h Source/ProfilerSystemComponent.cpp Source/ProfilerSystemComponent.h