Changeset View
Changeset View
Standalone View
Standalone View
source/lib/sysdep/os/win/whrt/tsc.cpp
/* Copyright (C) 2010 Wildfire Games. | /* Copyright (C) 2020 Wildfire Games. | ||||
* | * | ||||
* Permission is hereby granted, free of charge, to any person obtaining | * Permission is hereby granted, free of charge, to any person obtaining | ||||
* a copy of this software and associated documentation files (the | * a copy of this software and associated documentation files (the | ||||
* "Software"), to deal in the Software without restriction, including | * "Software"), to deal in the Software without restriction, including | ||||
* without limitation the rights to use, copy, modify, merge, publish, | * without limitation the rights to use, copy, modify, merge, publish, | ||||
* distribute, sublicense, and/or sell copies of the Software, and to | * distribute, sublicense, and/or sell copies of the Software, and to | ||||
* permit persons to whom the Software is furnished to do so, subject to | * permit persons to whom the Software is furnished to do so, subject to | ||||
* the following conditions: | * the following conditions: | ||||
Show All 23 Lines | |||||
#include "lib/sysdep/acpi.h" | #include "lib/sysdep/acpi.h" | ||||
#include "lib/sysdep/os_cpu.h" | #include "lib/sysdep/os_cpu.h" | ||||
#include "lib/sysdep/os/win/win.h" | #include "lib/sysdep/os/win/win.h" | ||||
#include "lib/sysdep/os/win/wutil.h" | #include "lib/sysdep/os/win/wutil.h" | ||||
#if ARCH_X86_X64 | #if ARCH_X86_X64 | ||||
# include "lib/sysdep/arch/x86_x64/x86_x64.h" // x86_x64::rdtsc | # include "lib/sysdep/arch/x86_x64/x86_x64.h" // x86_x64::rdtsc | ||||
# include "lib/sysdep/arch/x86_x64/topology.h" | # include "lib/sysdep/arch/x86_x64/topology.h" | ||||
# include "lib/sysdep/arch/x86_x64/msr.h" | |||||
#endif | #endif | ||||
//----------------------------------------------------------------------------- | //----------------------------------------------------------------------------- | ||||
static bool IsUniprocessor() | static bool IsUniprocessor() | ||||
{ | { | ||||
if(topology::NumPackages() != 1) | if(topology::NumPackages() != 1) | ||||
▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | if(fadt) | ||||
if(fadt->IsC3Supported()) | if(fadt->IsC3Supported()) | ||||
return false; | return false; | ||||
// frequency throttling possible => unsafe. | // frequency throttling possible => unsafe. | ||||
if(fadt->IsDutyCycleSupported()) | if(fadt->IsDutyCycleSupported()) | ||||
return false; | return false; | ||||
} | } | ||||
#if ARCH_X86_X64 | |||||
// recent CPU: | |||||
//if(x86_x64::Generation() >= 7) | |||||
{ | |||||
// note: 8th generation CPUs support C1-clock ramping, which causes | |||||
// drift on multi-core systems, but those were excluded above. | |||||
// in addition to frequency changes due to P-state transitions, | |||||
// we're also subject to STPCLK throttling. this happens when | |||||
// the chipset thinks the system is dangerously overheated; the | |||||
// OS isn't even notified. this may be rare, but could cause | |||||
// incorrect results => unsafe. | |||||
//return false; | |||||
} | |||||
#endif | |||||
// we're dealing with a single older CPU; the only problem there is | // we're dealing with a single older CPU; the only problem there is | ||||
// throttling, i.e. changes to the TSC frequency. we don't want to | // throttling, i.e. changes to the TSC frequency. we don't want to | ||||
// disable this because it may be important for cooling. the OS | // disable this because it may be important for cooling. the OS | ||||
// initiates changes but doesn't notify us; jumps are too frequent | // initiates changes but doesn't notify us; jumps are too frequent | ||||
// and drastic to detect and account for => unsafe. | // and drastic to detect and account for => unsafe. | ||||
if(IsThrottlingPossible()) | if(IsThrottlingPossible()) | ||||
return false; | return false; | ||||
return true; | return true; | ||||
} | } | ||||
u64 Counter() const | u64 Counter() const | ||||
{ | { | ||||
return x86_x64::rdtsc(); | return x86_x64::rdtsc(); | ||||
} | } | ||||
size_t CounterBits() const | size_t CounterBits() const | ||||
{ | { | ||||
return 64; | return 64; | ||||
} | } | ||||
double NominalFrequency() const | double NominalFrequency() const | ||||
{ | { | ||||
// WARNING: do not call x86_x64::ClockFrequency because it uses the | |||||
// HRT, which we're currently in the process of initializing. | |||||
// instead query CPU clock frequency via OS. | |||||
// | |||||
// note: even here, initial accuracy isn't critical because the | |||||
// clock is subject to thermal drift and would require continual | |||||
// recalibration anyway. | |||||
#if ARCH_X86_X64 | |||||
if(MSR::IsAccessible() && MSR::HasPlatformInfo()) | |||||
{ | |||||
const i64 busFrequency = IsSandyBridge()? 100000000 : 133333333; | |||||
const u64 platformInfo = MSR::Read(MSR::PLATFORM_INFO); | |||||
const u8 maxNonTurboRatio = bits(platformInfo, 8, 15); | |||||
return double(maxNonTurboRatio) * busFrequency; | |||||
} | |||||
else | |||||
#endif | |||||
return os_cpu_ClockFrequency(); | return os_cpu_ClockFrequency(); | ||||
} | } | ||||
double Resolution() const | double Resolution() const | ||||
{ | { | ||||
return 1.0 / NominalFrequency(); | return 1.0 / NominalFrequency(); | ||||
} | } | ||||
}; | }; | ||||
ICounter* CreateCounterTSC(void* address, size_t size) | ICounter* CreateCounterTSC(void* address, size_t size) | ||||
{ | { | ||||
ENSURE(sizeof(CounterTSC) <= size); | ENSURE(sizeof(CounterTSC) <= size); | ||||
return new(address) CounterTSC(); | return new(address) CounterTSC(); | ||||
} | } |
Wildfire Games · Phabricator