From b5af41a07bebc0a378428e7d7ddc68c9c750d2d1 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 3 Dec 2018 17:29:21 -0500 Subject: [PATCH] scheduler: Only work steal higher priority threads from other cores --- src/core/hle/kernel/scheduler.cpp | 38 ++++++++++++++----------------- src/core/hle/kernel/scheduler.h | 5 +--- src/core/hle/kernel/svc.cpp | 16 +++++-------- 3 files changed, 24 insertions(+), 35 deletions(-) diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index efe3551e2c..c6b7d5232c 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -170,16 +170,6 @@ void Scheduler::UnscheduleThread(Thread* thread, u32 priority) { ready_queue.remove(priority, thread); } -void Scheduler::MoveThreadToBackOfPriorityQueue(Thread* thread, u32 priority) { - std::lock_guard 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) { std::lock_guard lock(scheduler_mutex); @@ -190,12 +180,13 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) { ready_queue.prepare(priority); } -Thread* Scheduler::GetNextSuggestedThread(u32 core) const { +Thread* Scheduler::GetNextSuggestedThread(u32 core, u32 maximum_priority) const { std::lock_guard lock(scheduler_mutex); const u32 mask = 1U << core; - return ready_queue.get_first_filter( - [mask](Thread const* thread) { return (thread->GetAffinityMask() & mask) != 0; }); + return ready_queue.get_first_filter([mask, maximum_priority](Thread const* thread) { + return (thread->GetAffinityMask() & mask) != 0 && thread->GetPriority() < maximum_priority; + }); } void Scheduler::YieldWithoutLoadBalancing(Thread* thread) { @@ -206,9 +197,10 @@ void Scheduler::YieldWithoutLoadBalancing(Thread* thread) { // Sanity check that the priority is valid 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(); - MoveThreadToBackOfPriorityQueue(thread, thread->GetPriority()); } void Scheduler::YieldWithLoadBalancing(Thread* thread) { @@ -222,9 +214,9 @@ void Scheduler::YieldWithLoadBalancing(Thread* thread) { // Sanity check that the priority is valid ASSERT(priority < THREADPRIO_COUNT); - // Reschedule thread to end of queue. - Reschedule(); - MoveThreadToBackOfPriorityQueue(thread, priority); + // Sleep for zero time to be able to force reschedule to different thread + WaitCurrentThread_Sleep(); + GetCurrentThread()->WakeAfterDelay(0); Thread* suggested_thread = nullptr; @@ -235,16 +227,20 @@ void Scheduler::YieldWithLoadBalancing(Thread* thread) { continue; const auto res = - Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread(core); - if (res != nullptr) { + Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread( + core, priority); + if (res != nullptr && + (suggested_thread == nullptr || suggested_thread->GetPriority() > res->GetPriority())) { suggested_thread = res; - break; } } // If a suggested thread was found, queue that for this core if (suggested_thread != nullptr) suggested_thread->ChangeCore(core, suggested_thread->GetAffinityMask()); + + // Perform actual yielding. + Reschedule(); } void Scheduler::YieldAndWaitForLoadBalancing(Thread* thread) { diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 71b32589a1..97ced4dfc3 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -48,14 +48,11 @@ public: /// Unschedules a thread that was already scheduled 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 void SetThreadPriority(Thread* thread, u32 priority); /// 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 diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index c119f7be17..fabdedd3da 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -984,20 +984,16 @@ static void SleepThread(s64 nanoseconds) { scheduler.YieldAndWaitForLoadBalancing(GetCurrentThread()); break; default: - UNREACHABLE_MSG( - "Unimplemented sleep yield type '{:016X}'! Falling back to forced reschedule...", - nanoseconds); + UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); } + } else { + // Sleep current thread and check for next thread to schedule + WaitCurrentThread_Sleep(); - nanoseconds = 0; + // Create an event to wake the thread up after the specified nanosecond delay has passed + GetCurrentThread()->WakeAfterDelay(nanoseconds); } - // Sleep current thread and check for next thread to schedule - WaitCurrentThread_Sleep(); - - // Create an event to wake the thread up after the specified nanosecond delay has passed - GetCurrentThread()->WakeAfterDelay(nanoseconds); - Core::System::GetInstance().PrepareReschedule(); }