yuzu-emu
/
yuzu-android
Archived
1
0
Fork 0

core_timing: Use CNTPCT as the guest CPU tick

Previously, we were mixing the raw CPU frequency and CNTFRQ.
The raw CPU frequency (1020 MHz) should've never been used as CNTPCT (whose frequency is CNTFRQ) is the only counter available.
This commit is contained in:
Morph 2023-04-23 00:01:08 -04:00
parent bbd502f67a
commit 8e56a84566
14 changed files with 47 additions and 122 deletions

View File

@ -7,7 +7,6 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/memory.h" #include "core/memory.h"
namespace AudioCore::AudioRenderer::ADSP { namespace AudioCore::AudioRenderer::ADSP {

View File

@ -13,7 +13,6 @@
#include "common/thread.h" #include "common/thread.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/core_timing_util.h"
MICROPROFILE_DEFINE(Audio_Renderer, "Audio", "DSP", MP_RGB(60, 19, 97)); MICROPROFILE_DEFINE(Audio_Renderer, "Audio", "DSP", MP_RGB(60, 19, 97));
@ -144,6 +143,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) {
mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_InitializeOK); mailbox->ADSPSendMessage(RenderMessage::AudioRenderer_InitializeOK);
// 0.12 seconds (2304000 / 19200000)
constexpr u64 max_process_time{2'304'000ULL}; constexpr u64 max_process_time{2'304'000ULL};
while (!stop_token.stop_requested()) { while (!stop_token.stop_requested()) {
@ -184,8 +184,7 @@ void AudioRenderer::ThreadFunc(std::stop_token stop_token) {
u64 max_time{max_process_time}; u64 max_time{max_process_time};
if (index == 1 && command_buffer.applet_resource_user_id == if (index == 1 && command_buffer.applet_resource_user_id ==
mailbox->GetCommandBuffer(0).applet_resource_user_id) { mailbox->GetCommandBuffer(0).applet_resource_user_id) {
max_time = max_process_time - max_time = max_process_time - render_times_taken[0];
Core::Timing::CyclesToNs(render_times_taken[0]).count();
if (render_times_taken[0] > max_process_time) { if (render_times_taken[0] > max_process_time) {
max_time = 0; max_time = 0;
} }

View File

@ -9,7 +9,6 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/memory.h" #include "core/memory.h"
namespace AudioCore::AudioRenderer::ADSP { namespace AudioCore::AudioRenderer::ADSP {

View File

@ -5,7 +5,6 @@
#include "audio_core/renderer/command/performance/performance.h" #include "audio_core/renderer/command/performance/performance.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/core_timing_util.h"
namespace AudioCore::AudioRenderer { namespace AudioCore::AudioRenderer {
@ -18,20 +17,18 @@ void PerformanceCommand::Process(const ADSP::CommandListProcessor& processor) {
auto base{entry_address.translated_address}; auto base{entry_address.translated_address};
if (state == PerformanceState::Start) { if (state == PerformanceState::Start) {
auto start_time_ptr{reinterpret_cast<u32*>(base + entry_address.entry_start_time_offset)}; auto start_time_ptr{reinterpret_cast<u32*>(base + entry_address.entry_start_time_offset)};
*start_time_ptr = static_cast<u32>( *start_time_ptr =
Core::Timing::CyclesToUs(processor.system->CoreTiming().GetClockTicks() - static_cast<u32>(processor.system->CoreTiming().GetClockTicks() - processor.start_time -
processor.start_time - processor.current_processing_time) processor.current_processing_time);
.count());
} else if (state == PerformanceState::Stop) { } else if (state == PerformanceState::Stop) {
auto processed_time_ptr{ auto processed_time_ptr{
reinterpret_cast<u32*>(base + entry_address.entry_processed_time_offset)}; reinterpret_cast<u32*>(base + entry_address.entry_processed_time_offset)};
auto entry_count_ptr{ auto entry_count_ptr{
reinterpret_cast<u32*>(base + entry_address.header_entry_count_offset)}; reinterpret_cast<u32*>(base + entry_address.header_entry_count_offset)};
*processed_time_ptr = static_cast<u32>( *processed_time_ptr =
Core::Timing::CyclesToUs(processor.system->CoreTiming().GetClockTicks() - static_cast<u32>(processor.system->CoreTiming().GetClockTicks() - processor.start_time -
processor.start_time - processor.current_processing_time) processor.current_processing_time);
.count());
(*entry_count_ptr)++; (*entry_count_ptr)++;
} }
} }

View File

@ -15,7 +15,6 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/core_timing_util.h"
namespace AudioCore::Sink { namespace AudioCore::Sink {

View File

@ -38,6 +38,22 @@ public:
/// @returns Whether the clock directly uses the host's hardware clock. /// @returns Whether the clock directly uses the host's hardware clock.
virtual bool IsNative() const = 0; virtual bool IsNative() const = 0;
static inline u64 NSToCNTPCT(u64 ns) {
return ns * NsToCNTPCTRatio::num / NsToCNTPCTRatio::den;
}
static inline u64 USToCNTPCT(u64 us) {
return us * UsToCNTPCTRatio::num / UsToCNTPCTRatio::den;
}
static inline u64 CNTPCTToNS(u64 cntpct) {
return cntpct * NsToCNTPCTRatio::den / NsToCNTPCTRatio::num;
}
static inline u64 CNTPCTToUS(u64 cntpct) {
return cntpct * UsToCNTPCTRatio::den / UsToCNTPCTRatio::num;
}
protected: protected:
using NsRatio = std::nano; using NsRatio = std::nano;
using UsRatio = std::micro; using UsRatio = std::micro;
@ -46,6 +62,7 @@ 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>;
}; };
std::unique_ptr<WallClock> CreateOptimalClock(); std::unique_ptr<WallClock> CreateOptimalClock();

View File

@ -16,7 +16,6 @@ add_library(core STATIC
core.h core.h
core_timing.cpp core_timing.cpp
core_timing.h core_timing.h
core_timing_util.h
cpu_manager.cpp cpu_manager.cpp
cpu_manager.h cpu_manager.h
crypto/aes_util.cpp crypto/aes_util.cpp

View File

@ -16,7 +16,6 @@
#include "common/microprofile.h" #include "common/microprofile.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/hardware_properties.h" #include "core/hardware_properties.h"
namespace Core::Timing { namespace Core::Timing {
@ -45,9 +44,7 @@ struct CoreTiming::Event {
} }
}; };
CoreTiming::CoreTiming() CoreTiming::CoreTiming() : clock{Common::CreateOptimalClock()} {}
: cpu_clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)},
event_clock{Common::CreateStandardWallClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
CoreTiming::~CoreTiming() { CoreTiming::~CoreTiming() {
Reset(); Reset();
@ -180,7 +177,7 @@ void CoreTiming::AddTicks(u64 ticks_to_add) {
void CoreTiming::Idle() { void CoreTiming::Idle() {
if (!event_queue.empty()) { if (!event_queue.empty()) {
const u64 next_event_time = event_queue.front().time; const u64 next_event_time = event_queue.front().time;
const u64 next_ticks = nsToCycles(std::chrono::nanoseconds(next_event_time)) + 10U; const u64 next_ticks = Common::WallClock::NSToCNTPCT(next_event_time) + 10U;
if (next_ticks > ticks) { if (next_ticks > ticks) {
ticks = next_ticks; ticks = next_ticks;
} }
@ -193,18 +190,11 @@ void CoreTiming::ResetTicks() {
downcount = MAX_SLICE_LENGTH; downcount = MAX_SLICE_LENGTH;
} }
u64 CoreTiming::GetCPUTicks() const {
if (is_multicore) [[likely]] {
return cpu_clock->GetCPUCycles();
}
return ticks;
}
u64 CoreTiming::GetClockTicks() const { u64 CoreTiming::GetClockTicks() const {
if (is_multicore) [[likely]] { if (is_multicore) [[likely]] {
return cpu_clock->GetClockCycles(); return clock->GetCNTPCT();
} }
return CpuCyclesToClockCycles(ticks); return ticks;
} }
std::optional<s64> CoreTiming::Advance() { std::optional<s64> CoreTiming::Advance() {
@ -297,9 +287,7 @@ void CoreTiming::ThreadLoop() {
} }
paused_set = true; paused_set = true;
event_clock->Pause(true);
pause_event.Wait(); pause_event.Wait();
event_clock->Pause(false);
} }
} }
@ -315,25 +303,18 @@ void CoreTiming::Reset() {
has_started = false; has_started = false;
} }
std::chrono::nanoseconds CoreTiming::GetCPUTimeNs() const {
if (is_multicore) [[likely]] {
return cpu_clock->GetTimeNS();
}
return CyclesToNs(ticks);
}
std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const { std::chrono::nanoseconds CoreTiming::GetGlobalTimeNs() const {
if (is_multicore) [[likely]] { if (is_multicore) [[likely]] {
return event_clock->GetTimeNS(); return clock->GetTimeNS();
} }
return CyclesToNs(ticks); return std::chrono::nanoseconds{Common::WallClock::CNTPCTToNS(ticks)};
} }
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const { std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
if (is_multicore) [[likely]] { if (is_multicore) [[likely]] {
return event_clock->GetTimeUS(); return clock->GetTimeUS();
} }
return CyclesToUs(ticks); return std::chrono::microseconds{Common::WallClock::CNTPCTToUS(ticks)};
} }
} // namespace Core::Timing } // namespace Core::Timing

View File

@ -116,15 +116,9 @@ public:
return downcount; return downcount;
} }
/// Returns current time in emulated CPU cycles /// Returns the current CNTPCT tick value.
u64 GetCPUTicks() const;
/// Returns current time in emulated in Clock cycles
u64 GetClockTicks() const; u64 GetClockTicks() const;
/// Returns current time in nanoseconds.
std::chrono::nanoseconds GetCPUTimeNs() const;
/// Returns current time in microseconds. /// Returns current time in microseconds.
std::chrono::microseconds GetGlobalTimeUs() const; std::chrono::microseconds GetGlobalTimeUs() const;
@ -142,8 +136,7 @@ private:
void Reset(); void Reset();
std::unique_ptr<Common::WallClock> cpu_clock; std::unique_ptr<Common::WallClock> clock;
std::unique_ptr<Common::WallClock> event_clock;
s64 global_timer = 0; s64 global_timer = 0;

View File

@ -1,58 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <chrono>
#include "common/common_types.h"
#include "core/hardware_properties.h"
namespace Core::Timing {
namespace detail {
constexpr u64 CNTFREQ_ADJUSTED = Hardware::CNTFREQ / 1000;
constexpr u64 BASE_CLOCK_RATE_ADJUSTED = Hardware::BASE_CLOCK_RATE / 1000;
} // namespace detail
[[nodiscard]] constexpr s64 msToCycles(std::chrono::milliseconds ms) {
return ms.count() * detail::BASE_CLOCK_RATE_ADJUSTED;
}
[[nodiscard]] constexpr s64 usToCycles(std::chrono::microseconds us) {
return us.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000;
}
[[nodiscard]] constexpr s64 nsToCycles(std::chrono::nanoseconds ns) {
return ns.count() * detail::BASE_CLOCK_RATE_ADJUSTED / 1000000;
}
[[nodiscard]] constexpr u64 msToClockCycles(std::chrono::milliseconds ms) {
return static_cast<u64>(ms.count()) * detail::CNTFREQ_ADJUSTED;
}
[[nodiscard]] constexpr u64 usToClockCycles(std::chrono::microseconds us) {
return us.count() * detail::CNTFREQ_ADJUSTED / 1000;
}
[[nodiscard]] constexpr u64 nsToClockCycles(std::chrono::nanoseconds ns) {
return ns.count() * detail::CNTFREQ_ADJUSTED / 1000000;
}
[[nodiscard]] constexpr u64 CpuCyclesToClockCycles(u64 ticks) {
return ticks * detail::CNTFREQ_ADJUSTED / detail::BASE_CLOCK_RATE_ADJUSTED;
}
[[nodiscard]] constexpr std::chrono::milliseconds CyclesToMs(s64 cycles) {
return std::chrono::milliseconds(cycles / detail::BASE_CLOCK_RATE_ADJUSTED);
}
[[nodiscard]] constexpr std::chrono::nanoseconds CyclesToNs(s64 cycles) {
return std::chrono::nanoseconds(cycles * 1000000 / detail::BASE_CLOCK_RATE_ADJUSTED);
}
[[nodiscard]] constexpr std::chrono::microseconds CyclesToUs(s64 cycles) {
return std::chrono::microseconds(cycles * 1000 / detail::BASE_CLOCK_RATE_ADJUSTED);
}
} // namespace Core::Timing

View File

@ -184,7 +184,8 @@ u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
prev_highest_thread != highest_thread) [[likely]] { prev_highest_thread != highest_thread) [[likely]] {
if (prev_highest_thread != nullptr) [[likely]] { if (prev_highest_thread != nullptr) [[likely]] {
IncrementScheduledCount(prev_highest_thread); IncrementScheduledCount(prev_highest_thread);
prev_highest_thread->SetLastScheduledTick(m_kernel.System().CoreTiming().GetCPUTicks()); prev_highest_thread->SetLastScheduledTick(
m_kernel.System().CoreTiming().GetClockTicks());
} }
if (m_state.should_count_idle) { if (m_state.should_count_idle) {
if (highest_thread != nullptr) [[likely]] { if (highest_thread != nullptr) [[likely]] {
@ -351,7 +352,7 @@ void KScheduler::SwitchThread(KThread* next_thread) {
// Update the CPU time tracking variables. // Update the CPU time tracking variables.
const s64 prev_tick = m_last_context_switch_time; const s64 prev_tick = m_last_context_switch_time;
const s64 cur_tick = m_kernel.System().CoreTiming().GetCPUTicks(); const s64 cur_tick = m_kernel.System().CoreTiming().GetClockTicks();
const s64 tick_diff = cur_tick - prev_tick; const s64 tick_diff = cur_tick - prev_tick;
cur_thread->AddCpuTime(m_core_id, tick_diff); cur_thread->AddCpuTime(m_core_id, tick_diff);
if (cur_process != nullptr) { if (cur_process != nullptr) {

View File

@ -199,9 +199,9 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) { if (same_thread && info_sub_id == 0xFFFFFFFFFFFFFFFF) {
const u64 thread_ticks = current_thread->GetCpuTime(); const u64 thread_ticks = current_thread->GetCpuTime();
out_ticks = thread_ticks + (core_timing.GetCPUTicks() - prev_ctx_ticks); out_ticks = thread_ticks + (core_timing.GetClockTicks() - prev_ctx_ticks);
} else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) { } else if (same_thread && info_sub_id == system.Kernel().CurrentPhysicalCoreIndex()) {
out_ticks = core_timing.GetCPUTicks() - prev_ctx_ticks; out_ticks = core_timing.GetClockTicks() - prev_ctx_ticks;
} }
*result = out_ticks; *result = out_ticks;

View File

@ -5,7 +5,6 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/hid/hid_types.h" #include "core/hid/hid_types.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_readable_event.h"

View File

@ -194,17 +194,17 @@ struct GPU::Impl {
[[nodiscard]] u64 GetTicks() const { [[nodiscard]] u64 GetTicks() const {
// This values were reversed engineered by fincs from NVN // This values were reversed engineered by fincs from NVN
// The gpu clock is reported in units of 385/625 nanoseconds // The GPU clock is 614.4 MHz
constexpr u64 gpu_ticks_num = 384; using NsToGPUTickRatio = std::ratio<614'400'000, std::nano::den>;
constexpr u64 gpu_ticks_den = 625; static_assert(NsToGPUTickRatio::num == 384 && NsToGPUTickRatio::den == 625);
u64 nanoseconds = system.CoreTiming().GetGlobalTimeNs().count();
u64 nanoseconds = system.CoreTiming().GetCPUTimeNs().count();
if (Settings::values.use_fast_gpu_time.GetValue()) { if (Settings::values.use_fast_gpu_time.GetValue()) {
nanoseconds /= 256; nanoseconds /= 256;
} }
const u64 nanoseconds_num = nanoseconds / gpu_ticks_den;
const u64 nanoseconds_rem = nanoseconds % gpu_ticks_den; return nanoseconds * NsToGPUTickRatio::num / NsToGPUTickRatio::den;
return nanoseconds_num * gpu_ticks_num + (nanoseconds_rem * gpu_ticks_num) / gpu_ticks_den;
} }
[[nodiscard]] bool IsAsync() const { [[nodiscard]] bool IsAsync() const {