Compare commits

...

2 Commits

4 changed files with 59 additions and 33 deletions

View File

@@ -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();
}
CoreTiming::Idle();
CoreTiming::Advance();
PrepareReschedule();
} else {
if (IsMainCore()) {
CoreTiming::Advance();
}
CoreTiming::Advance();
if (tight_loop) {
arm_interface->Run();

View File

@@ -30,7 +30,7 @@ public:
void NotifyEnd();
bool Rendezvous();
bool Rendezvous(bool main_core);
private:
unsigned cores_waiting{NUM_CPU_CORES};

View File

@@ -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;
@@ -58,7 +61,7 @@ static Common::MPSCQueue<Event, false> ts_queue;
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(),
@@ -89,10 +92,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
@@ -113,19 +117,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() {
@@ -143,6 +145,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});
}
@@ -176,11 +179,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;
}
}
@@ -193,11 +199,19 @@ 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();
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;
@@ -216,12 +230,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() {
@@ -229,7 +249,8 @@ std::chrono::microseconds GetGlobalTimeUs() {
}
int GetDowncount() {
return downcount;
std::unique_lock<std::mutex> lock(mutex);
return downcount[Core::System::GetInstance().CurrentCoreIndex()];
}
} // namespace CoreTiming

View File

@@ -40,7 +40,6 @@ void Shutdown();
* doing something evil
*/
u64 GetTicks();
u64 GetIdleTicks();
void AddTicks(u64 ticks);
/**
@@ -82,6 +81,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();