Make RDTSC and ACPI timers stateful to fix overflows
Stateless RDTSC and ACPI timers were ticking relative to the host QPC and multiplied to nanoseconds. This resulted in values so huge they would overflow since 20-30 minutes. Introducing state allows to multiply to nanoseconds only over a delta value, which should be reasonably small in almost call cases.
This commit is contained in:
parent
216b5c274e
commit
0d1a8e3afd
|
@ -324,43 +324,64 @@ void InitDpcThread()
|
|||
g_DpcData.DpcEvent = CreateEvent(/*lpEventAttributes=*/nullptr, /*bManualReset=*/FALSE, /*bInitialState=*/FALSE, /*lpName=*/nullptr);
|
||||
}
|
||||
|
||||
#define XBOX_TSC_FREQUENCY 733333333 // Xbox Time Stamp Counter Frequency = 733333333 (CPU Clock)
|
||||
#define XBOX_ACPI_FREQUENCY 3375000 // Xbox ACPI frequency (3.375 mhz)
|
||||
ULONGLONG NativeToXbox_FactorForRdtsc;
|
||||
ULONGLONG NativeToXbox_FactorForAcpi;
|
||||
static constexpr uint32_t XBOX_TSC_FREQUENCY = 733333333; // Xbox Time Stamp Counter Frequency = 733333333 (CPU Clock)
|
||||
static constexpr uint32_t XBOX_ACPI_FREQUENCY = 3375000; // Xbox ACPI frequency (3.375 mhz)
|
||||
static constexpr uint32_t SEC_TO_NSEC = 1000000000; // For seconds -> nanoseconds conversions
|
||||
static uint64_t NativeToXbox_FactorForRdtsc = 0, NativeToXbox_FactorForAcpi = 0;
|
||||
|
||||
ULONGLONG CxbxGetPerformanceCounter(bool acpi) {
|
||||
LARGE_INTEGER tsc;
|
||||
ULARGE_INTEGER scaledTsc;
|
||||
// State for CxbxGetPerformanceCounter - concurrent access should be next to non-existent, but secure against it anyway
|
||||
static std::mutex RdtscLock, AcpiLock;
|
||||
static LARGE_INTEGER LastRdtscQPC, LastAcpiQPC;
|
||||
static ULONGLONG CurrentRdtsc = 0, CurrentAcpi = 0;
|
||||
static ULONGLONG CurrentRdtscRemainder = 0, CurrentAcpiRemainder = 0;
|
||||
|
||||
QueryPerformanceCounter(&tsc);
|
||||
ULONGLONG CxbxGetPerformanceCounter(bool acpi)
|
||||
{
|
||||
if (acpi == false && NativeToXbox_FactorForRdtsc != 0) {
|
||||
std::lock_guard<std::mutex> lock(RdtscLock);
|
||||
|
||||
scaledTsc.QuadPart = 1000000000;
|
||||
scaledTsc.QuadPart *= (ULONGLONG)tsc.QuadPart;
|
||||
LARGE_INTEGER tsc;
|
||||
QueryPerformanceCounter(&tsc);
|
||||
|
||||
if (acpi == false && NativeToXbox_FactorForRdtsc) {
|
||||
scaledTsc.QuadPart /= NativeToXbox_FactorForRdtsc;
|
||||
return scaledTsc.QuadPart;
|
||||
} else if (acpi == true && NativeToXbox_FactorForRdtsc) {
|
||||
scaledTsc.QuadPart /= NativeToXbox_FactorForAcpi;
|
||||
return scaledTsc.QuadPart;
|
||||
LARGE_INTEGER lastTsc = std::exchange(LastRdtscQPC, tsc);
|
||||
tsc.QuadPart -= lastTsc.QuadPart;
|
||||
tsc.QuadPart *= SEC_TO_NSEC;
|
||||
tsc.QuadPart += CurrentRdtscRemainder;
|
||||
ULONGLONG quotient = tsc.QuadPart / NativeToXbox_FactorForRdtsc;
|
||||
ULONGLONG remainder = tsc.QuadPart % NativeToXbox_FactorForRdtsc;
|
||||
|
||||
CurrentRdtscRemainder = remainder;
|
||||
return CurrentRdtsc += quotient;
|
||||
} else if (acpi == true && NativeToXbox_FactorForAcpi != 0) {
|
||||
std::lock_guard<std::mutex> lock(AcpiLock);
|
||||
|
||||
LARGE_INTEGER tsc;
|
||||
QueryPerformanceCounter(&tsc);
|
||||
|
||||
LARGE_INTEGER lastTsc = std::exchange(LastAcpiQPC, tsc);
|
||||
tsc.QuadPart -= lastTsc.QuadPart;
|
||||
tsc.QuadPart *= SEC_TO_NSEC;
|
||||
tsc.QuadPart += CurrentAcpiRemainder;
|
||||
ULONGLONG quotient = tsc.QuadPart / NativeToXbox_FactorForAcpi;
|
||||
ULONGLONG remainder = tsc.QuadPart % NativeToXbox_FactorForAcpi;
|
||||
|
||||
CurrentAcpiRemainder = remainder;
|
||||
return CurrentAcpi += quotient;
|
||||
}
|
||||
|
||||
return (uint64_t)tsc.QuadPart;
|
||||
LARGE_INTEGER tsc;
|
||||
QueryPerformanceCounter(&tsc);
|
||||
return static_cast<ULONGLONG>(tsc.QuadPart);
|
||||
}
|
||||
|
||||
void CxbxInitPerformanceCounters()
|
||||
{
|
||||
uint64_t t;
|
||||
t = 1000000000;
|
||||
t *= HostClockFrequency;
|
||||
t /= XBOX_TSC_FREQUENCY;
|
||||
NativeToXbox_FactorForRdtsc = t;
|
||||
NativeToXbox_FactorForRdtsc = Muldiv64(HostClockFrequency, SEC_TO_NSEC, XBOX_TSC_FREQUENCY);
|
||||
NativeToXbox_FactorForAcpi = Muldiv64(HostClockFrequency, SEC_TO_NSEC, XBOX_ACPI_FREQUENCY);
|
||||
|
||||
t = 1000000000;
|
||||
t *= HostClockFrequency;
|
||||
t /= XBOX_ACPI_FREQUENCY;
|
||||
NativeToXbox_FactorForAcpi = t;
|
||||
LARGE_INTEGER tsc;
|
||||
QueryPerformanceCounter(&tsc);
|
||||
LastRdtscQPC = LastAcpiQPC = tsc;
|
||||
|
||||
// Let's initialize the Dpc handling thread too,
|
||||
// here for now (should be called by our caller)
|
||||
|
|
Loading…
Reference in New Issue