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:
parent
3c44fe592b
commit
fffb499da2
|
@ -10,12 +10,16 @@
|
||||||
#include "AudioCommon/AudioCommon.h"
|
#include "AudioCommon/AudioCommon.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Event.h"
|
#include "Common/Event.h"
|
||||||
|
#include "Common/Timer.h"
|
||||||
#include "Core/CPUThreadConfigCallback.h"
|
#include "Core/CPUThreadConfigCallback.h"
|
||||||
|
#include "Core/Config/MainSettings.h"
|
||||||
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/Host.h"
|
#include "Core/Host.h"
|
||||||
#include "Core/PowerPC/GDBStub.h"
|
#include "Core/PowerPC/GDBStub.h"
|
||||||
#include "Core/PowerPC/PowerPC.h"
|
#include "Core/PowerPC/PowerPC.h"
|
||||||
#include "Core/System.h"
|
#include "Core/System.h"
|
||||||
|
#include "Core/TimePlayed.h"
|
||||||
#include "VideoCommon/Fifo.h"
|
#include "VideoCommon/Fifo.h"
|
||||||
|
|
||||||
namespace CPU
|
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()
|
void CPUManager::Run()
|
||||||
{
|
{
|
||||||
auto& power_pc = m_system.GetPowerPC();
|
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.
|
// We can't rely on PowerPC::Init doing it, since it's called from EmuThread.
|
||||||
PowerPC::RoundingModeUpdated(power_pc.GetPPCState());
|
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);
|
std::unique_lock state_lock(m_state_change_lock);
|
||||||
while (m_state != State::PowerDown)
|
while (m_state != State::PowerDown)
|
||||||
{
|
{
|
||||||
|
@ -165,6 +211,13 @@ void CPUManager::Run()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (timing.joinable())
|
||||||
|
{
|
||||||
|
m_time_played_finish_sync.Set();
|
||||||
|
timing.join();
|
||||||
|
}
|
||||||
|
|
||||||
state_lock.unlock();
|
state_lock.unlock();
|
||||||
Host_UpdateDisasmDialog();
|
Host_UpdateDisasmDialog();
|
||||||
}
|
}
|
||||||
|
@ -266,6 +319,7 @@ void CPUManager::SetStepping(bool stepping)
|
||||||
else if (SetStateLocked(State::Running))
|
else if (SetStateLocked(State::Running))
|
||||||
{
|
{
|
||||||
m_state_cpu_cvar.notify_one();
|
m_state_cpu_cvar.notify_one();
|
||||||
|
m_time_played_finish_sync.Set();
|
||||||
RunAdjacentSystems(true);
|
RunAdjacentSystems(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
#include "Common/Event.h"
|
||||||
|
|
||||||
namespace Common
|
namespace Common
|
||||||
{
|
{
|
||||||
class Event;
|
class Event;
|
||||||
|
@ -102,6 +104,7 @@ public:
|
||||||
private:
|
private:
|
||||||
void FlushStepSyncEventLocked();
|
void FlushStepSyncEventLocked();
|
||||||
void ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock);
|
void ExecutePendingJobs(std::unique_lock<std::mutex>& state_lock);
|
||||||
|
void StartTimePlayedTimer();
|
||||||
void RunAdjacentSystems(bool running);
|
void RunAdjacentSystems(bool running);
|
||||||
bool SetStateLocked(State s);
|
bool SetStateLocked(State s);
|
||||||
|
|
||||||
|
@ -133,6 +136,7 @@ private:
|
||||||
bool m_state_cpu_step_instruction = false;
|
bool m_state_cpu_step_instruction = false;
|
||||||
Common::Event* m_state_cpu_step_instruction_sync = nullptr;
|
Common::Event* m_state_cpu_step_instruction_sync = nullptr;
|
||||||
std::queue<std::function<void()>> m_pending_jobs;
|
std::queue<std::function<void()>> m_pending_jobs;
|
||||||
|
Common::Event m_time_played_finish_sync;
|
||||||
|
|
||||||
Core::System& m_system;
|
Core::System& m_system;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue