diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 751549583e..37be99b502 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -44,7 +44,6 @@ void LogSettings() { log_setting("System_LanguageIndex", values.language_index.GetValue()); log_setting("System_RegionIndex", values.region_index.GetValue()); log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue()); - log_setting("Core_UseMultiCore", values.use_multi_core.GetValue()); log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue()); log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue()); log_setting("Renderer_ScalingFilter", values.scaling_filter.GetValue()); @@ -166,7 +165,6 @@ void RestoreGlobalState(bool is_powered_on) { values.volume.SetGlobal(true); // Core - values.use_multi_core.SetGlobal(true); values.use_extended_memory_layout.SetGlobal(true); // CPU diff --git a/src/common/settings.h b/src/common/settings.h index a507744a22..f1d5e6c501 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -465,7 +465,6 @@ struct Values { RangedSetting volume{100, 0, 100, "volume"}; // Core - Setting use_multi_core{true, "use_multi_core"}; Setting use_extended_memory_layout{false, "use_extended_memory_layout"}; // Cpu diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 8a066ed914..97f418753b 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -37,10 +37,8 @@ public: YUZU_NON_COPYABLE(ARM_Interface); YUZU_NON_MOVEABLE(ARM_Interface); - explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_, - bool uses_wall_clock_) - : system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{ - uses_wall_clock_} {} + explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_) + : system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{true} {} virtual ~ARM_Interface() = default; struct ThreadContext32 { diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 10cf72a452..83a4a16590 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -125,26 +125,11 @@ public: } void AddTicks(u64 ticks) override { - ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); - - // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a - // rough approximation of the amount of executed ticks in the system, it may be thrown off - // if not all cores are doing a similar amount of work. Instead of doing this, we should - // device a way so that timing is consistent across all cores without increasing the ticks 4 - // times. - u64 amortized_ticks = - (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES; - // Always execute at least one tick. - amortized_ticks = std::max(amortized_ticks, 1); - - parent.system.CoreTiming().AddTicks(amortized_ticks); - num_interpreted_instructions = 0; + UNREACHABLE(); } u64 GetTicksRemaining() override { - ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); - - return std::max(parent.system.CoreTiming().GetDowncount(), 0); + UNREACHABLE(); } bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) { @@ -172,7 +157,6 @@ public: Core::Memory::Memory& memory; std::size_t num_interpreted_instructions{}; bool debugger_enabled{}; - static constexpr u64 minimum_run_cycles = 1000U; }; std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const { @@ -314,10 +298,8 @@ void ARM_Dynarmic_32::RewindBreakpointInstruction() { } ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, - bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, - std::size_t core_index_) - : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_}, - cb(std::make_unique(*this)), + ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_) + : ARM_Interface{system_, interrupt_handlers_}, cb(std::make_unique(*this)), cp15(std::make_shared(*this)), core_index{core_index_}, exclusive_monitor{dynamic_cast(exclusive_monitor_)}, null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {} diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index fcbe24f0c3..cf32cb4d07 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -28,7 +28,7 @@ class System; class ARM_Dynarmic_32 final : public ARM_Interface { public: - ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_, + ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); ~ARM_Dynarmic_32() override; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 92266aa9e8..b3d3ffca6f 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -166,24 +166,11 @@ public: } void AddTicks(u64 ticks) override { - ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); - - // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a - // rough approximation of the amount of executed ticks in the system, it may be thrown off - // if not all cores are doing a similar amount of work. Instead of doing this, we should - // device a way so that timing is consistent across all cores without increasing the ticks 4 - // times. - u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES; - // Always execute at least one tick. - amortized_ticks = std::max(amortized_ticks, 1); - - parent.system.CoreTiming().AddTicks(amortized_ticks); + UNREACHABLE(); } u64 GetTicksRemaining() override { - ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled"); - - return std::max(parent.system.CoreTiming().GetDowncount(), 0); + UNREACHABLE(); } u64 GetCNTPCT() override { @@ -216,7 +203,6 @@ public: u64 tpidrro_el0 = 0; u64 tpidr_el0 = 0; bool debugger_enabled{}; - static constexpr u64 minimum_run_cycles = 1000U; }; std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table, @@ -374,9 +360,8 @@ void ARM_Dynarmic_64::RewindBreakpointInstruction() { } ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, - bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_, - std::size_t core_index_) - : ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_}, + ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_) + : ARM_Interface{system_, interrupt_handlers_}, cb(std::make_unique(*this)), core_index{core_index_}, exclusive_monitor{dynamic_cast(exclusive_monitor_)}, null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {} diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 71dbaac5e1..66224bf8c6 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -26,7 +26,7 @@ class System; class ARM_Dynarmic_64 final : public ARM_Interface { public: - ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_, + ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_); ~ARM_Dynarmic_64() override; diff --git a/src/core/core.cpp b/src/core/core.cpp index 7723d9782a..74085f40b4 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -177,14 +177,8 @@ struct System::Impl { device_memory = std::make_unique(); - is_multicore = Settings::values.use_multi_core.GetValue(); is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue(); - kernel.SetMulticore(is_multicore); - cpu_manager.SetMulticore(is_multicore); - cpu_manager.SetAsyncGpu(is_async_gpu); - core_timing.SetMulticore(is_multicore); - kernel.Initialize(); cpu_manager.Initialize(); core_timing.Initialize([&system]() { system.RegisterHostThread(); }); @@ -449,7 +443,6 @@ struct System::Impl { std::unique_ptr perf_stats; Core::SpeedLimiter speed_limiter; - bool is_multicore{}; bool is_async_gpu{}; ExecuteProgramCallback execute_program_callback; @@ -818,10 +811,6 @@ void System::ExitDynarmicProfile() { MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]); } -bool System::IsMulticore() const { - return impl->is_multicore; -} - bool System::DebuggerEnabled() const { return Settings::values.use_gdbstub.GetValue(); } diff --git a/src/core/core.h b/src/core/core.h index 60efe44103..2550955509 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -378,9 +378,6 @@ public: /// Exit Dynarmic Microprofile void ExitDynarmicProfile(); - /// Tells if system is running on multicore. - [[nodiscard]] bool IsMulticore() const; - /// Tells if the system debugger is enabled. [[nodiscard]] bool DebuggerEnabled() const; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 1405780695..d497bd0e35 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -15,8 +15,6 @@ namespace Core::Timing { -constexpr s64 MAX_SLICE_LENGTH = 4000; - std::shared_ptr CreateEvent(std::string name, TimedCallback&& callback) { return std::make_shared(std::move(callback), std::move(name)); } @@ -57,16 +55,14 @@ void CoreTiming::Initialize(std::function&& on_thread_init_) { on_thread_init = std::move(on_thread_init_); event_fifo_id = 0; shutting_down = false; - ticks = 0; const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {}; ev_lost = CreateEvent("_lost_event", empty_timed_callback); - if (is_multicore) { - const auto hardware_concurrency = std::thread::hardware_concurrency(); - size_t id = 0; + + const auto hardware_concurrency = std::thread::hardware_concurrency(); + size_t id = 0; + worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++); + if (hardware_concurrency > 8) { worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++); - if (hardware_concurrency > 8) { - worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++); - } } } @@ -90,13 +86,13 @@ void CoreTiming::Pause(bool is_paused_) { if (is_paused_ == paused_state.load(std::memory_order_relaxed)) { return; } - if (is_multicore) { - is_paused = is_paused_; - event_cv.notify_all(); - if (!is_paused_) { - wait_pause_cv.notify_all(); - } + + is_paused = is_paused_; + event_cv.notify_all(); + if (!is_paused_) { + wait_pause_cv.notify_all(); } + paused_state.store(is_paused_, std::memory_order_relaxed); } @@ -106,20 +102,18 @@ void CoreTiming::SyncPause(bool is_paused_) { return; } - if (is_multicore) { - is_paused = is_paused_; - event_cv.notify_all(); - if (!is_paused_) { - wait_pause_cv.notify_all(); - } + is_paused = is_paused_; + event_cv.notify_all(); + if (!is_paused_) { + wait_pause_cv.notify_all(); } + paused_state.store(is_paused_, std::memory_order_relaxed); - if (is_multicore) { - if (is_paused_) { - wait_signal_cv.wait(main_lock, [this] { return pause_count == worker_threads.size(); }); - } else { - wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; }); - } + + if (is_paused_) { + wait_signal_cv.wait(main_lock, [this] { return pause_count == worker_threads.size(); }); + } else { + wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; }); } } @@ -144,9 +138,7 @@ void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); - if (is_multicore) { - event_cv.notify_one(); - } + event_cv.notify_one(); } void CoreTiming::UnscheduleEvent(const std::shared_ptr& event_type, @@ -164,39 +156,12 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr& event_type, } } -void CoreTiming::AddTicks(u64 ticks_to_add) { - ticks += ticks_to_add; - downcount -= static_cast(ticks); -} - -void CoreTiming::Idle() { - if (!event_queue.empty()) { - const u64 next_event_time = event_queue.front().time; - const u64 next_ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U; - if (next_ticks > ticks) { - ticks = next_ticks; - } - return; - } - ticks += 1000U; -} - -void CoreTiming::ResetTicks() { - downcount = MAX_SLICE_LENGTH; -} - u64 CoreTiming::GetCPUTicks() const { - if (is_multicore) { - return clock->GetCPUCycles(); - } - return ticks; + return clock->GetCPUCycles(); } u64 CoreTiming::GetClockTicks() const { - if (is_multicore) { - return clock->GetClockCycles(); - } - return CpuCyclesToClockCycles(ticks); + return clock->GetClockCycles(); } void CoreTiming::ClearPendingEvents() { @@ -285,17 +250,11 @@ void CoreTiming::ThreadLoop() { } std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { - if (is_multicore) { - return clock->GetTimeNS(); - } - return CyclesToNs(ticks); + return clock->GetTimeNS(); } std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { - if (is_multicore) { - return clock->GetTimeUS(); - } - return CyclesToUs(ticks); + return clock->GetTimeUS(); } } // namespace Core::Timing diff --git a/src/core/core_timing.h b/src/core/core_timing.h index a86553e08b..5dfa9c15af 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -65,16 +65,6 @@ public: /// Tears down all timing related functionality. void Shutdown(); - /// Sets if emulation is multicore or single core, must be set before Initialize - void SetMulticore(bool is_multicore_) { - is_multicore = is_multicore_; - } - - /// Check if it's using host timing. - bool IsHostTiming() const { - return is_multicore; - } - /// Pauses/Unpauses the execution of the timer thread. void Pause(bool is_paused); @@ -101,16 +91,6 @@ public: /// We only permit one event of each type in the queue at a time. void RemoveEvent(const std::shared_ptr& event_type); - void AddTicks(u64 ticks_to_add); - - void ResetTicks(); - - void Idle(); - - s64 GetDowncount() const { - return downcount; - } - /// Returns current time in emulated CPU cycles u64 GetCPUTicks() const; @@ -123,9 +103,6 @@ public: /// Returns current time in nanoseconds. std::chrono::nanoseconds GetGlobalTimeNs() const; - /// Checks for events manually and returns time in nanoseconds for next event, threadsafe. - std::optional Advance(); - private: struct Event; @@ -135,6 +112,9 @@ private: static void ThreadEntry(CoreTiming& instance, size_t id); void ThreadLoop(); + /// Checks for events manually and returns time in nanoseconds for next event, threadsafe. + std::optional Advance(); + std::unique_ptr clock; u64 global_timer = 0; @@ -162,12 +142,7 @@ private: std::atomic paused_state{}; bool is_paused{}; bool shutting_down{}; - bool is_multicore{}; size_t pause_count{}; - - /// Cycle timing - u64 ticks{}; - s64 downcount{}; }; /// Creates a core timing event with the given name and callback. diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 4281941291..055ae25e73 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -26,7 +26,7 @@ void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager } void CpuManager::Initialize() { - num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1; + const auto num_cores{Core::Hardware::NUM_CPU_CORES}; gpu_barrier = std::make_unique(num_cores + 1); for (std::size_t core = 0; core < num_cores; core++) { @@ -35,33 +35,13 @@ void CpuManager::Initialize() { } void CpuManager::Shutdown() { - for (std::size_t core = 0; core < num_cores; core++) { + for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { if (core_data[core].host_thread.joinable()) { core_data[core].host_thread.join(); } } } -void CpuManager::GuestActivateFunction() { - if (is_multicore) { - MultiCoreGuestActivate(); - } else { - SingleCoreGuestActivate(); - } -} - -void CpuManager::GuestThreadFunction() { - if (is_multicore) { - MultiCoreRunGuestThread(); - } else { - SingleCoreRunGuestThread(); - } -} - -void CpuManager::ShutdownThreadFunction() { - ShutdownThread(); -} - void CpuManager::WaitForAndHandleInterrupt() { auto& kernel = system.Kernel(); auto& physical_core = kernel.CurrentPhysicalCore(); @@ -82,30 +62,21 @@ void CpuManager::HandleInterrupt() { Kernel::KInterruptManager::HandleInterrupt(kernel, static_cast(core_index)); } -/////////////////////////////////////////////////////////////////////////////// -/// MultiCore /// -/////////////////////////////////////////////////////////////////////////////// - -void CpuManager::MultiCoreGuestActivate() { +void CpuManager::GuestActivate() { // Similar to the HorizonKernelMain callback in HOS auto& kernel = system.Kernel(); auto* scheduler = kernel.CurrentScheduler(); + kernel.SetCurrentEmuThread(scheduler->GetSchedulerCurrentThread()); scheduler->Activate(); + UNREACHABLE(); } -void CpuManager::MultiCoreRunGuestThread() { +void CpuManager::RunGuestThread() { // Similar to UserModeThreadStarter in HOS auto& kernel = system.Kernel(); - auto* thread = kernel.GetCurrentEmuThread(); - thread->EnableDispatch(); - - MultiCoreRunGuestLoop(); -} - -void CpuManager::MultiCoreRunGuestLoop() { - auto& kernel = system.Kernel(); + kernel.GetCurrentEmuThread()->EnableDispatch(); while (true) { auto* physical_core = &kernel.CurrentPhysicalCore(); @@ -116,24 +87,14 @@ void CpuManager::MultiCoreRunGuestLoop() { HandleInterrupt(); } + + UNREACHABLE(); } -/////////////////////////////////////////////////////////////////////////////// -/// SingleCore /// -/////////////////////////////////////////////////////////////////////////////// - -void CpuManager::SingleCoreGuestActivate() {} - -void CpuManager::SingleCoreRunGuestThread() {} - -void CpuManager::SingleCoreRunGuestLoop() {} - -void CpuManager::PreemptSingleCore(bool from_running_enviroment) {} - void CpuManager::ShutdownThread() { auto& kernel = system.Kernel(); auto* thread = kernel.GetCurrentEmuThread(); - auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0; + auto core = kernel.CurrentPhysicalCoreIndex(); Common::Fiber::YieldTo(thread->GetHostContext(), *core_data[core].host_context); UNREACHABLE(); @@ -142,16 +103,13 @@ void CpuManager::ShutdownThread() { void CpuManager::RunThread(std::size_t core) { /// Initialization system.RegisterCoreThread(core); - std::string name; - if (is_multicore) { - name = "yuzu:CPUCore_" + std::to_string(core); - } else { - name = "yuzu:CPUThread"; - } + + auto name{fmt::format("yuzu:CPUCore_{}", core)}; MicroProfileOnThreadCreate(name.c_str()); Common::SetCurrentThreadName(name.c_str()); Common::SetCurrentThreadPriority(Common::ThreadPriority::High); - auto& data = core_data[core]; + + auto& data{core_data[core]}; data.host_context = Common::Fiber::ThreadToFiber(); // Cleanup @@ -163,23 +121,8 @@ void CpuManager::RunThread(std::size_t core) { // Running gpu_barrier->Sync(); - if (!is_async_gpu && !is_multicore) { - system.GPU().ObtainContext(); - } - - auto& kernel = system.Kernel(); - - auto* main_thread = Kernel::KThread::Create(kernel); - main_thread->SetName(fmt::format("MainThread:{}", core)); - ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, static_cast(core)) - .IsSuccess()); - - auto* idle_thread = Kernel::KThread::Create(kernel); - ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, static_cast(core)) - .IsSuccess()); - - kernel.SetCurrentEmuThread(main_thread); - kernel.CurrentScheduler()->Initialize(idle_thread); + auto& kernel{system.Kernel()}; + auto* main_thread{kernel.CurrentScheduler()->GetSchedulerCurrentThread()}; Common::Fiber::YieldTo(data.host_context, *main_thread->GetHostContext()); } diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 8143424af2..0bc8419483 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -34,16 +34,6 @@ public: CpuManager& operator=(const CpuManager&) = delete; CpuManager& operator=(CpuManager&&) = delete; - /// Sets if emulation is multicore or single core, must be set before Initialize - void SetMulticore(bool is_multi) { - is_multicore = is_multi; - } - - /// Sets if emulation is using an asynchronous GPU. - void SetAsyncGpu(bool is_async) { - is_async_gpu = is_async; - } - void OnGpuReady() { gpu_barrier->Sync(); } @@ -53,42 +43,23 @@ public: void Shutdown(); std::function GetGuestActivateFunc() { - return [this] { GuestActivateFunction(); }; + return [this] { GuestActivate(); }; } std::function GetGuestThreadFunc() { - return [this] { GuestThreadFunction(); }; - } - std::function GetIdleThreadStartFunc() { - return [this] { IdleThreadFunction(); }; + return [this] { RunGuestThread(); }; } std::function GetShutdownThreadStartFunc() { - return [this] { ShutdownThreadFunction(); }; - } - - void PreemptSingleCore(bool from_running_enviroment = true); - - std::size_t CurrentCore() const { - return current_core.load(); + return [this] { ShutdownThread(); }; } private: - void GuestActivateFunction(); - void GuestThreadFunction(); - void IdleThreadFunction(); - void ShutdownThreadFunction(); - - void MultiCoreGuestActivate(); - void MultiCoreRunGuestThread(); - void MultiCoreRunGuestLoop(); - - void SingleCoreGuestActivate(); - void SingleCoreRunGuestThread(); - void SingleCoreRunGuestLoop(); - static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core); + void GuestActivate(); + void RunGuestThread(); void HandleInterrupt(); void ShutdownThread(); + void RunThread(std::size_t core); struct CoreData { @@ -98,14 +69,6 @@ private: std::unique_ptr gpu_barrier{}; std::array core_data{}; - - bool is_async_gpu{}; - bool is_multicore{}; - std::atomic current_core{}; - std::size_t idle_count{}; - std::size_t num_cores{}; - static constexpr std::size_t max_cycle_runs = 5; - System& system; }; diff --git a/src/core/hle/kernel/global_scheduler_context.cpp b/src/core/hle/kernel/global_scheduler_context.cpp index 21fd5cb678..65576b8c4b 100644 --- a/src/core/hle/kernel/global_scheduler_context.cpp +++ b/src/core/hle/kernel/global_scheduler_context.cpp @@ -42,11 +42,6 @@ void GlobalSchedulerContext::PreemptThreads() { for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { const u32 priority = preemption_priorities[core_id]; KScheduler::RotateScheduledQueue(kernel, core_id, priority); - - // Signal an interrupt occurred. For core 3, this is a certainty, as preemption will result - // in the rotator thread being scheduled. For cores 0-2, this is to simulate or system - // interrupts that may have occurred. - kernel.PhysicalCore(core_id).Interrupt(); } } diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 13915dbd99..570f41f6c2 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -125,9 +125,9 @@ void KScheduler::RescheduleCurrentCoreImpl() { } } -void KScheduler::Initialize(KThread* idle_thread) { +void KScheduler::Initialize(KThread* main_thread, KThread* idle_thread, s32 core_id) { // Set core ID/idle thread/interrupt task manager. - m_core_id = GetCurrentCoreId(kernel); + m_core_id = core_id; m_idle_thread = idle_thread; // m_state.idle_thread_stack = m_idle_thread->GetStackTop(); // m_state.interrupt_task_manager = &kernel.GetInterruptTaskManager(); @@ -145,7 +145,7 @@ void KScheduler::Initialize(KThread* idle_thread) { // KInterruptController::PriorityLevel_Scheduler, false, false); // Set the current thread. - m_current_thread = GetCurrentThreadPointer(kernel); + m_current_thread = main_thread; } void KScheduler::Activate() { @@ -389,8 +389,7 @@ void KScheduler::ScheduleImplOffStack() { // Save the original thread context. { - auto& physical_core = kernel.System().CurrentPhysicalCore(); - auto& cpu_core = physical_core.ArmInterface(); + auto& cpu_core = kernel.System().CurrentArmInterface(); cpu_core.SaveContext(cur_thread->GetContext32()); cpu_core.SaveContext(cur_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index 8f4eebf6ac..fb9807aece 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -41,12 +41,16 @@ public: explicit KScheduler(KernelCore& kernel); ~KScheduler(); - void Initialize(KThread* idle_thread); + void Initialize(KThread* main_thread, KThread* idle_thread, s32 core_id); void Activate(); void SetInterruptTaskRunnable(); void RequestScheduleOnInterrupt(); + void ScheduleOnPreemption() { + ScheduleOnInterrupt(); + } + u64 GetIdleCount() { return m_state.idle_count; } diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index c778e21fc1..99f0bfbac5 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -252,7 +252,6 @@ Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_ // Initialize emulation parameters. thread->host_context = std::make_shared(std::move(init_func)); - thread->is_single_core = !Settings::values.use_multi_core.GetValue(); return ResultSuccess; } @@ -1189,7 +1188,7 @@ KThread& GetCurrentThread(KernelCore& kernel) { } s32 GetCurrentCoreId(KernelCore& kernel) { - return GetCurrentThread(kernel).GetCurrentCore(); + return static_cast(kernel.CurrentPhysicalCoreIndex()); } KScopedDisableDispatch::~KScopedDisableDispatch() { @@ -1198,11 +1197,6 @@ KScopedDisableDispatch::~KScopedDisableDispatch() { return; } - // Skip the reschedule if single-core, as dispatch tracking is disabled here. - if (!Settings::values.use_multi_core.GetValue()) { - return; - } - if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) { auto scheduler = kernel.CurrentScheduler(); diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index 416a861a94..74988718cf 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -490,7 +490,7 @@ public: } [[nodiscard]] bool IsDispatchTrackingDisabled() const { - return is_single_core || IsKernelThread(); + return IsKernelThread(); } [[nodiscard]] s32 GetDisableDispatchCount() const { @@ -795,7 +795,6 @@ private: // For emulation std::shared_ptr host_context{}; - bool is_single_core{}; ThreadType thread_type{}; StepState step_state{}; std::mutex dummy_wait_lock; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 0e34bb2a8d..f51083e91a 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -51,10 +51,6 @@ struct KernelCore::Impl { : time_manager{system_}, service_threads_manager{1, "yuzu:ServiceThreadsManager"}, system{system_} {} - void SetMulticore(bool is_multi) { - is_multicore = is_multi; - } - void Initialize(KernelCore& kernel) { global_object_list_container = std::make_unique(kernel); global_scheduler_context = std::make_unique(kernel); @@ -62,10 +58,6 @@ struct KernelCore::Impl { global_handle_table->Initialize(KHandleTable::MaxTableSize); default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread"); - is_phantom_mode_for_singlecore = false; - - InitializePhysicalCores(); - // Derive the initial memory layout from the emulated board Init::InitializeSlabResourceCounts(kernel); DeriveInitialMemoryLayout(); @@ -76,6 +68,7 @@ struct KernelCore::Impl { InitializeMemoryLayout(); Init::InitializeKPageBufferSlabHeap(system); InitializeShutdownThreads(); + InitializePhysicalCores(); InitializePreemption(kernel); RegisterHostThread(); @@ -195,6 +188,18 @@ struct KernelCore::Impl { for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { schedulers[i] = std::make_unique(system.Kernel()); cores.emplace_back(i, system, *schedulers[i], interrupts); + + auto* main_thread = KThread::Create(system.Kernel()); + main_thread->SetName(fmt::format("MainThread:{}", i)); + main_thread->SetCurrentCore(static_cast(i)); + ASSERT(KThread::InitializeMainThread(system, main_thread, static_cast(i)) + .IsSuccess()); + + auto* idle_thread = KThread::Create(system.Kernel()); + ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, static_cast(i)) + .IsSuccess()); + + schedulers[i]->Initialize(main_thread, idle_thread, i); } } @@ -290,10 +295,7 @@ struct KernelCore::Impl { /// Registers a CPU core thread by allocating a host thread ID for it void RegisterCoreThread(std::size_t core_id) { ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); - const auto this_id = GetHostThreadId(core_id); - if (!is_multicore) { - single_core_thread_id = this_id; - } + [[maybe_unused]] const auto this_id = GetHostThreadId(core_id); } /// Registers a new host thread by allocating a host thread ID for it @@ -303,20 +305,7 @@ struct KernelCore::Impl { } [[nodiscard]] u32 GetCurrentHostThreadID() { - const auto this_id = GetHostThreadId(); - if (!is_multicore && single_core_thread_id == this_id) { - return static_cast(system.GetCpuManager().CurrentCore()); - } - return this_id; - } - - bool IsPhantomModeForSingleCore() const { - return is_phantom_mode_for_singlecore; - } - - void SetIsPhantomModeForSingleCore(bool value) { - ASSERT(!is_multicore); - is_phantom_mode_for_singlecore = value; + return GetHostThreadId(); } bool IsShuttingDown() const { @@ -771,10 +760,7 @@ struct KernelCore::Impl { std::array interrupts{}; std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; - bool is_multicore{}; std::atomic_bool is_shutting_down{}; - bool is_phantom_mode_for_singlecore{}; - u32 single_core_thread_id{}; std::array svc_ticks{}; @@ -787,10 +773,6 @@ struct KernelCore::Impl { KernelCore::KernelCore(Core::System& system) : impl{std::make_unique(system, *this)} {} KernelCore::~KernelCore() = default; -void KernelCore::SetMulticore(bool is_multicore) { - impl->SetMulticore(is_multicore); -} - void KernelCore::Initialize() { slab_heap_container = std::make_unique(); impl->Initialize(*this); @@ -1098,10 +1080,6 @@ void KernelCore::ShutdownCores() { InterruptAllPhysicalCores(); } -bool KernelCore::IsMulticore() const { - return impl->is_multicore; -} - bool KernelCore::IsShuttingDown() const { return impl->IsShuttingDown(); } @@ -1151,14 +1129,6 @@ const KMemoryLayout& KernelCore::MemoryLayout() const { return *impl->memory_layout; } -bool KernelCore::IsPhantomModeForSingleCore() const { - return impl->IsPhantomModeForSingleCore(); -} - -void KernelCore::SetIsPhantomModeForSingleCore(bool value) { - impl->SetIsPhantomModeForSingleCore(value); -} - Core::System& KernelCore::System() { return impl->system; } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index aa0ebaa02c..495f0ad5de 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -97,9 +97,6 @@ public: KernelCore(KernelCore&&) = delete; KernelCore& operator=(KernelCore&&) = delete; - /// Sets if emulation is multicore or single core, must be set before Initialize - void SetMulticore(bool is_multicore); - /// Resets the kernel to a clean slate for use. void Initialize(); @@ -283,8 +280,6 @@ public: /// Notify emulated CPU cores to shut down. void ShutdownCores(); - bool IsMulticore() const; - bool IsShuttingDown() const; void EnterSVCProfile(); @@ -318,10 +313,6 @@ public: */ void ReleaseServiceThread(std::weak_ptr service_thread); - /// Workaround for single-core mode when preempting threads while idle. - bool IsPhantomModeForSingleCore() const; - void SetIsPhantomModeForSingleCore(bool value); - Core::System& System(); const Core::System& System() const; diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index a5b16ae2eb..c34766e3ae 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -20,7 +20,7 @@ PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KSche // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. auto& kernel = system.Kernel(); arm_interface = std::make_unique( - system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); + system, interrupts, kernel.GetExclusiveMonitor(), core_index); #else #error Platform not supported yet. #endif @@ -34,7 +34,7 @@ void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) { if (!is_64_bit) { // We already initialized a 64-bit core, replace with a 32-bit one. arm_interface = std::make_unique( - system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); + system, interrupts, kernel.GetExclusiveMonitor(), core_index); } #else #error Platform not supported yet. diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 27e5a805db..a03b1ea7fb 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2102,16 +2102,8 @@ static void ChangeKernelTraceState([[maybe_unused]] Core::System& system, static u64 GetSystemTick(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); - auto& core_timing = system.CoreTiming(); - // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) - const u64 result{system.CoreTiming().GetClockTicks()}; - - if (!system.Kernel().IsMulticore()) { - core_timing.AddTicks(400U); - } - - return result; + return system.CoreTiming().GetClockTicks(); } static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) { diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 2b2985a2d4..1371baacae 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -26,8 +26,6 @@ namespace Service::NVFlinger { -constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60}; - void NVFlinger::SplitVSync(std::stop_token stop_token) { system.RegisterHostThread(); std::string name = "yuzu:VSyncThread"; @@ -78,18 +76,10 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr this->system.CoreTiming().ScheduleEvent(future_ns, composition_event); }); - if (system.IsMulticore()) { - vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); - } else { - system.CoreTiming().ScheduleEvent(frame_ns, composition_event); - } + vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); }); } NVFlinger::~NVFlinger() { - if (!system.IsMulticore()) { - system.CoreTiming().UnscheduleEvent(composition_event, 0); - } - for (auto& display : displays) { for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { display.GetLayer(layer).Core().NotifyShutdown(); diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp index 6ef459b7a4..c6ab7d5dcd 100644 --- a/src/core/perf_stats.cpp +++ b/src/core/perf_stats.cpp @@ -126,38 +126,6 @@ double PerfStats::GetLastFrameTimeScale() const { return duration_cast(previous_frame_length).count() / FRAME_LENGTH; } -void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) { - if (!Settings::values.use_speed_limit.GetValue() || - Settings::values.use_multi_core.GetValue()) { - return; - } - - auto now = Clock::now(); - - const double sleep_scale = Settings::values.speed_limit.GetValue() / 100.0; - - // Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current - // speed percent or it will clamp too much and prevent this from properly limiting to that - // percent. High values means it'll take longer after a slow frame to recover and start - // limiting - const microseconds max_lag_time_us = duration_cast( - std::chrono::duration(25ms / sleep_scale)); - speed_limiting_delta_err += duration_cast( - std::chrono::duration( - (current_system_time_us - previous_system_time_us) / sleep_scale)); - speed_limiting_delta_err -= duration_cast(now - previous_walltime); - speed_limiting_delta_err = - std::clamp(speed_limiting_delta_err, -max_lag_time_us, max_lag_time_us); - - if (speed_limiting_delta_err > microseconds::zero()) { - std::this_thread::sleep_for(speed_limiting_delta_err); - auto now_after_sleep = Clock::now(); - speed_limiting_delta_err -= duration_cast(now_after_sleep - now); - now = now_after_sleep; - } - - previous_system_time_us = current_system_time_us; - previous_walltime = now; -} +void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) {} } // namespace Core diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 654db0b524..ff380506ec 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -226,7 +226,6 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader, // Log user configuration information constexpr auto field_type = Telemetry::FieldType::UserConfig; AddField(field_type, "Audio_SinkId", Settings::values.sink_id.GetValue()); - AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue()); AddField(field_type, "Renderer_Backend", TranslateRenderer(Settings::values.renderer_backend.GetValue())); AddField(field_type, "Renderer_UseSpeedLimit", Settings::values.use_speed_limit.GetValue()); diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp index e687416a81..3196694c31 100644 --- a/src/tests/core/core_timing.cpp +++ b/src/tests/core/core_timing.cpp @@ -36,7 +36,6 @@ void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_ struct ScopeInit final { ScopeInit() { - core_timing.SetMulticore(true); core_timing.Initialize([]() {}); } ~ScopeInit() { diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 9df4752be6..622c2c12e4 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -467,7 +467,6 @@ void Config::ReadMotionTouchValues() { void Config::ReadCoreValues() { qt_config->beginGroup(QStringLiteral("Core")); - ReadGlobalSetting(Settings::values.use_multi_core); ReadGlobalSetting(Settings::values.use_extended_memory_layout); qt_config->endGroup(); @@ -1067,7 +1066,6 @@ void Config::SaveControlValues() { void Config::SaveCoreValues() { qt_config->beginGroup(QStringLiteral("Core")); - WriteGlobalSetting(Settings::values.use_multi_core); WriteGlobalSetting(Settings::values.use_extended_memory_layout); qt_config->endGroup(); diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index a31fabd3ff..a25f0e4aba 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -37,8 +37,6 @@ ConfigureGeneral::~ConfigureGeneral() = default; void ConfigureGeneral::SetConfiguration() { const bool runtime_lock = !system.IsPoweredOn(); - ui->use_multi_core->setEnabled(runtime_lock); - ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue()); ui->use_extended_memory_layout->setEnabled(runtime_lock); ui->use_extended_memory_layout->setChecked( Settings::values.use_extended_memory_layout.GetValue()); @@ -89,8 +87,6 @@ void ConfigureGeneral::ResetDefaults() { } void ConfigureGeneral::ApplyConfiguration() { - ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core, - use_multi_core); ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_extended_memory_layout, ui->use_extended_memory_layout, use_extended_memory_layout); @@ -161,8 +157,6 @@ void ConfigureGeneral::SetupPerGameUI() { ConfigurationShared::SetColoredTristate(ui->toggle_speed_limit, Settings::values.use_speed_limit, use_speed_limit); - ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, - use_multi_core); ConfigurationShared::SetColoredTristate(ui->use_extended_memory_layout, Settings::values.use_extended_memory_layout, use_extended_memory_layout); diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h index b6f3bb5edc..cf1501435d 100644 --- a/src/yuzu/configuration/configure_general.h +++ b/src/yuzu/configuration/configure_general.h @@ -47,7 +47,6 @@ private: std::unique_ptr ui; ConfigurationShared::CheckState use_speed_limit; - ConfigurationShared::CheckState use_multi_core; ConfigurationShared::CheckState use_extended_memory_layout; const Core::System& system; diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index c6ef2ab705..a5c9f2a88b 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -135,13 +135,6 @@ - - - - Multicore CPU Emulation - - - diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index b460020b16..871d5585e0 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -3286,7 +3286,7 @@ void GMainWindow::UpdateStatusBar() { emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2)); res_scale_label->setVisible(true); - emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue()); + emu_speed_label->setVisible(false); game_fps_label->setVisible(true); emu_frametime_label->setVisible(true); } diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index fc4744fb02..40d3279651 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -266,7 +266,6 @@ void Config::ReadValues() { ReadSetting("System", Settings::values.sound_index); // Core - ReadSetting("Core", Settings::values.use_multi_core); ReadSetting("Core", Settings::values.use_extended_memory_layout); // Cpu diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index a3b8432f51..6b85e87d71 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -121,11 +121,6 @@ mouse_enabled = # 0 (default): Disabled, 1: Enabled keyboard_enabled = -[Core] -# Whether to use multi-core for CPU emulation -# 0: Disabled, 1 (default): Enabled -use_multi_core = - # Enable extended guest system memory layout (6GB DRAM) # 0 (default): Disabled, 1: Enabled use_extended_memory_layout =