DolphinAnalytics: Extract timestamp functions

Moves functions that generate starting timestamps for performance
sampling to PerformanceSampleAggregator.
This commit is contained in:
Dentomologist 2021-01-26 16:36:12 -08:00 committed by Dr. Dystopia
commit d9b0fd2805
4 changed files with 56 additions and 21 deletions

View file

@ -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<u64>() % (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<u64>() % (PERFORMANCE_SAMPLING_WAIT_TIME_JITTER_SECS * 1000000);
m_sampling_next_start_us = Common::Timer::NowUs() + wait_us;
return true;
return static_cast<u64>(m_sample_aggregator.GetCurrentMicroseconds().count()) >=
m_sampling_next_start_us;
}
void DolphinAnalytics::MakeBaseBuilder()

View file

@ -13,6 +13,7 @@
#include "Common/CommonTypes.h"
#include "Core/PerformanceSample.h"
#include "Core/PerformanceSampleAggregator.h"
#if defined(ANDROID)
#include <functional>
@ -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<PerformanceSample> m_performance_samples;
PerformanceSampleAggregator m_sample_aggregator;
// What quirks have already been reported about the current game.
std::array<bool, static_cast<size_t>(GameQuirk::Count)> m_reported_quirks;

View file

@ -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<u64>() % 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<std::chrono::microseconds>(time_since_epoch);
}

View file

@ -4,8 +4,14 @@
#pragma once
#include <chrono>
class PerformanceSampleAggregator
{
public:
PerformanceSampleAggregator() = default;
static std::chrono::microseconds GetInitialSamplingStartTimestamp();
static std::chrono::microseconds GetRepeatSamplingStartTimestamp();
static std::chrono::microseconds GetCurrentMicroseconds();
};