diff options
| author | 2020-03-28 15:23:28 -0400 | |
|---|---|---|
| committer | 2020-06-27 11:36:01 -0400 | |
| commit | f5e32935ca9d1727624c86ca78aff91027caf819 (patch) | |
| tree | a041186cd47fcea90880b300af3351a56fb819aa /src | |
| parent | Scheduler: Correct Reload/Unload (diff) | |
| download | yuzu-f5e32935ca9d1727624c86ca78aff91027caf819.tar.gz yuzu-f5e32935ca9d1727624c86ca78aff91027caf819.tar.xz yuzu-f5e32935ca9d1727624c86ca78aff91027caf819.zip | |
SingleCore: Use Cycle Timing instead of Host Timing.
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/arm/arm_interface.h | 6 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.cpp | 37 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.h | 2 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 39 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.h | 2 | ||||
| -rw-r--r-- | src/core/arm/unicorn/arm_unicorn.cpp | 6 | ||||
| -rw-r--r-- | src/core/arm/unicorn/arm_unicorn.h | 4 | ||||
| -rw-r--r-- | src/core/core_timing.cpp | 41 | ||||
| -rw-r--r-- | src/core/core_timing.h | 14 | ||||
| -rw-r--r-- | src/core/core_timing_util.cpp | 29 | ||||
| -rw-r--r-- | src/core/core_timing_util.h | 15 | ||||
| -rw-r--r-- | src/core/cpu_manager.cpp | 18 | ||||
| -rw-r--r-- | src/core/cpu_manager.h | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc.cpp | 5 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 12 |
15 files changed, 152 insertions, 80 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index e5c484336..fbdce4134 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -26,8 +26,9 @@ using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CO | |||
| 26 | /// Generic ARMv8 CPU interface | 26 | /// Generic ARMv8 CPU interface |
| 27 | class ARM_Interface : NonCopyable { | 27 | class ARM_Interface : NonCopyable { |
| 28 | public: | 28 | public: |
| 29 | explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers) | 29 | explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers, bool uses_wall_clock) |
| 30 | : system{system_}, interrupt_handlers{interrupt_handlers} {} | 30 | : system{system_}, interrupt_handlers{interrupt_handlers}, uses_wall_clock{ |
| 31 | uses_wall_clock} {} | ||
| 31 | virtual ~ARM_Interface() = default; | 32 | virtual ~ARM_Interface() = default; |
| 32 | 33 | ||
| 33 | struct ThreadContext32 { | 34 | struct ThreadContext32 { |
| @@ -186,6 +187,7 @@ protected: | |||
| 186 | /// System context that this ARM interface is running under. | 187 | /// System context that this ARM interface is running under. |
| 187 | System& system; | 188 | System& system; |
| 188 | CPUInterrupts& interrupt_handlers; | 189 | CPUInterrupts& interrupt_handlers; |
| 190 | bool uses_wall_clock; | ||
| 189 | }; | 191 | }; |
| 190 | 192 | ||
| 191 | } // namespace Core | 193 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 9c47c133c..c4aeedef9 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -72,23 +72,35 @@ public: | |||
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | void AddTicks(u64 ticks) override { | 74 | void AddTicks(u64 ticks) override { |
| 75 | this->ticks -= ticks; | 75 | if (parent.uses_wall_clock) { |
| 76 | return; | ||
| 77 | } | ||
| 78 | // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a | ||
| 79 | // rough approximation of the amount of executed ticks in the system, it may be thrown off | ||
| 80 | // if not all cores are doing a similar amount of work. Instead of doing this, we should | ||
| 81 | // device a way so that timing is consistent across all cores without increasing the ticks 4 | ||
| 82 | // times. | ||
| 83 | u64 amortized_ticks = | ||
| 84 | (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES; | ||
| 85 | // Always execute at least one tick. | ||
| 86 | amortized_ticks = std::max<u64>(amortized_ticks, 1); | ||
| 87 | |||
| 88 | parent.system.CoreTiming().AddTicks(amortized_ticks); | ||
| 89 | num_interpreted_instructions = 0; | ||
| 76 | } | 90 | } |
| 77 | 91 | ||
| 78 | u64 GetTicksRemaining() override { | 92 | u64 GetTicksRemaining() override { |
| 79 | if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { | 93 | if (parent.uses_wall_clock) { |
| 80 | return std::max<s64>(ticks, 0); | 94 | if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { |
| 95 | return std::max<s64>(1000U, 0); | ||
| 96 | } | ||
| 97 | return 0ULL; | ||
| 81 | } | 98 | } |
| 82 | return 0ULL; | 99 | return std::max(parent.system.CoreTiming().GetDowncount(), 0LL); |
| 83 | } | ||
| 84 | |||
| 85 | void ResetTicks() { | ||
| 86 | ticks = 1000LL; | ||
| 87 | } | 100 | } |
| 88 | 101 | ||
| 89 | ARM_Dynarmic_32& parent; | 102 | ARM_Dynarmic_32& parent; |
| 90 | std::size_t num_interpreted_instructions{}; | 103 | std::size_t num_interpreted_instructions{}; |
| 91 | s64 ticks{}; | ||
| 92 | }; | 104 | }; |
| 93 | 105 | ||
| 94 | std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, | 106 | std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& page_table, |
| @@ -103,7 +115,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable& | |||
| 103 | } | 115 | } |
| 104 | 116 | ||
| 105 | void ARM_Dynarmic_32::Run() { | 117 | void ARM_Dynarmic_32::Run() { |
| 106 | cb->ResetTicks(); | ||
| 107 | jit->Run(); | 118 | jit->Run(); |
| 108 | } | 119 | } |
| 109 | 120 | ||
| @@ -112,8 +123,10 @@ void ARM_Dynarmic_32::Step() { | |||
| 112 | } | 123 | } |
| 113 | 124 | ||
| 114 | ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, | 125 | ARM_Dynarmic_32::ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, |
| 115 | ExclusiveMonitor& exclusive_monitor, std::size_t core_index) | 126 | bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, |
| 116 | : ARM_Interface{system, interrupt_handlers}, cb(std::make_unique<DynarmicCallbacks32>(*this)), | 127 | std::size_t core_index) |
| 128 | : ARM_Interface{system, interrupt_handlers, uses_wall_clock}, | ||
| 129 | cb(std::make_unique<DynarmicCallbacks32>(*this)), | ||
| 117 | cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index}, | 130 | cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index}, |
| 118 | exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} | 131 | exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor)} {} |
| 119 | 132 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index bea4933c8..8afd15c8b 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h | |||
| @@ -29,7 +29,7 @@ class System; | |||
| 29 | 29 | ||
| 30 | class ARM_Dynarmic_32 final : public ARM_Interface { | 30 | class ARM_Dynarmic_32 final : public ARM_Interface { |
| 31 | public: | 31 | public: |
| 32 | ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, | 32 | ARM_Dynarmic_32(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, |
| 33 | ExclusiveMonitor& exclusive_monitor, std::size_t core_index); | 33 | ExclusiveMonitor& exclusive_monitor, std::size_t core_index); |
| 34 | ~ARM_Dynarmic_32() override; | 34 | ~ARM_Dynarmic_32() override; |
| 35 | 35 | ||
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 03b3313cf..a518733b6 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -124,29 +124,41 @@ public: | |||
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | void AddTicks(u64 ticks) override { | 126 | void AddTicks(u64 ticks) override { |
| 127 | this->ticks -= ticks; | 127 | if (parent.uses_wall_clock) { |
| 128 | return; | ||
| 129 | } | ||
| 130 | // Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a | ||
| 131 | // rough approximation of the amount of executed ticks in the system, it may be thrown off | ||
| 132 | // if not all cores are doing a similar amount of work. Instead of doing this, we should | ||
| 133 | // device a way so that timing is consistent across all cores without increasing the ticks 4 | ||
| 134 | // times. | ||
| 135 | u64 amortized_ticks = | ||
| 136 | (ticks - num_interpreted_instructions) / Core::Hardware::NUM_CPU_CORES; | ||
| 137 | // Always execute at least one tick. | ||
| 138 | amortized_ticks = std::max<u64>(amortized_ticks, 1); | ||
| 139 | |||
| 140 | parent.system.CoreTiming().AddTicks(amortized_ticks); | ||
| 141 | num_interpreted_instructions = 0; | ||
| 128 | } | 142 | } |
| 129 | 143 | ||
| 130 | u64 GetTicksRemaining() override { | 144 | u64 GetTicksRemaining() override { |
| 131 | if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { | 145 | if (parent.uses_wall_clock) { |
| 132 | return std::max<s64>(ticks, 0); | 146 | if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) { |
| 147 | return std::max<s64>(1000U, 0); | ||
| 148 | } | ||
| 149 | return 0ULL; | ||
| 133 | } | 150 | } |
| 134 | return 0ULL; | 151 | return std::max(parent.system.CoreTiming().GetDowncount(), 0LL); |
| 135 | } | 152 | } |
| 136 | 153 | ||
| 137 | u64 GetCNTPCT() override { | 154 | u64 GetCNTPCT() override { |
| 138 | return parent.system.CoreTiming().GetClockTicks(); | 155 | return parent.system.CoreTiming().GetClockTicks(); |
| 139 | } | 156 | } |
| 140 | 157 | ||
| 141 | void ResetTicks() { | ||
| 142 | ticks = 1000LL; | ||
| 143 | } | ||
| 144 | |||
| 145 | ARM_Dynarmic_64& parent; | 158 | ARM_Dynarmic_64& parent; |
| 146 | std::size_t num_interpreted_instructions = 0; | 159 | std::size_t num_interpreted_instructions = 0; |
| 147 | u64 tpidrro_el0 = 0; | 160 | u64 tpidrro_el0 = 0; |
| 148 | u64 tpidr_el0 = 0; | 161 | u64 tpidr_el0 = 0; |
| 149 | s64 ticks{}; | ||
| 150 | }; | 162 | }; |
| 151 | 163 | ||
| 152 | std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table, | 164 | std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& page_table, |
| @@ -185,13 +197,12 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable& | |||
| 185 | } | 197 | } |
| 186 | 198 | ||
| 187 | // CNTPCT uses wall clock. | 199 | // CNTPCT uses wall clock. |
| 188 | config.wall_clock_cntpct = true; | 200 | config.wall_clock_cntpct = uses_wall_clock; |
| 189 | 201 | ||
| 190 | return std::make_shared<Dynarmic::A64::Jit>(config); | 202 | return std::make_shared<Dynarmic::A64::Jit>(config); |
| 191 | } | 203 | } |
| 192 | 204 | ||
| 193 | void ARM_Dynarmic_64::Run() { | 205 | void ARM_Dynarmic_64::Run() { |
| 194 | cb->ResetTicks(); | ||
| 195 | jit->Run(); | 206 | jit->Run(); |
| 196 | } | 207 | } |
| 197 | 208 | ||
| @@ -200,9 +211,11 @@ void ARM_Dynarmic_64::Step() { | |||
| 200 | } | 211 | } |
| 201 | 212 | ||
| 202 | ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, | 213 | ARM_Dynarmic_64::ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, |
| 203 | ExclusiveMonitor& exclusive_monitor, std::size_t core_index) | 214 | bool uses_wall_clock, ExclusiveMonitor& exclusive_monitor, |
| 204 | : ARM_Interface{system, interrupt_handler}, | 215 | std::size_t core_index) |
| 216 | : ARM_Interface{system, interrupt_handler, uses_wall_clock}, | ||
| 205 | cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handler, | 217 | cb(std::make_unique<DynarmicCallbacks64>(*this)), inner_unicorn{system, interrupt_handler, |
| 218 | uses_wall_clock, | ||
| 206 | ARM_Unicorn::Arch::AArch64, | 219 | ARM_Unicorn::Arch::AArch64, |
| 207 | core_index}, | 220 | core_index}, |
| 208 | core_index{core_index}, exclusive_monitor{ | 221 | core_index{core_index}, exclusive_monitor{ |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index c26b47249..31ec16521 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h | |||
| @@ -28,7 +28,7 @@ class System; | |||
| 28 | 28 | ||
| 29 | class ARM_Dynarmic_64 final : public ARM_Interface { | 29 | class ARM_Dynarmic_64 final : public ARM_Interface { |
| 30 | public: | 30 | public: |
| 31 | ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, | 31 | ARM_Dynarmic_64(System& system, CPUInterrupts& interrupt_handlers, bool uses_wall_clock, |
| 32 | ExclusiveMonitor& exclusive_monitor, std::size_t core_index); | 32 | ExclusiveMonitor& exclusive_monitor, std::size_t core_index); |
| 33 | ~ARM_Dynarmic_64() override; | 33 | ~ARM_Dynarmic_64() override; |
| 34 | 34 | ||
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 099229c8d..1cb71942b 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp | |||
| @@ -63,9 +63,9 @@ static bool UnmappedMemoryHook(uc_engine* uc, uc_mem_type type, u64 addr, int si | |||
| 63 | return false; | 63 | return false; |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | ARM_Unicorn::ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture, | 66 | ARM_Unicorn::ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, |
| 67 | std::size_t core_index) | 67 | bool uses_wall_clock, Arch architecture, std::size_t core_index) |
| 68 | : ARM_Interface{system, interrupt_handler}, core_index{core_index} { | 68 | : ARM_Interface{system, interrupt_handler, uses_wall_clock}, core_index{core_index} { |
| 69 | const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64; | 69 | const auto arch = architecture == Arch::AArch32 ? UC_ARCH_ARM : UC_ARCH_ARM64; |
| 70 | CHECKED(uc_open(arch, UC_MODE_ARM, &uc)); | 70 | CHECKED(uc_open(arch, UC_MODE_ARM, &uc)); |
| 71 | 71 | ||
diff --git a/src/core/arm/unicorn/arm_unicorn.h b/src/core/arm/unicorn/arm_unicorn.h index f09b24a85..a01751e65 100644 --- a/src/core/arm/unicorn/arm_unicorn.h +++ b/src/core/arm/unicorn/arm_unicorn.h | |||
| @@ -20,8 +20,8 @@ public: | |||
| 20 | AArch64, // 64-bit ARM | 20 | AArch64, // 64-bit ARM |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | explicit ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, Arch architecture, | 23 | explicit ARM_Unicorn(System& system, CPUInterruptHandler& interrupt_handler, |
| 24 | std::size_t core_index); | 24 | bool uses_wall_clock, Arch architecture, std::size_t core_index); |
| 25 | ~ARM_Unicorn() override; | 25 | ~ARM_Unicorn() override; |
| 26 | 26 | ||
| 27 | void SetPC(u64 pc) override; | 27 | void SetPC(u64 pc) override; |
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index 189d4aa34..12e9e60a4 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -14,6 +14,8 @@ | |||
| 14 | 14 | ||
| 15 | namespace Core::Timing { | 15 | namespace Core::Timing { |
| 16 | 16 | ||
| 17 | constexpr u64 MAX_SLICE_LENGTH = 4000; | ||
| 18 | |||
| 17 | std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { | 19 | std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { |
| 18 | return std::make_shared<EventType>(std::move(callback), std::move(name)); | 20 | return std::make_shared<EventType>(std::move(callback), std::move(name)); |
| 19 | } | 21 | } |
| @@ -53,6 +55,7 @@ void CoreTiming::ThreadEntry(CoreTiming& instance) { | |||
| 53 | void CoreTiming::Initialize(std::function<void(void)>&& on_thread_init_) { | 55 | void CoreTiming::Initialize(std::function<void(void)>&& on_thread_init_) { |
| 54 | on_thread_init = std::move(on_thread_init_); | 56 | on_thread_init = std::move(on_thread_init_); |
| 55 | event_fifo_id = 0; | 57 | event_fifo_id = 0; |
| 58 | ticks = 0; | ||
| 56 | const auto empty_timed_callback = [](u64, s64) {}; | 59 | const auto empty_timed_callback = [](u64, s64) {}; |
| 57 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); | 60 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); |
| 58 | if (is_multicore) { | 61 | if (is_multicore) { |
| @@ -126,20 +129,36 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u | |||
| 126 | basic_lock.unlock(); | 129 | basic_lock.unlock(); |
| 127 | } | 130 | } |
| 128 | 131 | ||
| 129 | void CoreTiming::AddTicks(std::size_t core_index, u64 ticks) { | 132 | void CoreTiming::AddTicks(u64 ticks) { |
| 130 | ticks_count[core_index] += ticks; | 133 | this->ticks += ticks; |
| 134 | downcount -= ticks; | ||
| 131 | } | 135 | } |
| 132 | 136 | ||
| 133 | void CoreTiming::ResetTicks(std::size_t core_index) { | 137 | void CoreTiming::Idle() { |
| 134 | ticks_count[core_index] = 0; | 138 | if (!event_queue.empty()) { |
| 139 | u64 next_event_time = event_queue.front().time; | ||
| 140 | ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U; | ||
| 141 | return; | ||
| 142 | } | ||
| 143 | ticks += 1000U; | ||
| 144 | } | ||
| 145 | |||
| 146 | void CoreTiming::ResetTicks() { | ||
| 147 | downcount = MAX_SLICE_LENGTH; | ||
| 135 | } | 148 | } |
| 136 | 149 | ||
| 137 | u64 CoreTiming::GetCPUTicks() const { | 150 | u64 CoreTiming::GetCPUTicks() const { |
| 138 | return clock->GetCPUCycles(); | 151 | if (is_multicore) { |
| 152 | return clock->GetCPUCycles(); | ||
| 153 | } | ||
| 154 | return ticks; | ||
| 139 | } | 155 | } |
| 140 | 156 | ||
| 141 | u64 CoreTiming::GetClockTicks() const { | 157 | u64 CoreTiming::GetClockTicks() const { |
| 142 | return clock->GetClockCycles(); | 158 | if (is_multicore) { |
| 159 | return clock->GetClockCycles(); | ||
| 160 | } | ||
| 161 | return CpuCyclesToClockCycles(ticks); | ||
| 143 | } | 162 | } |
| 144 | 163 | ||
| 145 | void CoreTiming::ClearPendingEvents() { | 164 | void CoreTiming::ClearPendingEvents() { |
| @@ -217,11 +236,17 @@ void CoreTiming::ThreadLoop() { | |||
| 217 | } | 236 | } |
| 218 | 237 | ||
| 219 | std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { | 238 | std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { |
| 220 | return clock->GetTimeNS(); | 239 | if (is_multicore) { |
| 240 | return clock->GetTimeNS(); | ||
| 241 | } | ||
| 242 | return CyclesToNs(ticks); | ||
| 221 | } | 243 | } |
| 222 | 244 | ||
| 223 | std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { | 245 | std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { |
| 224 | return clock->GetTimeUS(); | 246 | if (is_multicore) { |
| 247 | return clock->GetTimeUS(); | ||
| 248 | } | ||
| 249 | return CyclesToUs(ticks); | ||
| 225 | } | 250 | } |
| 226 | 251 | ||
| 227 | } // namespace Core::Timing | 252 | } // namespace Core::Timing |
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 03f9a5c76..ed5de9b97 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -98,9 +98,15 @@ public: | |||
| 98 | /// We only permit one event of each type in the queue at a time. | 98 | /// We only permit one event of each type in the queue at a time. |
| 99 | void RemoveEvent(const std::shared_ptr<EventType>& event_type); | 99 | void RemoveEvent(const std::shared_ptr<EventType>& event_type); |
| 100 | 100 | ||
| 101 | void AddTicks(std::size_t core_index, u64 ticks); | 101 | void AddTicks(u64 ticks); |
| 102 | 102 | ||
| 103 | void ResetTicks(std::size_t core_index); | 103 | void ResetTicks(); |
| 104 | |||
| 105 | void Idle(); | ||
| 106 | |||
| 107 | s64 GetDowncount() const { | ||
| 108 | return downcount; | ||
| 109 | } | ||
| 104 | 110 | ||
| 105 | /// Returns current time in emulated CPU cycles | 111 | /// Returns current time in emulated CPU cycles |
| 106 | u64 GetCPUTicks() const; | 112 | u64 GetCPUTicks() const; |
| @@ -154,7 +160,9 @@ private: | |||
| 154 | 160 | ||
| 155 | bool is_multicore{}; | 161 | bool is_multicore{}; |
| 156 | 162 | ||
| 157 | std::array<std::atomic<u64>, Core::Hardware::NUM_CPU_CORES> ticks_count{}; | 163 | /// Cycle timing |
| 164 | u64 ticks{}; | ||
| 165 | s64 downcount{}; | ||
| 158 | }; | 166 | }; |
| 159 | 167 | ||
| 160 | /// Creates a core timing event with the given name and callback. | 168 | /// Creates a core timing event with the given name and callback. |
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp index be34b26fe..aefc63663 100644 --- a/src/core/core_timing_util.cpp +++ b/src/core/core_timing_util.cpp | |||
| @@ -38,15 +38,8 @@ s64 usToCycles(std::chrono::microseconds us) { | |||
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | s64 nsToCycles(std::chrono::nanoseconds ns) { | 40 | s64 nsToCycles(std::chrono::nanoseconds ns) { |
| 41 | if (static_cast<u64>(ns.count() / 1000000000) > MAX_VALUE_TO_MULTIPLY) { | 41 | const u128 temporal = Common::Multiply64Into128(ns.count(), Hardware::BASE_CLOCK_RATE); |
| 42 | LOG_ERROR(Core_Timing, "Integer overflow, use max value"); | 42 | return Common::Divide128On32(temporal, static_cast<u32>(1000000000)).first; |
| 43 | return std::numeric_limits<s64>::max(); | ||
| 44 | } | ||
| 45 | if (static_cast<u64>(ns.count()) > MAX_VALUE_TO_MULTIPLY) { | ||
| 46 | LOG_DEBUG(Core_Timing, "Time very big, do rounding"); | ||
| 47 | return Hardware::BASE_CLOCK_RATE * (ns.count() / 1000000000); | ||
| 48 | } | ||
| 49 | return (Hardware::BASE_CLOCK_RATE * ns.count()) / 1000000000; | ||
| 50 | } | 43 | } |
| 51 | 44 | ||
| 52 | u64 msToClockCycles(std::chrono::milliseconds ns) { | 45 | u64 msToClockCycles(std::chrono::milliseconds ns) { |
| @@ -69,4 +62,22 @@ u64 CpuCyclesToClockCycles(u64 ticks) { | |||
| 69 | return Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first; | 62 | return Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first; |
| 70 | } | 63 | } |
| 71 | 64 | ||
| 65 | std::chrono::milliseconds CyclesToMs(s64 cycles) { | ||
| 66 | const u128 temporal = Common::Multiply64Into128(cycles, 1000); | ||
| 67 | u64 ms = Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first; | ||
| 68 | return std::chrono::milliseconds(ms); | ||
| 69 | } | ||
| 70 | |||
| 71 | std::chrono::nanoseconds CyclesToNs(s64 cycles) { | ||
| 72 | const u128 temporal = Common::Multiply64Into128(cycles, 1000000000); | ||
| 73 | u64 ns = Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first; | ||
| 74 | return std::chrono::nanoseconds(ns); | ||
| 75 | } | ||
| 76 | |||
| 77 | std::chrono::microseconds CyclesToUs(s64 cycles) { | ||
| 78 | const u128 temporal = Common::Multiply64Into128(cycles, 1000000); | ||
| 79 | u64 us = Common::Divide128On32(temporal, static_cast<u32>(Hardware::BASE_CLOCK_RATE)).first; | ||
| 80 | return std::chrono::microseconds(us); | ||
| 81 | } | ||
| 82 | |||
| 72 | } // namespace Core::Timing | 83 | } // namespace Core::Timing |
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h index b3c58447d..2ed979e14 100644 --- a/src/core/core_timing_util.h +++ b/src/core/core_timing_util.h | |||
| @@ -16,18 +16,9 @@ s64 nsToCycles(std::chrono::nanoseconds ns); | |||
| 16 | u64 msToClockCycles(std::chrono::milliseconds ns); | 16 | u64 msToClockCycles(std::chrono::milliseconds ns); |
| 17 | u64 usToClockCycles(std::chrono::microseconds ns); | 17 | u64 usToClockCycles(std::chrono::microseconds ns); |
| 18 | u64 nsToClockCycles(std::chrono::nanoseconds ns); | 18 | u64 nsToClockCycles(std::chrono::nanoseconds ns); |
| 19 | 19 | std::chrono::milliseconds CyclesToMs(s64 cycles); | |
| 20 | inline std::chrono::milliseconds CyclesToMs(s64 cycles) { | 20 | std::chrono::nanoseconds CyclesToNs(s64 cycles); |
| 21 | return std::chrono::milliseconds(cycles * 1000 / Hardware::BASE_CLOCK_RATE); | 21 | std::chrono::microseconds CyclesToUs(s64 cycles); |
| 22 | } | ||
| 23 | |||
| 24 | inline std::chrono::nanoseconds CyclesToNs(s64 cycles) { | ||
| 25 | return std::chrono::nanoseconds(cycles * 1000000000 / Hardware::BASE_CLOCK_RATE); | ||
| 26 | } | ||
| 27 | |||
| 28 | inline std::chrono::microseconds CyclesToUs(s64 cycles) { | ||
| 29 | return std::chrono::microseconds(cycles * 1000000 / Hardware::BASE_CLOCK_RATE); | ||
| 30 | } | ||
| 31 | 22 | ||
| 32 | u64 CpuCyclesToClockCycles(u64 ticks); | 23 | u64 CpuCyclesToClockCycles(u64 ticks); |
| 33 | 24 | ||
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp index 2e9dc9dc3..604405060 100644 --- a/src/core/cpu_manager.cpp +++ b/src/core/cpu_manager.cpp | |||
| @@ -232,13 +232,10 @@ void CpuManager::SingleCoreRunGuestLoop() { | |||
| 232 | auto* physical_core = &kernel.CurrentPhysicalCore(); | 232 | auto* physical_core = &kernel.CurrentPhysicalCore(); |
| 233 | auto& arm_interface = thread->ArmInterface(); | 233 | auto& arm_interface = thread->ArmInterface(); |
| 234 | system.EnterDynarmicProfile(); | 234 | system.EnterDynarmicProfile(); |
| 235 | while (!physical_core->IsInterrupted()) { | 235 | if (!physical_core->IsInterrupted()) { |
| 236 | system.CoreTiming().ResetTicks(); | ||
| 236 | arm_interface.Run(); | 237 | arm_interface.Run(); |
| 237 | physical_core = &kernel.CurrentPhysicalCore(); | 238 | physical_core = &kernel.CurrentPhysicalCore(); |
| 238 | preemption_count++; | ||
| 239 | if (preemption_count % max_cycle_runs == 0) { | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | } | 239 | } |
| 243 | system.ExitDynarmicProfile(); | 240 | system.ExitDynarmicProfile(); |
| 244 | thread->SetPhantomMode(true); | 241 | thread->SetPhantomMode(true); |
| @@ -255,7 +252,7 @@ void CpuManager::SingleCoreRunIdleThread() { | |||
| 255 | auto& kernel = system.Kernel(); | 252 | auto& kernel = system.Kernel(); |
| 256 | while (true) { | 253 | while (true) { |
| 257 | auto& physical_core = kernel.CurrentPhysicalCore(); | 254 | auto& physical_core = kernel.CurrentPhysicalCore(); |
| 258 | PreemptSingleCore(); | 255 | PreemptSingleCore(false); |
| 259 | idle_count++; | 256 | idle_count++; |
| 260 | auto& scheduler = physical_core.Scheduler(); | 257 | auto& scheduler = physical_core.Scheduler(); |
| 261 | scheduler.TryDoContextSwitch(); | 258 | scheduler.TryDoContextSwitch(); |
| @@ -279,12 +276,15 @@ void CpuManager::SingleCoreRunSuspendThread() { | |||
| 279 | } | 276 | } |
| 280 | } | 277 | } |
| 281 | 278 | ||
| 282 | void CpuManager::PreemptSingleCore() { | 279 | void CpuManager::PreemptSingleCore(bool from_running_enviroment) { |
| 283 | preemption_count = 0; | ||
| 284 | std::size_t old_core = current_core; | 280 | std::size_t old_core = current_core; |
| 285 | auto& scheduler = system.Kernel().Scheduler(old_core); | 281 | auto& scheduler = system.Kernel().Scheduler(old_core); |
| 286 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); | 282 | Kernel::Thread* current_thread = scheduler.GetCurrentThread(); |
| 287 | if (idle_count >= 4) { | 283 | if (idle_count >= 4 || from_running_enviroment) { |
| 284 | if (!from_running_enviroment) { | ||
| 285 | system.CoreTiming().Idle(); | ||
| 286 | idle_count = 0; | ||
| 287 | } | ||
| 288 | current_thread->SetPhantomMode(true); | 288 | current_thread->SetPhantomMode(true); |
| 289 | system.CoreTiming().Advance(); | 289 | system.CoreTiming().Advance(); |
| 290 | current_thread->SetPhantomMode(false); | 290 | current_thread->SetPhantomMode(false); |
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index e6b8612f0..ae55d6427 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h | |||
| @@ -55,7 +55,7 @@ public: | |||
| 55 | std::function<void(void*)> GetSuspendThreadStartFunc(); | 55 | std::function<void(void*)> GetSuspendThreadStartFunc(); |
| 56 | void* GetStartFuncParamater(); | 56 | void* GetStartFuncParamater(); |
| 57 | 57 | ||
| 58 | void PreemptSingleCore(); | 58 | void PreemptSingleCore(bool from_running_enviroment = true); |
| 59 | 59 | ||
| 60 | std::size_t CurrentCore() const { | 60 | std::size_t CurrentCore() const { |
| 61 | return current_core.load(); | 61 | return current_core.load(); |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 599972211..c47fa9167 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -1534,6 +1534,7 @@ static void SleepThread(Core::System& system, s64 nanoseconds) { | |||
| 1534 | 1534 | ||
| 1535 | if (is_redundant && !system.Kernel().IsMulticore()) { | 1535 | if (is_redundant && !system.Kernel().IsMulticore()) { |
| 1536 | system.Kernel().ExitSVCProfile(); | 1536 | system.Kernel().ExitSVCProfile(); |
| 1537 | system.CoreTiming().AddTicks(1000U); | ||
| 1537 | system.GetCpuManager().PreemptSingleCore(); | 1538 | system.GetCpuManager().PreemptSingleCore(); |
| 1538 | system.Kernel().EnterSVCProfile(); | 1539 | system.Kernel().EnterSVCProfile(); |
| 1539 | } | 1540 | } |
| @@ -1762,6 +1763,10 @@ static u64 GetSystemTick(Core::System& system) { | |||
| 1762 | // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) | 1763 | // Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick) |
| 1763 | const u64 result{system.CoreTiming().GetClockTicks()}; | 1764 | const u64 result{system.CoreTiming().GetClockTicks()}; |
| 1764 | 1765 | ||
| 1766 | if (!system.Kernel().IsMulticore()) { | ||
| 1767 | core_timing.AddTicks(400U); | ||
| 1768 | } | ||
| 1769 | |||
| 1765 | return result; | 1770 | return result; |
| 1766 | } | 1771 | } |
| 1767 | 1772 | ||
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 65fedfc9b..d88039a16 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -246,19 +246,23 @@ ResultVal<std::shared_ptr<Thread>> Thread::Create(Core::System& system, ThreadTy | |||
| 246 | #ifdef ARCHITECTURE_x86_64 | 246 | #ifdef ARCHITECTURE_x86_64 |
| 247 | if (owner_process && !owner_process->Is64BitProcess()) { | 247 | if (owner_process && !owner_process->Is64BitProcess()) { |
| 248 | thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( | 248 | thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( |
| 249 | system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); | 249 | system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), |
| 250 | processor_id); | ||
| 250 | } else { | 251 | } else { |
| 251 | thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( | 252 | thread->arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( |
| 252 | system, kernel.Interrupts(), kernel.GetExclusiveMonitor(), processor_id); | 253 | system, kernel.Interrupts(), kernel.IsMulticore(), kernel.GetExclusiveMonitor(), |
| 254 | processor_id); | ||
| 253 | } | 255 | } |
| 254 | 256 | ||
| 255 | #else | 257 | #else |
| 256 | if (owner_process && !owner_process->Is64BitProcess()) { | 258 | if (owner_process && !owner_process->Is64BitProcess()) { |
| 257 | thread->arm_interface = std::make_shared<Core::ARM_Unicorn>( | 259 | thread->arm_interface = std::make_shared<Core::ARM_Unicorn>( |
| 258 | system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch32, processor_id); | 260 | system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch32, |
| 261 | processor_id); | ||
| 259 | } else { | 262 | } else { |
| 260 | thread->arm_interface = std::make_shared<Core::ARM_Unicorn>( | 263 | thread->arm_interface = std::make_shared<Core::ARM_Unicorn>( |
| 261 | system, kernel.Interrupts(), ARM_Unicorn::Arch::AArch64, processor_id); | 264 | system, kernel.Interrupts(), kernel.IsMulticore(), ARM_Unicorn::Arch::AArch64, |
| 265 | processor_id); | ||
| 262 | } | 266 | } |
| 263 | LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); | 267 | LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); |
| 264 | #endif | 268 | #endif |