diff options
| author | 2018-12-03 17:29:21 -0500 | |
|---|---|---|
| committer | 2018-12-03 17:29:30 -0500 | |
| commit | b5af41a07bebc0a378428e7d7ddc68c9c750d2d1 (patch) | |
| tree | 97d4e53060fda78d6445ddd99ad24b36b38cec14 | |
| parent | svc: Avoid performance-degrading unnecessary reschedule (diff) | |
| download | yuzu-b5af41a07bebc0a378428e7d7ddc68c9c750d2d1.tar.gz yuzu-b5af41a07bebc0a378428e7d7ddc68c9c750d2d1.tar.xz yuzu-b5af41a07bebc0a378428e7d7ddc68c9c750d2d1.zip | |
scheduler: Only work steal higher priority threads from other cores
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/kernel/scheduler.cpp | 38 | ||||
| -rw-r--r-- | src/core/hle/kernel/scheduler.h | 5 | ||||
| -rw-r--r-- | 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 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) { | |||
| 170 | ready_queue.remove(priority, thread); | 170 | ready_queue.remove(priority, thread); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | void Scheduler::MoveThreadToBackOfPriorityQueue(Thread* thread, u32 priority) { | ||
| 174 | std::lock_guard<std::mutex> lock(scheduler_mutex); | ||
| 175 | |||
| 176 | // Thread is not in queue | ||
| 177 | ASSERT(ready_queue.contains(thread) != -1); | ||
| 178 | |||
| 179 | ready_queue.remove(priority, thread); | ||
| 180 | ready_queue.push_back(priority, thread); | ||
| 181 | } | ||
| 182 | |||
| 183 | void Scheduler::SetThreadPriority(Thread* thread, u32 priority) { | 173 | void Scheduler::SetThreadPriority(Thread* thread, u32 priority) { |
| 184 | std::lock_guard<std::mutex> lock(scheduler_mutex); | 174 | std::lock_guard<std::mutex> lock(scheduler_mutex); |
| 185 | 175 | ||
| @@ -190,12 +180,13 @@ void Scheduler::SetThreadPriority(Thread* thread, u32 priority) { | |||
| 190 | ready_queue.prepare(priority); | 180 | ready_queue.prepare(priority); |
| 191 | } | 181 | } |
| 192 | 182 | ||
| 193 | Thread* Scheduler::GetNextSuggestedThread(u32 core) const { | 183 | Thread* Scheduler::GetNextSuggestedThread(u32 core, u32 maximum_priority) const { |
| 194 | std::lock_guard<std::mutex> lock(scheduler_mutex); | 184 | std::lock_guard<std::mutex> lock(scheduler_mutex); |
| 195 | 185 | ||
| 196 | const u32 mask = 1U << core; | 186 | const u32 mask = 1U << core; |
| 197 | return ready_queue.get_first_filter( | 187 | return ready_queue.get_first_filter([mask, maximum_priority](Thread const* thread) { |
| 198 | [mask](Thread const* thread) { return (thread->GetAffinityMask() & mask) != 0; }); | 188 | return (thread->GetAffinityMask() & mask) != 0 && thread->GetPriority() < maximum_priority; |
| 189 | }); | ||
| 199 | } | 190 | } |
| 200 | 191 | ||
| 201 | void Scheduler::YieldWithoutLoadBalancing(Thread* thread) { | 192 | void Scheduler::YieldWithoutLoadBalancing(Thread* thread) { |
| @@ -206,9 +197,10 @@ void Scheduler::YieldWithoutLoadBalancing(Thread* thread) { | |||
| 206 | // Sanity check that the priority is valid | 197 | // Sanity check that the priority is valid |
| 207 | ASSERT(thread->GetPriority() < THREADPRIO_COUNT); | 198 | ASSERT(thread->GetPriority() < THREADPRIO_COUNT); |
| 208 | 199 | ||
| 209 | // Yield this thread | 200 | // Yield this thread -- sleep for zero time and force reschedule to different thread |
| 201 | WaitCurrentThread_Sleep(); | ||
| 202 | GetCurrentThread()->WakeAfterDelay(0); | ||
| 210 | Reschedule(); | 203 | Reschedule(); |
| 211 | MoveThreadToBackOfPriorityQueue(thread, thread->GetPriority()); | ||
| 212 | } | 204 | } |
| 213 | 205 | ||
| 214 | void Scheduler::YieldWithLoadBalancing(Thread* thread) { | 206 | void Scheduler::YieldWithLoadBalancing(Thread* thread) { |
| @@ -222,9 +214,9 @@ void Scheduler::YieldWithLoadBalancing(Thread* thread) { | |||
| 222 | // Sanity check that the priority is valid | 214 | // Sanity check that the priority is valid |
| 223 | ASSERT(priority < THREADPRIO_COUNT); | 215 | ASSERT(priority < THREADPRIO_COUNT); |
| 224 | 216 | ||
| 225 | // Reschedule thread to end of queue. | 217 | // Sleep for zero time to be able to force reschedule to different thread |
| 226 | Reschedule(); | 218 | WaitCurrentThread_Sleep(); |
| 227 | MoveThreadToBackOfPriorityQueue(thread, priority); | 219 | GetCurrentThread()->WakeAfterDelay(0); |
| 228 | 220 | ||
| 229 | Thread* suggested_thread = nullptr; | 221 | Thread* suggested_thread = nullptr; |
| 230 | 222 | ||
| @@ -235,16 +227,20 @@ void Scheduler::YieldWithLoadBalancing(Thread* thread) { | |||
| 235 | continue; | 227 | continue; |
| 236 | 228 | ||
| 237 | const auto res = | 229 | const auto res = |
| 238 | Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread(core); | 230 | Core::System::GetInstance().CpuCore(cur_core).Scheduler().GetNextSuggestedThread( |
| 239 | if (res != nullptr) { | 231 | core, priority); |
| 232 | if (res != nullptr && | ||
| 233 | (suggested_thread == nullptr || suggested_thread->GetPriority() > res->GetPriority())) { | ||
| 240 | suggested_thread = res; | 234 | suggested_thread = res; |
| 241 | break; | ||
| 242 | } | 235 | } |
| 243 | } | 236 | } |
| 244 | 237 | ||
| 245 | // If a suggested thread was found, queue that for this core | 238 | // If a suggested thread was found, queue that for this core |
| 246 | if (suggested_thread != nullptr) | 239 | if (suggested_thread != nullptr) |
| 247 | suggested_thread->ChangeCore(core, suggested_thread->GetAffinityMask()); | 240 | suggested_thread->ChangeCore(core, suggested_thread->GetAffinityMask()); |
| 241 | |||
| 242 | // Perform actual yielding. | ||
| 243 | Reschedule(); | ||
| 248 | } | 244 | } |
| 249 | 245 | ||
| 250 | void Scheduler::YieldAndWaitForLoadBalancing(Thread* thread) { | 246 | void Scheduler::YieldAndWaitForLoadBalancing(Thread* thread) { |
diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 71b32589a..97ced4dfc 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h | |||
| @@ -48,14 +48,11 @@ public: | |||
| 48 | /// Unschedules a thread that was already scheduled | 48 | /// Unschedules a thread that was already scheduled |
| 49 | void UnscheduleThread(Thread* thread, u32 priority); | 49 | void UnscheduleThread(Thread* thread, u32 priority); |
| 50 | 50 | ||
| 51 | /// Moves a thread to the back of the current priority queue | ||
| 52 | void MoveThreadToBackOfPriorityQueue(Thread* thread, u32 priority); | ||
| 53 | |||
| 54 | /// Sets the priority of a thread in the scheduler | 51 | /// Sets the priority of a thread in the scheduler |
| 55 | void SetThreadPriority(Thread* thread, u32 priority); | 52 | void SetThreadPriority(Thread* thread, u32 priority); |
| 56 | 53 | ||
| 57 | /// Gets the next suggested thread for load balancing | 54 | /// Gets the next suggested thread for load balancing |
| 58 | Thread* GetNextSuggestedThread(u32 core) const; | 55 | Thread* GetNextSuggestedThread(u32 core, u32 minimum_priority) const; |
| 59 | 56 | ||
| 60 | /** | 57 | /** |
| 61 | * YieldWithoutLoadBalancing -- analogous to normal yield on a system | 58 | * 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 c119f7be1..fabdedd3d 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -984,20 +984,16 @@ static void SleepThread(s64 nanoseconds) { | |||
| 984 | scheduler.YieldAndWaitForLoadBalancing(GetCurrentThread()); | 984 | scheduler.YieldAndWaitForLoadBalancing(GetCurrentThread()); |
| 985 | break; | 985 | break; |
| 986 | default: | 986 | default: |
| 987 | UNREACHABLE_MSG( | 987 | UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds); |
| 988 | "Unimplemented sleep yield type '{:016X}'! Falling back to forced reschedule...", | ||
| 989 | nanoseconds); | ||
| 990 | } | 988 | } |
| 989 | } else { | ||
| 990 | // Sleep current thread and check for next thread to schedule | ||
| 991 | WaitCurrentThread_Sleep(); | ||
| 991 | 992 | ||
| 992 | nanoseconds = 0; | 993 | // Create an event to wake the thread up after the specified nanosecond delay has passed |
| 994 | GetCurrentThread()->WakeAfterDelay(nanoseconds); | ||
| 993 | } | 995 | } |
| 994 | 996 | ||
| 995 | // Sleep current thread and check for next thread to schedule | ||
| 996 | WaitCurrentThread_Sleep(); | ||
| 997 | |||
| 998 | // Create an event to wake the thread up after the specified nanosecond delay has passed | ||
| 999 | GetCurrentThread()->WakeAfterDelay(nanoseconds); | ||
| 1000 | |||
| 1001 | Core::System::GetInstance().PrepareReschedule(); | 997 | Core::System::GetInstance().PrepareReschedule(); |
| 1002 | } | 998 | } |
| 1003 | 999 | ||