mirror of https://github.com/PCSX2/pcsx2.git
Common: Purge CPU frequency measurement
It's not accurate, and we can query the registry for the TSC frequency for thread timers. Also replaces InitCPUTicks() with a global constructor.
This commit is contained in:
parent
5d64a2b889
commit
8a8e6c5d20
|
@ -1,5 +1,5 @@
|
|||
/* PCSX2 - PS2 Emulator for PCs
|
||||
* Copyright (C) 2002-2014 PCSX2 Dev Team
|
||||
* Copyright (C) 2002-2023 PCSX2 Dev Team
|
||||
*
|
||||
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
||||
* of the GNU Lesser General Public License as published by the Free Software Found-
|
||||
|
@ -52,15 +52,12 @@ u64 GetPhysicalMemory()
|
|||
return getmem;
|
||||
}
|
||||
|
||||
static u64 tickfreq;
|
||||
static mach_timebase_info_data_t s_timebase_info;
|
||||
|
||||
void InitCPUTicks()
|
||||
{
|
||||
static const u64 tickfreq = []() {
|
||||
if (mach_timebase_info(&s_timebase_info) != KERN_SUCCESS)
|
||||
abort();
|
||||
tickfreq = (u64)1e9 * (u64)s_timebase_info.denom / (u64)s_timebase_info.numer;
|
||||
}
|
||||
return (u64)1e9 * (u64)s_timebase_info.denom / (u64)s_timebase_info.numer;
|
||||
}();
|
||||
|
||||
// returns the performance-counter frequency: ticks per second (Hz)
|
||||
//
|
||||
|
|
|
@ -196,7 +196,6 @@ private:
|
|||
#define SafeSysMunmap(ptr, size) \
|
||||
((void)(HostSys::Munmap(ptr, size), (ptr) = 0))
|
||||
|
||||
extern void InitCPUTicks();
|
||||
extern u64 GetTickFrequency();
|
||||
extern u64 GetCPUTicks();
|
||||
extern u64 GetPhysicalMemory();
|
||||
|
|
|
@ -47,11 +47,6 @@ u64 GetPhysicalMemory()
|
|||
return pages * getpagesize();
|
||||
}
|
||||
|
||||
|
||||
void InitCPUTicks()
|
||||
{
|
||||
}
|
||||
|
||||
u64 GetTickFrequency()
|
||||
{
|
||||
return 1000000000; // unix measures in nanoseconds
|
||||
|
|
|
@ -29,7 +29,12 @@
|
|||
#include <timeapi.h>
|
||||
#include <VersionHelpers.h>
|
||||
|
||||
alignas(16) static LARGE_INTEGER lfreq;
|
||||
// If anything tries to read this as an initializer, we're in trouble.
|
||||
static const LARGE_INTEGER lfreq = []() {
|
||||
LARGE_INTEGER ret = {};
|
||||
QueryPerformanceFrequency(&ret);
|
||||
return ret;
|
||||
}();
|
||||
|
||||
// This gets leaked... oh well.
|
||||
static thread_local HANDLE s_sleep_timer;
|
||||
|
@ -48,11 +53,6 @@ static HANDLE GetSleepTimer()
|
|||
return s_sleep_timer;
|
||||
}
|
||||
|
||||
void InitCPUTicks()
|
||||
{
|
||||
QueryPerformanceFrequency(&lfreq);
|
||||
}
|
||||
|
||||
u64 GetTickFrequency()
|
||||
{
|
||||
return lfreq.QuadPart;
|
||||
|
|
|
@ -217,7 +217,20 @@ u64 Threading::GetThreadTicksPerSecond()
|
|||
// So, the frequency is our base clock speed (and stable regardless of power management).
|
||||
static u64 frequency = 0;
|
||||
if (unlikely(frequency == 0))
|
||||
frequency = x86caps.CachedMHz() * u64(1000000);
|
||||
{
|
||||
HKEY key;
|
||||
LSTATUS res =
|
||||
RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", 0, KEY_READ, &key);
|
||||
if (res == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD mhz;
|
||||
DWORD size = sizeof(mhz);
|
||||
res = RegQueryValueExW(key, L"~MHz", nullptr, nullptr, reinterpret_cast<LPBYTE>(&mhz), &size);
|
||||
if (res == ERROR_SUCCESS)
|
||||
frequency = static_cast<u64>(mhz) * static_cast<u64>(1000000);
|
||||
RegCloseKey(key);
|
||||
}
|
||||
}
|
||||
return frequency;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,49 +106,6 @@ void x86capabilities::SIMD_EstablishMXCSRmask()
|
|||
MXCSR_Mask.bitmask = result;
|
||||
}
|
||||
|
||||
// Counts the number of cpu cycles executed over the requested number of PerformanceCounter
|
||||
// ticks. Returns that exact count.
|
||||
// For best results you should pick a period of time long enough to get a reading that won't
|
||||
// be prone to rounding error; but short enough that it'll be highly unlikely to be interrupted
|
||||
// by the operating system task switches.
|
||||
s64 x86capabilities::_CPUSpeedHz(u64 time) const
|
||||
{
|
||||
u64 timeStart, timeStop;
|
||||
s64 startCycle, endCycle;
|
||||
|
||||
if (!hasTimeStampCounter)
|
||||
return 0;
|
||||
|
||||
SingleCoreAffinity affinity_lock;
|
||||
|
||||
// Align the cpu execution to a cpuTick boundary.
|
||||
|
||||
do
|
||||
{
|
||||
timeStart = GetCPUTicks();
|
||||
startCycle = __rdtsc();
|
||||
} while (GetCPUTicks() == timeStart);
|
||||
|
||||
do
|
||||
{
|
||||
timeStop = GetCPUTicks();
|
||||
endCycle = __rdtsc();
|
||||
} while ((timeStop - timeStart) < time);
|
||||
|
||||
s64 cycleCount = endCycle - startCycle;
|
||||
s64 timeCount = timeStop - timeStart;
|
||||
s64 overrun = timeCount - time;
|
||||
if (!overrun)
|
||||
return cycleCount;
|
||||
|
||||
// interference could cause us to overshoot the target time, compensate:
|
||||
|
||||
double cyclesPerTick = (double)cycleCount / (double)timeCount;
|
||||
double newCycleCount = (double)cycleCount - (cyclesPerTick * overrun);
|
||||
|
||||
return (s64)newCycleCount;
|
||||
}
|
||||
|
||||
const char* x86capabilities::GetTypeName() const
|
||||
{
|
||||
switch (TypeID)
|
||||
|
@ -307,28 +264,3 @@ void x86capabilities::Identify()
|
|||
|
||||
isIdentified = true;
|
||||
}
|
||||
|
||||
u32 x86capabilities::CalculateMHz() const
|
||||
{
|
||||
InitCPUTicks();
|
||||
u64 span = GetTickFrequency();
|
||||
|
||||
if ((span % 1000) < 400) // helps minimize rounding errors
|
||||
return (u32)(_CPUSpeedHz(span / 1000) / 1000);
|
||||
else
|
||||
return (u32)(_CPUSpeedHz(span / 500) / 2000);
|
||||
}
|
||||
|
||||
u32 x86capabilities::CachedMHz()
|
||||
{
|
||||
static std::atomic<u32> cached{0};
|
||||
u32 local = cached.load(std::memory_order_relaxed);
|
||||
if (unlikely(local == 0))
|
||||
{
|
||||
x86capabilities caps;
|
||||
caps.Identify();
|
||||
local = caps.CalculateMHz();
|
||||
cached.store(local, std::memory_order_relaxed);
|
||||
}
|
||||
return local;
|
||||
}
|
||||
|
|
|
@ -116,13 +116,9 @@ public:
|
|||
void CountCores();
|
||||
const char* GetTypeName() const;
|
||||
|
||||
static u32 CachedMHz();
|
||||
u32 CalculateMHz() const;
|
||||
|
||||
void SIMD_EstablishMXCSRmask();
|
||||
|
||||
protected:
|
||||
s64 _CPUSpeedHz(u64 time) const;
|
||||
void CountLogicalCores();
|
||||
};
|
||||
|
||||
|
|
|
@ -103,19 +103,17 @@ void SysLogMachineCaps()
|
|||
GetOSVersionString().c_str(),
|
||||
(u32)(GetPhysicalMemory() / _1mb));
|
||||
|
||||
u32 speed = x86caps.CalculateMHz();
|
||||
|
||||
Console.Indent().WriteLn(
|
||||
"CPU name = %s\n"
|
||||
"Vendor/Model = %s (stepping %02X)\n"
|
||||
"CPU speed = %u.%03u ghz (%u logical thread%ls)\n"
|
||||
"Logical Cores = %u\n"
|
||||
"x86PType = %s\n"
|
||||
"x86Flags = %08x %08x\n"
|
||||
"x86EFlags = %08x",
|
||||
x86caps.FamilyName,
|
||||
x86caps.VendorName, x86caps.StepID,
|
||||
speed / 1000, speed % 1000,
|
||||
x86caps.LogicalCores, (x86caps.LogicalCores == 1) ? L"" : L"s",
|
||||
x86caps.LogicalCores,
|
||||
x86caps.GetTypeName(),
|
||||
x86caps.Flags, x86caps.Flags2,
|
||||
x86caps.EFlags);
|
||||
|
|
|
@ -306,7 +306,6 @@ bool VMManager::Internal::CPUThreadInitialize()
|
|||
x86caps.Identify();
|
||||
x86caps.CountCores();
|
||||
x86caps.SIMD_EstablishMXCSRmask();
|
||||
x86caps.CalculateMHz();
|
||||
SysLogMachineCaps();
|
||||
|
||||
pxAssert(!s_vm_memory && !s_cpu_provider_pack);
|
||||
|
|
Loading…
Reference in New Issue