mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	Merge pull request #9889 from Morph1984/time-is-ticking
core_timing: Reduce CPU usage on Windows
This commit is contained in:
		@@ -6,6 +6,10 @@
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
#include "common/windows/timer_resolution.h"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "common/microprofile.h"
 | 
			
		||||
#include "core/core_timing.h"
 | 
			
		||||
#include "core/core_timing_util.h"
 | 
			
		||||
@@ -38,7 +42,8 @@ struct CoreTiming::Event {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
CoreTiming::CoreTiming()
 | 
			
		||||
    : clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
 | 
			
		||||
    : cpu_clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)},
 | 
			
		||||
      event_clock{Common::CreateStandardWallClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
 | 
			
		||||
 | 
			
		||||
CoreTiming::~CoreTiming() {
 | 
			
		||||
    Reset();
 | 
			
		||||
@@ -185,15 +190,15 @@ void CoreTiming::ResetTicks() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u64 CoreTiming::GetCPUTicks() const {
 | 
			
		||||
    if (is_multicore) {
 | 
			
		||||
        return clock->GetCPUCycles();
 | 
			
		||||
    if (is_multicore) [[likely]] {
 | 
			
		||||
        return cpu_clock->GetCPUCycles();
 | 
			
		||||
    }
 | 
			
		||||
    return ticks;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u64 CoreTiming::GetClockTicks() const {
 | 
			
		||||
    if (is_multicore) {
 | 
			
		||||
        return clock->GetClockCycles();
 | 
			
		||||
    if (is_multicore) [[likely]] {
 | 
			
		||||
        return cpu_clock->GetClockCycles();
 | 
			
		||||
    }
 | 
			
		||||
    return CpuCyclesToClockCycles(ticks);
 | 
			
		||||
}
 | 
			
		||||
@@ -252,21 +257,20 @@ void CoreTiming::ThreadLoop() {
 | 
			
		||||
            const auto next_time = Advance();
 | 
			
		||||
            if (next_time) {
 | 
			
		||||
                // There are more events left in the queue, wait until the next event.
 | 
			
		||||
                const auto wait_time = *next_time - GetGlobalTimeNs().count();
 | 
			
		||||
                auto wait_time = *next_time - GetGlobalTimeNs().count();
 | 
			
		||||
                if (wait_time > 0) {
 | 
			
		||||
#ifdef _WIN32
 | 
			
		||||
                    // Assume a timer resolution of 1ms.
 | 
			
		||||
                    static constexpr s64 TimerResolutionNS = 1000000;
 | 
			
		||||
                    const auto timer_resolution_ns =
 | 
			
		||||
                        Common::Windows::GetCurrentTimerResolution().count();
 | 
			
		||||
 | 
			
		||||
                    // Sleep in discrete intervals of the timer resolution, and spin the rest.
 | 
			
		||||
                    const auto sleep_time = wait_time - (wait_time % TimerResolutionNS);
 | 
			
		||||
                    if (sleep_time > 0) {
 | 
			
		||||
                        event.WaitFor(std::chrono::nanoseconds(sleep_time));
 | 
			
		||||
                    }
 | 
			
		||||
                    while (!paused && !event.IsSet() && wait_time > 0) {
 | 
			
		||||
                        wait_time = *next_time - GetGlobalTimeNs().count();
 | 
			
		||||
 | 
			
		||||
                    while (!paused && !event.IsSet() && GetGlobalTimeNs().count() < *next_time) {
 | 
			
		||||
                        // Yield to reduce thread starvation.
 | 
			
		||||
                        std::this_thread::yield();
 | 
			
		||||
                        if (wait_time >= timer_resolution_ns) {
 | 
			
		||||
                            Common::Windows::SleepForOneTick();
 | 
			
		||||
                        } else {
 | 
			
		||||
                            std::this_thread::yield();
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (event.IsSet()) {
 | 
			
		||||
@@ -285,9 +289,9 @@ void CoreTiming::ThreadLoop() {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        paused_set = true;
 | 
			
		||||
        clock->Pause(true);
 | 
			
		||||
        event_clock->Pause(true);
 | 
			
		||||
        pause_event.Wait();
 | 
			
		||||
        clock->Pause(false);
 | 
			
		||||
        event_clock->Pause(false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -303,16 +307,23 @@ void CoreTiming::Reset() {
 | 
			
		||||
    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 {
 | 
			
		||||
    if (is_multicore) {
 | 
			
		||||
        return clock->GetTimeNS();
 | 
			
		||||
    if (is_multicore) [[likely]] {
 | 
			
		||||
        return event_clock->GetTimeNS();
 | 
			
		||||
    }
 | 
			
		||||
    return CyclesToNs(ticks);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::chrono::microseconds CoreTiming::GetGlobalTimeUs() const {
 | 
			
		||||
    if (is_multicore) {
 | 
			
		||||
        return clock->GetTimeUS();
 | 
			
		||||
    if (is_multicore) [[likely]] {
 | 
			
		||||
        return event_clock->GetTimeUS();
 | 
			
		||||
    }
 | 
			
		||||
    return CyclesToUs(ticks);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -122,6 +122,9 @@ public:
 | 
			
		||||
    /// Returns current time in emulated in Clock cycles
 | 
			
		||||
    u64 GetClockTicks() const;
 | 
			
		||||
 | 
			
		||||
    /// Returns current time in nanoseconds.
 | 
			
		||||
    std::chrono::nanoseconds GetCPUTimeNs() const;
 | 
			
		||||
 | 
			
		||||
    /// Returns current time in microseconds.
 | 
			
		||||
    std::chrono::microseconds GetGlobalTimeUs() const;
 | 
			
		||||
 | 
			
		||||
@@ -139,7 +142,8 @@ private:
 | 
			
		||||
 | 
			
		||||
    void Reset();
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Common::WallClock> clock;
 | 
			
		||||
    std::unique_ptr<Common::WallClock> cpu_clock;
 | 
			
		||||
    std::unique_ptr<Common::WallClock> event_clock;
 | 
			
		||||
 | 
			
		||||
    s64 global_timer = 0;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -13,11 +13,9 @@ namespace Core {
 | 
			
		||||
 | 
			
		||||
namespace Hardware {
 | 
			
		||||
 | 
			
		||||
// The below clock rate is based on Switch's clockspeed being widely known as 1.020GHz
 | 
			
		||||
// The exact value used is of course unverified.
 | 
			
		||||
constexpr u64 BASE_CLOCK_RATE = 1019215872; // Switch cpu frequency is 1020MHz un/docked
 | 
			
		||||
constexpr u64 CNTFREQ = 19200000;           // Switch's hardware clock speed
 | 
			
		||||
constexpr u32 NUM_CPU_CORES = 4;            // Number of CPU Cores
 | 
			
		||||
constexpr u64 BASE_CLOCK_RATE = 1'020'000'000; // Default CPU Frequency = 1020 MHz
 | 
			
		||||
constexpr u64 CNTFREQ = 19'200'000;            // CNTPCT_EL0 Frequency = 19.2 MHz
 | 
			
		||||
constexpr u32 NUM_CPU_CORES = 4;               // Number of CPU Cores
 | 
			
		||||
 | 
			
		||||
// Virtual to Physical core map.
 | 
			
		||||
constexpr std::array<s32, Common::BitSize<u64>()> VirtualToPhysicalCoreMap{
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user