From d9b0fd2805f1f24dc2907ca3d9d55a75416bdd5e Mon Sep 17 00:00:00 2001 From: Dentomologist Date: Tue, 26 Jan 2021 16:36:12 -0800 Subject: [PATCH] DolphinAnalytics: Extract timestamp functions Moves functions that generate starting timestamps for performance sampling to PerformanceSampleAggregator. --- Source/Core/Core/DolphinAnalytics.cpp | 18 ++------- Source/Core/Core/DolphinAnalytics.h | 14 +++---- .../Core/Core/PerformanceSampleAggregator.cpp | 39 +++++++++++++++++++ .../Core/Core/PerformanceSampleAggregator.h | 6 +++ 4 files changed, 56 insertions(+), 21 deletions(-) diff --git a/Source/Core/Core/DolphinAnalytics.cpp b/Source/Core/Core/DolphinAnalytics.cpp index 03b07d27b2..54e3f5f7fc 100644 --- a/Source/Core/Core/DolphinAnalytics.cpp +++ b/Source/Core/Core/DolphinAnalytics.cpp @@ -27,7 +27,6 @@ #include "Common/Crypto/SHA1.h" #include "Common/EnumUtils.h" #include "Common/Random.h" -#include "Common/Timer.h" #include "Common/Version.h" #include "Core/Config/MainSettings.h" @@ -35,7 +34,6 @@ #include "Core/HW/GCPad.h" #include "Core/Movie.h" #include "Core/NetPlayProto.h" -#include "Core/PerformanceSampleAggregator.h" #include "Core/System.h" #include "InputCommon/GCAdapter.h" @@ -321,6 +319,7 @@ void DolphinAnalytics::ReportPerformanceInfo(PerformanceSample&& sample) // Clear up and stop sampling until next time ShouldStartPerformanceSampling() says so. m_performance_samples.clear(); m_sampling_performance_info = false; + m_sampling_next_start_us = m_sample_aggregator.GetRepeatSamplingStartTimestamp().count(); } } @@ -329,22 +328,13 @@ void DolphinAnalytics::InitializePerformanceSampling() m_performance_samples.clear(); m_sampling_performance_info = false; - const u64 wait_us = - PERFORMANCE_SAMPLING_INITIAL_WAIT_TIME_SECS * 1000000 + - Common::Random::GenerateValue() % (PERFORMANCE_SAMPLING_WAIT_TIME_JITTER_SECS * 1000000); - m_sampling_next_start_us = Common::Timer::NowUs() + wait_us; + m_sampling_next_start_us = m_sample_aggregator.GetInitialSamplingStartTimestamp().count(); } bool DolphinAnalytics::ShouldStartPerformanceSampling() { - if (Common::Timer::NowUs() < m_sampling_next_start_us) - return false; - - const u64 wait_us = - PERFORMANCE_SAMPLING_INTERVAL_SECS * 1000000 + - Common::Random::GenerateValue() % (PERFORMANCE_SAMPLING_WAIT_TIME_JITTER_SECS * 1000000); - m_sampling_next_start_us = Common::Timer::NowUs() + wait_us; - return true; + return static_cast(m_sample_aggregator.GetCurrentMicroseconds().count()) >= + m_sampling_next_start_us; } void DolphinAnalytics::MakeBaseBuilder() diff --git a/Source/Core/Core/DolphinAnalytics.h b/Source/Core/Core/DolphinAnalytics.h index 400e73e6ed..76180aaba1 100644 --- a/Source/Core/Core/DolphinAnalytics.h +++ b/Source/Core/Core/DolphinAnalytics.h @@ -13,6 +13,7 @@ #include "Common/CommonTypes.h" #include "Core/PerformanceSample.h" +#include "Core/PerformanceSampleAggregator.h" #if defined(ANDROID) #include @@ -138,6 +139,10 @@ public: // Reports performance information. This method performs its own throttling / aggregation -- // calling it does not guarantee when a report will actually be sent. + // Performance reports are generated using data from 100 consecutive frames. + // Report starting times are randomized to obtain a wider range of sample data. + // The first report begins 5-8 minutes after a game is launched. + // Successive reports begin 30-33 minutes after the previous report finishes. // // This method is NOT thread-safe. void ReportPerformanceInfo(PerformanceSample&& sample); @@ -165,21 +170,16 @@ private: // values created by MakeUniqueId. std::string m_unique_id; - // Performance sampling configuration constants. - // - // 5min after startup + rand(0, 3min) jitter time, collect performance for 100 frames in a row. - // Repeat collection after 30min + rand(0, 3min). static constexpr int NUM_PERFORMANCE_SAMPLES_PER_REPORT = 100; - static constexpr int PERFORMANCE_SAMPLING_INITIAL_WAIT_TIME_SECS = 300; - static constexpr int PERFORMANCE_SAMPLING_WAIT_TIME_JITTER_SECS = 180; - static constexpr int PERFORMANCE_SAMPLING_INTERVAL_SECS = 1800; // Performance sampling state & internal helpers. void InitializePerformanceSampling(); // Called on game start / title switch. bool ShouldStartPerformanceSampling(); + u64 m_sampling_next_start_us; // Next timestamp (in us) at which to trigger sampling. bool m_sampling_performance_info = false; // Whether we are currently collecting samples. std::vector m_performance_samples; + PerformanceSampleAggregator m_sample_aggregator; // What quirks have already been reported about the current game. std::array(GameQuirk::Count)> m_reported_quirks; diff --git a/Source/Core/Core/PerformanceSampleAggregator.cpp b/Source/Core/Core/PerformanceSampleAggregator.cpp index 1e0b8ddf4b..f4ec11924a 100644 --- a/Source/Core/Core/PerformanceSampleAggregator.cpp +++ b/Source/Core/Core/PerformanceSampleAggregator.cpp @@ -3,3 +3,42 @@ // Refer to the license.txt file included. #include "Core/PerformanceSampleAggregator.h" + +#include "Common/Random.h" + +namespace +{ +std::chrono::microseconds GetSamplingStartTimeJitter() +{ + constexpr long long max_delay = std::chrono::microseconds(std::chrono::minutes(3)).count(); + return std::chrono::microseconds(Common::Random::GenerateValue() % max_delay); +} + +std::chrono::microseconds +GetSamplingStartTimestampUsingBaseDelay(const std::chrono::microseconds base_delay) +{ + const std::chrono::microseconds now = PerformanceSampleAggregator::GetCurrentMicroseconds(); + const std::chrono::microseconds jitter = GetSamplingStartTimeJitter(); + const std::chrono::microseconds sampling_start_timestamp = now + base_delay + jitter; + return sampling_start_timestamp; +} +} // namespace + +std::chrono::microseconds PerformanceSampleAggregator::GetInitialSamplingStartTimestamp() +{ + constexpr std::chrono::microseconds base_initial_delay = std::chrono::minutes(5); + return GetSamplingStartTimestampUsingBaseDelay(base_initial_delay); +} + +std::chrono::microseconds PerformanceSampleAggregator::GetRepeatSamplingStartTimestamp() +{ + constexpr std::chrono::microseconds base_repeat_delay = std::chrono::minutes(30); + return GetSamplingStartTimestampUsingBaseDelay(base_repeat_delay); +} + +std::chrono::microseconds PerformanceSampleAggregator::GetCurrentMicroseconds() +{ + const std::chrono::high_resolution_clock::duration time_since_epoch = + std::chrono::high_resolution_clock::now().time_since_epoch(); + return std::chrono::duration_cast(time_since_epoch); +} diff --git a/Source/Core/Core/PerformanceSampleAggregator.h b/Source/Core/Core/PerformanceSampleAggregator.h index 59f5c86484..a3a8bc4e4a 100644 --- a/Source/Core/Core/PerformanceSampleAggregator.h +++ b/Source/Core/Core/PerformanceSampleAggregator.h @@ -4,8 +4,14 @@ #pragma once +#include + class PerformanceSampleAggregator { public: PerformanceSampleAggregator() = default; + + static std::chrono::microseconds GetInitialSamplingStartTimestamp(); + static std::chrono::microseconds GetRepeatSamplingStartTimestamp(); + static std::chrono::microseconds GetCurrentMicroseconds(); };