From 409dcf0e0aecfdb676fd3b64223a25e47c1b1c1a Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 18 Nov 2018 23:44:19 -0500 Subject: svc: Implement yield types 0 and -1 --- src/core/hle/kernel/scheduler.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/core/hle/kernel/scheduler.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 5a5f4cef1..fb5e14950 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -169,6 +169,16 @@ void Scheduler::UnscheduleThread(Thread* thread, u32 priority) { ready_queue.remove(priority, thread); } +void Scheduler::RescheduleThread(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); @@ -179,4 +189,12 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) { ready_queue.prepare(priority); } +Thread* Scheduler::GetNextSuggestedThread(u32 core) { + std::lock_guard lock(scheduler_mutex); + + const auto mask = 1 << core; + return ready_queue.get_first_filter( + [&mask](Thread* thread) { return (thread->GetAffinityMask() & mask) != 0; }); +} + } // namespace Kernel -- cgit v1.2.3 From 820d81b9a5392951c18daa5a47d6c0ffd28baa9b Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Thu, 22 Nov 2018 00:33:53 -0500 Subject: scheduler: Add explanations for YieldWith and WithoutLoadBalancing --- src/core/hle/kernel/scheduler.cpp | 61 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 4 deletions(-) (limited to 'src/core/hle/kernel/scheduler.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index fb5e14950..624c841ad 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "core/arm/arm_interface.h" #include "core/core.h" +#include "core/core_cpu.h" #include "core/core_timing.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" @@ -169,7 +170,7 @@ void Scheduler::UnscheduleThread(Thread* thread, u32 priority) { ready_queue.remove(priority, thread); } -void Scheduler::RescheduleThread(Thread* thread, u32 priority) { +void Scheduler::MoveThreadToBackOfPriorityQueue(Thread* thread, u32 priority) { std::lock_guard lock(scheduler_mutex); // Thread is not in queue @@ -189,12 +190,64 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) { ready_queue.prepare(priority); } -Thread* Scheduler::GetNextSuggestedThread(u32 core) { +Thread* Scheduler::GetNextSuggestedThread(u32 core) const { std::lock_guard lock(scheduler_mutex); - const auto mask = 1 << core; + const u32 mask = 1U << core; return ready_queue.get_first_filter( - [&mask](Thread* thread) { return (thread->GetAffinityMask() & mask) != 0; }); + [mask](Thread const* thread) { return (thread->GetAffinityMask() & mask) != 0; }); +} + +void Scheduler::YieldWithoutLoadBalancing(Thread* thread) { + ASSERT(thread != nullptr); + // Avoid yielding if the thread isn't even running. + ASSERT(thread->GetStatus() == ThreadStatus::Running); + + // Sanity check that the priority is valid + ASSERT(thread->GetPriority() < THREADPRIO_COUNT); + + // Yield this thread + MoveThreadToBackOfPriorityQueue(thread, thread->GetPriority()); + Reschedule(); +} + +void Scheduler::YieldWithLoadBalancing(Thread* thread) { + ASSERT(thread != nullptr); + const auto priority = thread->GetPriority(); + const auto core = static_cast(thread->GetProcessorID()); + + // Avoid yielding if the thread isn't even running. + ASSERT(thread->GetStatus() == ThreadStatus::Running); + + // Sanity check that the priority is valid + ASSERT(priority < THREADPRIO_COUNT); + + // Reschedule thread to end of queue. + MoveThreadToBackOfPriorityQueue(thread, priority); + + Thread* suggested_thread = nullptr; + + // Search through all of the cpu cores (except this one) for a suggested thread. + // Take the first non-nullptr one + for (unsigned cur_core = 0; cur_core < Core::NUM_CPU_CORES; ++cur_core) { + if (cur_core == core) + continue; + + const auto res = + Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread(core); + if (res != nullptr) { + 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()); +} + +void Scheduler::YieldAndWaitForLoadBalancing(Thread* thread) { + UNIMPLEMENTED_MSG("Wait for load balancing thread yield type is not implemented!"); } } // namespace Kernel -- cgit v1.2.3 From 3476830b26b61410b633c827e985bffa1dc52528 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sun, 2 Dec 2018 00:44:40 -0500 Subject: svc: Avoid performance-degrading unnecessary reschedule --- src/core/hle/kernel/scheduler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/core/hle/kernel/scheduler.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 624c841ad..efe3551e2 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -207,8 +207,8 @@ void Scheduler::YieldWithoutLoadBalancing(Thread* thread) { ASSERT(thread->GetPriority() < THREADPRIO_COUNT); // Yield this thread - MoveThreadToBackOfPriorityQueue(thread, thread->GetPriority()); Reschedule(); + MoveThreadToBackOfPriorityQueue(thread, thread->GetPriority()); } void Scheduler::YieldWithLoadBalancing(Thread* thread) { @@ -223,6 +223,7 @@ void Scheduler::YieldWithLoadBalancing(Thread* thread) { ASSERT(priority < THREADPRIO_COUNT); // Reschedule thread to end of queue. + Reschedule(); MoveThreadToBackOfPriorityQueue(thread, priority); Thread* suggested_thread = nullptr; -- cgit v1.2.3 From b5af41a07bebc0a378428e7d7ddc68c9c750d2d1 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 3 Dec 2018 17:29:21 -0500 Subject: scheduler: Only work steal higher priority threads from other cores --- src/core/hle/kernel/scheduler.cpp | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) (limited to 'src/core/hle/kernel/scheduler.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index efe3551e2..c6b7d5232 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) { -- cgit v1.2.3 From ddf5903cd9c05f1fecd8a5b8e8ad702b9b20eef8 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 3 Dec 2018 21:22:09 -0500 Subject: scheduler: Avoid manual Reschedule call This will automatically occur anyway when PrepareReschedule is called--- src/core/hle/kernel/scheduler.cpp | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'src/core/hle/kernel/scheduler.cpp') diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index c6b7d5232..df4d6cf0a 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -200,7 +200,6 @@ void Scheduler::YieldWithoutLoadBalancing(Thread* thread) { // Yield this thread -- sleep for zero time and force reschedule to different thread WaitCurrentThread_Sleep(); GetCurrentThread()->WakeAfterDelay(0); - Reschedule(); } void Scheduler::YieldWithLoadBalancing(Thread* thread) { @@ -223,24 +222,23 @@ void Scheduler::YieldWithLoadBalancing(Thread* thread) { // Search through all of the cpu cores (except this one) for a suggested thread. // Take the first non-nullptr one for (unsigned cur_core = 0; cur_core < Core::NUM_CPU_CORES; ++cur_core) { - if (cur_core == core) - continue; - const auto res = Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread( core, priority); - if (res != nullptr && - (suggested_thread == nullptr || suggested_thread->GetPriority() > res->GetPriority())) { - suggested_thread = res; + + // If scheduler provides a suggested thread + if (res != nullptr) { + // And its better than the current suggested thread (or is the first valid one) + if (suggested_thread == nullptr || + suggested_thread->GetPriority() > res->GetPriority()) { + suggested_thread = res; + } } } // 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) { -- cgit v1.2.3