From 7ee76003adbc24bdc651710bcab9860efe3b8c22 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 24 Feb 2020 22:04:12 -0400 Subject: General: Recover Prometheus project from harddrive failure This commit: Implements CPU Interrupts, Replaces Cycle Timing for Host Timing, Reworks the Kernel's Scheduler, Introduce Idle State and Suspended State, Recreates the bootmanager, Initializes Multicore system. --- src/core/core.cpp | 57 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 27 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index f9f8a30009..e8936b09d5 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -11,7 +11,6 @@ #include "common/string_util.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" -#include "core/core_manager.h" #include "core/core_timing.h" #include "core/cpu_manager.h" #include "core/device_memory.h" @@ -117,23 +116,30 @@ struct System::Impl { : kernel{system}, fs_controller{system}, memory{system}, cpu_manager{system}, reporter{system}, applet_manager{system} {} - CoreManager& CurrentCoreManager() { - return cpu_manager.GetCurrentCoreManager(); - } - Kernel::PhysicalCore& CurrentPhysicalCore() { - const auto index = cpu_manager.GetActiveCoreIndex(); - return kernel.PhysicalCore(index); + return kernel.CurrentPhysicalCore(); } Kernel::PhysicalCore& GetPhysicalCore(std::size_t index) { return kernel.PhysicalCore(index); } - ResultStatus RunLoop(bool tight_loop) { + ResultStatus Run() { status = ResultStatus::Success; - cpu_manager.RunLoop(tight_loop); + kernel.Suspend(false); + core_timing.SyncPause(false); + cpu_manager.Pause(false); + + return status; + } + + ResultStatus Pause() { + status = ResultStatus::Success; + + kernel.Suspend(true); + core_timing.SyncPause(true); + cpu_manager.Pause(true); return status; } @@ -143,7 +149,7 @@ struct System::Impl { device_memory = std::make_unique(system); - core_timing.Initialize(); + core_timing.Initialize([&system]() { system.RegisterHostThread(); }); kernel.Initialize(); cpu_manager.Initialize(); @@ -387,20 +393,24 @@ struct System::Impl { System::System() : impl{std::make_unique(*this)} {} System::~System() = default; -CoreManager& System::CurrentCoreManager() { - return impl->CurrentCoreManager(); +CpuManager& System::GetCpuManager() { + return impl->cpu_manager; +} + +const CpuManager& System::GetCpuManager() const { + return impl->cpu_manager; } -const CoreManager& System::CurrentCoreManager() const { - return impl->CurrentCoreManager(); +System::ResultStatus System::Run() { + return impl->Run(); } -System::ResultStatus System::RunLoop(bool tight_loop) { - return impl->RunLoop(tight_loop); +System::ResultStatus System::Pause() { + return impl->Pause(); } System::ResultStatus System::SingleStep() { - return RunLoop(false); + return ResultStatus::Success; } void System::InvalidateCpuInstructionCaches() { @@ -444,7 +454,9 @@ const ARM_Interface& System::CurrentArmInterface() const { } std::size_t System::CurrentCoreIndex() const { - return impl->cpu_manager.GetActiveCoreIndex(); + std::size_t core = impl->kernel.GetCurrentHostThreadID(); + ASSERT(core < Core::Hardware::NUM_CPU_CORES); + return core; } Kernel::Scheduler& System::CurrentScheduler() { @@ -497,15 +509,6 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const { return impl->GetPhysicalCore(core_index).ArmInterface(); } -CoreManager& System::GetCoreManager(std::size_t core_index) { - return impl->cpu_manager.GetCoreManager(core_index); -} - -const CoreManager& System::GetCoreManager(std::size_t core_index) const { - ASSERT(core_index < NUM_CPU_CORES); - return impl->cpu_manager.GetCoreManager(core_index); -} - ExclusiveMonitor& System::Monitor() { return impl->kernel.GetExclusiveMonitor(); } -- cgit v1.2.3 From fb1d75a78885c2231cea1816150bd06027c12644 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 12:28:55 -0400 Subject: HostTiming: Pause the hardware clock on pause. --- src/common/wall_clock.cpp | 4 ++++ src/common/wall_clock.h | 2 ++ src/common/x64/native_clock.cpp | 7 +++++++ src/common/x64/native_clock.h | 2 ++ src/core/core.cpp | 2 +- src/core/core_timing.cpp | 6 ++++++ src/core/core_timing.h | 1 + 7 files changed, 23 insertions(+), 1 deletion(-) (limited to 'src/core/core.cpp') diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp index d4d35f4e7a..a46db6bbfb 100644 --- a/src/common/wall_clock.cpp +++ b/src/common/wall_clock.cpp @@ -53,6 +53,10 @@ public: return Common::Divide128On32(temporary, 1000000000).first; } + void Pause(bool is_paused) override { + // Do nothing in this clock type. + } + private: base_time_point start_time; }; diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h index ed284cf502..367d721348 100644 --- a/src/common/wall_clock.h +++ b/src/common/wall_clock.h @@ -28,6 +28,8 @@ public: /// Returns current wall time in emulated cpu cycles virtual u64 GetCPUCycles() = 0; + virtual void Pause(bool is_paused) = 0; + /// Tells if the wall clock, uses the host CPU's hardware clock bool IsNative() const { return is_native; diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index 26d4d0ba68..926f92ff86 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -65,6 +65,13 @@ u64 NativeClock::GetRTSC() { return accumulated_ticks; } +void NativeClock::Pause(bool is_paused) { + if (!is_paused) { + _mm_mfence(); + last_measure = __rdtsc(); + } +} + std::chrono::nanoseconds NativeClock::GetTimeNS() { const u64 rtsc_value = GetRTSC(); return std::chrono::nanoseconds{MultiplyAndDivide64(rtsc_value, 1000000000, rtsc_frequency)}; diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h index b58cf9f5a4..3851f8fc22 100644 --- a/src/common/x64/native_clock.h +++ b/src/common/x64/native_clock.h @@ -26,6 +26,8 @@ public: u64 GetCPUCycles() override; + void Pause(bool is_paused) override; + private: u64 GetRTSC(); diff --git a/src/core/core.cpp b/src/core/core.cpp index e8936b09d5..1d6179a80e 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -137,8 +137,8 @@ struct System::Impl { ResultStatus Pause() { status = ResultStatus::Success; - kernel.Suspend(true); core_timing.SyncPause(true); + kernel.Suspend(true); cpu_manager.Pause(true); return status; diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index cc32a853b9..5a7abcfca9 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -77,6 +77,9 @@ void CoreTiming::SyncPause(bool is_paused) { return; } Pause(is_paused); + if (!is_paused) { + pause_event.Set(); + } event.Set(); while (paused_set != is_paused) ; @@ -197,6 +200,9 @@ void CoreTiming::ThreadLoop() { wait_set = false; } paused_set = true; + clock->Pause(true); + pause_event.Wait(); + clock->Pause(false); } } diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 707c8ef0c2..c70b605c89 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -136,6 +136,7 @@ private: std::shared_ptr ev_lost; Common::Event event{}; + Common::Event pause_event{}; Common::SpinLock basic_lock{}; Common::SpinLock advance_lock{}; std::unique_ptr timer_thread; -- cgit v1.2.3 From b2fea85499d2cbcdb1a7b0d522c64cb89dc74736 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Feb 2020 13:22:11 -0400 Subject: SVC: Correct GetThreadPriority, SetThreadPriority, GetThreadCoreMask, SetThreadCoreMask, GetCurrentProcessorNumber --- src/core/core.cpp | 8 ++++++++ src/core/core.h | 7 +++++++ src/core/hle/kernel/svc.cpp | 17 ++++++++--------- src/core/hle/kernel/thread.cpp | 6 ++---- src/core/hle/kernel/thread.h | 3 +-- 5 files changed, 26 insertions(+), 15 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 1d6179a80e..5d4ecdce5a 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -467,6 +467,14 @@ const Kernel::Scheduler& System::CurrentScheduler() const { return impl->CurrentPhysicalCore().Scheduler(); } +Kernel::PhysicalCore& System::CurrentPhysicalCore() { + return impl->CurrentPhysicalCore(); +} + +const Kernel::PhysicalCore& System::CurrentPhysicalCore() const { + return impl->CurrentPhysicalCore(); +} + Kernel::Scheduler& System::Scheduler(std::size_t core_index) { return impl->GetPhysicalCore(core_index).Scheduler(); } diff --git a/src/core/core.h b/src/core/core.h index 7f170fc54e..9a0dd10753 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -27,6 +27,7 @@ class VfsFilesystem; namespace Kernel { class GlobalScheduler; class KernelCore; +class PhysicalCore; class Process; class Scheduler; } // namespace Kernel @@ -211,6 +212,12 @@ public: /// Gets the scheduler for the CPU core that is currently running const Kernel::Scheduler& CurrentScheduler() const; + /// Gets the physical core for the CPU core that is currently running + Kernel::PhysicalCore& CurrentPhysicalCore(); + + /// Gets the physical core for the CPU core that is currently running + const Kernel::PhysicalCore& CurrentPhysicalCore() const; + /// Gets a reference to an ARM interface for the CPU core with the specified index ARM_Interface& ArmInterface(std::size_t core_index); diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dfb032b4b6..2a218e2942 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -27,6 +27,7 @@ #include "core/hle/kernel/memory/memory_block.h" #include "core/hle/kernel/memory/page_table.h" #include "core/hle/kernel/mutex.h" +#include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/readable_event.h" #include "core/hle/kernel/resource_limit.h" @@ -1071,6 +1072,7 @@ static ResultCode GetThreadPriority(Core::System& system, u32* priority, Handle const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable(); const std::shared_ptr thread = handle_table.Get(handle); if (!thread) { + *priority = 0; LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); return ERR_INVALID_HANDLE; } @@ -1105,14 +1107,13 @@ static ResultCode SetThreadPriority(Core::System& system, Handle handle, u32 pri thread->SetPriority(priority); - system.PrepareReschedule(thread->GetProcessorID()); return RESULT_SUCCESS; } /// Get which CPU core is executing the current thread static u32 GetCurrentProcessorNumber(Core::System& system) { LOG_TRACE(Kernel_SVC, "called"); - return system.CurrentScheduler().GetCurrentThread()->GetProcessorID(); + return static_cast(system.CurrentPhysicalCore().CoreIndex()); } static ResultCode MapSharedMemory(Core::System& system, Handle shared_memory_handle, VAddr addr, @@ -1430,8 +1431,8 @@ static ResultCode CreateThread(Core::System& system, Handle* out_handle, VAddr e ThreadType type = THREADTYPE_USER; CASCADE_RESULT(std::shared_ptr thread, - Thread::Create(system, type, "", entry_point, priority, arg, processor_id, stack_top, - current_process)); + Thread::Create(system, type, "", entry_point, priority, arg, processor_id, + stack_top, current_process)); const auto new_thread_handle = current_process->GetHandleTable().Create(thread); if (new_thread_handle.Failed()) { @@ -1804,6 +1805,8 @@ static ResultCode GetThreadCoreMask(Core::System& system, Handle thread_handle, if (!thread) { LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", thread_handle); + *core = 0; + *mask = 0; return ERR_INVALID_HANDLE; } @@ -1866,11 +1869,7 @@ static ResultCode SetThreadCoreMask(Core::System& system, Handle thread_handle, return ERR_INVALID_HANDLE; } - system.PrepareReschedule(thread->GetProcessorID()); - thread->ChangeCore(core, affinity_mask); - system.PrepareReschedule(thread->GetProcessorID()); - - return RESULT_SUCCESS; + return thread->SetCoreAndAffinityMask(core, affinity_mask); } static ResultCode CreateEvent(Core::System& system, Handle* write_handle, Handle* read_handle) { diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index d9e6102722..e6bb7c6663 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -250,6 +250,7 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy } void Thread::SetPriority(u32 priority) { + SchedulerLock lock(kernel); ASSERT_MSG(priority <= THREADPRIO_LOWEST && priority >= THREADPRIO_HIGHEST, "Invalid priority value."); nominal_priority = priority; @@ -383,10 +384,6 @@ void Thread::UpdatePriority() { lock_owner->UpdatePriority(); } -void Thread::ChangeCore(u32 core, u64 mask) { - SetCoreAndAffinityMask(core, mask); -} - bool Thread::AllSynchronizationObjectsReady() const { return std::none_of(wait_objects.begin(), wait_objects.end(), [this](const std::shared_ptr& object) { @@ -467,6 +464,7 @@ void Thread::SetCurrentPriority(u32 new_priority) { } ResultCode Thread::SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask) { + SchedulerLock lock(kernel); const auto HighestSetCore = [](u64 mask, u32 max_cores) { for (s32 core = static_cast(max_cores - 1); core >= 0; core--) { if (((mask >> core) & 1) != 0) { diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 78a4357b00..29fe5483b4 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -221,7 +221,7 @@ public: void UpdatePriority(); /// Changes the core that the thread is running or scheduled to run on. - void ChangeCore(u32 core, u64 mask); + ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); /** * Gets the thread's thread ID @@ -522,7 +522,6 @@ private: void SetSchedulingStatus(ThreadSchedStatus new_status); void SetCurrentPriority(u32 new_priority); - ResultCode SetCoreAndAffinityMask(s32 new_core, u64 new_affinity_mask); void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); -- cgit v1.2.3 From cc2f7dcd08ae9455524098d2c575eed484d8f08c Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 8 Mar 2020 22:39:41 -0400 Subject: General: Initial Setup for Single Core. --- src/core/core.cpp | 3 + src/core/cpu_manager.cpp | 186 +++++++++++++++++++++++---- src/core/cpu_manager.h | 30 ++++- src/core/hle/kernel/kernel.cpp | 19 +++ src/core/hle/kernel/kernel.h | 3 + src/core/memory.cpp | 8 +- src/yuzu/configuration/configure_general.cpp | 6 + src/yuzu/configuration/configure_general.ui | 7 + 8 files changed, 228 insertions(+), 34 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 5d4ecdce5a..fd1bdcaf0a 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -149,6 +149,9 @@ struct System::Impl { device_memory = std::make_unique(system); + kernel.SetMulticore(Settings::values.use_multi_core); + cpu_manager.SetMulticore(Settings::values.use_multi_core); + core_timing.Initialize([&system]() { system.RegisterHostThread(); }); kernel.Initialize(); cpu_manager.Initialize(); diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 9a261968a7..e72f898083 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -26,9 +26,13 @@ void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) { void CpuManager::Initialize() { running_mode = true; - for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { - core_data[core].host_thread = - std::make_unique(ThreadStart, std::ref(*this), core); + if (is_multicore) { + for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { + core_data[core].host_thread = + std::make_unique(ThreadStart, std::ref(*this), core); + } + } else { + core_data[0].host_thread = std::make_unique(ThreadStart, std::ref(*this), 0); } } @@ -41,52 +45,72 @@ void CpuManager::Shutdown() { } } +std::function CpuManager::GetGuestThreadStartFunc() { + return std::function(GuestThreadFunction); +} + +std::function CpuManager::GetIdleThreadStartFunc() { + return std::function(IdleThreadFunction); +} + +std::function CpuManager::GetSuspendThreadStartFunc() { + return std::function(SuspendThreadFunction); +} + void CpuManager::GuestThreadFunction(void* cpu_manager_) { CpuManager* cpu_manager = static_cast(cpu_manager_); - cpu_manager->RunGuestThread(); + if (cpu_manager->is_multicore) { + cpu_manager->MultiCoreRunGuestThread(); + } else { + cpu_manager->SingleCoreRunGuestThread(); + } } void CpuManager::GuestRewindFunction(void* cpu_manager_) { CpuManager* cpu_manager = static_cast(cpu_manager_); - cpu_manager->RunGuestLoop(); + if (cpu_manager->is_multicore) { + cpu_manager->MultiCoreRunGuestLoop(); + } else { + cpu_manager->SingleCoreRunGuestLoop(); + } } void CpuManager::IdleThreadFunction(void* cpu_manager_) { CpuManager* cpu_manager = static_cast(cpu_manager_); - cpu_manager->RunIdleThread(); + if (cpu_manager->is_multicore) { + cpu_manager->MultiCoreRunIdleThread(); + } else { + cpu_manager->SingleCoreRunIdleThread(); + } } void CpuManager::SuspendThreadFunction(void* cpu_manager_) { CpuManager* cpu_manager = static_cast(cpu_manager_); - cpu_manager->RunSuspendThread(); -} - -std::function CpuManager::GetGuestThreadStartFunc() { - return std::function(GuestThreadFunction); -} - -std::function CpuManager::GetIdleThreadStartFunc() { - return std::function(IdleThreadFunction); -} - -std::function CpuManager::GetSuspendThreadStartFunc() { - return std::function(SuspendThreadFunction); + if (cpu_manager->is_multicore) { + cpu_manager->MultiCoreRunSuspendThread(); + } else { + cpu_manager->SingleCoreRunSuspendThread(); + } } void* CpuManager::GetStartFuncParamater() { return static_cast(this); } -void CpuManager::RunGuestThread() { +/////////////////////////////////////////////////////////////////////////////// +/// MultiCore /// +/////////////////////////////////////////////////////////////////////////////// + +void CpuManager::MultiCoreRunGuestThread() { auto& kernel = system.Kernel(); { auto& sched = kernel.CurrentScheduler(); sched.OnThreadStart(); } - RunGuestLoop(); + MultiCoreRunGuestLoop(); } -void CpuManager::RunGuestLoop() { +void CpuManager::MultiCoreRunGuestLoop() { auto& kernel = system.Kernel(); auto* thread = kernel.CurrentScheduler().GetCurrentThread(); auto host_context = thread->GetHostContext(); @@ -103,7 +127,7 @@ void CpuManager::RunGuestLoop() { } } -void CpuManager::RunIdleThread() { +void CpuManager::MultiCoreRunIdleThread() { auto& kernel = system.Kernel(); while (true) { auto& physical_core = kernel.CurrentPhysicalCore(); @@ -113,7 +137,7 @@ void CpuManager::RunIdleThread() { } } -void CpuManager::RunSuspendThread() { +void CpuManager::MultiCoreRunSuspendThread() { auto& kernel = system.Kernel(); { auto& sched = kernel.CurrentScheduler(); @@ -130,7 +154,7 @@ void CpuManager::RunSuspendThread() { } } -void CpuManager::Pause(bool paused) { +void CpuManager::MultiCorePause(bool paused) { if (!paused) { bool all_not_barrier = false; while (!all_not_barrier) { @@ -171,10 +195,120 @@ void CpuManager::Pause(bool paused) { paused_state = paused; } +/////////////////////////////////////////////////////////////////////////////// +/// SingleCore /// +/////////////////////////////////////////////////////////////////////////////// + +void CpuManager::SingleCoreRunGuestThread() { + auto& kernel = system.Kernel(); + { + auto& sched = kernel.CurrentScheduler(); + sched.OnThreadStart(); + } + SingleCoreRunGuestLoop(); +} + +void CpuManager::SingleCoreRunGuestLoop() { + auto& kernel = system.Kernel(); + auto* thread = kernel.CurrentScheduler().GetCurrentThread(); + auto host_context = thread->GetHostContext(); + host_context->SetRewindPoint(std::function(GuestRewindFunction), this); + host_context.reset(); + while (true) { + auto& physical_core = kernel.CurrentPhysicalCore(); + while (!physical_core.IsInterrupted()) { + physical_core.Run(); + preemption_count++; + if (preemption_count % max_cycle_runs == 0) { + break; + } + } + physical_core.ClearExclusive(); + PreemptSingleCore(); + auto& scheduler = physical_core.Scheduler(); + scheduler.TryDoContextSwitch(); + } +} + +void CpuManager::SingleCoreRunIdleThread() { + auto& kernel = system.Kernel(); + while (true) { + auto& physical_core = kernel.CurrentPhysicalCore(); + PreemptSingleCore(); + auto& scheduler = physical_core.Scheduler(); + scheduler.TryDoContextSwitch(); + } +} + +void CpuManager::SingleCoreRunSuspendThread() { + auto& kernel = system.Kernel(); + { + auto& sched = kernel.CurrentScheduler(); + sched.OnThreadStart(); + } + while (true) { + auto core = kernel.GetCurrentHostThreadID(); + auto& scheduler = kernel.CurrentScheduler(); + Kernel::Thread* current_thread = scheduler.GetCurrentThread(); + Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context); + ASSERT(scheduler.ContextSwitchPending()); + ASSERT(core == kernel.GetCurrentHostThreadID()); + scheduler.TryDoContextSwitch(); + } +} + +void CpuManager::PreemptSingleCore() { + preemption_count = 0; + std::size_t old_core = current_core; + current_core = (current_core + 1) % Core::Hardware::NUM_CPU_CORES; + auto& scheduler = system.Kernel().Scheduler(old_core); + Kernel::Thread* current_thread = system.Kernel().Scheduler(old_core).GetCurrentThread(); + Kernel::Thread* next_thread = system.Kernel().Scheduler(current_core).GetCurrentThread(); + Common::Fiber::YieldTo(current_thread->GetHostContext(), next_thread->GetHostContext()); +} + +void CpuManager::SingleCorePause(bool paused) { + if (!paused) { + bool all_not_barrier = false; + while (!all_not_barrier) { + all_not_barrier = !core_data[0].is_running.load() && core_data[0].initialized.load(); + } + core_data[0].enter_barrier->Set(); + if (paused_state.load()) { + bool all_barrier = false; + while (!all_barrier) { + all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load(); + } + core_data[0].exit_barrier->Set(); + } + } else { + /// Wait until all cores are paused. + bool all_barrier = false; + while (!all_barrier) { + all_barrier = core_data[0].is_paused.load() && core_data[0].initialized.load(); + } + /// Don't release the barrier + } + paused_state = paused; +} + +void CpuManager::Pause(bool paused) { + if (is_multicore) { + MultiCorePause(paused); + } else { + SingleCorePause(paused); + } +} + void CpuManager::RunThread(std::size_t core) { /// Initialization system.RegisterCoreThread(core); - std::string name = "yuzu:CoreHostThread_" + std::to_string(core); + std::string name; + if (is_multicore) { + name = "yuzu:CoreCPUThread_" + std::to_string(core); + } else { + name = "yuzu:CPUThread"; + } MicroProfileOnThreadCreate(name.c_str()); Common::SetCurrentThreadName(name.c_str()); auto& data = core_data[core]; diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index e83ab20f9c..1e81481ec2 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -30,6 +30,10 @@ 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_multicore) { + this->is_multicore = is_multicore; + } void Initialize(); void Shutdown(); @@ -40,21 +44,34 @@ public: std::function GetSuspendThreadStartFunc(); void* GetStartFuncParamater(); + std::size_t CurrentCore() const { + return current_core; + } + private: static void GuestThreadFunction(void* cpu_manager); static void GuestRewindFunction(void* cpu_manager); static void IdleThreadFunction(void* cpu_manager); static void SuspendThreadFunction(void* cpu_manager); - void RunGuestThread(); - void RunGuestLoop(); - void RunIdleThread(); - void RunSuspendThread(); + void MultiCoreRunGuestThread(); + void MultiCoreRunGuestLoop(); + void MultiCoreRunIdleThread(); + void MultiCoreRunSuspendThread(); + void MultiCorePause(bool paused); + + void SingleCoreRunGuestThread(); + void SingleCoreRunGuestLoop(); + void SingleCoreRunIdleThread(); + void SingleCoreRunSuspendThread(); + void SingleCorePause(bool paused); static void ThreadStart(CpuManager& cpu_manager, std::size_t core); void RunThread(std::size_t core); + void PreemptSingleCore(); + struct CoreData { std::shared_ptr host_context; std::unique_ptr enter_barrier; @@ -70,6 +87,11 @@ private: std::array core_data{}; + bool is_multicore{}; + std::size_t current_core{}; + std::size_t preemption_count{}; + static constexpr std::size_t max_cycle_runs = 5; + System& system; }; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 721ab1e708..4a091ea381 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -113,6 +113,10 @@ struct KernelCore::Impl { explicit Impl(Core::System& system, KernelCore& kernel) : global_scheduler{kernel}, synchronization{system}, time_manager{system}, system{system} {} + void SetMulticore(bool is_multicore) { + this->is_multicore = is_multicore; + } + void Initialize(KernelCore& kernel) { Shutdown(); @@ -237,6 +241,9 @@ struct KernelCore::Impl { void RegisterCoreThread(std::size_t core_id) { std::unique_lock lock{register_thread_mutex}; + if (!is_multicore) { + single_core_thread_id = std::this_thread::get_id(); + } const std::thread::id this_id = std::this_thread::get_id(); const auto it = host_thread_ids.find(this_id); ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); @@ -258,6 +265,11 @@ struct KernelCore::Impl { u32 GetCurrentHostThreadID() const { const std::thread::id this_id = std::this_thread::get_id(); + if (!is_multicore) { + if (single_core_thread_id == this_id) { + return static_cast(system.GetCpuManager().CurrentCore()); + } + } const auto it = host_thread_ids.find(this_id); if (it == host_thread_ids.end()) { return Core::INVALID_HOST_THREAD_ID; @@ -378,6 +390,9 @@ struct KernelCore::Impl { std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; + bool is_multicore{}; + std::thread::id single_core_thread_id{}; + // System context Core::System& system; }; @@ -387,6 +402,10 @@ KernelCore::~KernelCore() { Shutdown(); } +void KernelCore::SetMulticore(bool is_multicore) { + impl->SetMulticore(is_multicore); +} + void KernelCore::Initialize() { impl->Initialize(*this); } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 5d32a83294..162bbd2f8d 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -65,6 +65,9 @@ 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(); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 4cb5d05e59..7def007689 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -715,8 +715,8 @@ struct Memory::Impl { ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); break; case Common::PageType::RasterizerCachedMemory: { - u8* host_ptr{GetPointerFromVMA(vaddr)}; - system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(T)); + u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)}; + system.GPU().InvalidateRegion(vaddr, sizeof(T)); T volatile* pointer = reinterpret_cast(&host_ptr); return Common::AtomicCompareAndSwap(pointer, data, expected); break; @@ -745,8 +745,8 @@ struct Memory::Impl { ASSERT_MSG(false, "Mapped memory page without a pointer @ {:016X}", vaddr); break; case Common::PageType::RasterizerCachedMemory: { - u8* host_ptr{GetPointerFromVMA(vaddr)}; - system.GPU().InvalidateRegion(ToCacheAddr(host_ptr), sizeof(u128)); + u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)}; + system.GPU().InvalidateRegion(vaddr, sizeof(u128)); u64 volatile* pointer = reinterpret_cast(&host_ptr); return Common::AtomicCompareAndSwap(pointer, data, expected); break; diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index cb95423e09..74b2ad537b 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -23,6 +23,11 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent) ConfigureGeneral::~ConfigureGeneral() = default; void ConfigureGeneral::SetConfiguration() { + const bool runtime_lock = !Core::System::GetInstance().IsPoweredOn(); + + ui->use_multi_core->setEnabled(runtime_lock); + ui->use_multi_core->setChecked(Settings::values.use_multi_core); + ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot); ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background); @@ -41,6 +46,7 @@ void ConfigureGeneral::ApplyConfiguration() { Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); Settings::values.frame_limit = ui->frame_limit->value(); + Settings::values.use_multi_core = ui->use_multi_core->isChecked(); } void ConfigureGeneral::changeEvent(QEvent* event) { diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index fc3b7e65a5..f872bddecf 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -51,6 +51,13 @@ + + + + Emulate CPU in Multiple Cores + + + -- cgit v1.2.3 From b121009e0362a7f8539737324030c59fcef3e2c5 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 12 Mar 2020 16:48:43 -0400 Subject: General: Fix microprofile on dynarmic/svc, fix wait tree showing which threads were running. --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 4 ---- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 5 +---- src/core/core.cpp | 15 +++++++++++++++ src/core/core.h | 6 ++++++ src/core/cpu_manager.cpp | 4 ++++ src/core/hle/kernel/kernel.cpp | 15 +++++++++++++++ src/core/hle/kernel/kernel.h | 4 ++++ src/core/hle/kernel/scheduler.cpp | 7 +++++++ src/core/hle/kernel/svc.cpp | 10 +++++++--- src/core/hle/kernel/thread.h | 18 ++++++++++++++++++ src/yuzu/debugger/wait_tree.cpp | 12 ++++++++++-- 11 files changed, 87 insertions(+), 13 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 30bf62ac1c..618f02f30a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -7,7 +7,6 @@ #include #include #include -#include "common/microprofile.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/dynarmic/arm_dynarmic_32.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" @@ -97,10 +96,7 @@ std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable& return std::make_unique(config); } -MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_32, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); - void ARM_Dynarmic_32::Run() { - MICROPROFILE_SCOPE(ARM_Jit_Dynarmic_32); jit->Run(); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index a22c22bf00..84b872f0b8 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -7,7 +7,6 @@ #include #include #include "common/logging/log.h" -#include "common/microprofile.h" #include "common/page_table.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" @@ -181,11 +180,9 @@ std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& return std::make_shared(config); } -MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_64, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); -void ARM_Dynarmic_64::Run() { - MICROPROFILE_SCOPE(ARM_Jit_Dynarmic_64); +void ARM_Dynarmic_64::Run() { jit->Run(); } diff --git a/src/core/core.cpp b/src/core/core.cpp index fd1bdcaf0a..032da7aa58 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -8,6 +8,7 @@ #include "common/file_util.h" #include "common/logging/log.h" +#include "common/microprofile.h" #include "common/string_util.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" @@ -50,6 +51,8 @@ #include "video_core/renderer_base.h" #include "video_core/video_core.h" +MICROPROFILE_DEFINE(ARM_Jit_Dynarmic, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); + namespace Core { namespace { @@ -391,6 +394,8 @@ struct System::Impl { std::unique_ptr perf_stats; Core::FrameLimiter frame_limiter; + + std::array dynarmic_ticks{}; }; System::System() : impl{std::make_unique(*this)} {} @@ -736,4 +741,14 @@ void System::RegisterHostThread() { impl->kernel.RegisterHostThread(); } +void System::EnterDynarmicProfile() { + std::size_t core = impl->kernel.GetCurrentHostThreadID(); + impl->dynarmic_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(ARM_Jit_Dynarmic)); +} + +void System::ExitDynarmicProfile() { + std::size_t core = impl->kernel.GetCurrentHostThreadID(); + MicroProfileLeave(MICROPROFILE_TOKEN(ARM_Jit_Dynarmic), impl->dynarmic_ticks[core]); +} + } // namespace Core diff --git a/src/core/core.h b/src/core/core.h index 9a0dd10753..87df79d573 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -377,6 +377,12 @@ public: /// Register a host thread as an auxiliary thread. void RegisterHostThread(); + /// Enter Dynarmic Microprofile + void EnterDynarmicProfile(); + + /// Exit Dynarmic Microprofile + void ExitDynarmicProfile(); + private: System(); diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 95842aad10..9e2e6d49fb 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -118,9 +118,11 @@ void CpuManager::MultiCoreRunGuestLoop() { host_context.reset(); while (true) { auto& physical_core = kernel.CurrentPhysicalCore(); + system.EnterDynarmicProfile(); while (!physical_core.IsInterrupted()) { physical_core.Run(); } + system.ExitDynarmicProfile(); physical_core.ClearExclusive(); auto& scheduler = physical_core.Scheduler(); scheduler.TryDoContextSwitch(); @@ -216,6 +218,7 @@ void CpuManager::SingleCoreRunGuestLoop() { host_context.reset(); while (true) { auto& physical_core = kernel.CurrentPhysicalCore(); + system.EnterDynarmicProfile(); while (!physical_core.IsInterrupted()) { physical_core.Run(); preemption_count++; @@ -224,6 +227,7 @@ void CpuManager::SingleCoreRunGuestLoop() { } } physical_core.ClearExclusive(); + system.ExitDynarmicProfile(); PreemptSingleCore(); auto& scheduler = kernel.Scheduler(current_core); scheduler.TryDoContextSwitch(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 24da4367e4..d2f5f9bf23 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -13,6 +13,7 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "common/microprofile.h" #include "common/thread.h" #include "core/arm/arm_interface.h" #include "core/arm/exclusive_monitor.h" @@ -41,6 +42,8 @@ #include "core/hle/result.h" #include "core/memory.h" +MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); + namespace Kernel { /** @@ -408,6 +411,8 @@ struct KernelCore::Impl { bool is_multicore{}; std::thread::id single_core_thread_id{}; + std::array svc_ticks{}; + // System context Core::System& system; }; @@ -666,4 +671,14 @@ void KernelCore::ExceptionalExit() { Suspend(true); } +void KernelCore::EnterSVCProfile() { + std::size_t core = impl->GetCurrentHostThreadID(); + impl->svc_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(Kernel_SVC)); +} + +void KernelCore::ExitSVCProfile() { + std::size_t core = impl->GetCurrentHostThreadID(); + MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[core]); +} + } // namespace Kernel diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 50eeb50ec1..1eb6ede73e 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -214,6 +214,10 @@ public: bool IsMulticore() const; + void EnterSVCProfile(); + + void ExitSVCProfile(); + private: friend class Object; friend class Process; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 25fc8a3e8b..2ad380b175 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -354,7 +354,9 @@ void GlobalScheduler::EnableInterruptAndSchedule(u32 cores_pending_reschedule, } if (must_context_switch) { auto& core_scheduler = kernel.CurrentScheduler(); + kernel.ExitSVCProfile(); core_scheduler.TryDoContextSwitch(); + kernel.EnterSVCProfile(); } } @@ -628,6 +630,7 @@ void Scheduler::Reload() { // Cancel any outstanding wakeup events for this thread thread->SetIsRunning(true); + thread->SetWasRunning(false); thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); auto* const thread_owner_process = thread->GetOwnerProcess(); @@ -660,6 +663,7 @@ void Scheduler::SwitchContextStep2() { // Cancel any outstanding wakeup events for this thread new_thread->SetIsRunning(true); new_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + new_thread->SetWasRunning(false); auto* const thread_owner_process = current_thread->GetOwnerProcess(); if (previous_process != thread_owner_process && thread_owner_process != nullptr) { @@ -698,6 +702,9 @@ void Scheduler::SwitchContext() { // Save context for previous thread if (previous_thread) { + if (new_thread != nullptr && new_thread->IsSuspendThread()) { + previous_thread->SetWasRunning(true); + } previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); if (!previous_thread->IsHLEThread()) { diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index d3d4e7bf9f..9b9f9402ea 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2454,10 +2454,10 @@ static const FunctionDef* GetSVCInfo64(u32 func_num) { return &SVC_Table_64[func_num]; } -MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); - void Call(Core::System& system, u32 immediate) { - MICROPROFILE_SCOPE(Kernel_SVC); + system.ExitDynarmicProfile(); + auto& kernel = system.Kernel(); + kernel.EnterSVCProfile(); auto* thread = system.CurrentScheduler().GetCurrentThread(); thread->SetContinuousOnSVC(true); @@ -2474,10 +2474,14 @@ void Call(Core::System& system, u32 immediate) { LOG_CRITICAL(Kernel_SVC, "Unknown SVC function 0x{:X}", immediate); } + kernel.ExitSVCProfile(); + if (!thread->IsContinuousOnSVC()) { auto* host_context = thread->GetHostContext().get(); host_context->Rewind(); } + + system.EnterDynarmicProfile(); } } // namespace Kernel::Svc diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 168828ab0f..f42d7bd136 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -350,6 +350,22 @@ public: return (type & THREADTYPE_HLE) != 0; } + bool IsSuspendThread() const { + return (type & THREADTYPE_SUSPEND) != 0; + } + + bool IsIdleThread() const { + return (type & THREADTYPE_IDLE) != 0; + } + + bool WasRunning() const { + return was_running; + } + + void SetWasRunning(bool value) { + was_running = value; + } + std::shared_ptr GetHostContext() const; ThreadStatus GetStatus() const { @@ -684,6 +700,8 @@ private: bool will_be_terminated = false; + bool was_running = false; + std::string name; }; diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp index ab7b18abec..fa091f4573 100644 --- a/src/yuzu/debugger/wait_tree.cpp +++ b/src/yuzu/debugger/wait_tree.cpp @@ -209,7 +209,11 @@ QString WaitTreeThread::GetText() const { break; case Kernel::ThreadStatus::Ready: if (!thread.IsPaused()) { - status = tr("ready"); + if (thread.WasRunning()) { + status = tr("running"); + } else { + status = tr("ready"); + } } else { status = tr("paused"); } @@ -261,7 +265,11 @@ QColor WaitTreeThread::GetColor() const { return QColor(Qt::GlobalColor::darkGreen); case Kernel::ThreadStatus::Ready: if (!thread.IsPaused()) { - return QColor(Qt::GlobalColor::darkBlue); + if (thread.WasRunning()) { + return QColor(Qt::GlobalColor::darkGreen); + } else { + return QColor(Qt::GlobalColor::darkBlue); + } } else { return QColor(Qt::GlobalColor::lightGray); } -- cgit v1.2.3 From 1bcceea736be6f164fde37dfcded52101667320e Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 15 Mar 2020 21:34:22 -0400 Subject: GUI: Make multicore only work with Async and add GUI for multicore. --- src/core/core.cpp | 11 +++++++++-- src/core/cpu_manager.cpp | 11 +++++++++++ src/core/cpu_manager.h | 14 ++++++++++++++ src/yuzu/configuration/configure_general.ui | 2 +- src/yuzu/main.cpp | 29 +++++++++++++++++++++++++++-- src/yuzu/main.h | 1 + 6 files changed, 63 insertions(+), 5 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 032da7aa58..0f0eb885ad 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -152,8 +152,12 @@ struct System::Impl { device_memory = std::make_unique(system); - kernel.SetMulticore(Settings::values.use_multi_core); - cpu_manager.SetMulticore(Settings::values.use_multi_core); + is_multicore = Settings::values.use_multi_core; + is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation; + + kernel.SetMulticore(is_multicore); + cpu_manager.SetMulticore(is_multicore); + cpu_manager.SetAsyncGpu(is_async_gpu); core_timing.Initialize([&system]() { system.RegisterHostThread(); }); kernel.Initialize(); @@ -395,6 +399,9 @@ struct System::Impl { std::unique_ptr perf_stats; Core::FrameLimiter frame_limiter; + bool is_multicore{}; + bool is_async_gpu{}; + std::array dynarmic_ticks{}; }; diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index e92b0fb376..d7bd162bc5 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -9,6 +9,7 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/cpu_manager.h" +#include "core/frontend/emu_window.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" @@ -21,7 +22,17 @@ CpuManager::CpuManager(System& system) : system{system} {} CpuManager::~CpuManager() = default; void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) { + if (!cpu_manager.is_async_gpu && !cpu_manager.is_multicore) { + cpu_manager.render_window->MakeCurrent(); + } cpu_manager.RunThread(core); + if (!cpu_manager.is_async_gpu && !cpu_manager.is_multicore) { + cpu_manager.render_window->DoneCurrent(); + } +} + +void CpuManager::SetRenderWindow(Core::Frontend::EmuWindow& render_window) { + this->render_window = &render_window; } void CpuManager::Initialize() { diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index c0e454a7dd..37cef2b122 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -16,6 +16,10 @@ class Event; class Fiber; } // namespace Common +namespace Core::Frontend { +class EmuWindow; +} // namespace Core::Frontend + namespace Core { class System; @@ -35,6 +39,12 @@ public: void SetMulticore(bool is_multicore) { this->is_multicore = is_multicore; } + + /// Sets if emulation is using an asynchronous GPU. + void SetAsyncGpu(bool is_async_gpu) { + this->is_async_gpu = is_async_gpu; + } + void Initialize(); void Shutdown(); @@ -51,6 +61,8 @@ public: return current_core.load(); } + void SetRenderWindow(Core::Frontend::EmuWindow& render_window); + private: static void GuestThreadFunction(void* cpu_manager); static void GuestRewindFunction(void* cpu_manager); @@ -88,10 +100,12 @@ private: std::array core_data{}; + bool is_async_gpu{}; bool is_multicore{}; std::atomic current_core{}; std::size_t preemption_count{}; static constexpr std::size_t max_cycle_runs = 5; + Core::Frontend::EmuWindow* render_window; System& system; }; diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index f872bddecf..2711116a23 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui @@ -54,7 +54,7 @@ - Emulate CPU in Multiple Cores + Multicore CPU Emulation diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index de0c7fe8cc..f1d9ec326a 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -534,14 +534,34 @@ void GMainWindow::InitializeWidgets() { if (emulation_running) { return; } - Settings::values.use_asynchronous_gpu_emulation = - !Settings::values.use_asynchronous_gpu_emulation; + bool is_async = !Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; + Settings::values.use_asynchronous_gpu_emulation = is_async; async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); Settings::Apply(); }); async_status_button->setText(tr("ASYNC")); async_status_button->setCheckable(true); async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); + + // Setup Multicore button + multicore_status_button = new QPushButton(); + multicore_status_button->setObjectName(QStringLiteral("TogglableStatusBarButton")); + multicore_status_button->setFocusPolicy(Qt::NoFocus); + connect(multicore_status_button, &QPushButton::clicked, [&] { + if (emulation_running) { + return; + } + Settings::values.use_multi_core = !Settings::values.use_multi_core; + bool is_async = Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; + Settings::values.use_asynchronous_gpu_emulation = is_async; + async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); + multicore_status_button->setChecked(Settings::values.use_multi_core); + Settings::Apply(); + }); + multicore_status_button->setText(tr("MULTICORE")); + multicore_status_button->setCheckable(true); + multicore_status_button->setChecked(Settings::values.use_multi_core); + statusBar()->insertPermanentWidget(0, multicore_status_button); statusBar()->insertPermanentWidget(0, async_status_button); // Setup Renderer API button @@ -1043,6 +1063,7 @@ void GMainWindow::BootGame(const QString& filename) { } status_bar_update_timer.start(2000); async_status_button->setDisabled(true); + multicore_status_button->setDisabled(true); renderer_status_button->setDisabled(true); if (UISettings::values.hide_mouse) { @@ -1130,6 +1151,7 @@ void GMainWindow::ShutdownGame() { game_fps_label->setVisible(false); emu_frametime_label->setVisible(false); async_status_button->setEnabled(true); + multicore_status_button->setEnabled(true); #ifdef HAS_VULKAN renderer_status_button->setEnabled(true); #endif @@ -1935,7 +1957,10 @@ void GMainWindow::OnConfigure() { } dock_status_button->setChecked(Settings::values.use_docked_mode); + multicore_status_button->setChecked(Settings::values.use_multi_core); + Settings::values.use_asynchronous_gpu_emulation = Settings::values.use_asynchronous_gpu_emulation || Settings::values.use_multi_core; async_status_button->setChecked(Settings::values.use_asynchronous_gpu_emulation); + #ifdef HAS_VULKAN renderer_status_button->setChecked(Settings::values.renderer_backend == Settings::RendererBackend::Vulkan); diff --git a/src/yuzu/main.h b/src/yuzu/main.h index d55e55cc66..5581874ed6 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h @@ -235,6 +235,7 @@ private: QLabel* game_fps_label = nullptr; QLabel* emu_frametime_label = nullptr; QPushButton* async_status_button = nullptr; + QPushButton* multicore_status_button = nullptr; QPushButton* renderer_status_button = nullptr; QPushButton* dock_status_button = nullptr; QTimer status_bar_update_timer; -- cgit v1.2.3 From 287ea2d3b4324110eec1a972ebe59fa702c082e9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 19 Mar 2020 13:09:32 -0400 Subject: SingleCore: Move Host Timing from a sepparate thread to main cpu thread. --- src/core/core.cpp | 2 ++ src/core/core_timing.cpp | 20 +++++++++++++------- src/core/core_timing.h | 7 +++++++ src/core/cpu_manager.cpp | 17 +++++++++++++++-- src/core/cpu_manager.h | 1 + src/core/hle/kernel/kernel.cpp | 2 +- src/core/hle/kernel/thread.h | 9 +++++++++ 7 files changed, 48 insertions(+), 10 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 0f0eb885ad..2ca9c0be54 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -158,6 +158,8 @@ struct System::Impl { kernel.SetMulticore(is_multicore); cpu_manager.SetMulticore(is_multicore); cpu_manager.SetAsyncGpu(is_async_gpu); + core_timing.SetMulticore(is_multicore); + cpu_manager.SetRenderWindow(emu_window); core_timing.Initialize([&system]() { system.RegisterHostThread(); }); kernel.Initialize(); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 3438f79cee..189d4aa34d 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -55,7 +55,9 @@ void CoreTiming::Initialize(std::function&& on_thread_init_) { event_fifo_id = 0; const auto empty_timed_callback = [](u64, s64) {}; ev_lost = CreateEvent("_lost_event", empty_timed_callback); - timer_thread = std::make_unique(ThreadEntry, std::ref(*this)); + if (is_multicore) { + timer_thread = std::make_unique(ThreadEntry, std::ref(*this)); + } } void CoreTiming::Shutdown() { @@ -63,7 +65,9 @@ void CoreTiming::Shutdown() { shutting_down = true; pause_event.Set(); event.Set(); - timer_thread->join(); + if (timer_thread) { + timer_thread->join(); + } ClearPendingEvents(); timer_thread.reset(); has_started = false; @@ -78,12 +82,14 @@ void CoreTiming::SyncPause(bool is_paused) { return; } Pause(is_paused); - if (!is_paused) { - pause_event.Set(); + if (timer_thread) { + if (!is_paused) { + pause_event.Set(); + } + event.Set(); + while (paused_set != is_paused) + ; } - event.Set(); - while (paused_set != is_paused) - ; } bool CoreTiming::IsRunning() const { diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 032eb08aad..03f9a5c764 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h @@ -67,6 +67,11 @@ 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) { + this->is_multicore = is_multicore; + } + /// Pauses/Unpauses the execution of the timer thread. void Pause(bool is_paused); @@ -147,6 +152,8 @@ private: std::atomic has_started{}; std::function on_thread_init{}; + bool is_multicore{}; + std::array, Core::Hardware::NUM_CPU_CORES> ticks_count{}; }; diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index d7bd162bc5..2aea95a257 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -242,8 +242,11 @@ void CpuManager::SingleCoreRunGuestLoop() { break; } } - physical_core.ClearExclusive(); system.ExitDynarmicProfile(); + thread->SetPhantomMode(true); + system.CoreTiming().Advance(); + thread->SetPhantomMode(false); + physical_core.ClearExclusive(); PreemptSingleCore(); auto& scheduler = kernel.Scheduler(current_core); scheduler.TryDoContextSwitch(); @@ -255,6 +258,7 @@ void CpuManager::SingleCoreRunIdleThread() { while (true) { auto& physical_core = kernel.CurrentPhysicalCore(); PreemptSingleCore(); + idle_count++; auto& scheduler = physical_core.Scheduler(); scheduler.TryDoContextSwitch(); } @@ -280,15 +284,24 @@ void CpuManager::SingleCoreRunSuspendThread() { void CpuManager::PreemptSingleCore() { preemption_count = 0; std::size_t old_core = current_core; - current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); auto& scheduler = system.Kernel().Scheduler(old_core); Kernel::Thread* current_thread = scheduler.GetCurrentThread(); + if (idle_count >= 4) { + current_thread->SetPhantomMode(true); + system.CoreTiming().Advance(); + current_thread->SetPhantomMode(false); + } + current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES); scheduler.Unload(); auto& next_scheduler = system.Kernel().Scheduler(current_core); Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext()); /// May have changed scheduler auto& current_scheduler = system.Kernel().Scheduler(current_core); current_scheduler.Reload(); + auto* currrent_thread2 = current_scheduler.GetCurrentThread(); + if (!currrent_thread2->IsIdleThread()) { + idle_count = 0; + } } void CpuManager::SingleCorePause(bool paused) { diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 37cef2b122..e6b8612f0e 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -104,6 +104,7 @@ private: bool is_multicore{}; std::atomic current_core{}; std::size_t preemption_count{}; + std::size_t idle_count{}; static constexpr std::size_t max_cycle_runs = 5; Core::Frontend::EmuWindow* render_window; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index d2f5f9bf23..a19cd7a1ff 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -303,7 +303,7 @@ struct KernelCore::Impl { } const Kernel::Scheduler& sched = cores[result.host_handle].Scheduler(); const Kernel::Thread* current = sched.GetCurrentThread(); - if (current != nullptr) { + if (current != nullptr && !current->IsPhantomMode()) { result.guest_handle = current->GetGlobalHandle(); } else { result.guest_handle = InvalidHandle; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f42d7bd136..f998890c4b 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -597,6 +597,14 @@ public: is_continuous_on_svc = is_continuous; } + bool IsPhantomMode() const { + return is_phantom_mode; + } + + void SetPhantomMode(bool phantom) { + is_phantom_mode = phantom; + } + private: friend class GlobalScheduler; friend class Scheduler; @@ -699,6 +707,7 @@ private: bool is_continuous_on_svc = false; bool will_be_terminated = false; + bool is_phantom_mode = false; bool was_running = false; -- cgit v1.2.3 From db60ca2704b15d8d31e58185a583e6fbe4189f53 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 1 Mar 2020 12:14:17 -0400 Subject: General: Move ARM_Interface into Threads. --- src/core/arm/arm_interface.h | 2 ++ src/core/arm/dynarmic/arm_dynarmic_32.cpp | 4 +++ src/core/arm/dynarmic/arm_dynarmic_32.h | 1 + src/core/arm/dynarmic/arm_dynarmic_64.cpp | 4 +++ src/core/arm/dynarmic/arm_dynarmic_64.h | 1 + src/core/arm/unicorn/arm_unicorn.cpp | 4 +++ src/core/arm/unicorn/arm_unicorn.h | 1 + src/core/core.cpp | 34 ++++++++---------- src/core/core_manager.cpp | 18 ++-------- src/core/cpu_manager.cpp | 30 ++++++++-------- src/core/hle/kernel/kernel.cpp | 59 +++++++++++-------------------- src/core/hle/kernel/kernel.h | 8 ++++- src/core/hle/kernel/physical_core.cpp | 37 +++---------------- src/core/hle/kernel/physical_core.h | 37 ++++--------------- src/core/hle/kernel/scheduler.cpp | 12 +++---- src/core/hle/kernel/svc.cpp | 11 ++---- src/core/hle/kernel/thread.cpp | 35 ++++++++++++++++++ src/core/hle/kernel/thread.h | 8 ++++- 18 files changed, 136 insertions(+), 170 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index dc9b2ff7b9..e5c4843364 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -148,6 +148,8 @@ public: */ virtual void SetTPIDR_EL0(u64 value) = 0; + virtual void ChangeProcessorId(std::size_t new_core_id) = 0; + virtual void SaveContext(ThreadContext32& ctx) = 0; virtual void SaveContext(ThreadContext64& ctx) = 0; virtual void LoadContext(const ThreadContext32& ctx) = 0; diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index f36c5f4017..9c47c133c9 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -165,6 +165,10 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { cp15->uprw = static_cast(value); } +void ARM_Dynarmic_32::ChangeProcessorId(std::size_t new_core_id) { + // jit->ChangeProcessorId(new_core_id); +} + void ARM_Dynarmic_32::SaveContext(ThreadContext32& ctx) { Dynarmic::A32::Context context; jit->SaveContext(context); diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 2dd9a4df0e..bea4933c81 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -47,6 +47,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; + void ChangeProcessorId(std::size_t new_core_id) override; void SaveContext(ThreadContext32& ctx) override; void SaveContext(ThreadContext64& ctx) override {} diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 8401ba631e..03b3313cf1 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -258,6 +258,10 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { cb->tpidr_el0 = value; } +void ARM_Dynarmic_64::ChangeProcessorId(std::size_t new_core_id) { + jit->ChangeProcessorId(new_core_id); +} + void ARM_Dynarmic_64::SaveContext(ThreadContext64& ctx) { ctx.cpu_registers = jit->GetRegisters(); ctx.sp = jit->GetSP(); diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 1c6791d4e5..c26b47249c 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -46,6 +46,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; + void ChangeProcessorId(std::size_t new_core_id) override; void SaveContext(ThreadContext32& ctx) override {} void SaveContext(ThreadContext64& ctx) override; diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index d81d1b5b08..099229c8d4 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -159,6 +159,10 @@ void ARM_Unicorn::SetTPIDR_EL0(u64 value) { CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value)); } +void ARM_Unicorn::ChangeProcessorId(std::size_t new_core_id) { + core_index = new_core_id; +} + void ARM_Unicorn::Run() { if (GDBStub::IsServerEnabled()) { ExecuteInstructions(std::max(4000000U, 0U)); diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index e3da368de9..f09b24a850 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -36,6 +36,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; + void ChangeProcessorId(std::size_t new_core_id) override; void PrepareReschedule() override; void ClearExclusiveState() override; void ExecuteInstructions(std::size_t num_instructions); diff --git a/src/core/core.cpp b/src/core/core.cpp index 2ca9c0be54..40eea297ef 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -119,14 +119,6 @@ struct System::Impl { : kernel{system}, fs_controller{system}, memory{system}, cpu_manager{system}, reporter{system}, applet_manager{system} {} - Kernel::PhysicalCore& CurrentPhysicalCore() { - return kernel.CurrentPhysicalCore(); - } - - Kernel::PhysicalCore& GetPhysicalCore(std::size_t index) { - return kernel.PhysicalCore(index); - } - ResultStatus Run() { status = ResultStatus::Success; @@ -443,7 +435,7 @@ bool System::IsPoweredOn() const { } void System::PrepareReschedule() { - impl->CurrentPhysicalCore().Stop(); + //impl->CurrentPhysicalCore().Stop(); } void System::PrepareReschedule(const u32 core_index) { @@ -463,11 +455,11 @@ const TelemetrySession& System::TelemetrySession() const { } ARM_Interface& System::CurrentArmInterface() { - return impl->CurrentPhysicalCore().ArmInterface(); + return impl->kernel.CurrentScheduler().GetCurrentThread()->ArmInterface(); } const ARM_Interface& System::CurrentArmInterface() const { - return impl->CurrentPhysicalCore().ArmInterface(); + return impl->kernel.CurrentScheduler().GetCurrentThread()->ArmInterface(); } std::size_t System::CurrentCoreIndex() const { @@ -477,27 +469,27 @@ std::size_t System::CurrentCoreIndex() const { } Kernel::Scheduler& System::CurrentScheduler() { - return impl->CurrentPhysicalCore().Scheduler(); + return impl->kernel.CurrentScheduler(); } const Kernel::Scheduler& System::CurrentScheduler() const { - return impl->CurrentPhysicalCore().Scheduler(); + return impl->kernel.CurrentScheduler(); } Kernel::PhysicalCore& System::CurrentPhysicalCore() { - return impl->CurrentPhysicalCore(); + return impl->kernel.CurrentPhysicalCore(); } const Kernel::PhysicalCore& System::CurrentPhysicalCore() const { - return impl->CurrentPhysicalCore(); + return impl->kernel.CurrentPhysicalCore(); } Kernel::Scheduler& System::Scheduler(std::size_t core_index) { - return impl->GetPhysicalCore(core_index).Scheduler(); + return impl->kernel.Scheduler(core_index); } const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const { - return impl->GetPhysicalCore(core_index).Scheduler(); + return impl->kernel.Scheduler(core_index); } /// Gets the global scheduler @@ -527,11 +519,15 @@ const Kernel::Process* System::CurrentProcess() const { } ARM_Interface& System::ArmInterface(std::size_t core_index) { - return impl->GetPhysicalCore(core_index).ArmInterface(); + auto* thread = impl->kernel.Scheduler(core_index).GetCurrentThread(); + ASSERT(thread && !thread->IsHLEThread()); + return thread->ArmInterface(); } const ARM_Interface& System::ArmInterface(std::size_t core_index) const { - return impl->GetPhysicalCore(core_index).ArmInterface(); + auto* thread = impl->kernel.Scheduler(core_index).GetCurrentThread(); + ASSERT(thread && !thread->IsHLEThread()); + return thread->ArmInterface(); } ExclusiveMonitor& System::Monitor() { diff --git a/src/core/core_manager.cpp b/src/core/core_manager.cpp index 45f0bb5470..82d7acb406 100644 --- a/src/core/core_manager.cpp +++ b/src/core/core_manager.cpp @@ -28,21 +28,7 @@ CoreManager::CoreManager(System& system, std::size_t core_index) CoreManager::~CoreManager() = default; void CoreManager::RunLoop(bool tight_loop) { - Reschedule(); - - // If we don't have a currently active thread then don't execute instructions, - // instead advance to the next event and try to yield to the next thread - if (Kernel::GetCurrentThread() == nullptr) { - LOG_TRACE(Core, "Core-{} idling", core_index); - } else { - if (tight_loop) { - physical_core.Run(); - } else { - physical_core.Step(); - } - } - - Reschedule(); + /// Deprecated } void CoreManager::SingleStep() { @@ -50,7 +36,7 @@ void CoreManager::SingleStep() { } void CoreManager::PrepareReschedule() { - physical_core.Stop(); + //physical_core.Stop(); } void CoreManager::Reschedule() { diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 2aea95a257..2e9dc9dc3d 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -129,18 +129,17 @@ void CpuManager::MultiCoreRunGuestThread() { void CpuManager::MultiCoreRunGuestLoop() { auto& kernel = system.Kernel(); auto* thread = kernel.CurrentScheduler().GetCurrentThread(); - auto host_context = thread->GetHostContext(); - host_context->SetRewindPoint(std::function(GuestRewindFunction), this); - host_context.reset(); while (true) { - auto& physical_core = kernel.CurrentPhysicalCore(); + auto* physical_core = &kernel.CurrentPhysicalCore(); + auto& arm_interface = thread->ArmInterface(); system.EnterDynarmicProfile(); - while (!physical_core.IsInterrupted()) { - physical_core.Run(); + while (!physical_core->IsInterrupted()) { + arm_interface.Run(); + physical_core = &kernel.CurrentPhysicalCore(); } system.ExitDynarmicProfile(); - physical_core.ClearExclusive(); - auto& scheduler = physical_core.Scheduler(); + arm_interface.ClearExclusiveState(); + auto& scheduler = kernel.CurrentScheduler(); scheduler.TryDoContextSwitch(); } } @@ -150,7 +149,7 @@ void CpuManager::MultiCoreRunIdleThread() { while (true) { auto& physical_core = kernel.CurrentPhysicalCore(); physical_core.Idle(); - auto& scheduler = physical_core.Scheduler(); + auto& scheduler = kernel.CurrentScheduler(); scheduler.TryDoContextSwitch(); } } @@ -229,14 +228,13 @@ void CpuManager::SingleCoreRunGuestThread() { void CpuManager::SingleCoreRunGuestLoop() { auto& kernel = system.Kernel(); auto* thread = kernel.CurrentScheduler().GetCurrentThread(); - auto host_context = thread->GetHostContext(); - host_context->SetRewindPoint(std::function(GuestRewindFunction), this); - host_context.reset(); while (true) { - auto& physical_core = kernel.CurrentPhysicalCore(); + auto* physical_core = &kernel.CurrentPhysicalCore(); + auto& arm_interface = thread->ArmInterface(); system.EnterDynarmicProfile(); - while (!physical_core.IsInterrupted()) { - physical_core.Run(); + while (!physical_core->IsInterrupted()) { + arm_interface.Run(); + physical_core = &kernel.CurrentPhysicalCore(); preemption_count++; if (preemption_count % max_cycle_runs == 0) { break; @@ -246,7 +244,7 @@ void CpuManager::SingleCoreRunGuestLoop() { thread->SetPhantomMode(true); system.CoreTiming().Advance(); thread->SetPhantomMode(false); - physical_core.ClearExclusive(); + arm_interface.ClearExclusiveState(); PreemptSingleCore(); auto& scheduler = kernel.Scheduler(current_core); scheduler.TryDoContextSwitch(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index e33ef53238..3feddd9ad8 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -19,7 +19,6 @@ #include "core/arm/arm_interface.h" #include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" -#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -45,11 +44,6 @@ #include "core/hle/result.h" #include "core/memory.h" -#ifdef ARCHITECTURE_x86_64 -#include "core/arm/dynarmic/arm_dynarmic_32.h" -#include "core/arm/dynarmic/arm_dynarmic_64.h" -#endif - MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); namespace Kernel { @@ -186,20 +180,8 @@ struct KernelCore::Impl { exclusive_monitor = Core::MakeExclusiveMonitor(system.Memory(), Core::Hardware::NUM_CPU_CORES); for (std::size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { -#ifdef ARCHITECTURE_x86_64 - arm_interfaces_32[i] = - std::make_unique(system, interrupts, *exclusive_monitor, i); - arm_interfaces_64[i] = - std::make_unique(system, interrupts, *exclusive_monitor, i); -#else - arm_interfaces_32[i] = std::make_shared( - system, interrupts, ARM_Unicorn::Arch::AArch32, i); - arm_interfaces_64[i] = std::make_shared( - system, interrupts, ARM_Unicorn::Arch::AArch64, i); - LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); -#endif - cores.emplace_back(system, i, *exclusive_monitor, interrupts[i], *arm_interfaces_32[i], - *arm_interfaces_64[i]); + schedulers[i] = std::make_unique(system, i); + cores.emplace_back(system, i, *schedulers[i], interrupts[i]); } } @@ -268,10 +250,6 @@ struct KernelCore::Impl { return; } - for (auto& core : cores) { - core.SetIs64Bit(process->Is64BitProcess()); - } - u32 core_id = GetCurrentHostThreadID(); if (core_id < Core::Hardware::NUM_CPU_CORES) { system.Memory().SetCurrentPageTable(*process, core_id); @@ -429,10 +407,7 @@ struct KernelCore::Impl { std::array, Core::Hardware::NUM_CPU_CORES> suspend_threads{}; std::array interrupts{}; - std::array, Core::Hardware::NUM_CPU_CORES> - arm_interfaces_32{}; - std::array, Core::Hardware::NUM_CPU_CORES> - arm_interfaces_64{}; + std::array, Core::Hardware::NUM_CPU_CORES> schedulers{}; bool is_multicore{}; std::thread::id single_core_thread_id{}; @@ -497,11 +472,11 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { } Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) { - return impl->cores[id].Scheduler(); + return *impl->schedulers[id]; } const Kernel::Scheduler& KernelCore::Scheduler(std::size_t id) const { - return impl->cores[id].Scheduler(); + return *impl->schedulers[id]; } Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { @@ -525,11 +500,23 @@ const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { } Kernel::Scheduler& KernelCore::CurrentScheduler() { - return CurrentPhysicalCore().Scheduler(); + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return *impl->schedulers[core_id]; } const Kernel::Scheduler& KernelCore::CurrentScheduler() const { - return CurrentPhysicalCore().Scheduler(); + u32 core_id = impl->GetCurrentHostThreadID(); + ASSERT(core_id < Core::Hardware::NUM_CPU_CORES); + return *impl->schedulers[core_id]; +} + +std::array& KernelCore::Interrupts() { + return impl->interrupts; +} + +const std::array& KernelCore::Interrupts() const { + return impl->interrupts; } Kernel::Synchronization& KernelCore::Synchronization() { @@ -557,15 +544,11 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) { - PhysicalCore(i).ArmInterface().ClearInstructionCache(); - } + //TODO: Reimplement, this } void KernelCore::PrepareReschedule(std::size_t id) { - if (id < impl->global_scheduler.CpuCoresCount()) { - impl->cores[id].Stop(); - } + // TODO: Reimplement, this } void KernelCore::AddNamedPort(std::string name, std::shared_ptr port) { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 1eb6ede73e..846056b85a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -4,15 +4,17 @@ #pragma once +#include #include #include #include #include +#include "core/hardware_properties.h" #include "core/hle/kernel/memory/memory_types.h" #include "core/hle/kernel/object.h" namespace Core { -struct EmuThreadHandle; +class CPUInterruptHandler; class ExclusiveMonitor; class System; } // namespace Core @@ -144,6 +146,10 @@ public: const Core::ExclusiveMonitor& GetExclusiveMonitor() const; + std::array& Interrupts(); + + const std::array& Interrupts() const; + void InvalidateAllInstructionCaches(); /// Adds a port to the named port table diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 9146b331d4..c82c60a16d 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -20,50 +20,21 @@ namespace Kernel { -PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, - Core::ExclusiveMonitor& exclusive_monitor, - Core::CPUInterruptHandler& interrupt_handler, - Core::ARM_Interface& arm_interface32, - Core::ARM_Interface& arm_interface64) - : interrupt_handler{interrupt_handler}, core_index{id}, arm_interface_32{arm_interface32}, - arm_interface_64{arm_interface64} { +PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler) + : interrupt_handler{interrupt_handler}, core_index{id}, scheduler{scheduler} { - scheduler = std::make_unique(system, core_index); guard = std::make_unique(); } PhysicalCore::~PhysicalCore() = default; -void PhysicalCore::Run() { - arm_interface->Run(); -} - -void PhysicalCore::ClearExclusive() { - arm_interface->ClearExclusiveState(); -} - -void PhysicalCore::Step() { - arm_interface->Step(); -} - void PhysicalCore::Idle() { interrupt_handler.AwaitInterrupt(); } -void PhysicalCore::Stop() { - arm_interface->PrepareReschedule(); -} - void PhysicalCore::Shutdown() { - scheduler->Shutdown(); -} - -void PhysicalCore::SetIs64Bit(bool is_64_bit) { - if (is_64_bit) { - arm_interface = &arm_interface_64; - } else { - arm_interface = &arm_interface_32; - } + scheduler.Shutdown(); } void PhysicalCore::Interrupt() { diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 2673d90f28..751b994a78 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -10,7 +10,7 @@ #include "core/arm/cpu_interrupt_handler.h" namespace Common { -class SpinLock; + class SpinLock; } namespace Kernel { @@ -27,9 +27,9 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor, - Core::CPUInterruptHandler& interrupt_handler, Core::ARM_Interface& arm_interface32, - Core::ARM_Interface& arm_interface64); + PhysicalCore(Core::System& system, std::size_t id, + Kernel::Scheduler& scheduler, + Core::CPUInterruptHandler& interrupt_handler); ~PhysicalCore(); PhysicalCore(const PhysicalCore&) = delete; @@ -38,17 +38,7 @@ public: PhysicalCore(PhysicalCore&&) = default; PhysicalCore& operator=(PhysicalCore&&) = default; - /// Execute current jit state - void Run(); - /// Clear Exclusive state. - void ClearExclusive(); - /// Set this core in IdleState. void Idle(); - /// Execute a single instruction in current jit. - void Step(); - /// Stop JIT execution/exit - void Stop(); - /// Interrupt this physical core. void Interrupt(); @@ -63,14 +53,6 @@ public: // Shutdown this physical core. void Shutdown(); - Core::ARM_Interface& ArmInterface() { - return *arm_interface; - } - - const Core::ARM_Interface& ArmInterface() const { - return *arm_interface; - } - bool IsMainCore() const { return core_index == 0; } @@ -84,22 +66,17 @@ public: } Kernel::Scheduler& Scheduler() { - return *scheduler; + return scheduler; } const Kernel::Scheduler& Scheduler() const { - return *scheduler; + return scheduler; } - void SetIs64Bit(bool is_64_bit); - private: Core::CPUInterruptHandler& interrupt_handler; std::size_t core_index; - Core::ARM_Interface& arm_interface_32; - Core::ARM_Interface& arm_interface_64; - std::unique_ptr scheduler; - Core::ARM_Interface* arm_interface{}; + Kernel::Scheduler& scheduler; std::unique_ptr guard; }; diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 8d56b49ce6..a5083ae7c4 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -681,15 +681,16 @@ void Scheduler::SwitchContextStep2() { new_thread->SetWasRunning(false); auto* const thread_owner_process = current_thread->GetOwnerProcess(); - if (previous_process != thread_owner_process && thread_owner_process != nullptr) { + if (thread_owner_process != nullptr) { system.Kernel().MakeCurrentProcess(thread_owner_process); } if (!new_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + Core::ARM_Interface& cpu_core = new_thread->ArmInterface(); cpu_core.LoadContext(new_thread->GetContext32()); cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); + cpu_core.ChangeProcessorId(this->core_id); cpu_core.ClearExclusiveState(); } } @@ -722,18 +723,15 @@ void Scheduler::SwitchContext() { } previous_thread->SetContinuousOnSVC(false); previous_thread->last_running_ticks = system.CoreTiming().GetCPUTicks(); + previous_thread->SetIsRunning(false); if (!previous_thread->IsHLEThread()) { - auto& cpu_core = system.ArmInterface(core_id); + Core::ARM_Interface& cpu_core = previous_thread->ArmInterface(); cpu_core.SaveContext(previous_thread->GetContext32()); cpu_core.SaveContext(previous_thread->GetContext64()); // Save the TPIDR_EL0 system register in case it was modified. previous_thread->SetTPIDR_EL0(cpu_core.GetTPIDR_EL0()); cpu_core.ClearExclusiveState(); } - if (previous_thread->GetStatus() == ThreadStatus::Running) { - previous_thread->SetStatus(ThreadStatus::Ready); - } - previous_thread->SetIsRunning(false); previous_thread->context_guard.unlock(); } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f087452262..5999722119 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -1533,7 +1533,9 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { } if (is_redundant && !system.Kernel().IsMulticore()) { + system.Kernel().ExitSVCProfile(); system.GetCpuManager().PreemptSingleCore(); + system.Kernel().EnterSVCProfile(); } } @@ -2457,9 +2459,6 @@ void Call(Core::System& system, u32 immediate) { auto& kernel = system.Kernel(); kernel.EnterSVCProfile(); - auto* thread = system.CurrentScheduler().GetCurrentThread(); - thread->SetContinuousOnSVC(true); - const FunctionDef* info = system.CurrentProcess()->Is64BitProcess() ? GetSVCInfo64(immediate) : GetSVCInfo32(immediate); if (info) { @@ -2473,12 +2472,6 @@ void Call(Core::System& system, u32 immediate) { } kernel.ExitSVCProfile(); - - if (!thread->IsContinuousOnSVC()) { - auto* host_context = thread->GetHostContext().get(); - host_context->Rewind(); - } - system.EnterDynarmicProfile(); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 6f8e7a070a..58b06aa9ec 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,6 +13,13 @@ #include "common/logging/log.h" #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" +#ifdef ARCHITECTURE_x86_64 +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" +#endif +#include "core/arm/cpu_interrupt_handler.h" +#include "core/arm/exclusive_monitor.h" +#include "core/arm/unicorn/arm_unicorn.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -232,7 +239,27 @@ ResultVal> Thread::Create(Core::System& system, ThreadTy } // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used // to initialize the context + thread->arm_interface.reset(); if ((type_flags & THREADTYPE_HLE) == 0) { +#ifdef ARCHITECTURE_x86_64 + if (owner_process && !owner_process->Is64BitProcess()) { + thread->arm_interface = std::make_unique( + system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + } else { + thread->arm_interface = std::make_unique( + system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); + } + +#else + if (owner_process && !owner_process->Is64BitProcess()) { + thread->arm_interface = std::make_shared( + system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch32, processor_id); + } else { + thread->arm_interface = std::make_shared( + system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch64, processor_id); + } + LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); +#endif ResetThreadContext32(thread->context_32, static_cast(stack_top), static_cast(entry_point), static_cast(arg)); ResetThreadContext64(thread->context_64, stack_top, entry_point, arg); @@ -276,6 +303,14 @@ VAddr Thread::GetCommandBufferAddress() const { return GetTLSAddress() + command_header_offset; } +Core::ARM_Interface& Thread::ArmInterface() { + return *arm_interface; +} + +const Core::ARM_Interface& Thread::ArmInterface() const { + return *arm_interface; +} + void Thread::SetStatus(ThreadStatus new_status) { if (new_status == status) { return; diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index f998890c4b..c08fc3a894 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -21,6 +21,7 @@ class Fiber; } namespace Core { +class ARM_Interface; class System; } // namespace Core @@ -271,6 +272,10 @@ public: void SetSynchronizationResults(SynchronizationObject* object, ResultCode result); + Core::ARM_Interface& ArmInterface(); + + const Core::ARM_Interface& ArmInterface() const; + SynchronizationObject* GetSignalingObject() const { return signaling_object; } @@ -617,9 +622,10 @@ private: void AdjustSchedulingOnAffinity(u64 old_affinity_mask, s32 old_core); + Common::SpinLock context_guard{}; ThreadContext32 context_32{}; ThreadContext64 context_64{}; - Common::SpinLock context_guard{}; + std::unique_ptr arm_interface{}; std::shared_ptr host_context{}; u64 thread_id = 0; -- cgit v1.2.3 From 543b6b315ff90ecad860b4f3009721cdb4e96244 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 3 Apr 2020 11:58:43 -0400 Subject: General: Correct rebase, sync gpu and context management. --- src/core/core.cpp | 3 +-- src/core/cpu_manager.cpp | 11 ++--------- src/core/cpu_manager.h | 7 ------- src/video_core/gpu.h | 6 ++++++ src/video_core/gpu_asynch.cpp | 9 ++++++++- src/video_core/gpu_asynch.h | 2 ++ src/video_core/gpu_synch.cpp | 8 +++++++- src/video_core/gpu_synch.h | 2 ++ src/yuzu/bootmanager.cpp | 29 +++++++++++++++++------------ 9 files changed, 45 insertions(+), 32 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 40eea297ef..3393c33eb6 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -151,7 +151,6 @@ struct System::Impl { cpu_manager.SetMulticore(is_multicore); cpu_manager.SetAsyncGpu(is_async_gpu); core_timing.SetMulticore(is_multicore); - cpu_manager.SetRenderWindow(emu_window); core_timing.Initialize([&system]() { system.RegisterHostThread(); }); kernel.Initialize(); @@ -435,7 +434,7 @@ bool System::IsPoweredOn() const { } void System::PrepareReschedule() { - //impl->CurrentPhysicalCore().Stop(); + // impl->CurrentPhysicalCore().Stop(); } void System::PrepareReschedule(const u32 core_index) { diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index b7c2a78322..63c5788520 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp @@ -9,12 +9,12 @@ #include "core/core.h" #include "core/core_timing.h" #include "core/cpu_manager.h" -#include "core/frontend/emu_window.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_core.h" #include "core/hle/kernel/scheduler.h" #include "core/hle/kernel/thread.h" +#include "video_core/gpu.h" namespace Core { @@ -25,10 +25,6 @@ void CpuManager::ThreadStart(CpuManager& cpu_manager, std::size_t core) { cpu_manager.RunThread(core); } -void CpuManager::SetRenderWindow(Core::Frontend::EmuWindow& render_window) { - this->render_window = &render_window; -} - void CpuManager::Initialize() { running_mode = true; if (is_multicore) { @@ -354,7 +350,7 @@ void CpuManager::RunThread(std::size_t core) { data.is_running = false; data.enter_barrier->Wait(); if (sc_sync_first_use) { - render_window->MakeCurrent(); + system.GPU().ObtainContext(); sc_sync_first_use = false; } auto& scheduler = system.Kernel().CurrentScheduler(); @@ -366,9 +362,6 @@ void CpuManager::RunThread(std::size_t core) { data.exit_barrier->Wait(); data.is_paused = false; } - if (sc_sync) { - render_window->DoneCurrent(); - } /// Time to cleanup data.host_context->Exit(); data.enter_barrier.reset(); diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index ae55d6427e..35929ed94f 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -16,10 +16,6 @@ class Event; class Fiber; } // namespace Common -namespace Core::Frontend { -class EmuWindow; -} // namespace Core::Frontend - namespace Core { class System; @@ -61,8 +57,6 @@ public: return current_core.load(); } - void SetRenderWindow(Core::Frontend::EmuWindow& render_window); - private: static void GuestThreadFunction(void* cpu_manager); static void GuestRewindFunction(void* cpu_manager); @@ -106,7 +100,6 @@ private: std::size_t preemption_count{}; std::size_t idle_count{}; static constexpr std::size_t max_cycle_runs = 5; - Core::Frontend::EmuWindow* render_window; System& system; }; diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index a1b4c305ca..2c42483bd8 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -284,6 +284,12 @@ public: /// core timing events. virtual void Start() = 0; + /// Obtain the CPU Context + virtual void ObtainContext() = 0; + + /// Release the CPU Context + virtual void ReleaseContext() = 0; + /// Push GPU command entries to be processed virtual void PushGPUEntries(Tegra::CommandList&& entries) = 0; diff --git a/src/video_core/gpu_asynch.cpp b/src/video_core/gpu_asynch.cpp index 53305ab436..7b855f63e6 100644 --- a/src/video_core/gpu_asynch.cpp +++ b/src/video_core/gpu_asynch.cpp @@ -19,10 +19,17 @@ GPUAsynch::GPUAsynch(Core::System& system, std::unique_ptrMakeCurrent(); gpu_thread.StartThread(*renderer, *gpu_context, *dma_pusher); } +void GPUAsynch::ObtainContext() { + cpu_context->MakeCurrent(); +} + +void GPUAsynch::ReleaseContext() { + cpu_context->DoneCurrent(); +} + void GPUAsynch::PushGPUEntries(Tegra::CommandList&& entries) { gpu_thread.SubmitList(std::move(entries)); } diff --git a/src/video_core/gpu_asynch.h b/src/video_core/gpu_asynch.h index 5176586127..15e9f1d380 100644 --- a/src/video_core/gpu_asynch.h +++ b/src/video_core/gpu_asynch.h @@ -25,6 +25,8 @@ public: ~GPUAsynch() override; void Start() override; + void ObtainContext() override; + void ReleaseContext() override; void PushGPUEntries(Tegra::CommandList&& entries) override; void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; void FlushRegion(VAddr addr, u64 size) override; diff --git a/src/video_core/gpu_synch.cpp b/src/video_core/gpu_synch.cpp index 6f38a672a2..aaeb9811d6 100644 --- a/src/video_core/gpu_synch.cpp +++ b/src/video_core/gpu_synch.cpp @@ -13,10 +13,16 @@ GPUSynch::GPUSynch(Core::System& system, std::unique_ptrMakeCurrent(); } +void GPUSynch::ReleaseContext() { + context->DoneCurrent(); +} + void GPUSynch::PushGPUEntries(Tegra::CommandList&& entries) { dma_pusher->Push(std::move(entries)); dma_pusher->DispatchCalls(); diff --git a/src/video_core/gpu_synch.h b/src/video_core/gpu_synch.h index 4a6e9a01d7..762c20aa55 100644 --- a/src/video_core/gpu_synch.h +++ b/src/video_core/gpu_synch.h @@ -24,6 +24,8 @@ public: ~GPUSynch() override; void Start() override; + void ObtainContext() override; + void ReleaseContext() override; void PushGPUEntries(Tegra::CommandList&& entries) override; void SwapBuffers(const Tegra::FramebufferConfig* framebuffer) override; void FlushRegion(VAddr addr, u64 size) override; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 6aa161e99b..5f93bd432d 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -48,24 +48,29 @@ void EmuThread::run() { MicroProfileOnThreadCreate(name.c_str()); Common::SetCurrentThreadName(name.c_str()); + auto& system = Core::System::GetInstance(); + + system.RegisterHostThread(); + + auto& gpu = system.GPU(); + // Main process has been loaded. Make the context current to this thread and begin GPU and CPU // execution. - Core::System::GetInstance().GPU().Start(); + gpu.Start(); - emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); + gpu.ObtainContext(); - Core::System::GetInstance().RegisterHostThread(); - - context.MakeCurrent(); + emit LoadProgress(VideoCore::LoadCallbackStage::Prepare, 0, 0); - Core::System::GetInstance().Renderer().Rasterizer().LoadDiskResources( + system.Renderer().Rasterizer().LoadDiskResources( stop_run, [this](VideoCore::LoadCallbackStage stage, std::size_t value, std::size_t total) { emit LoadProgress(stage, value, total); }); emit LoadProgress(VideoCore::LoadCallbackStage::Complete, 0, 0); - context.DoneCurrent(); + gpu.ReleaseContext(); + // Holds whether the cpu was running during the last iteration, // so that the DebugModeLeft signal can be emitted before the @@ -78,18 +83,18 @@ void EmuThread::run() { } running_guard = true; - Core::System::ResultStatus result = Core::System::GetInstance().Run(); + Core::System::ResultStatus result = system.Run(); if (result != Core::System::ResultStatus::Success) { running_guard = false; this->SetRunning(false); - emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails()); + emit ErrorThrown(result, system.GetStatusDetails()); } running_wait.Wait(); - result = Core::System::GetInstance().Pause(); + result = system.Pause(); if (result != Core::System::ResultStatus::Success) { running_guard = false; this->SetRunning(false); - emit ErrorThrown(result, Core::System::GetInstance().GetStatusDetails()); + emit ErrorThrown(result, system.GetStatusDetails()); } running_guard = false; @@ -106,7 +111,7 @@ void EmuThread::run() { } // Shutdown the core emulation - Core::System::GetInstance().Shutdown(); + system.Shutdown(); #if MICROPROFILE_ENABLED MicroProfileOnThreadExit(); -- cgit v1.2.3 From d98995c00157f0fbbabbbd6f54715a199896114b Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 12 Apr 2020 19:25:53 -0400 Subject: Core: Split Microprofile Dynarmic timing per Core --- src/core/core.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 3393c33eb6..50656697fe 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -51,7 +51,10 @@ #include "video_core/renderer_base.h" #include "video_core/video_core.h" -MICROPROFILE_DEFINE(ARM_Jit_Dynarmic, "ARM JIT", "Dynarmic", MP_RGB(255, 64, 64)); +MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU0, "ARM JIT", "Dynarmic CPU 0", MP_RGB(255, 64, 64)); +MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU1, "ARM JIT", "Dynarmic CPU 1", MP_RGB(255, 64, 64)); +MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU2, "ARM JIT", "Dynarmic CPU 2", MP_RGB(255, 64, 64)); +MICROPROFILE_DEFINE(ARM_Jit_Dynarmic_CPU3, "ARM JIT", "Dynarmic CPU 3", MP_RGB(255, 64, 64)); namespace Core { @@ -189,6 +192,11 @@ struct System::Impl { is_powered_on = true; exit_lock = false; + microprofile_dynarmic[0] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU0); + microprofile_dynarmic[1] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU1); + microprofile_dynarmic[2] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU2); + microprofile_dynarmic[3] = MICROPROFILE_TOKEN(ARM_Jit_Dynarmic_CPU3); + LOG_DEBUG(Core, "Initialized OK"); return ResultStatus::Success; @@ -396,6 +404,7 @@ struct System::Impl { bool is_async_gpu{}; std::array dynarmic_ticks{}; + std::array microprofile_dynarmic{}; }; System::System() : impl{std::make_unique(*this)} {} @@ -747,12 +756,12 @@ void System::RegisterHostThread() { void System::EnterDynarmicProfile() { std::size_t core = impl->kernel.GetCurrentHostThreadID(); - impl->dynarmic_ticks[core] = MicroProfileEnter(MICROPROFILE_TOKEN(ARM_Jit_Dynarmic)); + impl->dynarmic_ticks[core] = MicroProfileEnter(impl->microprofile_dynarmic[core]); } void System::ExitDynarmicProfile() { std::size_t core = impl->kernel.GetCurrentHostThreadID(); - MicroProfileLeave(MICROPROFILE_TOKEN(ARM_Jit_Dynarmic), impl->dynarmic_ticks[core]); + MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]); } } // namespace Core -- cgit v1.2.3 From fda56510722d099bae0fecef6f278d16ebad8dd1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 29 May 2020 15:00:17 -0400 Subject: Services/NvFlinger: Do vSync in a sepparate thread on Multicore. --- src/core/core.cpp | 8 +++-- src/core/core.h | 3 ++ src/core/hle/service/nvflinger/nvflinger.cpp | 49 ++++++++++++++++++++++++++-- src/core/hle/service/nvflinger/nvflinger.h | 14 ++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/core/core.cpp b/src/core/core.cpp index 50656697fe..8256ec0fc5 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -294,8 +294,6 @@ struct System::Impl { service_manager.reset(); cheat_engine.reset(); telemetry_session.reset(); - perf_stats.reset(); - gpu_core.reset(); device_memory.reset(); // Close all CPU/threading state @@ -307,6 +305,8 @@ struct System::Impl { // Close app loader app_loader.reset(); + gpu_core.reset(); + perf_stats.reset(); // Clear all applets applet_manager.ClearAll(); @@ -764,4 +764,8 @@ void System::ExitDynarmicProfile() { MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]); } +bool System::IsMulticore() const { + return impl->is_multicore; +} + } // namespace Core diff --git a/src/core/core.h b/src/core/core.h index d2d1fcc5be..133ecb8e1c 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -381,6 +381,9 @@ public: /// Exit Dynarmic Microprofile void ExitDynarmicProfile(); + /// Tells if system is running on multicore. + bool IsMulticore() const; + private: System(); diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index b97f713500..2f44d37794 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/microprofile.h" #include "common/scope_exit.h" +#include "common/thread.h" #include "core/core.h" #include "core/core_timing.h" #include "core/core_timing_util.h" @@ -30,6 +31,33 @@ namespace Service::NVFlinger { constexpr s64 frame_ticks = static_cast(1000000000 / 60); constexpr s64 frame_ticks_30fps = static_cast(1000000000 / 30); +void NVFlinger::VSyncThread(NVFlinger& nv_flinger) { + nv_flinger.SplitVSync(); +} + +void NVFlinger::SplitVSync() { + system.RegisterHostThread(); + std::string name = "yuzu:VSyncThread"; + MicroProfileOnThreadCreate(name.c_str()); + Common::SetCurrentThreadName(name.c_str()); + Common::SetCurrentThreadPriority(Common::ThreadPriority::High); + s64 delay = 0; + while (is_running) { + guard->lock(); + const s64 time_start = system.CoreTiming().GetGlobalTimeNs().count(); + Compose(); + const auto ticks = GetNextTicks(); + const s64 time_end = system.CoreTiming().GetGlobalTimeNs().count(); + const s64 time_passed = time_end - time_start; + const s64 next_time = std::max(0, ticks - time_passed - delay); + guard->unlock(); + if (next_time > 0) { + wait_event->WaitFor(std::chrono::nanoseconds{next_time}); + } + delay = (system.CoreTiming().GetGlobalTimeNs().count() - time_end) - next_time; + } +} + NVFlinger::NVFlinger(Core::System& system) : system(system) { displays.emplace_back(0, "Default", system); displays.emplace_back(1, "External", system); @@ -47,12 +75,25 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) { this->system.CoreTiming().ScheduleEvent(std::max(0LL, ticks - ns_late), composition_event); }); - - system.CoreTiming().ScheduleEvent(frame_ticks, composition_event); + if (system.IsMulticore()) { + is_running = true; + wait_event = std::make_unique(); + vsync_thread = std::make_unique(VSyncThread, std::ref(*this)); + } else { + system.CoreTiming().ScheduleEvent(frame_ticks, composition_event); + } } NVFlinger::~NVFlinger() { - system.CoreTiming().UnscheduleEvent(composition_event, 0); + if (system.IsMulticore()) { + is_running = false; + wait_event->Set(); + vsync_thread->join(); + vsync_thread.reset(); + wait_event.reset(); + } else { + system.CoreTiming().UnscheduleEvent(composition_event, 0); + } } void NVFlinger::SetNVDrvInstance(std::shared_ptr instance) { @@ -200,10 +241,12 @@ void NVFlinger::Compose() { auto& gpu = system.GPU(); const auto& multi_fence = buffer->get().multi_fence; + guard->unlock(); for (u32 fence_id = 0; fence_id < multi_fence.num_fences; fence_id++) { const auto& fence = multi_fence.fences[fence_id]; gpu.WaitFence(fence.id, fence.value); } + guard->lock(); MicroProfileFlip(); diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 02c081494d..4bc3d7ab2e 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -4,16 +4,22 @@ #pragma once +#include #include #include #include #include #include #include +#include #include "common/common_types.h" #include "core/hle/kernel/object.h" +namespace Common { +class Event; +} // namespace Common + namespace Core::Timing { class CoreTiming; struct EventType; @@ -97,6 +103,10 @@ private: /// Finds the layer identified by the specified ID in the desired display. const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const; + static void VSyncThread(NVFlinger& nv_flinger); + + void SplitVSync(); + std::shared_ptr nvdrv; std::vector displays; @@ -116,6 +126,10 @@ private: std::shared_ptr guard; Core::System& system; + + std::unique_ptr vsync_thread; + std::unique_ptr wait_event; + std::atomic is_running{}; }; } // namespace Service::NVFlinger -- cgit v1.2.3 From 94a51e6b212e989be5ffb2a38dfcdc3140640cfe Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 27 Jun 2020 18:20:06 -0400 Subject: Core/Common: Address Feedback. --- src/common/fiber.cpp | 10 +++------- src/common/spin_lock.cpp | 6 +++--- src/common/spin_lock.h | 5 +++++ src/common/x64/native_clock.cpp | 4 ++-- src/core/arm/arm_interface.h | 2 +- src/core/arm/cpu_interrupt_handler.h | 2 +- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 5 +++-- src/core/arm/dynarmic/arm_dynarmic_32.h | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 5 +++-- src/core/arm/dynarmic/arm_dynarmic_64.h | 2 +- src/core/arm/unicorn/arm_unicorn.cpp | 2 +- src/core/arm/unicorn/arm_unicorn.h | 2 +- src/core/core.cpp | 2 +- src/core/core.h | 4 ++-- src/core/core_timing.cpp | 28 ++++++++++++---------------- src/core/hle/kernel/kernel.cpp | 14 +++++--------- src/core/hle/kernel/physical_core.cpp | 4 ++++ src/core/hle/kernel/physical_core.h | 7 ++----- src/core/hle/kernel/scheduler.cpp | 4 ++-- src/core/hle/kernel/scheduler.h | 4 ++++ src/tests/common/fibers.cpp | 2 +- 21 files changed, 58 insertions(+), 58 deletions(-) (limited to 'src/core/core.cpp') diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index f97ad433b4..1c1d09ccb8 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -54,9 +54,7 @@ Fiber::Fiber(std::function&& entry_point_func, void* start_paramete impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this); } -Fiber::Fiber() { - impl = std::make_unique(); -} +Fiber::Fiber() : impl{std::make_unique()} {} Fiber::~Fiber() { if (released) { @@ -116,8 +114,8 @@ std::shared_ptr Fiber::ThreadToFiber() { struct Fiber::FiberImpl { alignas(64) std::array stack; - u8* stack_limit; alignas(64) std::array rewind_stack; + u8* stack_limit; u8* rewind_stack_limit; boost::context::detail::fcontext_t context; boost::context::detail::fcontext_t rewind_context; @@ -168,9 +166,7 @@ void Fiber::SetRewindPoint(std::function&& rewind_func, void* start rewind_parameter = start_parameter; } -Fiber::Fiber() { - impl = std::make_unique(); -} +Fiber::Fiber() : impl{std::make_unique()} {} Fiber::~Fiber() { if (released) { diff --git a/src/common/spin_lock.cpp b/src/common/spin_lock.cpp index c7b46aac6b..c1524220f6 100644 --- a/src/common/spin_lock.cpp +++ b/src/common/spin_lock.cpp @@ -20,7 +20,7 @@ namespace { -void thread_pause() { +void ThreadPause() { #if __x86_64__ _mm_pause(); #elif __aarch64__ && _MSC_VER @@ -30,13 +30,13 @@ void thread_pause() { #endif } -} // namespace +} // Anonymous namespace namespace Common { void SpinLock::lock() { while (lck.test_and_set(std::memory_order_acquire)) { - thread_pause(); + ThreadPause(); } } diff --git a/src/common/spin_lock.h b/src/common/spin_lock.h index 70282a961f..1df5528c47 100644 --- a/src/common/spin_lock.h +++ b/src/common/spin_lock.h @@ -8,6 +8,11 @@ namespace Common { +/** + * SpinLock class + * a lock similar to mutex that forces a thread to spin wait instead calling the + * supervisor. Should be used on short sequences of code. + */ class SpinLock { public: void lock(); diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp index f1bc60fd20..424b39b1f1 100644 --- a/src/common/x64/native_clock.cpp +++ b/src/common/x64/native_clock.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #ifdef _MSC_VER @@ -52,7 +53,7 @@ NativeClock::NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequenc } u64 NativeClock::GetRTSC() { - rtsc_serialize.lock(); + std::scoped_lock scope{rtsc_serialize}; _mm_mfence(); const u64 current_measure = __rdtsc(); u64 diff = current_measure - last_measure; @@ -61,7 +62,6 @@ u64 NativeClock::GetRTSC() { last_measure = current_measure; } accumulated_ticks += diff; - rtsc_serialize.unlock(); /// The clock cannot be more precise than the guest timer, remove the lower bits return accumulated_ticks & inaccuracy_mask; } diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 0c1d6ac391..1f24051e4a 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -148,7 +148,7 @@ public: */ virtual void SetTPIDR_EL0(u64 value) = 0; - virtual void ChangeProcessorId(std::size_t new_core_id) = 0; + virtual void ChangeProcessorID(std::size_t new_core_id) = 0; virtual void SaveContext(ThreadContext32& ctx) = 0; virtual void SaveContext(ThreadContext64& ctx) = 0; diff --git a/src/core/arm/cpu_interrupt_handler.h b/src/core/arm/cpu_interrupt_handler.h index 91c31a2710..3d062d326b 100644 --- a/src/core/arm/cpu_interrupt_handler.h +++ b/src/core/arm/cpu_interrupt_handler.h @@ -23,7 +23,7 @@ public: CPUInterruptHandler(CPUInterruptHandler&&) = default; CPUInterruptHandler& operator=(CPUInterruptHandler&&) = default; - constexpr bool IsInterrupted() const { + bool IsInterrupted() const { return is_interrupted; } diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index cfda120988..0d4ab95b72 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -107,7 +107,7 @@ public: u64 GetTicksRemaining() override { if (parent.uses_wall_clock) { if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { - return 1000U; + return minimum_run_cycles; } return 0U; } @@ -116,6 +116,7 @@ public: ARM_Dynarmic_32& parent; std::size_t num_interpreted_instructions{}; + static constexpr u64 minimum_run_cycles = 1000U; }; std::shared_ptr ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, @@ -214,7 +215,7 @@ void ARM_Dynarmic_32::SetTPIDR_EL0(u64 value) { cp15->uprw = static_cast(value); } -void ARM_Dynarmic_32::ChangeProcessorId(std::size_t new_core_id) { +void ARM_Dynarmic_32::ChangeProcessorID(std::size_t new_core_id) { jit->ChangeProcessorID(new_core_id); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index d9c0bfede2..2bab31b920 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -47,7 +47,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; - void ChangeProcessorId(std::size_t new_core_id) override; + void ChangeProcessorID(std::size_t new_core_id) override; void SaveContext(ThreadContext32& ctx) override; void SaveContext(ThreadContext64& ctx) override {} diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 35a99e28aa..7909810346 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -144,7 +144,7 @@ public: u64 GetTicksRemaining() override { if (parent.uses_wall_clock) { if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { - return 1000U; + return minimum_run_cycles; } return 0U; } @@ -159,6 +159,7 @@ public: std::size_t num_interpreted_instructions = 0; u64 tpidrro_el0 = 0; u64 tpidr_el0 = 0; + static constexpr u64 minimum_run_cycles = 1000U; }; std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table, @@ -271,7 +272,7 @@ void ARM_Dynarmic_64::SetTPIDR_EL0(u64 value) { cb->tpidr_el0 = value; } -void ARM_Dynarmic_64::ChangeProcessorId(std::size_t new_core_id) { +void ARM_Dynarmic_64::ChangeProcessorID(std::size_t new_core_id) { jit->ChangeProcessorID(new_core_id); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index c74fcbcea5..403c559615 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -45,7 +45,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; - void ChangeProcessorId(std::size_t new_core_id) override; + void ChangeProcessorID(std::size_t new_core_id) override; void SaveContext(ThreadContext32& ctx) override {} void SaveContext(ThreadContext64& ctx) override; diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 35e8f42e86..1df3f3ed1e 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp @@ -159,7 +159,7 @@ void ARM_Unicorn::SetTPIDR_EL0(u64 value) { CHECKED(uc_reg_write(uc, UC_ARM64_REG_TPIDR_EL0, &value)); } -void ARM_Unicorn::ChangeProcessorId(std::size_t new_core_id) { +void ARM_Unicorn::ChangeProcessorID(std::size_t new_core_id) { core_index = new_core_id; } diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index 8ace8b86fa..810aff311e 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h @@ -36,7 +36,7 @@ public: void SetTlsAddress(VAddr address) override; void SetTPIDR_EL0(u64 value) override; u64 GetTPIDR_EL0() const override; - void ChangeProcessorId(std::size_t new_core_id) override; + void ChangeProcessorID(std::size_t new_core_id) override; void PrepareReschedule() override; void ClearExclusiveState() override; void ExecuteInstructions(std::size_t num_instructions); diff --git a/src/core/core.cpp b/src/core/core.cpp index 8256ec0fc5..1a243c515a 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -443,7 +443,7 @@ bool System::IsPoweredOn() const { } void System::PrepareReschedule() { - // impl->CurrentPhysicalCore().Stop(); + // Deprecated, does nothing, kept for backward compatibility. } void System::PrepareReschedule(const u32 core_index) { diff --git a/src/core/core.h b/src/core/core.h index 133ecb8e1c..5c6cfbffe1 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -138,13 +138,13 @@ public: /** * Run the OS and Application - * This function will start emulation and run the competent devices + * This function will start emulation and run the relevant devices */ ResultStatus Run(); /** * Pause the OS and Application - * This function will pause emulation and stop the competent devices + * This function will pause emulation and stop the relevant devices */ ResultStatus Pause(); diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 1aa89a1ccd..5c83c41a40 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp @@ -45,9 +45,9 @@ CoreTiming::CoreTiming() { CoreTiming::~CoreTiming() = default; void CoreTiming::ThreadEntry(CoreTiming& instance) { - std::string name = "yuzu:HostTiming"; - MicroProfileOnThreadCreate(name.c_str()); - Common::SetCurrentThreadName(name.c_str()); + constexpr char name[] = "yuzu:HostTiming"; + MicroProfileOnThreadCreate(name); + Common::SetCurrentThreadName(name); Common::SetCurrentThreadPriority(Common::ThreadPriority::VeryHigh); instance.on_thread_init(); instance.ThreadLoop(); @@ -108,18 +108,19 @@ bool CoreTiming::HasPendingEvents() const { void CoreTiming::ScheduleEvent(s64 ns_into_future, const std::shared_ptr& event_type, u64 userdata) { - basic_lock.lock(); - const u64 timeout = static_cast(GetGlobalTimeNs().count() + ns_into_future); + { + std::scoped_lock scope{basic_lock}; + const u64 timeout = static_cast(GetGlobalTimeNs().count() + ns_into_future); - event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); + event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); - std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); - basic_lock.unlock(); + std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); + } event.Set(); } void CoreTiming::UnscheduleEvent(const std::shared_ptr& event_type, u64 userdata) { - basic_lock.lock(); + std::scoped_lock scope{basic_lock}; const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { return e.type.lock().get() == event_type.get() && e.userdata == userdata; }); @@ -129,7 +130,6 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr& event_type, u event_queue.erase(itr, event_queue.end()); std::make_heap(event_queue.begin(), event_queue.end(), std::greater<>()); } - basic_lock.unlock(); } void CoreTiming::AddTicks(u64 ticks) { @@ -187,8 +187,8 @@ void CoreTiming::RemoveEvent(const std::shared_ptr& event_type) { } std::optional CoreTiming::Advance() { - advance_lock.lock(); - basic_lock.lock(); + std::scoped_lock advance_scope{advance_lock}; + std::scoped_lock basic_scope{basic_lock}; global_timer = GetGlobalTimeNs().count(); while (!event_queue.empty() && event_queue.front().time <= global_timer) { @@ -207,12 +207,8 @@ std::optional CoreTiming::Advance() { if (!event_queue.empty()) { const s64 next_time = event_queue.front().time - global_timer; - basic_lock.unlock(); - advance_lock.unlock(); return next_time; } else { - basic_lock.unlock(); - advance_lock.unlock(); return std::nullopt; } } diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index dbb75416d7..1f2af7a1b5 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -472,16 +472,12 @@ const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { } void KernelCore::InvalidateAllInstructionCaches() { - if (!IsMulticore()) { - auto& threads = GlobalScheduler().GetThreadList(); - for (auto& thread : threads) { - if (!thread->IsHLEThread()) { - auto& arm_interface = thread->ArmInterface(); - arm_interface.ClearInstructionCache(); - } + auto& threads = GlobalScheduler().GetThreadList(); + for (auto& thread : threads) { + if (!thread->IsHLEThread()) { + auto& arm_interface = thread->ArmInterface(); + arm_interface.ClearInstructionCache(); } - } else { - UNIMPLEMENTED_MSG("Cache Invalidation unimplemented for multicore"); } } diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index c82c60a16d..c6bbdb080e 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -37,6 +37,10 @@ void PhysicalCore::Shutdown() { scheduler.Shutdown(); } +bool PhysicalCore::IsInterrupted() const { + return interrupt_handler.IsInterrupted(); +} + void PhysicalCore::Interrupt() { guard->lock(); interrupt_handler.SetInterrupt(true); diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 85f6dec055..d7a7a951ca 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -7,8 +7,6 @@ #include #include -#include "core/arm/cpu_interrupt_handler.h" - namespace Common { class SpinLock; } @@ -19,6 +17,7 @@ class Scheduler; namespace Core { class ARM_Interface; +class CPUInterruptHandler; class ExclusiveMonitor; class System; } // namespace Core @@ -45,9 +44,7 @@ public: void ClearInterrupt(); /// Check if this core is interrupted - bool IsInterrupted() const { - return interrupt_handler.IsInterrupted(); - } + bool IsInterrupted() const; // Shutdown this physical core. void Shutdown(); diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index 61b8a396a8..2b12c0dbf4 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp @@ -658,7 +658,7 @@ void Scheduler::Reload() { cpu_core.LoadContext(thread->GetContext64()); cpu_core.SetTlsAddress(thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(thread->GetTPIDR_EL0()); - cpu_core.ChangeProcessorId(this->core_id); + cpu_core.ChangeProcessorID(this->core_id); cpu_core.ClearExclusiveState(); } } @@ -691,7 +691,7 @@ void Scheduler::SwitchContextStep2() { cpu_core.LoadContext(new_thread->GetContext64()); cpu_core.SetTlsAddress(new_thread->GetTLSAddress()); cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0()); - cpu_core.ChangeProcessorId(this->core_id); + cpu_core.ChangeProcessorID(this->core_id); cpu_core.ClearExclusiveState(); } } diff --git a/src/core/hle/kernel/scheduler.h b/src/core/hle/kernel/scheduler.h index 3481071603..b3b4b51699 100644 --- a/src/core/hle/kernel/scheduler.h +++ b/src/core/hle/kernel/scheduler.h @@ -240,6 +240,10 @@ public: return switch_fiber; } + const std::shared_ptr& ControlContext() const { + return switch_fiber; + } + private: friend class GlobalScheduler; diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp index 12536b6d88..4fd92428f8 100644 --- a/src/tests/common/fibers.cpp +++ b/src/tests/common/fibers.cpp @@ -68,7 +68,7 @@ static void ThreadStart1(u32 id, TestControl1& test_control) { * doing all the work required. */ TEST_CASE("Fibers::Setup", "[common]") { - constexpr u32 num_threads = 7; + constexpr std::size_t num_threads = 7; TestControl1 test_control{}; test_control.thread_fibers.resize(num_threads); test_control.work_fibers.resize(num_threads); -- cgit v1.2.3