Просмотр исходного кода

Kernel: Preempt Single core on redudant yields.

Fernando Sahmkow 6 лет назад
Родитель
Сommit
d494b074e8

+ 2 - 2
src/core/cpu_manager.h

@@ -45,6 +45,8 @@ public:
     std::function<void(void*)> GetSuspendThreadStartFunc();
     void* GetStartFuncParamater();
 
+    void PreemptSingleCore();
+
     std::size_t CurrentCore() const {
         return current_core.load();
     }
@@ -71,8 +73,6 @@ private:
 
     void RunThread(std::size_t core);
 
-    void PreemptSingleCore();
-
     struct CoreData {
         std::shared_ptr<Common::Fiber> host_context;
         std::unique_ptr<Common::Event> enter_barrier;

+ 4 - 0
src/core/hle/kernel/kernel.cpp

@@ -642,6 +642,10 @@ void KernelCore::Suspend(bool in_suspention) {
     }
 }
 
+bool KernelCore::IsMulticore() const {
+    return impl->is_multicore;
+}
+
 void KernelCore::ExceptionalExit() {
     exception_exited = true;
     Suspend(true);

+ 2 - 0
src/core/hle/kernel/kernel.h

@@ -212,6 +212,8 @@ public:
     /// Exceptional exit the OS.
     void ExceptionalExit();
 
+    bool IsMulticore() const;
+
 private:
     friend class Object;
     friend class Process;

+ 17 - 6
src/core/hle/kernel/svc.cpp

@@ -19,6 +19,7 @@
 #include "core/core_manager.h"
 #include "core/core_timing.h"
 #include "core/core_timing_util.h"
+#include "core/cpu_manager.h"
 #include "core/hle/kernel/address_arbiter.h"
 #include "core/hle/kernel/client_port.h"
 #include "core/hle/kernel/client_session.h"
@@ -1509,21 +1510,31 @@ static void SleepThread(Core::System& system, s64 nanoseconds) {
 
     if (nanoseconds <= 0) {
         switch (static_cast<SleepType>(nanoseconds)) {
-        case SleepType::YieldWithoutLoadBalancing:
-            current_thread->YieldSimple();
+        case SleepType::YieldWithoutLoadBalancing: {
+            auto pair = current_thread->YieldSimple();
+            is_redundant = pair.second;
             break;
-        case SleepType::YieldWithLoadBalancing:
-            current_thread->YieldAndBalanceLoad();
+        }
+        case SleepType::YieldWithLoadBalancing: {
+            auto pair = current_thread->YieldAndBalanceLoad();
+            is_redundant = pair.second;
             break;
-        case SleepType::YieldAndWaitForLoadBalancing:
-            current_thread->YieldAndWaitForLoadBalancing();
+        }
+        case SleepType::YieldAndWaitForLoadBalancing: {
+            auto pair = current_thread->YieldAndWaitForLoadBalancing();
+            is_redundant = pair.second;
             break;
+        }
         default:
             UNREACHABLE_MSG("Unimplemented sleep yield type '{:016X}'!", nanoseconds);
         }
     } else {
         current_thread->Sleep(nanoseconds);
     }
+
+    if (is_redundant && !system.Kernel().IsMulticore()) {
+        system.GetCpuManager().PreemptSingleCore();
+    }
 }
 
 /// Wait process wide key atomic

+ 12 - 9
src/core/hle/kernel/thread.cpp

@@ -435,28 +435,31 @@ ResultCode Thread::Sleep(s64 nanoseconds) {
     return RESULT_SUCCESS;
 }
 
-ResultCode Thread::YieldSimple() {
+std::pair<ResultCode, bool> Thread::YieldSimple() {
+    bool is_redundant = false;
     {
         SchedulerLock lock(kernel);
-        kernel.GlobalScheduler().YieldThread(this);
+        is_redundant = kernel.GlobalScheduler().YieldThread(this);
     }
-    return RESULT_SUCCESS;
+    return {RESULT_SUCCESS, is_redundant};
 }
 
-ResultCode Thread::YieldAndBalanceLoad() {
+std::pair<ResultCode, bool> Thread::YieldAndBalanceLoad() {
+    bool is_redundant = false;
     {
         SchedulerLock lock(kernel);
-        kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this);
+        is_redundant = kernel.GlobalScheduler().YieldThreadAndBalanceLoad(this);
     }
-    return RESULT_SUCCESS;
+    return {RESULT_SUCCESS, is_redundant};
 }
 
-ResultCode Thread::YieldAndWaitForLoadBalancing() {
+std::pair<ResultCode, bool> Thread::YieldAndWaitForLoadBalancing() {
+    bool is_redundant = false;
     {
         SchedulerLock lock(kernel);
-        kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this);
+        is_redundant = kernel.GlobalScheduler().YieldThreadAndWaitForLoadBalancing(this);
     }
-    return RESULT_SUCCESS;
+    return {RESULT_SUCCESS, is_redundant};
 }
 
 void Thread::AddSchedulingFlag(ThreadSchedFlags flag) {

+ 5 - 4
src/core/hle/kernel/thread.h

@@ -6,6 +6,7 @@
 
 #include <functional>
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "common/common_types.h"
@@ -503,13 +504,13 @@ public:
     ResultCode Sleep(s64 nanoseconds);
 
     /// Yields this thread without rebalancing loads.
-    ResultCode YieldSimple();
+    std::pair<ResultCode, bool> YieldSimple();
 
     /// Yields this thread and does a load rebalancing.
-    ResultCode YieldAndBalanceLoad();
+    std::pair<ResultCode, bool> YieldAndBalanceLoad();
 
     /// Yields this thread and if the core is left idle, loads are rebalanced
-    ResultCode YieldAndWaitForLoadBalancing();
+    std::pair<ResultCode, bool> YieldAndWaitForLoadBalancing();
 
     void IncrementYieldCount() {
         yield_count++;
@@ -587,7 +588,7 @@ private:
     ThreadContext32 context_32{};
     ThreadContext64 context_64{};
     Common::SpinLock context_guard{};
-    std::shared_ptr<Common::Fiber> host_context{};
+    std::shared_ptr<Common::Fiber> host_context{};
 
     u64 thread_id = 0;