forked from suyu/suyu
core_timing: Fix SingleCore cycle timer
This commit is contained in:
parent
907507886d
commit
2e1e725443
4 changed files with 31 additions and 43 deletions
|
@ -13,8 +13,9 @@ namespace Common {
|
||||||
|
|
||||||
class WallClock {
|
class WallClock {
|
||||||
public:
|
public:
|
||||||
static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz
|
static constexpr u64 CNTFRQ = 19'200'000; // CNTPCT_EL0 Frequency = 19.2 MHz
|
||||||
static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz
|
static constexpr u64 GPUTickFreq = 614'400'000; // GM20B GPU Tick Frequency = 614.4 MHz
|
||||||
|
static constexpr u64 CPUTickFreq = 1'020'000'000; // T210/4 A57 CPU Tick Frequency = 1020.0 MHz
|
||||||
|
|
||||||
virtual ~WallClock() = default;
|
virtual ~WallClock() = default;
|
||||||
|
|
||||||
|
@ -46,28 +47,26 @@ public:
|
||||||
return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
|
return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 USToCNTPCT(u64 us) {
|
|
||||||
return us * UsToCNTPCTRatio::num / UsToCNTPCTRatio::den;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline u64 NSToGPUTick(u64 ns) {
|
static inline u64 NSToGPUTick(u64 ns) {
|
||||||
return ns * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
|
return ns * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 CNTPCTToNS(u64 cntpct) {
|
// Cycle Timing
|
||||||
return cntpct * NsToCNTPCTRatio::den / NsToCNTPCTRatio::num;
|
|
||||||
|
static inline u64 CPUTickToNS(u64 cpu_tick) {
|
||||||
|
return cpu_tick * CPUTickToNsRatio::num / CPUTickToNsRatio::den;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 CNTPCTToUS(u64 cntpct) {
|
static inline u64 CPUTickToUS(u64 cpu_tick) {
|
||||||
return cntpct * UsToCNTPCTRatio::den / UsToCNTPCTRatio::num;
|
return cpu_tick * CPUTickToUsRatio::num / CPUTickToUsRatio::den;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 GPUTickToNS(u64 gpu_tick) {
|
static inline u64 CPUTickToCNTPCT(u64 cpu_tick) {
|
||||||
return gpu_tick * NsToGPUTickRatio::den / NsToGPUTickRatio::num;
|
return cpu_tick * CPUTickToCNTPCTRatio::num / CPUTickToCNTPCTRatio::den;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 CNTPCTToGPUTick(u64 cntpct) {
|
static inline u64 CPUTickToGPUTick(u64 cpu_tick) {
|
||||||
return cntpct * CNTPCTToGPUTickRatio::num / CNTPCTToGPUTickRatio::den;
|
return cpu_tick * CPUTickToGPUTickRatio::num / CPUTickToGPUTickRatio::den;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -78,9 +77,14 @@ protected:
|
||||||
using NsToUsRatio = std::ratio_divide<std::nano, std::micro>;
|
using NsToUsRatio = std::ratio_divide<std::nano, std::micro>;
|
||||||
using NsToMsRatio = std::ratio_divide<std::nano, std::milli>;
|
using NsToMsRatio = std::ratio_divide<std::nano, std::milli>;
|
||||||
using NsToCNTPCTRatio = std::ratio<CNTFRQ, std::nano::den>;
|
using NsToCNTPCTRatio = std::ratio<CNTFRQ, std::nano::den>;
|
||||||
using UsToCNTPCTRatio = std::ratio<CNTFRQ, std::micro::den>;
|
|
||||||
using NsToGPUTickRatio = std::ratio<GPUTickFreq, std::nano::den>;
|
using NsToGPUTickRatio = std::ratio<GPUTickFreq, std::nano::den>;
|
||||||
using CNTPCTToGPUTickRatio = std::ratio<GPUTickFreq, CNTFRQ>;
|
|
||||||
|
// Cycle Timing
|
||||||
|
|
||||||
|
using CPUTickToNsRatio = std::ratio<std::nano::den, CPUTickFreq>;
|
||||||
|
using CPUTickToUsRatio = std::ratio<std::micro::den, CPUTickFreq>;
|
||||||
|
using CPUTickToCNTPCTRatio = std::ratio<CNTFRQ, CPUTickFreq>;
|
||||||
|
using CPUTickToGPUTickRatio = std::ratio<GPUTickFreq, CPUTickFreq>;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<WallClock> CreateOptimalClock();
|
std::unique_ptr<WallClock> CreateOptimalClock();
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
namespace Core::Timing {
|
namespace Core::Timing {
|
||||||
|
|
||||||
constexpr s64 MAX_SLICE_LENGTH = 4000;
|
constexpr s64 MAX_SLICE_LENGTH = 10000;
|
||||||
|
|
||||||
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
|
||||||
return std::make_shared<EventType>(std::move(callback), std::move(name));
|
return std::make_shared<EventType>(std::move(callback), std::move(name));
|
||||||
|
@ -65,7 +65,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
|
||||||
on_thread_init = std::move(on_thread_init_);
|
on_thread_init = std::move(on_thread_init_);
|
||||||
event_fifo_id = 0;
|
event_fifo_id = 0;
|
||||||
shutting_down = false;
|
shutting_down = false;
|
||||||
ticks = 0;
|
cpu_ticks = 0;
|
||||||
const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
|
const auto empty_timed_callback = [](std::uintptr_t, u64, std::chrono::nanoseconds)
|
||||||
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
|
-> std::optional<std::chrono::nanoseconds> { return std::nullopt; };
|
||||||
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
|
ev_lost = CreateEvent("_lost_event", empty_timed_callback);
|
||||||
|
@ -170,20 +170,12 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::AddTicks(u64 ticks_to_add) {
|
void CoreTiming::AddTicks(u64 ticks_to_add) {
|
||||||
ticks += ticks_to_add;
|
cpu_ticks += ticks_to_add;
|
||||||
downcount -= static_cast<s64>(ticks);
|
downcount -= static_cast<s64>(cpu_ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::Idle() {
|
void CoreTiming::Idle() {
|
||||||
if (!event_queue.empty()) {
|
cpu_ticks += 1000U;
|
||||||
const u64 next_event_time = event_queue.front().time;
|
|
||||||
const u64 next_ticks = Common::WallClock::NSToCNTPCT(next_event_time) + 10U;
|
|
||||||
if (next_ticks > ticks) {
|
|
||||||
ticks = next_ticks;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ticks += 1000U;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CoreTiming::ResetTicks() {
|
void CoreTiming::ResetTicks() {
|
||||||
|
@ -194,14 +186,14 @@ u64 CoreTiming::GetClockTicks() const {
|
||||||
if (is_multicore) [[likely]] {
|
if (is_multicore) [[likely]] {
|
||||||
return clock->GetCNTPCT();
|
return clock->GetCNTPCT();
|
||||||
}
|
}
|
||||||
return ticks;
|
return Common::WallClock::CPUTickToCNTPCT(cpu_ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 CoreTiming::GetGPUTicks() const {
|
u64 CoreTiming::GetGPUTicks() const {
|
||||||
if (is_multicore) [[likely]] {
|
if (is_multicore) [[likely]] {
|
||||||
return clock->GetGPUTick();
|
return clock->GetGPUTick();
|
||||||
}
|
}
|
||||||
return Common::WallClock::CNTPCTToGPUTick(ticks);
|
return Common::WallClock::CPUTickToGPUTick(cpu_ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<s64> CoreTiming::Advance() {
|
std::optional<s64> CoreTiming::Advance() {
|
||||||
|
@ -314,14 +306,14 @@ std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const {
|
||||||
if (is_multicore) [[likely]] {
|
if (is_multicore) [[likely]] {
|
||||||
return clock->GetTimeNS();
|
return clock->GetTimeNS();
|
||||||
}
|
}
|
||||||
return std::chrono::nanoseconds{Common::WallClock::CNTPCTToNS(ticks)};
|
return std::chrono::nanoseconds{Common::WallClock::CPUTickToNS(cpu_ticks)};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
|
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
|
||||||
if (is_multicore) [[likely]] {
|
if (is_multicore) [[likely]] {
|
||||||
return clock->GetTimeUS();
|
return clock->GetTimeUS();
|
||||||
}
|
}
|
||||||
return std::chrono::microseconds{Common::WallClock::CNTPCTToUS(ticks)};
|
return std::chrono::microseconds{Common::WallClock::CPUTickToUS(cpu_ticks)};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Core::Timing
|
} // namespace Core::Timing
|
||||||
|
|
|
@ -167,7 +167,7 @@ private:
|
||||||
s64 pause_end_time{};
|
s64 pause_end_time{};
|
||||||
|
|
||||||
/// Cycle timing
|
/// Cycle timing
|
||||||
u64 ticks{};
|
u64 cpu_ticks{};
|
||||||
s64 downcount{};
|
s64 downcount{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -12,16 +12,8 @@ namespace Kernel::Svc {
|
||||||
int64_t GetSystemTick(Core::System& system) {
|
int64_t GetSystemTick(Core::System& system) {
|
||||||
LOG_TRACE(Kernel_SVC, "called");
|
LOG_TRACE(Kernel_SVC, "called");
|
||||||
|
|
||||||
auto& core_timing = system.CoreTiming();
|
|
||||||
|
|
||||||
// Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
|
// Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
|
||||||
const u64 result{core_timing.GetClockTicks()};
|
return static_cast<int64_t>(system.CoreTiming().GetClockTicks());
|
||||||
|
|
||||||
if (!system.Kernel().IsMulticore()) {
|
|
||||||
core_timing.AddTicks(400U);
|
|
||||||
}
|
|
||||||
|
|
||||||
return static_cast<int64_t>(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t GetSystemTick64(Core::System& system) {
|
int64_t GetSystemTick64(Core::System& system) {
|
||||||
|
|
Loading…
Reference in a new issue