Core/HW: Add time tracking thread in CPU manager

Introduce method to track the time played for a game via time differences and TimePlayed methods. Threads are synchronized via Common::Event.
This commit is contained in:
Aneesh Maganti 2025-02-10 15:28:32 -05:00 committed by Admiral H. Curtiss
parent 3c44fe592b
commit fffb499da2
No known key found for this signature in database
GPG Key ID: F051B4C4044F33FB
2 changed files with 58 additions and 0 deletions

View File

@ -10,12 +10,16 @@
#include "AudioCommon/AudioCommon.h"
#include "Common/CommonTypes.h"
#include "Common/Event.h"
#include "Common/Timer.h"
#include "Core/CPUThreadConfigCallback.h"
#include "Core/Config/MainSettings.h"
#include "Core/ConfigManager.h"
#include "Core/Core.h"
#include "Core/Host.h"
#include "Core/PowerPC/GDBStub.h"
#include "Core/PowerPC/PowerPC.h"
#include "Core/System.h"
#include "Core/TimePlayed.h"
#include "VideoCommon/Fifo.h"
namespace CPU
@ -63,6 +67,41 @@ void CPUManager::ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock)
}
}
void CPUManager::StartTimePlayedTimer()
{
// Steady clock for greater accuracy of timing
std::chrono::steady_clock timer;
auto prev_time = timer.now();
while (true)
{
const std::string game_id = SConfig::GetInstance().GetGameID();
TimePlayed time_played(game_id);
auto curr_time = timer.now();
// Check that emulation is not paused
// If the emulation is paused, wait for SetStepping() to reactivate
if (m_state == State::Running)
{
const auto diff_time =
std::chrono::duration_cast<std::chrono::milliseconds>(curr_time - prev_time);
time_played.AddTime(diff_time);
}
else if (m_state == State::Stepping)
{
m_time_played_finish_sync.Wait();
curr_time = timer.now();
}
prev_time = curr_time;
if (m_state == State::PowerDown)
return;
m_time_played_finish_sync.WaitFor(std::chrono::seconds(30));
}
}
void CPUManager::Run()
{
auto& power_pc = m_system.GetPowerPC();
@ -71,6 +110,13 @@ void CPUManager::Run()
// We can't rely on PowerPC::Init doing it, since it's called from EmuThread.
PowerPC::RoundingModeUpdated(power_pc.GetPPCState());
// Start a separate time tracker thread
std::thread timing;
if (Config::Get(Config::MAIN_TIME_TRACKING))
{
timing = std::thread(&CPUManager::StartTimePlayedTimer, this);
}
std::unique_lock state_lock(m_state_change_lock);
while (m_state != State::PowerDown)
{
@ -165,6 +211,13 @@ void CPUManager::Run()
break;
}
}
if (timing.joinable())
{
m_time_played_finish_sync.Set();
timing.join();
}
state_lock.unlock();
Host_UpdateDisasmDialog();
}
@ -266,6 +319,7 @@ void CPUManager::SetStepping(bool stepping)
else if (SetStateLocked(State::Running))
{
m_state_cpu_cvar.notify_one();
m_time_played_finish_sync.Set();
RunAdjacentSystems(true);
}
}

View File

@ -8,6 +8,8 @@
#include <mutex>
#include <queue>
#include "Common/Event.h"
namespace Common
{
class Event;
@ -102,6 +104,7 @@ public:
private:
void FlushStepSyncEventLocked();
void ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock);
void StartTimePlayedTimer();
void RunAdjacentSystems(bool running);
bool SetStateLocked(State s);
@ -133,6 +136,7 @@ private:
bool m_state_cpu_step_instruction = false;
Common::Event* m_state_cpu_step_instruction_sync = nullptr;
std::queue<std::function<void()>> m_pending_jobs;
Common::Event m_time_played_finish_sync;
Core::System& m_system;
};