general: remove references to single core mode

This commit is contained in:
Liam
2022-06-26 18:50:13 -04:00
parent 074cb70419
commit 6ef7ed25c7
33 changed files with 95 additions and 429 deletions

View File

@@ -44,7 +44,6 @@ void LogSettings() {
log_setting("System_LanguageIndex", values.language_index.GetValue());
log_setting("System_RegionIndex", values.region_index.GetValue());
log_setting("System_TimeZoneIndex", values.time_zone_index.GetValue());
log_setting("Core_UseMultiCore", values.use_multi_core.GetValue());
log_setting("CPU_Accuracy", values.cpu_accuracy.GetValue());
log_setting("Renderer_UseResolutionScaling", values.resolution_setup.GetValue());
log_setting("Renderer_ScalingFilter", values.scaling_filter.GetValue());
@@ -166,7 +165,6 @@ void RestoreGlobalState(bool is_powered_on) {
values.volume.SetGlobal(true);
// Core
values.use_multi_core.SetGlobal(true);
values.use_extended_memory_layout.SetGlobal(true);
// CPU

View File

@@ -465,7 +465,6 @@ struct Values {
RangedSetting<u8> volume{100, 0, 100, "volume"};
// Core
Setting<bool> use_multi_core{true, "use_multi_core"};
Setting<bool> use_extended_memory_layout{false, "use_extended_memory_layout"};
// Cpu

View File

@@ -37,10 +37,8 @@ public:
YUZU_NON_COPYABLE(ARM_Interface);
YUZU_NON_MOVEABLE(ARM_Interface);
explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_,
bool uses_wall_clock_)
: system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{
uses_wall_clock_} {}
explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_)
: system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{true} {}
virtual ~ARM_Interface() = default;
struct ThreadContext32 {

View File

@@ -125,26 +125,11 @@ public:
}
void AddTicks(u64 ticks) override {
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
// rough approximation of the amount of executed ticks in the system, it may be thrown off
// if not all cores are doing a similar amount of work. Instead of doing this, we should
// device a way so that timing is consistent across all cores without increasing the ticks 4
// times.
u64 amortized_ticks =
(ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES;
// Always execute at least one tick.
amortized_ticks = std::max<u64>(amortized_ticks, 1);
parent.system.CoreTiming().AddTicks(amortized_ticks);
num_interpreted_instructions = 0;
UNREACHABLE();
}
u64 GetTicksRemaining() override {
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
UNREACHABLE();
}
bool CheckMemoryAccess(VAddr addr, u64 size, Kernel::DebugWatchpointType type) {
@@ -172,7 +157,6 @@ public:
Core::Memory::Memory& memory;
std::size_t num_interpreted_instructions{};
bool debugger_enabled{};
static constexpr u64 minimum_run_cycles = 1000U;
};
std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const {
@@ -314,10 +298,8 @@ void ARM_Dynarmic_32::RewindBreakpointInstruction() {
}
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,
bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
std::size_t core_index_)
: ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
cb(std::make_unique<DynarmicCallbacks32>(*this)),
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
: ARM_Interface{system_, interrupt_handlers_}, cb(std::make_unique<DynarmicCallbacks32>(*this)),
cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}

View File

@@ -28,7 +28,7 @@ class System;
class ARM_Dynarmic_32 final : public ARM_Interface {
public:
ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
~ARM_Dynarmic_32() override;

View File

@@ -166,24 +166,11 @@ public:
}
void AddTicks(u64 ticks) override {
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
// rough approximation of the amount of executed ticks in the system, it may be thrown off
// if not all cores are doing a similar amount of work. Instead of doing this, we should
// device a way so that timing is consistent across all cores without increasing the ticks 4
// times.
u64 amortized_ticks = ticks / Core::Hardware::NUM_CPU_CORES;
// Always execute at least one tick.
amortized_ticks = std::max<u64>(amortized_ticks, 1);
parent.system.CoreTiming().AddTicks(amortized_ticks);
UNREACHABLE();
}
u64 GetTicksRemaining() override {
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
UNREACHABLE();
}
u64 GetCNTPCT() override {
@@ -216,7 +203,6 @@ public:
u64 tpidrro_el0 = 0;
u64 tpidr_el0 = 0;
bool debugger_enabled{};
static constexpr u64 minimum_run_cycles = 1000U;
};
std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table,
@@ -374,9 +360,8 @@ void ARM_Dynarmic_64::RewindBreakpointInstruction() {
}
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
std::size_t core_index_)
: ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
: ARM_Interface{system_, interrupt_handlers_},
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}

View File

@@ -26,7 +26,7 @@ class System;
class ARM_Dynarmic_64 final : public ARM_Interface {
public:
ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
~ARM_Dynarmic_64() override;

View File

@@ -177,14 +177,8 @@ struct System::Impl {
device_memory = std::make_unique<Core::DeviceMemory>();
is_multicore = Settings::values.use_multi_core.GetValue();
is_async_gpu = Settings::values.use_asynchronous_gpu_emulation.GetValue();
kernel.SetMulticore(is_multicore);
cpu_manager.SetMulticore(is_multicore);
cpu_manager.SetAsyncGpu(is_async_gpu);
core_timing.SetMulticore(is_multicore);
kernel.Initialize();
cpu_manager.Initialize();
core_timing.Initialize([&system]() { system.RegisterHostThread(); });
@@ -449,7 +443,6 @@ struct System::Impl {
std::unique_ptr<Core::PerfStats> perf_stats;
Core::SpeedLimiter speed_limiter;
bool is_multicore{};
bool is_async_gpu{};
ExecuteProgramCallback execute_program_callback;
@@ -818,10 +811,6 @@ void System::ExitDynarmicProfile() {
MicroProfileLeave(impl->microprofile_dynarmic[core], impl->dynarmic_ticks[core]);
}
bool System::IsMulticore() const {
return impl->is_multicore;
}
bool System::DebuggerEnabled() const {
return Settings::values.use_gdbstub.GetValue();
}

View File

@@ -378,9 +378,6 @@ public:
/// Exit Dynarmic Microprofile
void ExitDynarmicProfile();
/// Tells if system is running on multicore.
[[nodiscard]] bool IsMulticore() const;
/// Tells if the system debugger is enabled.
[[nodiscard]] bool DebuggerEnabled() const;

View File

@@ -15,8 +15,6 @@
namespace Core::Timing {
constexpr s64 MAX_SLICE_LENGTH = 4000;
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
return std::make_shared<EventType>(std::move(callback), std::move(name));
}
@@ -57,10 +55,9 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
on_thread_init = std::move(on_thread_init_);
event_fifo_id = 0;
shutting_down = false;
ticks = 0;
const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {};
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
if (is_multicore) {
const auto hardware_concurrency = std::thread::hardware_concurrency();
size_t id = 0;
worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
@@ -68,7 +65,6 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
worker_threads.emplace_back(ThreadEntry, std::ref(*this), id++);
}
}
}
void CoreTiming::Shutdown() {
is_paused = true;
@@ -90,13 +86,13 @@ void CoreTiming::Pause(bool is_paused_) {
if (is_paused_ == paused_state.load(std::memory_order_relaxed)) {
return;
}
if (is_multicore) {
is_paused = is_paused_;
event_cv.notify_all();
if (!is_paused_) {
wait_pause_cv.notify_all();
}
}
paused_state.store(is_paused_, std::memory_order_relaxed);
}
@@ -106,22 +102,20 @@ void CoreTiming::SyncPause(bool is_paused_) {
return;
}
if (is_multicore) {
is_paused = is_paused_;
event_cv.notify_all();
if (!is_paused_) {
wait_pause_cv.notify_all();
}
}
paused_state.store(is_paused_, std::memory_order_relaxed);
if (is_multicore) {
if (is_paused_) {
wait_signal_cv.wait(main_lock, [this] { return pause_count == worker_threads.size(); });
} else {
wait_signal_cv.wait(main_lock, [this] { return pause_count == 0; });
}
}
}
bool CoreTiming::IsRunning() const {
return !paused_state.load(std::memory_order_acquire);
@@ -144,10 +138,8 @@ void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
if (is_multicore) {
event_cv.notify_one();
}
}
void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
std::uintptr_t user_data) {
@@ -164,40 +156,13 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
}
}
void CoreTiming::AddTicks(u64 ticks_to_add) {
ticks += ticks_to_add;
downcount -= static_cast<s64>(ticks);
}
void CoreTiming::Idle() {
if (!event_queue.empty()) {
const u64 next_event_time = event_queue.front().time;
const u64 next_ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U;
if (next_ticks > ticks) {
ticks = next_ticks;
}
return;
}
ticks += 1000U;
}
void CoreTiming::ResetTicks() {
downcount = MAX_SLICE_LENGTH;
}
u64 CoreTiming::GetCPUTicks() const {
if (is_multicore) {
return clock->GetCPUCycles();
}
return ticks;
}
u64 CoreTiming::GetClockTicks() const {
if (is_multicore) {
return clock->GetClockCycles();
}
return CpuCyclesToClockCycles(ticks);
}
void CoreTiming::ClearPendingEvents() {
std::unique_lock main_lock(event_mutex);
@@ -285,17 +250,11 @@ void CoreTiming::ThreadLoop() {
}
std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const {
if (is_multicore) {
return clock->GetTimeNS();
}
return CyclesToNs(ticks);
}
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
if (is_multicore) {
return clock->GetTimeUS();
}
return CyclesToUs(ticks);
}
} // namespace Core::Timing

View File

@@ -65,16 +65,6 @@ public:
/// Tears down all timing related functionality.
void Shutdown();
/// Sets if emulation is multicore or single core, must be set before Initialize
void SetMulticore(bool is_multicore_) {
is_multicore = is_multicore_;
}
/// Check if it's using host timing.
bool IsHostTiming() const {
return is_multicore;
}
/// Pauses/Unpauses the execution of the timer thread.
void Pause(bool is_paused);
@@ -101,16 +91,6 @@ public:
/// We only permit one event of each type in the queue at a time.
void RemoveEvent(const std::shared_ptr<EventType>& event_type);
void AddTicks(u64 ticks_to_add);
void ResetTicks();
void Idle();
s64 GetDowncount() const {
return downcount;
}
/// Returns current time in emulated CPU cycles
u64 GetCPUTicks() const;
@@ -123,9 +103,6 @@ public:
/// Returns current time in nanoseconds.
std::chrono::nanoseconds GetGlobalTimeNs() const;
/// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
std::optional<s64> Advance();
private:
struct Event;
@@ -135,6 +112,9 @@ private:
static void ThreadEntry(CoreTiming& instance, size_t id);
void ThreadLoop();
/// Checks for events manually and returns time in nanoseconds for next event, threadsafe.
std::optional<s64> Advance();
std::unique_ptr<Common::WallClock> clock;
u64 global_timer = 0;
@@ -162,12 +142,7 @@ private:
std::atomic<bool> paused_state{};
bool is_paused{};
bool shutting_down{};
bool is_multicore{};
size_t pause_count{};
/// Cycle timing
u64 ticks{};
s64 downcount{};
};
/// Creates a core timing event with the given name and callback.

View File

@@ -26,7 +26,7 @@ void CpuManager::ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager
}
void CpuManager::Initialize() {
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
const auto num_cores{Core::Hardware::NUM_CPU_CORES};
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
for (std::size_t core = 0; core < num_cores; core++) {
@@ -35,33 +35,13 @@ void CpuManager::Initialize() {
}
void CpuManager::Shutdown() {
for (std::size_t core = 0; core < num_cores; core++) {
for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
if (core_data[core].host_thread.joinable()) {
core_data[core].host_thread.join();
}
}
}
void CpuManager::GuestActivateFunction() {
if (is_multicore) {
MultiCoreGuestActivate();
} else {
SingleCoreGuestActivate();
}
}
void CpuManager::GuestThreadFunction() {
if (is_multicore) {
MultiCoreRunGuestThread();
} else {
SingleCoreRunGuestThread();
}
}
void CpuManager::ShutdownThreadFunction() {
ShutdownThread();
}
void CpuManager::WaitForAndHandleInterrupt() {
auto& kernel = system.Kernel();
auto& physical_core = kernel.CurrentPhysicalCore();
@@ -82,30 +62,21 @@ void CpuManager::HandleInterrupt() {
Kernel::KInterruptManager::HandleInterrupt(kernel, static_cast<s32>(core_index));
}
///////////////////////////////////////////////////////////////////////////////
/// MultiCore ///
///////////////////////////////////////////////////////////////////////////////
void CpuManager::MultiCoreGuestActivate() {
void CpuManager::GuestActivate() {
// Similar to the HorizonKernelMain callback in HOS
auto& kernel = system.Kernel();
auto* scheduler = kernel.CurrentScheduler();
kernel.SetCurrentEmuThread(scheduler->GetSchedulerCurrentThread());
scheduler->Activate();
UNREACHABLE();
}
void CpuManager::MultiCoreRunGuestThread() {
void CpuManager::RunGuestThread() {
// Similar to UserModeThreadStarter in HOS
auto& kernel = system.Kernel();
auto* thread = kernel.GetCurrentEmuThread();
thread->EnableDispatch();
MultiCoreRunGuestLoop();
}
void CpuManager::MultiCoreRunGuestLoop() {
auto& kernel = system.Kernel();
kernel.GetCurrentEmuThread()->EnableDispatch();
while (true) {
auto* physical_core = &kernel.CurrentPhysicalCore();
@@ -116,24 +87,14 @@ void CpuManager::MultiCoreRunGuestLoop() {
HandleInterrupt();
}
UNREACHABLE();
}
///////////////////////////////////////////////////////////////////////////////
/// SingleCore ///
///////////////////////////////////////////////////////////////////////////////
void CpuManager::SingleCoreGuestActivate() {}
void CpuManager::SingleCoreRunGuestThread() {}
void CpuManager::SingleCoreRunGuestLoop() {}
void CpuManager::PreemptSingleCore(bool from_running_enviroment) {}
void CpuManager::ShutdownThread() {
auto& kernel = system.Kernel();
auto* thread = kernel.GetCurrentEmuThread();
auto core = is_multicore ? kernel.CurrentPhysicalCoreIndex() : 0;
auto core = kernel.CurrentPhysicalCoreIndex();
Common::Fiber::YieldTo(thread->GetHostContext(), *core_data[core].host_context);
UNREACHABLE();
@@ -142,16 +103,13 @@ void CpuManager::ShutdownThread() {
void CpuManager::RunThread(std::size_t core) {
/// Initialization
system.RegisterCoreThread(core);
std::string name;
if (is_multicore) {
name = "yuzu:CPUCore_" + std::to_string(core);
} else {
name = "yuzu:CPUThread";
}
auto name{fmt::format("yuzu:CPUCore_{}", core)};
MicroProfileOnThreadCreate(name.c_str());
Common::SetCurrentThreadName(name.c_str());
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
auto& data = core_data[core];
auto& data{core_data[core]};
data.host_context = Common::Fiber::ThreadToFiber();
// Cleanup
@@ -163,23 +121,8 @@ void CpuManager::RunThread(std::size_t core) {
// Running
gpu_barrier->Sync();
if (!is_async_gpu && !is_multicore) {
system.GPU().ObtainContext();
}
auto& kernel = system.Kernel();
auto* main_thread = Kernel::KThread::Create(kernel);
main_thread->SetName(fmt::format("MainThread:{}", core));
ASSERT(Kernel::KThread::InitializeMainThread(system, main_thread, static_cast<s32>(core))
.IsSuccess());
auto* idle_thread = Kernel::KThread::Create(kernel);
ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, static_cast<s32>(core))
.IsSuccess());
kernel.SetCurrentEmuThread(main_thread);
kernel.CurrentScheduler()->Initialize(idle_thread);
auto& kernel{system.Kernel()};
auto* main_thread{kernel.CurrentScheduler()->GetSchedulerCurrentThread()};
Common::Fiber::YieldTo(data.host_context, *main_thread->GetHostContext());
}

View File

@@ -34,16 +34,6 @@ public:
CpuManager& operator=(const CpuManager&) = delete;
CpuManager& operator=(CpuManager&&) = delete;
/// Sets if emulation is multicore or single core, must be set before Initialize
void SetMulticore(bool is_multi) {
is_multicore = is_multi;
}
/// Sets if emulation is using an asynchronous GPU.
void SetAsyncGpu(bool is_async) {
is_async_gpu = is_async;
}
void OnGpuReady() {
gpu_barrier->Sync();
}
@@ -53,42 +43,23 @@ public:
void Shutdown();
std::function<void()> GetGuestActivateFunc() {
return [this] { GuestActivateFunction(); };
return [this] { GuestActivate(); };
}
std::function<void()> GetGuestThreadFunc() {
return [this] { GuestThreadFunction(); };
}
std::function<void()> GetIdleThreadStartFunc() {
return [this] { IdleThreadFunction(); };
return [this] { RunGuestThread(); };
}
std::function<void()> GetShutdownThreadStartFunc() {
return [this] { ShutdownThreadFunction(); };
}
void PreemptSingleCore(bool from_running_enviroment = true);
std::size_t CurrentCore() const {
return current_core.load();
return [this] { ShutdownThread(); };
}
private:
void GuestActivateFunction();
void GuestThreadFunction();
void IdleThreadFunction();
void ShutdownThreadFunction();
void MultiCoreGuestActivate();
void MultiCoreRunGuestThread();
void MultiCoreRunGuestLoop();
void SingleCoreGuestActivate();
void SingleCoreRunGuestThread();
void SingleCoreRunGuestLoop();
static void ThreadStart(std::stop_token stop_token, CpuManager& cpu_manager, std::size_t core);
void GuestActivate();
void RunGuestThread();
void HandleInterrupt();
void ShutdownThread();
void RunThread(std::size_t core);
struct CoreData {
@@ -98,14 +69,6 @@ private:
std::unique_ptr<Common::Barrier> gpu_barrier{};
std::array<CoreData, Core::Hardware::NUM_CPU_CORES> core_data{};
bool is_async_gpu{};
bool is_multicore{};
std::atomic<std::size_t> current_core{};
std::size_t idle_count{};
std::size_t num_cores{};
static constexpr std::size_t max_cycle_runs = 5;
System& system;
};

View File

@@ -42,11 +42,6 @@ void GlobalSchedulerContext::PreemptThreads() {
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
const u32 priority = preemption_priorities[core_id];
KScheduler::RotateScheduledQueue(kernel, core_id, priority);
// Signal an interrupt occurred. For core 3, this is a certainty, as preemption will result
// in the rotator thread being scheduled. For cores 0-2, this is to simulate or system
// interrupts that may have occurred.
kernel.PhysicalCore(core_id).Interrupt();
}
}

View File

@@ -125,9 +125,9 @@ void KScheduler::RescheduleCurrentCoreImpl() {
}
}
void KScheduler::Initialize(KThread* idle_thread) {
void KScheduler::Initialize(KThread* main_thread, KThread* idle_thread, s32 core_id) {
// Set core ID/idle thread/interrupt task manager.
m_core_id = GetCurrentCoreId(kernel);
m_core_id = core_id;
m_idle_thread = idle_thread;
// m_state.idle_thread_stack = m_idle_thread->GetStackTop();
// m_state.interrupt_task_manager = &kernel.GetInterruptTaskManager();
@@ -145,7 +145,7 @@ void KScheduler::Initialize(KThread* idle_thread) {
// KInterruptController::PriorityLevel_Scheduler, false, false);
// Set the current thread.
m_current_thread = GetCurrentThreadPointer(kernel);
m_current_thread = main_thread;
}
void KScheduler::Activate() {
@@ -389,8 +389,7 @@ void KScheduler::ScheduleImplOffStack() {
// Save the original thread context.
{
auto& physical_core = kernel.System().CurrentPhysicalCore();
auto& cpu_core = physical_core.ArmInterface();
auto& cpu_core = kernel.System().CurrentArmInterface();
cpu_core.SaveContext(cur_thread->GetContext32());
cpu_core.SaveContext(cur_thread->GetContext64());
// Save the TPIDR_EL0 system register in case it was modified.

View File

@@ -41,12 +41,16 @@ public:
explicit KScheduler(KernelCore& kernel);
~KScheduler();
void Initialize(KThread* idle_thread);
void Initialize(KThread* main_thread, KThread* idle_thread, s32 core_id);
void Activate();
void SetInterruptTaskRunnable();
void RequestScheduleOnInterrupt();
void ScheduleOnPreemption() {
ScheduleOnInterrupt();
}
u64 GetIdleCount() {
return m_state.idle_count;
}

View File

@@ -252,7 +252,6 @@ Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_
// Initialize emulation parameters.
thread->host_context = std::make_shared<Common::Fiber>(std::move(init_func));
thread->is_single_core = !Settings::values.use_multi_core.GetValue();
return ResultSuccess;
}
@@ -1189,7 +1188,7 @@ KThread& GetCurrentThread(KernelCore& kernel) {
}
s32 GetCurrentCoreId(KernelCore& kernel) {
return GetCurrentThread(kernel).GetCurrentCore();
return static_cast<s32>(kernel.CurrentPhysicalCoreIndex());
}
KScopedDisableDispatch::~KScopedDisableDispatch() {
@@ -1198,11 +1197,6 @@ KScopedDisableDispatch::~KScopedDisableDispatch() {
return;
}
// Skip the reschedule if single-core, as dispatch tracking is disabled here.
if (!Settings::values.use_multi_core.GetValue()) {
return;
}
if (GetCurrentThread(kernel).GetDisableDispatchCount() <= 1) {
auto scheduler = kernel.CurrentScheduler();

View File

@@ -490,7 +490,7 @@ public:
}
[[nodiscard]] bool IsDispatchTrackingDisabled() const {
return is_single_core || IsKernelThread();
return IsKernelThread();
}
[[nodiscard]] s32 GetDisableDispatchCount() const {
@@ -795,7 +795,6 @@ private:
// For emulation
std::shared_ptr<Common::Fiber> host_context{};
bool is_single_core{};
ThreadType thread_type{};
StepState step_state{};
std::mutex dummy_wait_lock;

View File

@@ -51,10 +51,6 @@ struct KernelCore::Impl {
: time_manager{system_},
service_threads_manager{1, "yuzu:ServiceThreadsManager"}, system{system_} {}
void SetMulticore(bool is_multi) {
is_multicore = is_multi;
}
void Initialize(KernelCore& kernel) {
global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel);
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
@@ -62,10 +58,6 @@ struct KernelCore::Impl {
global_handle_table->Initialize(KHandleTable::MaxTableSize);
default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
is_phantom_mode_for_singlecore = false;
InitializePhysicalCores();
// Derive the initial memory layout from the emulated board
Init::InitializeSlabResourceCounts(kernel);
DeriveInitialMemoryLayout();
@@ -76,6 +68,7 @@ struct KernelCore::Impl {
InitializeMemoryLayout();
Init::InitializeKPageBufferSlabHeap(system);
InitializeShutdownThreads();
InitializePhysicalCores();
InitializePreemption(kernel);
RegisterHostThread();
@@ -195,6 +188,18 @@ struct KernelCore::Impl {
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel());
cores.emplace_back(i, system, *schedulers[i], interrupts);
auto* main_thread = KThread::Create(system.Kernel());
main_thread->SetName(fmt::format("MainThread:{}", i));
main_thread->SetCurrentCore(static_cast<s32>(i));
ASSERT(KThread::InitializeMainThread(system, main_thread, static_cast<s32>(i))
.IsSuccess());
auto* idle_thread = KThread::Create(system.Kernel());
ASSERT(Kernel::KThread::InitializeIdleThread(system, idle_thread, static_cast<s32>(i))
.IsSuccess());
schedulers[i]->Initialize(main_thread, idle_thread, i);
}
}
@@ -290,10 +295,7 @@ struct KernelCore::Impl {
/// Registers a CPU core thread by allocating a host thread ID for it
void RegisterCoreThread(std::size_t core_id) {
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
const auto this_id = GetHostThreadId(core_id);
if (!is_multicore) {
single_core_thread_id = this_id;
}
[[maybe_unused]] const auto this_id = GetHostThreadId(core_id);
}
/// Registers a new host thread by allocating a host thread ID for it
@@ -303,20 +305,7 @@ struct KernelCore::Impl {
}
[[nodiscard]] u32 GetCurrentHostThreadID() {
const auto this_id = GetHostThreadId();
if (!is_multicore && single_core_thread_id == this_id) {
return static_cast<u32>(system.GetCpuManager().CurrentCore());
}
return this_id;
}
bool IsPhantomModeForSingleCore() const {
return is_phantom_mode_for_singlecore;
}
void SetIsPhantomModeForSingleCore(bool value) {
ASSERT(!is_multicore);
is_phantom_mode_for_singlecore = value;
return GetHostThreadId();
}
bool IsShuttingDown() const {
@@ -771,10 +760,7 @@ struct KernelCore::Impl {
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
bool is_multicore{};
std::atomic_bool is_shutting_down{};
bool is_phantom_mode_for_singlecore{};
u32 single_core_thread_id{};
std::array<u64, Core::Hardware::NUM_CPU_CORES> svc_ticks{};
@@ -787,10 +773,6 @@ struct KernelCore::Impl {
KernelCore::KernelCore(Core::System& system) : impl{std::make_unique<Impl>(system, *this)} {}
KernelCore::~KernelCore() = default;
void KernelCore::SetMulticore(bool is_multicore) {
impl->SetMulticore(is_multicore);
}
void KernelCore::Initialize() {
slab_heap_container = std::make_unique<SlabHeapContainer>();
impl->Initialize(*this);
@@ -1098,10 +1080,6 @@ void KernelCore::ShutdownCores() {
InterruptAllPhysicalCores();
}
bool KernelCore::IsMulticore() const {
return impl->is_multicore;
}
bool KernelCore::IsShuttingDown() const {
return impl->IsShuttingDown();
}
@@ -1151,14 +1129,6 @@ const KMemoryLayout& KernelCore::MemoryLayout() const {
return *impl->memory_layout;
}
bool KernelCore::IsPhantomModeForSingleCore() const {
return impl->IsPhantomModeForSingleCore();
}
void KernelCore::SetIsPhantomModeForSingleCore(bool value) {
impl->SetIsPhantomModeForSingleCore(value);
}
Core::System& KernelCore::System() {
return impl->system;
}

View File

@@ -97,9 +97,6 @@ public:
KernelCore(KernelCore&&) = delete;
KernelCore& operator=(KernelCore&&) = delete;
/// Sets if emulation is multicore or single core, must be set before Initialize
void SetMulticore(bool is_multicore);
/// Resets the kernel to a clean slate for use.
void Initialize();
@@ -283,8 +280,6 @@ public:
/// Notify emulated CPU cores to shut down.
void ShutdownCores();
bool IsMulticore() const;
bool IsShuttingDown() const;
void EnterSVCProfile();
@@ -318,10 +313,6 @@ public:
*/
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
/// Workaround for single-core mode when preempting threads while idle.
bool IsPhantomModeForSingleCore() const;
void SetIsPhantomModeForSingleCore(bool value);
Core::System& System();
const Core::System& System() const;

View File

@@ -20,7 +20,7 @@ PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KSche
// a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
auto& kernel = system.Kernel();
arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
system, interrupts, kernel.GetExclusiveMonitor(), core_index);
#else
#error Platform not supported yet.
#endif
@@ -34,7 +34,7 @@ void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
if (!is_64_bit) {
// We already initialized a 64-bit core, replace with a 32-bit one.
arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
system, interrupts, kernel.GetExclusiveMonitor(), core_index);
}
#else
#error Platform not supported yet.

View File

@@ -2102,16 +2102,8 @@ static void ChangeKernelTraceState([[maybe_unused]] Core::System& system,
static u64 GetSystemTick(Core::System& system) {
LOG_TRACE(Kernel_SVC, "called");
auto& core_timing = system.CoreTiming();
// Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
const u64 result{system.CoreTiming().GetClockTicks()};
if (!system.Kernel().IsMulticore()) {
core_timing.AddTicks(400U);
}
return result;
return system.CoreTiming().GetClockTicks();
}
static void GetSystemTick32(Core::System& system, u32* time_low, u32* time_high) {

View File

@@ -26,8 +26,6 @@
namespace Service::NVFlinger {
constexpr auto frame_ns = std::chrono::nanoseconds{1000000000 / 60};
void NVFlinger::SplitVSync(std::stop_token stop_token) {
system.RegisterHostThread();
std::string name = "yuzu:VSyncThread";
@@ -78,18 +76,10 @@ NVFlinger::NVFlinger(Core::System& system_, HosBinderDriverServer& hos_binder_dr
this->system.CoreTiming().ScheduleEvent(future_ns, composition_event);
});
if (system.IsMulticore()) {
vsync_thread = std::jthread([this](std::stop_token token) { SplitVSync(token); });
} else {
system.CoreTiming().ScheduleEvent(frame_ns, composition_event);
}
}
NVFlinger::~NVFlinger() {
if (!system.IsMulticore()) {
system.CoreTiming().UnscheduleEvent(composition_event, 0);
}
for (auto& display : displays) {
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
display.GetLayer(layer).Core().NotifyShutdown();

View File

@@ -126,38 +126,6 @@ double PerfStats::GetLastFrameTimeScale() const {
return duration_cast<DoubleSecs>(previous_frame_length).count() / FRAME_LENGTH;
}
void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) {
if (!Settings::values.use_speed_limit.GetValue() ||
Settings::values.use_multi_core.GetValue()) {
return;
}
auto now = Clock::now();
const double sleep_scale = Settings::values.speed_limit.GetValue() / 100.0;
// Max lag caused by slow frames. Shouldn't be more than the length of a frame at the current
// speed percent or it will clamp too much and prevent this from properly limiting to that
// percent. High values means it'll take longer after a slow frame to recover and start
// limiting
const microseconds max_lag_time_us = duration_cast<microseconds>(
std::chrono::duration<double, std::chrono::microseconds::period>(25ms / sleep_scale));
speed_limiting_delta_err += duration_cast<microseconds>(
std::chrono::duration<double, std::chrono::microseconds::period>(
(current_system_time_us - previous_system_time_us) / sleep_scale));
speed_limiting_delta_err -= duration_cast<microseconds>(now - previous_walltime);
speed_limiting_delta_err =
std::clamp(speed_limiting_delta_err, -max_lag_time_us, max_lag_time_us);
if (speed_limiting_delta_err > microseconds::zero()) {
std::this_thread::sleep_for(speed_limiting_delta_err);
auto now_after_sleep = Clock::now();
speed_limiting_delta_err -= duration_cast<microseconds>(now_after_sleep - now);
now = now_after_sleep;
}
previous_system_time_us = current_system_time_us;
previous_walltime = now;
}
void SpeedLimiter::DoSpeedLimiting(microseconds current_system_time_us) {}
} // namespace Core

View File

@@ -226,7 +226,6 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader,
// Log user configuration information
constexpr auto field_type = Telemetry::FieldType::UserConfig;
AddField(field_type, "Audio_SinkId", Settings::values.sink_id.GetValue());
AddField(field_type, "Core_UseMultiCore", Settings::values.use_multi_core.GetValue());
AddField(field_type, "Renderer_Backend",
TranslateRenderer(Settings::values.renderer_backend.GetValue()));
AddField(field_type, "Renderer_UseSpeedLimit", Settings::values.use_speed_limit.GetValue());

View File

@@ -36,7 +36,6 @@ void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_
struct ScopeInit final {
ScopeInit() {
core_timing.SetMulticore(true);
core_timing.Initialize([]() {});
}
~ScopeInit() {

View File

@@ -467,7 +467,6 @@ void Config::ReadMotionTouchValues() {
void Config::ReadCoreValues() {
qt_config->beginGroup(QStringLiteral("Core"));
ReadGlobalSetting(Settings::values.use_multi_core);
ReadGlobalSetting(Settings::values.use_extended_memory_layout);
qt_config->endGroup();
@@ -1067,7 +1066,6 @@ void Config::SaveControlValues() {
void Config::SaveCoreValues() {
qt_config->beginGroup(QStringLiteral("Core"));
WriteGlobalSetting(Settings::values.use_multi_core);
WriteGlobalSetting(Settings::values.use_extended_memory_layout);
qt_config->endGroup();

View File

@@ -37,8 +37,6 @@ ConfigureGeneral::~ConfigureGeneral() = default;
void ConfigureGeneral::SetConfiguration() {
const bool runtime_lock = !system.IsPoweredOn();
ui->use_multi_core->setEnabled(runtime_lock);
ui->use_multi_core->setChecked(Settings::values.use_multi_core.GetValue());
ui->use_extended_memory_layout->setEnabled(runtime_lock);
ui->use_extended_memory_layout->setChecked(
Settings::values.use_extended_memory_layout.GetValue());
@@ -89,8 +87,6 @@ void ConfigureGeneral::ResetDefaults() {
}
void ConfigureGeneral::ApplyConfiguration() {
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, ui->use_multi_core,
use_multi_core);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_extended_memory_layout,
ui->use_extended_memory_layout,
use_extended_memory_layout);
@@ -161,8 +157,6 @@ void ConfigureGeneral::SetupPerGameUI() {
ConfigurationShared::SetColoredTristate(ui->toggle_speed_limit,
Settings::values.use_speed_limit, use_speed_limit);
ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core,
use_multi_core);
ConfigurationShared::SetColoredTristate(ui->use_extended_memory_layout,
Settings::values.use_extended_memory_layout,
use_extended_memory_layout);

View File

@@ -47,7 +47,6 @@ private:
std::unique_ptr<Ui::ConfigureGeneral> ui;
ConfigurationShared::CheckState use_speed_limit;
ConfigurationShared::CheckState use_multi_core;
ConfigurationShared::CheckState use_extended_memory_layout;
const Core::System& system;

View File

@@ -135,13 +135,6 @@
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="use_multi_core">
<property name="text">
<string>Multicore CPU Emulation</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="use_extended_memory_layout">
<property name="text">

View File

@@ -3286,7 +3286,7 @@ void GMainWindow::UpdateStatusBar() {
emu_frametime_label->setText(tr("Frame: %1 ms").arg(results.frametime * 1000.0, 0, 'f', 2));
res_scale_label->setVisible(true);
emu_speed_label->setVisible(!Settings::values.use_multi_core.GetValue());
emu_speed_label->setVisible(false);
game_fps_label->setVisible(true);
emu_frametime_label->setVisible(true);
}

View File

@@ -266,7 +266,6 @@ void Config::ReadValues() {
ReadSetting("System", Settings::values.sound_index);
// Core
ReadSetting("Core", Settings::values.use_multi_core);
ReadSetting("Core", Settings::values.use_extended_memory_layout);
// Cpu

View File

@@ -121,11 +121,6 @@ mouse_enabled =
# 0 (default): Disabled, 1: Enabled
keyboard_enabled =
[Core]
# Whether to use multi-core for CPU emulation
# 0: Disabled, 1 (default): Enabled
use_multi_core =
# Enable extended guest system memory layout (6GB DRAM)
# 0 (default): Disabled, 1: Enabled
use_extended_memory_layout =