Skip to content

Commit

Permalink
coreinit: Fix thread scheduler not resetting quantum
Browse files Browse the repository at this point in the history
When a thread was force-rescheduled (e.g. via OSYieldThread) the next time it resumed it would not reset the time slice duration (remainingCycles) back to ppcThreadQuantum. As a consequence threads were often immediately rescheduled and only on the next turn they would get their full time slice.

Aside from (very slightly) improving performance, this also fixes the OSDisableInterrupts warning spam in the log for TPHD.
  • Loading branch information
Exzap committed Feb 22, 2023
1 parent 9d25b88 commit 80b1c50
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 15 deletions.
5 changes: 1 addition & 4 deletions src/Cafe/OS/libs/coreinit/coreinit_Scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ namespace coreinit
// disables interrupts and scheduling
uint32 OSDisableInterrupts()
{
// todo - rename SchedulerLock.cpp/h to Scheduler.cpp and move this there?
PPCInterpreter_t* hCPU = PPCInterpreter_getCurrentInstance();
if (hCPU == nullptr)
return 0;
Expand All @@ -77,9 +76,7 @@ namespace coreinit
{
// we have no efficient method to turn off scheduling completely, so instead we just increase the remaining cycles
if (hCPU->remainingCycles >= 0x40000000)
{
forceLogDebug_printf("OSDisableInterrupts(): Warning - Interrupts already disabled? remCycles %08x LR %08x", hCPU->remainingCycles, hCPU->spr.LR);
}
cemuLog_log(LogType::Force, "OSDisableInterrupts(): Warning - Interrupts already disabled but the mask was still set? remCycles {:08x} LR {:08x}", hCPU->remainingCycles, hCPU->spr.LR);
hCPU->remainingCycles += 0x40000000;
}
hCPU->coreInterruptMask = 0;
Expand Down
30 changes: 19 additions & 11 deletions src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -962,6 +962,22 @@ namespace coreinit
thread->wakeUpCount = thread->wakeUpCount + 1;
}

uint32 s_lehmer_lcg[PPC_CORE_COUNT] = { 0 };

void __OSThreadStartTimeslice(OSThread_t* thread, PPCInterpreter_t* hCPU)
{
uint32 coreIndex = PPCInterpreter_getCoreIndex(hCPU);
// run one timeslice
hCPU->remainingCycles = ppcThreadQuantum;
hCPU->skippedCycles = 0;
// we add a slight randomized variance to the thread quantum to avoid getting stuck in repeated code sequences where one or multiple threads always unload inside a lock
// this was seen in Mario Party 10 during early boot where several OSLockMutex operations would align in such a way that one thread would never successfully acquire the lock
if (s_lehmer_lcg[coreIndex] == 0)
s_lehmer_lcg[coreIndex] = 12345;
hCPU->remainingCycles += (s_lehmer_lcg[coreIndex] & 0x7F);
s_lehmer_lcg[coreIndex] = (uint32)((uint64)s_lehmer_lcg[coreIndex] * 279470273ull % 0xfffffffbull);
}

OSThread_t* __OSGetNextRunableThread(uint32 coreIndex)
{
cemu_assert_debug(__OSHasSchedulerLock());
Expand Down Expand Up @@ -1088,8 +1104,9 @@ namespace coreinit
cemu_assert_debug(__OSHasSchedulerLock());
cemu_assert_debug(g_isMulticoreMode == false || hostThread->selectedCore == t_assignedCoreIndex);

// load self thread
// received next time slice, load self again
__OSLoadThread(hostThread->m_thread, &hostThread->ppcInstance, hostThread->selectedCore);
__OSThreadStartTimeslice(hostThread->m_thread, &hostThread->ppcInstance);
}

void __OSFiberThreadEntry(void* _thread)
Expand All @@ -1100,21 +1117,12 @@ namespace coreinit
_mm_setcsr(_mm_getcsr() | 0x8000); // flush denormals to zero
#endif

uint32 lehmer_lcg = 12345;

PPCInterpreter_t* hCPU = &hostThread->ppcInstance;
__OSLoadThread(hostThread->m_thread, hCPU, hostThread->selectedCore);
__OSThreadStartTimeslice(hostThread->m_thread, &hostThread->ppcInstance);
__OSUnlockScheduler(); // lock is always held when switching to a fiber, so we need to unlock it here
while (true)
{
// run one timeslice
hCPU->remainingCycles = ppcThreadQuantum;
hCPU->skippedCycles = 0;
// we add a slight randomized variance to the thread quantum to avoid getting stuck in repeated code sequences where the duration matches the thread quantum perfectly
// this was seen in Mario Party 10 on launch where several OSLockMutex operations would align in such a way that one thread would never successfully acquire the lock
hCPU->remainingCycles += (lehmer_lcg & 0x7F);
lehmer_lcg = (uint32)((uint64)lehmer_lcg * 279470273ull % 0xfffffffbull);

if (hCPU->remainingCycles > 0)
{
// try to enter recompiler immediately
Expand Down

0 comments on commit 80b1c50

Please sign in to comment.