diff --git a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp index 0bb92b923d..4abda46214 100644 --- a/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp +++ b/Code/Framework/AzCore/AzCore/Debug/Profiler.cpp @@ -7,4 +7,44 @@ */ #include +#include +#include +#include +namespace AZ::Debug +{ + AZ_CVAR(AZ::CVarFixedString, bg_profilerCaptureLocation, "@user@/Profiler", nullptr, ConsoleFunctorFlags::Null, + "Specify where to save profiler capture data"); + + AZStd::string GenerateOutputFile(const char* nameHint) + { + AZStd::string timeString; + AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); + + AZ::CVarFixedString captureOutput = static_cast(bg_profilerCaptureLocation); + + return AZStd::string::format("%s/capture_%s_%s.json", captureOutput.c_str(), nameHint, timeString.c_str()); + } + + void ProfilerCaptureFrame([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + { + AZStd::string captureFile = GenerateOutputFile("single"); + AZLOG_INFO("Setting capture file to %s", captureFile.c_str()); + AZ::Debug::ProfilerRequestBus::Broadcast(&AZ::Debug::ProfilerRequestBus::Events::CaptureFrame, captureFile); + } + AZ_CONSOLEFREEFUNC(ProfilerCaptureFrame, AZ::ConsoleFunctorFlags::DontReplicate, "Capture a single frame of profiling data"); + + void ProfilerStartCapture([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + { + AZStd::string captureFile = GenerateOutputFile("multi"); + AZLOG_INFO("Setting capture file to %s", captureFile.c_str()); + ProfilerRequestBus::Broadcast(&ProfilerRequestBus::Events::StartCapture, captureFile); + } + AZ_CONSOLEFREEFUNC(ProfilerStartCapture, AZ::ConsoleFunctorFlags::DontReplicate, "Start a multi-frame capture of profiling data"); + + void ProfilerEndCapture([[maybe_unused]] const AZ::ConsoleCommandContainer& arguments) + { + AZ::Debug::ProfilerRequestBus::Broadcast(&AZ::Debug::ProfilerRequestBus::Events::EndCapture); + } + AZ_CONSOLEFREEFUNC(ProfilerEndCapture, AZ::ConsoleFunctorFlags::DontReplicate, "End and dump an in-progress continuous capture"); +} // namespace AZ::Debug diff --git a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp index 0320020e86..52fe09f9e8 100644 --- a/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp +++ b/Gems/Profiler/Code/Source/ImGuiCpuProfiler.cpp @@ -12,6 +12,7 @@ #include +#include #include #include #include @@ -24,10 +25,13 @@ #include #include +namespace AZ::Debug +{ + AZ_CVAR_EXTERNED(AZ::CVarFixedString, bg_profilerCaptureLocation); +} + namespace Profiler { - static constexpr const char* defaultSaveLocation = "@user@/Profiler"; - namespace CpuProfilerImGuiHelper { float TicksToMs(double ticks) @@ -222,8 +226,10 @@ namespace Profiler // Only update the cached file list when opened so that we aren't making IO calls on every frame. m_cachedCapturePaths.clear(); + AZ::CVarFixedString captureOutput = static_cast(AZ::Debug::bg_profilerCaptureLocation); + auto* base = AZ::IO::FileIOBase::GetInstance(); - base->FindFiles(defaultSaveLocation, "*.json", + base->FindFiles(captureOutput.c_str(), "*.json", [&paths = m_cachedCapturePaths](const char* path) -> bool { auto foundPath = AZ::IO::Path(path); @@ -410,7 +416,9 @@ namespace Profiler AZStd::string timeString; AZStd::to_string(timeString, AZStd::GetTimeNowSecond()); - const AZStd::string frameDataFilePath = AZStd::string::format("%s/cpu_%s_%s.json", defaultSaveLocation, nameHint, timeString.c_str()); + AZ::CVarFixedString captureOutput = static_cast(AZ::Debug::bg_profilerCaptureLocation); + + const AZStd::string frameDataFilePath = AZStd::string::format("%s/cpu_%s_%s.json", captureOutput.c_str(), nameHint, timeString.c_str()); char resolvedPath[AZ::IO::MaxPathLength]; AZ::IO::FileIOBase::GetInstance()->ResolvePath(frameDataFilePath.c_str(), resolvedPath, AZ::IO::MaxPathLength);