diff options
| author | 2022-06-13 15:48:03 -0700 | |
|---|---|---|
| committer | 2022-06-13 15:48:03 -0700 | |
| commit | 741da9c8bfaa77f96d4c7ddbc82346b2322491db (patch) | |
| tree | d309493a62422a627f7b42aa5f582ce55b68e123 | |
| parent | Merge pull request #8446 from liamwhite/cmd-gdb (diff) | |
| parent | CpuManager: simplify pausing (diff) | |
| download | yuzu-741da9c8bfaa77f96d4c7ddbc82346b2322491db.tar.gz yuzu-741da9c8bfaa77f96d4c7ddbc82346b2322491db.tar.xz yuzu-741da9c8bfaa77f96d4c7ddbc82346b2322491db.zip | |
Merge pull request #8388 from liamwhite/simpler-pause
CpuManager: simplify pausing
| -rw-r--r-- | src/core/cpu_manager.cpp | 116 | ||||
| -rw-r--r-- | src/core/cpu_manager.h | 11 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.cpp | 4 |
3 files changed, 36 insertions, 95 deletions
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 09d9c5163..b4718fbbe 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -16,7 +16,8 @@ | |||
| 16 | 16 | ||
| 17 | namespace Core { | 17 | namespace Core { |
| 18 | 18 | ||
| 19 | CpuManager::CpuManager(System& system_) : system{system_} {} | 19 | CpuManager::CpuManager(System& system_) |
| 20 | : pause_barrier{std::make_unique<Common::Barrier>(1)}, system{system_} {} | ||
| 20 | CpuManager::~CpuManager() = default; | 21 | CpuManager::~CpuManager() = default; |
| 21 | 22 | ||
| 22 | void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, | 23 | void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, |
| @@ -30,8 +31,10 @@ void CpuManager::Initialize() { | |||
| 30 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { | 31 | for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { |
| 31 | core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core); | 32 | core_data[core].host_thread = std::jthread(ThreadStart, std::ref(*this), core); |
| 32 | } | 33 | } |
| 34 | pause_barrier = std::make_unique<Common::Barrier>(Core::Hardware::NUM_CPU_CORES + 1); | ||
| 33 | } else { | 35 | } else { |
| 34 | core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0); | 36 | core_data[0].host_thread = std::jthread(ThreadStart, std::ref(*this), 0); |
| 37 | pause_barrier = std::make_unique<Common::Barrier>(2); | ||
| 35 | } | 38 | } |
| 36 | } | 39 | } |
| 37 | 40 | ||
| @@ -138,51 +141,14 @@ void CpuManager::MultiCoreRunSuspendThread() { | |||
| 138 | auto core = kernel.CurrentPhysicalCoreIndex(); | 141 | auto core = kernel.CurrentPhysicalCoreIndex(); |
| 139 | auto& scheduler = *kernel.CurrentScheduler(); | 142 | auto& scheduler = *kernel.CurrentScheduler(); |
| 140 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | 143 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); |
| 144 | current_thread->DisableDispatch(); | ||
| 145 | |||
| 141 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); | 146 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[core].host_context); |
| 142 | ASSERT(scheduler.ContextSwitchPending()); | ||
| 143 | ASSERT(core == kernel.CurrentPhysicalCoreIndex()); | 147 | ASSERT(core == kernel.CurrentPhysicalCoreIndex()); |
| 144 | scheduler.RescheduleCurrentCore(); | 148 | scheduler.RescheduleCurrentCore(); |
| 145 | } | 149 | } |
| 146 | } | 150 | } |
| 147 | 151 | ||
| 148 | void CpuManager::MultiCorePause(bool paused) { | ||
| 149 | if (!paused) { | ||
| 150 | bool all_not_barrier = false; | ||
| 151 | while (!all_not_barrier) { | ||
| 152 | all_not_barrier = true; | ||
| 153 | for (const auto& data : core_data) { | ||
| 154 | all_not_barrier &= !data.is_running.load() && data.initialized.load(); | ||
| 155 | } | ||
| 156 | } | ||
| 157 | for (auto& data : core_data) { | ||
| 158 | data.enter_barrier->Set(); | ||
| 159 | } | ||
| 160 | if (paused_state.load()) { | ||
| 161 | bool all_barrier = false; | ||
| 162 | while (!all_barrier) { | ||
| 163 | all_barrier = true; | ||
| 164 | for (const auto& data : core_data) { | ||
| 165 | all_barrier &= data.is_paused.load() && data.initialized.load(); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | for (auto& data : core_data) { | ||
| 169 | data.exit_barrier->Set(); | ||
| 170 | } | ||
| 171 | } | ||
| 172 | } else { | ||
| 173 | /// Wait until all cores are paused. | ||
| 174 | bool all_barrier = false; | ||
| 175 | while (!all_barrier) { | ||
| 176 | all_barrier = true; | ||
| 177 | for (const auto& data : core_data) { | ||
| 178 | all_barrier &= data.is_paused.load() && data.initialized.load(); | ||
| 179 | } | ||
| 180 | } | ||
| 181 | /// Don't release the barrier | ||
| 182 | } | ||
| 183 | paused_state = paused; | ||
| 184 | } | ||
| 185 | |||
| 186 | /////////////////////////////////////////////////////////////////////////////// | 152 | /////////////////////////////////////////////////////////////////////////////// |
| 187 | /// SingleCore /// | 153 | /// SingleCore /// |
| 188 | /////////////////////////////////////////////////////////////////////////////// | 154 | /////////////////////////////////////////////////////////////////////////////// |
| @@ -235,8 +201,9 @@ void CpuManager::SingleCoreRunSuspendThread() { | |||
| 235 | auto core = kernel.GetCurrentHostThreadID(); | 201 | auto core = kernel.GetCurrentHostThreadID(); |
| 236 | auto& scheduler = *kernel.CurrentScheduler(); | 202 | auto& scheduler = *kernel.CurrentScheduler(); |
| 237 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); | 203 | Kernel::KThread* current_thread = scheduler.GetCurrentThread(); |
| 204 | current_thread->DisableDispatch(); | ||
| 205 | |||
| 238 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context); | 206 | Common::Fiber::YieldTo(current_thread->GetHostContext(), *core_data[0].host_context); |
| 239 | ASSERT(scheduler.ContextSwitchPending()); | ||
| 240 | ASSERT(core == kernel.GetCurrentHostThreadID()); | 207 | ASSERT(core == kernel.GetCurrentHostThreadID()); |
| 241 | scheduler.RescheduleCurrentCore(); | 208 | scheduler.RescheduleCurrentCore(); |
| 242 | } | 209 | } |
| @@ -274,37 +241,21 @@ void CpuManager::PreemptSingleCore(bool from_running_enviroment) { | |||
| 274 | } | 241 | } |
| 275 | } | 242 | } |
| 276 | 243 | ||
| 277 | void CpuManager::SingleCorePause(bool paused) { | ||
| 278 | if (!paused) { | ||
| 279 | bool all_not_barrier = false; | ||
| 280 | while (!all_not_barrier) { | ||
| 281 | all_not_barrier = !core_data[0].is_running.load() && core_data[0].initialized.load(); | ||
| 282 | } | ||
| 283 | core_data[0].enter_barrier->Set(); | ||
| 284 | if (paused_state.load()) { | ||
| 285 | bool all_barrier = false; | ||
| 286 | while (!all_barrier) { | ||
| 287 | all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load(); | ||
| 288 | } | ||
| 289 | core_data[0].exit_barrier->Set(); | ||
| 290 | } | ||
| 291 | } else { | ||
| 292 | /// Wait until all cores are paused. | ||
| 293 | bool all_barrier = false; | ||
| 294 | while (!all_barrier) { | ||
| 295 | all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load(); | ||
| 296 | } | ||
| 297 | /// Don't release the barrier | ||
| 298 | } | ||
| 299 | paused_state = paused; | ||
| 300 | } | ||
| 301 | |||
| 302 | void CpuManager::Pause(bool paused) { | 244 | void CpuManager::Pause(bool paused) { |
| 303 | if (is_multicore) { | 245 | std::scoped_lock lk{pause_lock}; |
| 304 | MultiCorePause(paused); | 246 | |
| 305 | } else { | 247 | if (pause_state == paused) { |
| 306 | SingleCorePause(paused); | 248 | return; |
| 307 | } | 249 | } |
| 250 | |||
| 251 | // Set the new state | ||
| 252 | pause_state.store(paused); | ||
| 253 | |||
| 254 | // Wake up any waiting threads | ||
| 255 | pause_state.notify_all(); | ||
| 256 | |||
| 257 | // Wait for all threads to successfully change state before returning | ||
| 258 | pause_barrier->Sync(); | ||
| 308 | } | 259 | } |
| 309 | 260 | ||
| 310 | void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { | 261 | void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { |
| @@ -320,27 +271,29 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { | |||
| 320 | Common::SetCurrentThreadName(name.c_str()); | 271 | Common::SetCurrentThreadName(name.c_str()); |
| 321 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); | 272 | Common::SetCurrentThreadPriority(Common::ThreadPriority::High); |
| 322 | auto& data = core_data[core]; | 273 | auto& data = core_data[core]; |
| 323 | data.enter_barrier = std::make_unique<Common::Event>(); | ||
| 324 | data.exit_barrier = std::make_unique<Common::Event>(); | ||
| 325 | data.host_context = Common::Fiber::ThreadToFiber(); | 274 | data.host_context = Common::Fiber::ThreadToFiber(); |
| 326 | data.is_running = false; | ||
| 327 | data.initialized = true; | ||
| 328 | const bool sc_sync = !is_async_gpu && !is_multicore; | 275 | const bool sc_sync = !is_async_gpu && !is_multicore; |
| 329 | bool sc_sync_first_use = sc_sync; | 276 | bool sc_sync_first_use = sc_sync; |
| 330 | 277 | ||
| 331 | // Cleanup | 278 | // Cleanup |
| 332 | SCOPE_EXIT({ | 279 | SCOPE_EXIT({ |
| 333 | data.host_context->Exit(); | 280 | data.host_context->Exit(); |
| 334 | data.enter_barrier.reset(); | ||
| 335 | data.exit_barrier.reset(); | ||
| 336 | data.initialized = false; | ||
| 337 | MicroProfileOnThreadExit(); | 281 | MicroProfileOnThreadExit(); |
| 338 | }); | 282 | }); |
| 339 | 283 | ||
| 340 | /// Running | 284 | /// Running |
| 341 | while (running_mode) { | 285 | while (running_mode) { |
| 342 | data.is_running = false; | 286 | if (pause_state.load(std::memory_order_relaxed)) { |
| 343 | data.enter_barrier->Wait(); | 287 | // Wait for caller to acknowledge pausing |
| 288 | pause_barrier->Sync(); | ||
| 289 | |||
| 290 | // Wait until unpaused | ||
| 291 | pause_state.wait(true, std::memory_order_relaxed); | ||
| 292 | |||
| 293 | // Wait for caller to acknowledge unpausing | ||
| 294 | pause_barrier->Sync(); | ||
| 295 | } | ||
| 296 | |||
| 344 | if (sc_sync_first_use) { | 297 | if (sc_sync_first_use) { |
| 345 | system.GPU().ObtainContext(); | 298 | system.GPU().ObtainContext(); |
| 346 | sc_sync_first_use = false; | 299 | sc_sync_first_use = false; |
| @@ -352,12 +305,7 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { | |||
| 352 | } | 305 | } |
| 353 | 306 | ||
| 354 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); | 307 | auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread(); |
| 355 | data.is_running = true; | ||
| 356 | Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); | 308 | Common::Fiber::YieldTo(data.host_context, *current_thread->GetHostContext()); |
| 357 | data.is_running = false; | ||
| 358 | data.is_paused = true; | ||
| 359 | data.exit_barrier->Wait(); | ||
| 360 | data.is_paused = false; | ||
| 361 | } | 309 | } |
| 362 | } | 310 | } |
| 363 | 311 | ||
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index aee352245..ddd9691ca 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h | |||
| @@ -69,13 +69,11 @@ private: | |||
| 69 | void MultiCoreRunGuestLoop(); | 69 | void MultiCoreRunGuestLoop(); |
| 70 | void MultiCoreRunIdleThread(); | 70 | void MultiCoreRunIdleThread(); |
| 71 | void MultiCoreRunSuspendThread(); | 71 | void MultiCoreRunSuspendThread(); |
| 72 | void MultiCorePause(bool paused); | ||
| 73 | 72 | ||
| 74 | void SingleCoreRunGuestThread(); | 73 | void SingleCoreRunGuestThread(); |
| 75 | void SingleCoreRunGuestLoop(); | 74 | void SingleCoreRunGuestLoop(); |
| 76 | void SingleCoreRunIdleThread(); | 75 | void SingleCoreRunIdleThread(); |
| 77 | void SingleCoreRunSuspendThread(); | 76 | void SingleCoreRunSuspendThread(); |
| 78 | void SingleCorePause(bool paused); | ||
| 79 | 77 | ||
| 80 | static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core); | 78 | static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core); |
| 81 | 79 | ||
| @@ -83,16 +81,13 @@ private: | |||
| 83 | 81 | ||
| 84 | struct CoreData { | 82 | struct CoreData { |
| 85 | std::shared_ptr<Common::Fiber> host_context; | 83 | std::shared_ptr<Common::Fiber> host_context; |
| 86 | std::unique_ptr<Common::Event> enter_barrier; | ||
| 87 | std::unique_ptr<Common::Event> exit_barrier; | ||
| 88 | std::atomic<bool> is_running; | ||
| 89 | std::atomic<bool> is_paused; | ||
| 90 | std::atomic<bool> initialized; | ||
| 91 | std::jthread host_thread; | 84 | std::jthread host_thread; |
| 92 | }; | 85 | }; |
| 93 | 86 | ||
| 94 | std::atomic<bool> running_mode{}; | 87 | std::atomic<bool> running_mode{}; |
| 95 | std::atomic<bool> paused_state{}; | 88 | std::atomic<bool> pause_state{}; |
| 89 | std::unique_ptr<Common::Barrier> pause_barrier{}; | ||
| 90 | std::mutex pause_lock{}; | ||
| 96 | 91 | ||
| 97 | std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{}; | 92 | std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{}; |
| 98 | 93 | ||
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 92f6d8c49..7eb961912 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -252,6 +252,7 @@ struct KernelCore::Impl { | |||
| 252 | core_id) | 252 | core_id) |
| 253 | .IsSuccess()); | 253 | .IsSuccess()); |
| 254 | suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); | 254 | suspend_threads[core_id]->SetName(fmt::format("SuspendThread:{}", core_id)); |
| 255 | suspend_threads[core_id]->DisableDispatch(); | ||
| 255 | } | 256 | } |
| 256 | } | 257 | } |
| 257 | 258 | ||
| @@ -1073,9 +1074,6 @@ void KernelCore::Suspend(bool in_suspention) { | |||
| 1073 | impl->suspend_threads[core_id]->SetState(state); | 1074 | impl->suspend_threads[core_id]->SetState(state); |
| 1074 | impl->suspend_threads[core_id]->SetWaitReasonForDebugging( | 1075 | impl->suspend_threads[core_id]->SetWaitReasonForDebugging( |
| 1075 | ThreadWaitReasonForDebugging::Suspended); | 1076 | ThreadWaitReasonForDebugging::Suspended); |
| 1076 | if (!should_suspend) { | ||
| 1077 | impl->suspend_threads[core_id]->DisableDispatch(); | ||
| 1078 | } | ||
| 1079 | } | 1077 | } |
| 1080 | } | 1078 | } |
| 1081 | } | 1079 | } |