Merge 03d13290b3 into 4d7e1662c8
This commit is contained in:
@@ -25,7 +25,7 @@ void CpuBarrier::NotifyEnd() {
|
||||
condition.notify_all();
|
||||
}
|
||||
|
||||
bool CpuBarrier::Rendezvous() {
|
||||
bool CpuBarrier::Rendezvous(bool main_core) {
|
||||
if (!Settings::values.use_multi_core) {
|
||||
// Meaningless when running in single-core mode
|
||||
return true;
|
||||
@@ -36,11 +36,21 @@ bool CpuBarrier::Rendezvous() {
|
||||
|
||||
--cores_waiting;
|
||||
if (!cores_waiting) {
|
||||
if (CoreTiming::MainSliceWasCropped() && main_core) {
|
||||
// This is the main thread but we were cropped, so just continue;
|
||||
++cores_waiting;
|
||||
return true;
|
||||
}
|
||||
cores_waiting = NUM_CPU_CORES;
|
||||
condition.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (CoreTiming::MainSliceWasCropped() && main_core) {
|
||||
// This is the main thread but we were cropped, so just continue;
|
||||
++cores_waiting;
|
||||
return true;
|
||||
}
|
||||
condition.wait(lock);
|
||||
return true;
|
||||
}
|
||||
@@ -80,7 +90,7 @@ std::shared_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(size_t num_cores) {
|
||||
|
||||
void Cpu::RunLoop(bool tight_loop) {
|
||||
// Wait for all other CPU cores to complete the previous slice, such that they run in lock-step
|
||||
if (!cpu_barrier->Rendezvous()) {
|
||||
if (!cpu_barrier->Rendezvous(IsMainCore())) {
|
||||
// If rendezvous failed, session has been killed
|
||||
return;
|
||||
}
|
||||
@@ -89,18 +99,11 @@ void Cpu::RunLoop(bool tight_loop) {
|
||||
// instead advance to the next event and try to yield to the next thread
|
||||
if (Kernel::GetCurrentThread() == nullptr) {
|
||||
LOG_TRACE(Core, "Core-{} idling", core_index);
|
||||
|
||||
if (IsMainCore()) {
|
||||
// TODO(Subv): Only let CoreTiming idle if all 4 cores are idling.
|
||||
CoreTiming::Idle();
|
||||
CoreTiming::Advance();
|
||||
}
|
||||
|
||||
PrepareReschedule();
|
||||
} else {
|
||||
if (IsMainCore()) {
|
||||
CoreTiming::Advance();
|
||||
}
|
||||
|
||||
if (tight_loop) {
|
||||
arm_interface->Run();
|
||||
|
||||
@@ -30,7 +30,7 @@ public:
|
||||
|
||||
void NotifyEnd();
|
||||
|
||||
bool Rendezvous();
|
||||
bool Rendezvous(bool main_core);
|
||||
|
||||
private:
|
||||
unsigned cores_waiting{NUM_CPU_CORES};
|
||||
|
||||
@@ -13,13 +13,16 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/thread.h"
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_cpu.h"
|
||||
#include "core/core_timing_util.h"
|
||||
|
||||
namespace CoreTiming {
|
||||
|
||||
static s64 global_timer;
|
||||
static int slice_length;
|
||||
static int downcount;
|
||||
static int next_slice_length;
|
||||
static std::array<int, Core::NUM_CPU_CORES> downcount;
|
||||
|
||||
struct EventType {
|
||||
TimedCallback callback;
|
||||
@@ -61,7 +64,7 @@ static Common::MPSCQueue<std::pair<const EventType*, u64>, false> unschedule_que
|
||||
|
||||
constexpr int MAX_SLICE_LENGTH = 20000;
|
||||
|
||||
static s64 idled_cycles;
|
||||
static std::mutex mutex;
|
||||
|
||||
// Are we in a function that has been called from Advance()
|
||||
// If events are sheduled from a function that gets called from Advance(),
|
||||
@@ -92,10 +95,11 @@ void UnregisterAllEvents() {
|
||||
}
|
||||
|
||||
void Init() {
|
||||
downcount = MAX_SLICE_LENGTH;
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
downcount.fill(MAX_SLICE_LENGTH);
|
||||
slice_length = MAX_SLICE_LENGTH;
|
||||
next_slice_length = MAX_SLICE_LENGTH;
|
||||
global_timer = 0;
|
||||
idled_cycles = 0;
|
||||
|
||||
// The time between CoreTiming being intialized and the first call to Advance() is considered
|
||||
// the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before
|
||||
@@ -116,19 +120,17 @@ void Shutdown() {
|
||||
// This should only be called from the CPU thread. If you are calling
|
||||
// it from any other thread, you are doing something evil
|
||||
u64 GetTicks() {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
u64 ticks = static_cast<u64>(global_timer);
|
||||
if (!is_global_timer_sane) {
|
||||
ticks += slice_length - downcount;
|
||||
ticks += slice_length - downcount[0];
|
||||
}
|
||||
return ticks;
|
||||
}
|
||||
|
||||
void AddTicks(u64 ticks) {
|
||||
downcount -= static_cast<int>(ticks);
|
||||
}
|
||||
|
||||
u64 GetIdleTicks() {
|
||||
return static_cast<u64>(idled_cycles);
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
downcount[Core::System::GetInstance().CurrentCoreIndex()] -= static_cast<int>(ticks);
|
||||
}
|
||||
|
||||
void ClearPendingEvents() {
|
||||
@@ -146,6 +148,7 @@ void ScheduleEvent(s64 cycles_into_future, const EventType* event_type, u64 user
|
||||
}
|
||||
|
||||
void ScheduleEventThreadsafe(s64 cycles_into_future, const EventType* event_type, u64 userdata) {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
ts_queue.Push(Event{global_timer + cycles_into_future, 0, userdata, event_type});
|
||||
}
|
||||
|
||||
@@ -183,11 +186,14 @@ void RemoveNormalAndThreadsafeEvent(const EventType* event_type) {
|
||||
|
||||
void ForceExceptionCheck(s64 cycles) {
|
||||
cycles = std::max<s64>(0, cycles);
|
||||
if (downcount > cycles) {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
if (downcount[0] > cycles) {
|
||||
// downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int
|
||||
// here. Account for cycles already executed by adjusting the g.slice_length
|
||||
slice_length -= downcount - static_cast<int>(cycles);
|
||||
downcount = static_cast<int>(cycles);
|
||||
slice_length -= downcount[0] - static_cast<int>(cycles);
|
||||
downcount[0] = static_cast<int>(cycles);
|
||||
if (next_slice_length <= 0)
|
||||
next_slice_length = MAX_SLICE_LENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,14 +206,22 @@ void MoveEvents() {
|
||||
}
|
||||
|
||||
void Advance() {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
const size_t current_core = Core::System::GetInstance().CurrentCoreIndex();
|
||||
if (current_core != 0) {
|
||||
downcount[current_core] = MAX_SLICE_LENGTH;
|
||||
return;
|
||||
}
|
||||
|
||||
MoveEvents();
|
||||
for (std::pair<const EventType*, u64> ev; unschedule_queue.Pop(ev);) {
|
||||
UnscheduleEvent(ev.first, ev.second);
|
||||
}
|
||||
|
||||
int cycles_executed = slice_length - downcount;
|
||||
int cycles_executed = slice_length - downcount[0];
|
||||
global_timer += cycles_executed;
|
||||
slice_length = MAX_SLICE_LENGTH;
|
||||
slice_length = next_slice_length;
|
||||
next_slice_length = MAX_SLICE_LENGTH;
|
||||
|
||||
is_global_timer_sane = true;
|
||||
|
||||
@@ -226,12 +240,18 @@ void Advance() {
|
||||
std::min<s64>(event_queue.front().time - global_timer, MAX_SLICE_LENGTH));
|
||||
}
|
||||
|
||||
downcount = slice_length;
|
||||
downcount[0] = slice_length;
|
||||
next_slice_length = MAX_SLICE_LENGTH - slice_length;
|
||||
}
|
||||
|
||||
void Idle() {
|
||||
idled_cycles += downcount;
|
||||
downcount = 0;
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
downcount[Core::System::GetInstance().CurrentCoreIndex()] = 0;
|
||||
}
|
||||
|
||||
bool MainSliceWasCropped() {
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
return next_slice_length != MAX_SLICE_LENGTH;
|
||||
}
|
||||
|
||||
std::chrono::microseconds GetGlobalTimeUs() {
|
||||
@@ -239,7 +259,8 @@ std::chrono::microseconds GetGlobalTimeUs() {
|
||||
}
|
||||
|
||||
int GetDowncount() {
|
||||
return downcount;
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
return downcount[Core::System::GetInstance().CurrentCoreIndex()];
|
||||
}
|
||||
|
||||
} // namespace CoreTiming
|
||||
|
||||
@@ -40,7 +40,6 @@ void Shutdown();
|
||||
* doing something evil
|
||||
*/
|
||||
u64 GetTicks();
|
||||
u64 GetIdleTicks();
|
||||
void AddTicks(u64 ticks);
|
||||
|
||||
/**
|
||||
@@ -83,6 +82,9 @@ void MoveEvents();
|
||||
/// Pretend that the main CPU has executed enough cycles to reach the next event.
|
||||
void Idle();
|
||||
|
||||
/// Checks if the Main Core executed less then MAX_SLICE_LENGTH
|
||||
bool MainSliceWasCropped();
|
||||
|
||||
/// Clear all pending events. This should ONLY be done on exit.
|
||||
void ClearPendingEvents();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user