mirror of
https://github.com/yuzu-emu/yuzu-mainline.git
synced 2024-12-27 01:45:41 +00:00
scheduler: Only work steal higher priority threads from other cores
This commit is contained in:
parent
3476830b26
commit
b5af41a07b
|
@ -170,16 +170,6 @@ void Scheduler::UnscheduleThread(Thread* thread, u32 priority) {
|
||||||
ready_queue.remove(priority, thread);
|
ready_queue.remove(priority, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::MoveThreadToBackOfPriorityQueue(Thread* thread, u32 priority) {
|
|
||||||
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
|
||||||
|
|
||||||
// Thread is not in queue
|
|
||||||
ASSERT(ready_queue.contains(thread) != -1);
|
|
||||||
|
|
||||||
ready_queue.remove(priority, thread);
|
|
||||||
ready_queue.push_back(priority, thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
|
void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
|
||||||
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
||||||
|
|
||||||
|
@ -190,12 +180,13 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) {
|
||||||
ready_queue.prepare(priority);
|
ready_queue.prepare(priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread* Scheduler::GetNextSuggestedThread(u32 core) const {
|
Thread* Scheduler::GetNextSuggestedThread(u32 core, u32 maximum_priority) const {
|
||||||
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
std::lock_guard<std::mutex> lock(scheduler_mutex);
|
||||||
|
|
||||||
const u32 mask = 1U << core;
|
const u32 mask = 1U << core;
|
||||||
return ready_queue.get_first_filter(
|
return ready_queue.get_first_filter([mask, maximum_priority](Thread const* thread) {
|
||||||
[mask](Thread const* thread) { return (thread->GetAffinityMask() & mask) != 0; });
|
return (thread->GetAffinityMask() & mask) != 0 && thread->GetPriority() < maximum_priority;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::YieldWithoutLoadBalancing(Thread* thread) {
|
void Scheduler::YieldWithoutLoadBalancing(Thread* thread) {
|
||||||
|
@ -206,9 +197,10 @@ void Scheduler::YieldWithoutLoadBalancing(Thread* thread) {
|
||||||
// Sanity check that the priority is valid
|
// Sanity check that the priority is valid
|
||||||
ASSERT(thread->GetPriority() < THREADPRIO_COUNT);
|
ASSERT(thread->GetPriority() < THREADPRIO_COUNT);
|
||||||
|
|
||||||
// Yield this thread
|
// Yield this thread -- sleep for zero time and force reschedule to different thread
|
||||||
|
WaitCurrentThread_Sleep();
|
||||||
|
GetCurrentThread()->WakeAfterDelay(0);
|
||||||
Reschedule();
|
Reschedule();
|
||||||
MoveThreadToBackOfPriorityQueue(thread, thread->GetPriority());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::YieldWithLoadBalancing(Thread* thread) {
|
void Scheduler::YieldWithLoadBalancing(Thread* thread) {
|
||||||
|
@ -222,9 +214,9 @@ void Scheduler::YieldWithLoadBalancing(Thread* thread) {
|
||||||
// Sanity check that the priority is valid
|
// Sanity check that the priority is valid
|
||||||
ASSERT(priority < THREADPRIO_COUNT);
|
ASSERT(priority < THREADPRIO_COUNT);
|
||||||
|
|
||||||
// Reschedule thread to end of queue.
|
// Sleep for zero time to be able to force reschedule to different thread
|
||||||
Reschedule();
|
WaitCurrentThread_Sleep();
|
||||||
MoveThreadToBackOfPriorityQueue(thread, priority);
|
GetCurrentThread()->WakeAfterDelay(0);
|
||||||
|
|
||||||
Thread* suggested_thread = nullptr;
|
Thread* suggested_thread = nullptr;
|
||||||
|
|
||||||
|
@ -235,16 +227,20 @@ void Scheduler::YieldWithLoadBalancing(Thread* thread) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
const auto res =
|
const auto res =
|
||||||
Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread(core);
|
Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread(
|
||||||
if (res != nullptr) {
|
core, priority);
|
||||||
|
if (res != nullptr &&
|
||||||
|
(suggested_thread == nullptr || suggested_thread->GetPriority() > res->GetPriority())) {
|
||||||
suggested_thread = res;
|
suggested_thread = res;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If a suggested thread was found, queue that for this core
|
// If a suggested thread was found, queue that for this core
|
||||||
if (suggested_thread != nullptr)
|
if (suggested_thread != nullptr)
|
||||||
suggested_thread->ChangeCore(core, suggested_thread->GetAffinityMask());
|
suggested_thread->ChangeCore(core, suggested_thread->GetAffinityMask());
|
||||||
|
|
||||||
|
// Perform actual yielding.
|
||||||
|
Reschedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scheduler::YieldAndWaitForLoadBalancing(Thread* thread) {
|
void Scheduler::YieldAndWaitForLoadBalancing(Thread* thread) {
|
||||||
|
|
|
@ -48,14 +48,11 @@ public:
|
||||||
/// Unschedules a thread that was already scheduled
|
/// Unschedules a thread that was already scheduled
|
||||||
void UnscheduleThread(Thread* thread, u32 priority);
|
void UnscheduleThread(Thread* thread, u32 priority);
|
||||||
|
|
||||||
/// Moves a thread to the back of the current priority queue
|
|
||||||
void MoveThreadToBackOfPriorityQueue(Thread* thread, u32 priority);
|
|
||||||
|
|
||||||
/// Sets the priority of a thread in the scheduler
|
/// Sets the priority of a thread in the scheduler
|
||||||
void SetThreadPriority(Thread* thread, u32 priority);
|
void SetThreadPriority(Thread* thread, u32 priority);
|
||||||
|
|
||||||
/// Gets the next suggested thread for load balancing
|
/// Gets the next suggested thread for load balancing
|
||||||
Thread* GetNextSuggestedThread(u32 core) const;
|
Thread* GetNextSuggestedThread(u32 core, u32 minimum_priority) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* YieldWithoutLoadBalancing -- analogous to normal yield on a system
|
* YieldWithoutLoadBalancing -- analogous to normal yield on a system
|
||||||
|
|
|
@ -984,19 +984,15 @@ static void SleepThread(s64 nanoseconds) {
|
||||||
scheduler.YieldAndWaitForLoadBalancing(GetCurrentThread());
|
scheduler.YieldAndWaitForLoadBalancing(GetCurrentThread());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE_MSG(
|
UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
|
||||||
"Unimplemented sleep yield type '{:016X}'! Falling back to forced reschedule...",
|
|
||||||
nanoseconds);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
nanoseconds = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sleep current thread and check for next thread to schedule
|
// Sleep current thread and check for next thread to schedule
|
||||||
WaitCurrentThread_Sleep();
|
WaitCurrentThread_Sleep();
|
||||||
|
|
||||||
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||||
GetCurrentThread()->WakeAfterDelay(nanoseconds);
|
GetCurrentThread()->WakeAfterDelay(nanoseconds);
|
||||||
|
}
|
||||||
|
|
||||||
Core::System::GetInstance().PrepareReschedule();
|
Core::System::GetInstance().PrepareReschedule();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue