summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAneesh Maganti <28660350+aminoa@users.noreply.github.com>2025-02-10 15:28:32 -0500
committerAdmiral H. Curtiss <pikachu025@gmail.com>2025-02-16 23:15:12 +0100
commitfffb499da2fdde53e1ff25e17f2f718cd608167f (patch)
tree007fd7dd4e761db3ffc70f2ffece0d1369f2cd43
parent3c44fe592b8db19bf7be5f5e1cb45e5cb0062950 (diff)
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.
-rw-r--r--Source/Core/Core/HW/CPU.cpp54
-rw-r--r--Source/Core/Core/HW/CPU.h4
2 files changed, 58 insertions, 0 deletions
diff --git a/Source/Core/Core/HW/CPU.cpp b/Source/Core/Core/HW/CPU.cpp
index 1eae912476..487a33c6ff 100644
--- a/Source/Core/Core/HW/CPU.cpp
+++ b/Source/Core/Core/HW/CPU.cpp
@@ -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);
}
}
diff --git a/Source/Core/Core/HW/CPU.h b/Source/Core/Core/HW/CPU.h
index 57e8a31a29..b73471136d 100644
--- a/Source/Core/Core/HW/CPU.h
+++ b/Source/Core/Core/HW/CPU.h
@@ -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;
};