summaryrefslogtreecommitdiff
path: root/src/core/core.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2018-05-11 12:59:23 -0400
committerGravatar GitHub2018-05-11 12:59:23 -0400
commit1b5c02fc37206bbd33715d2dde6258c3f835581c (patch)
tree1c33c66e734ff55228e4293cd2720070cd467080 /src/core/core.cpp
parentMerge pull request #439 from ogniK5377/GetTPCMasks (diff)
parentcore: Add several missing docstrings. (diff)
downloadyuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.tar.gz
yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.tar.xz
yuzu-1b5c02fc37206bbd33715d2dde6258c3f835581c.zip
Merge pull request #436 from bunnei/multi-core
Initial support for multi-core
Diffstat (limited to 'src/core/core.cpp')
-rw-r--r--src/core/core.cpp117
1 files changed, 72 insertions, 45 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 9e2229d02..84ab876cc 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -5,10 +5,6 @@
5#include <memory> 5#include <memory>
6#include <utility> 6#include <utility>
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#ifdef ARCHITECTURE_x86_64
9#include "core/arm/dynarmic/arm_dynarmic.h"
10#endif
11#include "core/arm/unicorn/arm_unicorn.h"
12#include "core/core.h" 8#include "core/core.h"
13#include "core/core_timing.h" 9#include "core/core_timing.h"
14#include "core/gdbstub/gdbstub.h" 10#include "core/gdbstub/gdbstub.h"
@@ -31,11 +27,31 @@ namespace Core {
31 27
32System::~System() = default; 28System::~System() = default;
33 29
30/// Runs a CPU core while the system is powered on
31static void RunCpuCore(std::shared_ptr<Cpu> cpu_state) {
32 while (Core::System().GetInstance().IsPoweredOn()) {
33 cpu_state->RunLoop(true);
34 }
35}
36
37Cpu& System::CurrentCpuCore() {
38 // If multicore is enabled, use host thread to figure out the current CPU core
39 if (Settings::values.use_multi_core) {
40 const auto& search = thread_to_cpu.find(std::this_thread::get_id());
41 ASSERT(search != thread_to_cpu.end());
42 ASSERT(search->second);
43 return *search->second;
44 }
45
46 // Otherwise, use single-threaded mode active_core variable
47 return *cpu_cores[active_core];
48}
49
34System::ResultStatus System::RunLoop(bool tight_loop) { 50System::ResultStatus System::RunLoop(bool tight_loop) {
35 status = ResultStatus::Success; 51 status = ResultStatus::Success;
36 if (!cpu_core) { 52
37 return ResultStatus::ErrorNotInitialized; 53 // Update thread_to_cpu in case Core 0 is run from a different host thread
38 } 54 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0];
39 55
40 if (GDBStub::IsServerEnabled()) { 56 if (GDBStub::IsServerEnabled()) {
41 GDBStub::HandlePacket(); 57 GDBStub::HandlePacket();
@@ -52,25 +68,14 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
52 } 68 }
53 } 69 }
54 70
55 // If we don't have a currently active thread then don't execute instructions, 71 for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
56 // instead advance to the next event and try to yield to the next thread 72 cpu_cores[active_core]->RunLoop(tight_loop);
57 if (Kernel::GetCurrentThread() == nullptr) { 73 if (Settings::values.use_multi_core) {
58 NGLOG_TRACE(Core_ARM, "Idling"); 74 // Cores 1-3 are run on other threads in this mode
59 CoreTiming::Idle(); 75 break;
60 CoreTiming::Advance();
61 PrepareReschedule();
62 } else {
63 CoreTiming::Advance();
64 if (tight_loop) {
65 cpu_core->Run();
66 } else {
67 cpu_core->Step();
68 } 76 }
69 } 77 }
70 78
71 HW::Update();
72 Reschedule();
73
74 return status; 79 return status;
75} 80}
76 81
@@ -133,21 +138,26 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
133} 138}
134 139
135void System::PrepareReschedule() { 140void System::PrepareReschedule() {
136 cpu_core->PrepareReschedule(); 141 CurrentCpuCore().PrepareReschedule();
137 reschedule_pending = true;
138} 142}
139 143
140PerfStats::Results System::GetAndResetPerfStats() { 144PerfStats::Results System::GetAndResetPerfStats() {
141 return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs()); 145 return perf_stats.GetAndResetStats(CoreTiming::GetGlobalTimeUs());
142} 146}
143 147
144void System::Reschedule() { 148const std::shared_ptr<Kernel::Scheduler>& System::Scheduler(size_t core_index) {
145 if (!reschedule_pending) { 149 ASSERT(core_index < NUM_CPU_CORES);
146 return; 150 return cpu_cores[core_index]->Scheduler();
147 } 151}
148 152
149 reschedule_pending = false; 153ARM_Interface& System::ArmInterface(size_t core_index) {
150 Core::System::GetInstance().Scheduler().Reschedule(); 154 ASSERT(core_index < NUM_CPU_CORES);
155 return cpu_cores[core_index]->ArmInterface();
156}
157
158Cpu& System::CpuCore(size_t core_index) {
159 ASSERT(core_index < NUM_CPU_CORES);
160 return *cpu_cores[core_index];
151} 161}
152 162
153System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) { 163System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
@@ -157,26 +167,17 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
157 167
158 current_process = Kernel::Process::Create("main"); 168 current_process = Kernel::Process::Create("main");
159 169
160 if (Settings::values.use_cpu_jit) { 170 cpu_barrier = std::make_shared<CpuBarrier>();
161#ifdef ARCHITECTURE_x86_64 171 for (size_t index = 0; index < cpu_cores.size(); ++index) {
162 cpu_core = std::make_shared<ARM_Dynarmic>(); 172 cpu_cores[index] = std::make_shared<Cpu>(cpu_barrier, index);
163#else
164 cpu_core = std::make_shared<ARM_Unicorn>();
165 NGLOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
166#endif
167 } else {
168 cpu_core = std::make_shared<ARM_Unicorn>();
169 } 173 }
170 174
171 gpu_core = std::make_unique<Tegra::GPU>(); 175 gpu_core = std::make_unique<Tegra::GPU>();
172
173 telemetry_session = std::make_unique<Core::TelemetrySession>(); 176 telemetry_session = std::make_unique<Core::TelemetrySession>();
174
175 service_manager = std::make_shared<Service::SM::ServiceManager>(); 177 service_manager = std::make_shared<Service::SM::ServiceManager>();
176 178
177 HW::Init(); 179 HW::Init();
178 Kernel::Init(system_mode); 180 Kernel::Init(system_mode);
179 scheduler = std::make_unique<Kernel::Scheduler>(cpu_core.get());
180 Service::Init(service_manager); 181 Service::Init(service_manager);
181 GDBStub::Init(); 182 GDBStub::Init();
182 183
@@ -184,6 +185,17 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
184 return ResultStatus::ErrorVideoCore; 185 return ResultStatus::ErrorVideoCore;
185 } 186 }
186 187
188 // Create threads for CPU cores 1-3, and build thread_to_cpu map
189 // CPU core 0 is run on the main thread
190 thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0];
191 if (Settings::values.use_multi_core) {
192 for (size_t index = 0; index < cpu_core_threads.size(); ++index) {
193 cpu_core_threads[index] =
194 std::make_unique<std::thread>(RunCpuCore, cpu_cores[index + 1]);
195 thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1];
196 }
197 }
198
187 NGLOG_DEBUG(Core, "Initialized OK"); 199 NGLOG_DEBUG(Core, "Initialized OK");
188 200
189 // Reset counters and set time origin to current frame 201 // Reset counters and set time origin to current frame
@@ -207,15 +219,30 @@ void System::Shutdown() {
207 VideoCore::Shutdown(); 219 VideoCore::Shutdown();
208 GDBStub::Shutdown(); 220 GDBStub::Shutdown();
209 Service::Shutdown(); 221 Service::Shutdown();
210 scheduler.reset();
211 Kernel::Shutdown(); 222 Kernel::Shutdown();
212 HW::Shutdown(); 223 HW::Shutdown();
213 service_manager.reset(); 224 service_manager.reset();
214 telemetry_session.reset(); 225 telemetry_session.reset();
215 gpu_core.reset(); 226 gpu_core.reset();
216 cpu_core.reset(); 227
228 // Close all CPU/threading state
229 cpu_barrier->NotifyEnd();
230 if (Settings::values.use_multi_core) {
231 for (auto& thread : cpu_core_threads) {
232 thread->join();
233 thread.reset();
234 }
235 }
236 thread_to_cpu.clear();
237 for (auto& cpu_core : cpu_cores) {
238 cpu_core.reset();
239 }
240 cpu_barrier.reset();
241
242 // Close core timing
217 CoreTiming::Shutdown(); 243 CoreTiming::Shutdown();
218 244
245 // Close app loader
219 app_loader.reset(); 246 app_loader.reset();
220 247
221 NGLOG_DEBUG(Core, "Shutdown OK"); 248 NGLOG_DEBUG(Core, "Shutdown OK");