diff --git a/profiler/src/main.cpp b/profiler/src/main.cpp index 7159ca31fb..5d86f85952 100644 --- a/profiler/src/main.cpp +++ b/profiler/src/main.cpp @@ -777,6 +777,15 @@ static void DrawContents() ImGui::EndDisabled(); } + ImGui::Spacing(); + if( ImGui::Checkbox( "Time limit", &tracy::s_config.timeLimit ) ) tracy::SaveConfig(); + ImGui::SameLine(); + tracy::DrawHelpMarker( "When enabled, the profiler will stop recording data once the connection duration exceeds the specified value (in seconds). Note that the capture duration itself is not correlated to the connection duration." ); + ImGui::SameLine(); + ImGui::SetNextItemWidth( 70 * dpiScale ); + if( ImGui::InputFloat( "##timelimit", &tracy::s_config.connectionTimeLimitSeconds, 0.f, 0.f, "%.2f" ) ) { tracy::s_config.connectionTimeLimitSeconds = std::max( tracy::s_config.connectionTimeLimitSeconds, 0.f ); tracy::SaveConfig(); } + ImGui::SameLine(); + ImGui::TextUnformatted( "s" ); ImGui::Spacing(); if( ImGui::Checkbox( "Enable achievements", &tracy::s_config.achievements ) ) tracy::SaveConfig(); ImGui::Spacing(); @@ -970,11 +979,18 @@ static void DrawContents() } } } - if( tracy::s_config.memoryLimit ) + if( tracy::s_config.memoryLimit || tracy::s_config.timeLimit ) { ImGui::SameLine(); tracy::TextColoredUnformatted( 0xFF00FFFF, ICON_FA_TRIANGLE_EXCLAMATION ); - tracy::TooltipIfHovered( "Memory limit is active" ); + if( tracy::s_config.memoryLimit ) + { + tracy::TooltipIfHovered( "Memory limit is active" ); + } + if( tracy::s_config.timeLimit ) + { + tracy::TooltipIfHovered( "Capture duration limit is active" ); + } } ImGui::SameLine( 0, ImGui::GetTextLineHeight() * 2 ); diff --git a/profiler/src/profiler/TracyConfig.cpp b/profiler/src/profiler/TracyConfig.cpp index aaeaf30825..387f5356a1 100644 --- a/profiler/src/profiler/TracyConfig.cpp +++ b/profiler/src/profiler/TracyConfig.cpp @@ -30,6 +30,8 @@ void LoadConfig() if( ini_sget( ini, "timeline", "verticalScrollMultiplier", "%lf", &v1 ) && v1 > 0.0 ) s_config.verticalScrollMultiplier = v1; if( ini_sget( ini, "memory", "limit", "%d", &v ) ) s_config.memoryLimit = v; if( ini_sget( ini, "memory", "percent", "%d", &v ) && v >= 1 && v < 1000 ) s_config.memoryLimitPercent = v; + if( ini_sget( ini, "connection", "durationLimitEnabled", "%d", &v ) && v >= 1 ) s_config.timeLimit = v; + if( ini_sget( ini, "connection", "durationLimitInSeconds", "%lf", &v1 ) ) s_config.connectionTimeLimitSeconds = v1; if( ini_sget( ini, "achievements", "enabled", "%d", &v ) ) s_config.achievements = v; if( ini_sget( ini, "achievements", "asked", "%d", &v ) ) s_config.achievementsAsked = v; if( ini_sget( ini, "ui", "saveUserScale", "%d", &v ) ) s_config.saveUserScale = v; @@ -67,6 +69,10 @@ bool SaveConfig() fprintf( f, "limit = %i\n", (int)s_config.memoryLimit ); fprintf( f, "percent = %i\n", s_config.memoryLimitPercent ); + fprintf( f, "\n[connection]\n" ); + fprintf( f, "durationLimitEnabled = %i\n", (int)s_config.timeLimit ); + fprintf( f, "durationLimitInSeconds = %f\n", s_config.connectionTimeLimitSeconds ); + fprintf( f, "\n[achievements]\n" ); fprintf( f, "enabled = %i\n", (int)s_config.achievements ); fprintf( f, "asked = %i\n", (int)s_config.achievementsAsked ); diff --git a/profiler/src/profiler/TracyConfig.hpp b/profiler/src/profiler/TracyConfig.hpp index dca00a6412..e553d06ba3 100644 --- a/profiler/src/profiler/TracyConfig.hpp +++ b/profiler/src/profiler/TracyConfig.hpp @@ -17,6 +17,8 @@ struct Config double verticalScrollMultiplier = 1.0; bool memoryLimit = false; int memoryLimitPercent = 80; + bool timeLimit = false; + float connectionTimeLimitSeconds = 10.f; bool achievements = false; bool achievementsAsked = false; int dynamicColors = 1; diff --git a/profiler/src/profiler/TracyView.cpp b/profiler/src/profiler/TracyView.cpp index ee970358f7..863c1e5b2c 100644 --- a/profiler/src/profiler/TracyView.cpp +++ b/profiler/src/profiler/TracyView.cpp @@ -38,7 +38,7 @@ namespace tracy double s_time = 0; View::View( void(*cbMainThread)(const std::function&, bool), const char* addr, uint16_t port, SetTitleCallback stcb, SetScaleCallback sscb, AttentionCallback acb, AchievementsMgr* amgr ) - : m_worker( addr, port, s_config.memoryLimit == 0 ? -1 : ( s_config.memoryLimitPercent * tracy::GetPhysicalMemorySize() / 100 ) ) + : m_worker( addr, port, s_config.memoryLimit == 0 ? -1 : ( s_config.memoryLimitPercent * tracy::GetPhysicalMemorySize() / 100 ), s_config.timeLimit == 0 ? -1 : s_config.connectionTimeLimitSeconds ) , m_staticView( false ) , m_viewMode( ViewMode::LastFrames ) , m_viewModeHeuristicTry( true ) @@ -825,9 +825,9 @@ bool View::DrawImpl() ImGui::SameLine(); if( ImGui::BeginPopup( "TracyConnectionPopup" ) ) { - const bool wasDisconnectIssued = m_disconnectIssued; + const bool wasDisconnectIssued = m_worker.WasDisconnectIssued(); const bool discardData = !DrawConnection(); - const bool disconnectIssuedJustNow = m_disconnectIssued != wasDisconnectIssued; + const bool disconnectIssuedJustNow = m_worker.WasDisconnectIssued() != wasDisconnectIssued; if( discardData ) keepOpen = false; if( disconnectIssuedJustNow || discardData ) ImGui::CloseCurrentPopup(); ImGui::EndPopup(); @@ -1079,11 +1079,16 @@ bool View::DrawImpl() if( dx < targetLabelSize ) ImGui::SameLine( cx + targetLabelSize ); ImGui::Spacing(); + const auto timeLimit = m_worker.GetTimeLimit(); + const auto timeRemaining = timeLimit - ( std::chrono::steady_clock::now() - m_worker.GetStartTime() ); + const bool timeLimitReached = timeLimit.count() > 0 && timeRemaining.count() < 0; const auto memoryLimit = m_worker.GetMemoryLimit(); - if( memoryLimit > 0 ) + const auto memoryRemainingBeforeLimit = memoryLimit - memUsage.load( std::memory_order_relaxed ); + const bool memoryLimitReached = memoryLimit > 0 && memoryRemainingBeforeLimit < 0; + if( memoryLimit > 0 || timeLimit.count() > 0.f ) { ImGui::SameLine(); - if( memUsage.load( std::memory_order_relaxed ) > memoryLimit ) + if( memoryLimitReached || timeLimitReached ) { TextColoredUnformatted( 0xFF2222FF, ICON_FA_TRIANGLE_EXCLAMATION ); } @@ -1094,7 +1099,24 @@ bool View::DrawImpl() if( ImGui::IsItemHovered() ) { ImGui::BeginTooltip(); - ImGui::Text( "Memory limit: %s", MemSizeToString( memoryLimit ) ); + if( memoryLimit > 0 ) + { + ImGui::Text( "Memory limit: %s", MemSizeToString( memoryLimit ) ); + if( !memoryLimitReached ) + { + ImGui::SameLine(); + ImGui::Text( " (%s remaining)", MemSizeToString( memoryRemainingBeforeLimit ) ); + } + } + if( timeLimit.count() > 0.f ) + { + ImGui::Text( "Capture time limit: %.2f s", timeLimit.count() ); + if( !timeLimitReached ) + { + ImGui::SameLine(); + ImGui::Text( " (%.2f s remaining)", std::chrono::duration( timeRemaining ).count() ); + } + } ImGui::EndTooltip(); } } diff --git a/profiler/src/profiler/TracyView.hpp b/profiler/src/profiler/TracyView.hpp index 272b187869..2a552c61cc 100644 --- a/profiler/src/profiler/TracyView.hpp +++ b/profiler/src/profiler/TracyView.hpp @@ -498,7 +498,6 @@ class View size_t m_prevMessages = 0; bool m_messagesShowCallstack = false; Vector m_msgList; - bool m_disconnectIssued = false; uint64_t m_selectedThread = 0; DecayValue m_drawThreadMigrations = 0; DecayValue m_drawThreadHighlight = 0; diff --git a/profiler/src/profiler/TracyView_ConnectionState.cpp b/profiler/src/profiler/TracyView_ConnectionState.cpp index 77c18ac00d..fcb658e9ab 100644 --- a/profiler/src/profiler/TracyView_ConnectionState.cpp +++ b/profiler/src/profiler/TracyView_ConnectionState.cpp @@ -143,12 +143,11 @@ bool View::DrawConnection() ImGui::SameLine( 0, 2 * ty ); const char* stopStr = ICON_FA_PLUG " Stop"; Worker::MainThreadDataLockGuard lock = m_worker.ObtainLockForMainThread(); - if( !m_disconnectIssued && m_worker.IsConnected() ) + if( !m_worker.WasDisconnectIssued() && m_worker.IsConnected() ) { if( ImGui::Button( stopStr ) ) { m_worker.Disconnect(); - m_disconnectIssued = true; } } else diff --git a/server/TracyWorker.cpp b/server/TracyWorker.cpp index 483e3233d0..4d5874766e 100644 --- a/server/TracyWorker.cpp +++ b/server/TracyWorker.cpp @@ -255,7 +255,7 @@ static bool IsQueryPrio( ServerQuery type ) LoadProgress Worker::s_loadProgress; -Worker::Worker( const char* addr, uint16_t port, int64_t memoryLimit ) +Worker::Worker( const char* addr, uint16_t port, int64_t memoryLimit, float timeLimit ) : m_addr( addr ) , m_port( port ) , m_hasData( false ) @@ -272,6 +272,7 @@ Worker::Worker( const char* addr, uint16_t port, int64_t memoryLimit ) , m_pendingCallstackSubframes( 0 ) , m_pendingSymbolCode( 0 ) , m_memoryLimit( memoryLimit ) + , m_timeLimit( timeLimit ) , m_callstackFrameStaging( nullptr ) , m_traceVersion( CurrentVersion ) , m_loadTime( 0 ) @@ -313,6 +314,7 @@ Worker::Worker( const char* name, const char* program, const std::vector 0 && memUsage.load( std::memory_order_relaxed ) > m_memoryLimit ) ) + if( m_shutdown.load( std::memory_order_relaxed ) + || ( m_memoryLimit > 0 && memUsage.load( std::memory_order_relaxed ) > m_memoryLimit ) + || ( m_timeLimit.count() > 0.f && std::chrono::steady_clock::now() > m_data.startTime + m_timeLimit ) ) { QueryTerminate(); goto close; diff --git a/server/TracyWorker.hpp b/server/TracyWorker.hpp index 2aa09a0eb3..b424a9dacb 100644 --- a/server/TracyWorker.hpp +++ b/server/TracyWorker.hpp @@ -407,6 +407,8 @@ class Worker bool hasBranchRetirement = false; unordered_flat_map fiberToThreadMap; + + std::chrono::time_point startTime; }; struct MbpsBlock @@ -455,7 +457,7 @@ class Worker NUM_FAILURES }; - Worker( const char* addr, uint16_t port, int64_t memoryLimit ); + Worker( const char* addr, uint16_t port, int64_t memoryLimit, float timeLimit ); Worker( const char* name, const char* program, const std::vector& timeline, const std::vector& messages, const std::vector& plots, const std::unordered_map& threadNames ); Worker( FileRead& f, EventType::Type eventMask = EventType::All, bool bgTasks = true, bool allowStringModification = false); ~Worker(); @@ -671,6 +673,8 @@ class Worker void Disconnect(); bool WasDisconnectIssued() const { return m_disconnect; } int64_t GetMemoryLimit() const { return m_memoryLimit; } + std::chrono::duration GetTimeLimit() const { return m_timeLimit; } + std::chrono::steady_clock::time_point GetStartTime() const { return m_data.startTime; } void Write( FileWrite& f, bool fiDict ); int GetTraceVersion() const { return m_traceVersion; } @@ -1068,6 +1072,7 @@ class Worker Slab<64*1024*1024> m_slab; int64_t m_memoryLimit; + std::chrono::duration m_timeLimit; DataBlock m_data; MbpsBlock m_mbpsData;