From c763961112f858732c1cad58e286d7a076ef7e5f Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Wed, 5 Mar 2025 02:06:05 -0600 Subject: [PATCH] PerformanceTracker: Use std::deque instead of hand-rolled circular queue. --- .../Core/VideoCommon/PerformanceTracker.cpp | 82 ++++++------------- Source/Core/VideoCommon/PerformanceTracker.h | 41 ++-------- 2 files changed, 33 insertions(+), 90 deletions(-) diff --git a/Source/Core/VideoCommon/PerformanceTracker.cpp b/Source/Core/VideoCommon/PerformanceTracker.cpp index 64729a5cad..302adc6a57 100644 --- a/Source/Core/VideoCommon/PerformanceTracker.cpp +++ b/Source/Core/VideoCommon/PerformanceTracker.cpp @@ -16,6 +16,8 @@ #include "VideoCommon/VideoConfig.h" static constexpr double SAMPLE_RC_RATIO = 0.25; +static constexpr u64 MAX_DT_QUEUE_SIZE = 1UL << 12; +static constexpr u64 MAX_QUALITY_GRAPH_SIZE = 1UL << 8; PerformanceTracker::PerformanceTracker(const std::optional log_name, const std::optional
sample_window_duration) @@ -39,7 +41,8 @@ void PerformanceTracker::Reset() { std::unique_lock lock{m_mutex}; - QueueClear(); + m_dt_total = DT::zero(); + m_dt_queue.clear(); m_last_time = Clock::now(); m_hz_avg = 0.0; m_dt_avg = DT::zero(); @@ -60,17 +63,16 @@ void PerformanceTracker::Count() m_last_time = time; - QueuePush(diff); - m_dt_total += diff; + PushFront(diff); - if (m_dt_queue_begin == m_dt_queue_end) - m_dt_total -= QueuePop(); + if (m_dt_queue.size() == MAX_DT_QUEUE_SIZE) + PopBack(); - while (window <= m_dt_total - QueueTop()) - m_dt_total -= QueuePop(); + while (m_dt_total - m_dt_queue.back() >= window) + PopBack(); // Simple Moving Average Throughout the Window - m_dt_avg = m_dt_total / QueueSize(); + m_dt_avg = m_dt_total / m_dt_queue.size(); const double hz = DT_s(1.0) / m_dt_avg; // Exponential Moving Average @@ -114,28 +116,28 @@ DT PerformanceTracker::GetDtStd() const if (m_dt_std) return *m_dt_std; - if (QueueEmpty()) + if (m_dt_queue.empty()) return *(m_dt_std = DT::zero()); double total = 0.0; - for (std::size_t i = m_dt_queue_begin; i != m_dt_queue_end; i = IncrementIndex(i)) + for (auto dt : m_dt_queue) { - double diff = DT_s(m_dt_queue[i] - m_dt_avg).count(); + double diff = DT_s(dt - m_dt_avg).count(); total += diff * diff; } // This is a weighted standard deviation - return *(m_dt_std = std::chrono::duration_cast
(DT_s(std::sqrt(total / QueueSize())))); + return *(m_dt_std = std::chrono::duration_cast
(DT_s(std::sqrt(total / m_dt_queue.size())))); } DT PerformanceTracker::GetLastRawDt() const { std::shared_lock lock{m_mutex}; - if (QueueEmpty()) + if (m_dt_queue.empty()) return DT::zero(); - return QueueBottom(); + return m_dt_queue.front(); } void PerformanceTracker::ImPlotPlotLines(const char* label) const @@ -144,14 +146,14 @@ void PerformanceTracker::ImPlotPlotLines(const char* label) const std::shared_lock lock{m_mutex}; - if (QueueEmpty()) + if (m_dt_queue.empty()) return; // Decides if there are too many points to plot using rectangles - const bool quality = QueueSize() < MAX_QUALITY_GRAPH_SIZE; + const bool quality = m_dt_queue.size() < MAX_QUALITY_GRAPH_SIZE; const DT update_time = Clock::now() - m_last_time; - const float predicted_frame_time = DT_ms(std::max(update_time, QueueBottom())).count(); + const float predicted_frame_time = DT_ms(std::max(update_time, m_dt_queue.front())).count(); std::size_t points = 0; if (quality) @@ -165,11 +167,9 @@ void PerformanceTracker::ImPlotPlotLines(const char* label) const y[points] = predicted_frame_time; ++points; - const std::size_t begin = DecrementIndex(m_dt_queue_end); - const std::size_t end = DecrementIndex(m_dt_queue_begin); - for (std::size_t i = begin; i != end; i = DecrementIndex(i)) + for (auto dt : m_dt_queue) { - const float frame_time_ms = DT_ms(m_dt_queue[i]).count(); + const float frame_time_ms = DT_ms(dt).count(); if (quality) { @@ -186,44 +186,16 @@ void PerformanceTracker::ImPlotPlotLines(const char* label) const ImPlot::PlotLine(label, x.data(), y.data(), static_cast(points)); } -void PerformanceTracker::QueueClear() +void PerformanceTracker::PushFront(DT value) { - m_dt_total = DT::zero(); - m_dt_queue_begin = 0; - m_dt_queue_end = 0; + m_dt_queue.push_front(value); + m_dt_total += value; } -void PerformanceTracker::QueuePush(DT dt) +void PerformanceTracker::PopBack() { - m_dt_queue[m_dt_queue_end] = dt; - m_dt_queue_end = IncrementIndex(m_dt_queue_end); -} - -const DT& PerformanceTracker::QueuePop() -{ - const std::size_t top = m_dt_queue_begin; - m_dt_queue_begin = IncrementIndex(m_dt_queue_begin); - return m_dt_queue[top]; -} - -const DT& PerformanceTracker::QueueTop() const -{ - return m_dt_queue[m_dt_queue_begin]; -} - -const DT& PerformanceTracker::QueueBottom() const -{ - return m_dt_queue[DecrementIndex(m_dt_queue_end)]; -} - -std::size_t PerformanceTracker::QueueSize() const -{ - return GetDifference(m_dt_queue_begin, m_dt_queue_end); -} - -bool PerformanceTracker::QueueEmpty() const -{ - return m_dt_queue_begin == m_dt_queue_end; + m_dt_total -= m_dt_queue.back(); + m_dt_queue.pop_back(); } void PerformanceTracker::LogRenderTimeToFile(DT val) diff --git a/Source/Core/VideoCommon/PerformanceTracker.h b/Source/Core/VideoCommon/PerformanceTracker.h index a41271abaa..8f39994d18 100644 --- a/Source/Core/VideoCommon/PerformanceTracker.h +++ b/Source/Core/VideoCommon/PerformanceTracker.h @@ -3,7 +3,7 @@ #pragma once -#include +#include #include #include #include @@ -12,26 +12,6 @@ class PerformanceTracker { -private: - // Must be powers of 2 for masking to work - static constexpr u64 MAX_DT_QUEUE_SIZE = 1UL << 12; - static constexpr u64 MAX_QUALITY_GRAPH_SIZE = 1UL << 8; - - static inline std::size_t IncrementIndex(const std::size_t index) - { - return (index + 1) & (MAX_DT_QUEUE_SIZE - 1); - } - - static inline std::size_t DecrementIndex(const std::size_t index) - { - return (index - 1) & (MAX_DT_QUEUE_SIZE - 1); - } - - static inline std::size_t GetDifference(const std::size_t begin, const std::size_t end) - { - return (end - begin) & (MAX_DT_QUEUE_SIZE - 1); - } - public: PerformanceTracker(const std::optional log_name = std::nullopt, const std::optional
sample_window_duration = std::nullopt); @@ -58,20 +38,13 @@ public: void ImPlotPlotLines(const char* label) const; -private: // Functions for managing dt queue - inline void QueueClear(); - inline void QueuePush(DT dt); - inline const DT& QueuePop(); - inline const DT& QueueTop() const; - inline const DT& QueueBottom() const; - - std::size_t inline QueueSize() const; - bool inline QueueEmpty() const; - - // Handle pausing and logging +private: void LogRenderTimeToFile(DT val); void SetPaused(bool paused); + void PushFront(DT value); + void PopBack(); + bool m_paused = false; int m_on_state_changed_handle; @@ -87,9 +60,7 @@ private: // Functions for managing dt queue // Queue + Running Total used to calculate average dt DT m_dt_total = DT::zero(); - std::array m_dt_queue; - std::size_t m_dt_queue_begin = 0; - std::size_t m_dt_queue_end = 0; + std::deque
m_dt_queue; // Average rate/time throughout the window DT m_dt_avg = DT::zero(); // Uses Moving Average