Changeset View
Changeset View
Standalone View
Standalone View
source/lib/sysdep/os/win/whrt/qpc.cpp
Property | Old Value | New Value |
---|---|---|
svn:eol-style | native \ No newline at end of property | null |
/* Copyright (C) 2010 Wildfire Games. | |||||
* | |||||
* Permission is hereby granted, free of charge, to any person obtaining | |||||
* a copy of this software and associated documentation files (the | |||||
* "Software"), to deal in the Software without restriction, including | |||||
* without limitation the rights to use, copy, modify, merge, publish, | |||||
* distribute, sublicense, and/or sell copies of the Software, and to | |||||
* permit persons to whom the Software is furnished to do so, subject to | |||||
* the following conditions: | |||||
* | |||||
* The above copyright notice and this permission notice shall be included | |||||
* in all copies or substantial portions of the Software. | |||||
* | |||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |||||
*/ | |||||
/* | |||||
* Timer implementation using QueryPerformanceCounter | |||||
*/ | |||||
#include "precompiled.h" | |||||
#include "lib/sysdep/os/win/whrt/qpc.h" | |||||
#include "lib/sysdep/os/win/whrt/counter.h" | |||||
#include "lib/sysdep/os_cpu.h" | |||||
#include "lib/sysdep/os/win/win.h" | |||||
#include "lib/sysdep/os/win/wutil.h" // wutil_argv | |||||
#include "lib/sysdep/os/win/whrt/pit.h" // PIT_FREQ | |||||
#include "lib/sysdep/os/win/whrt/pmt.h" // PMT_FREQ | |||||
class CounterQPC : public ICounter | |||||
vladislavbelov: Can it be used? Since it uses QPC. | |||||
Done Inline ActionsI did inially, but it's unecessary overhead. And @wraitii asked me to remove it to extract the core functionnality. Stan: I did inially, but it's unecessary overhead. And @wraitii asked me to remove it to extract the… | |||||
{ | |||||
public: | |||||
CounterQPC() | |||||
: m_frequency(-1) | |||||
{ | |||||
} | |||||
virtual const char* Name() const | |||||
{ | |||||
return "QPC"; | |||||
} | |||||
Status Activate() | |||||
{ | |||||
// note: QPC is observed to be universally supported, but the API | |||||
// provides for failure, so play it safe. | |||||
LARGE_INTEGER qpcFreq, qpcValue; | |||||
const BOOL ok1 = QueryPerformanceFrequency(&qpcFreq); | |||||
const BOOL ok2 = QueryPerformanceCounter(&qpcValue); | |||||
if(!ok1 || !ok2) | |||||
WARN_RETURN(ERR::FAIL); | |||||
if(!qpcFreq.QuadPart || !qpcValue.QuadPart) | |||||
WARN_RETURN(ERR::FAIL); | |||||
m_frequency = (i64)qpcFreq.QuadPart; | |||||
return INFO::OK; | |||||
} | |||||
void Shutdown() | |||||
{ | |||||
} | |||||
bool IsSafe() const | |||||
{ | |||||
// note: we have separate modules that directly access some of the | |||||
// counters potentially used by QPC. disabling the redundant counters | |||||
// would be ugly (increased coupling). instead, we'll make sure our | |||||
// implementations could (if necessary) coexist with QPC, but it | |||||
// shouldn't come to that since only one counter is needed/used. | |||||
// the PIT is entirely safe (even if annoyingly slow to read) | |||||
if(m_frequency == PIT_FREQ) | |||||
return true; | |||||
// the PMT is generally safe (see discussion in CounterPmt::IsSafe), | |||||
// but older QPC implementations had problems with 24-bit rollover. | |||||
// "System clock problem can inflate benchmark scores" | |||||
// (http://www.lionbridge.com/bi/cont2000/200012/perfcnt.asp ; no longer | |||||
// online, nor findable in Google Cache / archive.org) tells of | |||||
// incorrect values every 4.6 seconds (i.e. 24 bits @ 3.57 MHz) unless | |||||
// the timer is polled in the meantime. fortunately, this is guaranteed | |||||
// by our periodic updates (which come at least that often). | |||||
if(m_frequency == PMT_FREQ) | |||||
return true; | |||||
// the TSC has been known to be buggy (even mentioned in MSDN). it is | |||||
// used on MP HAL systems and can be detected by comparing QPF with the | |||||
// CPU clock. we consider it unsafe unless the user promises (via | |||||
// command line) that it's patched and thus reliable on their system. | |||||
bool usesTsc = IsSimilarMagnitude((double)m_frequency, os_cpu_ClockFrequency()); | |||||
// unconfirmed reports indicate QPC sometimes uses 1/3 of the | |||||
// CPU clock frequency, so check that as well. | |||||
usesTsc |= IsSimilarMagnitude((double)m_frequency, os_cpu_ClockFrequency()/3); | |||||
if(usesTsc) | |||||
{ | |||||
const bool isTscSafe = wutil_HasCommandLineArgument(L"-wQpcTscSafe"); | |||||
return isTscSafe; | |||||
} | |||||
// the HPET is reliable and used on Vista. it can't easily be recognized | |||||
// since its frequency is variable (the spec says > 10 MHz; the master | |||||
// 14.318 MHz oscillator is often used). considering frequencies in | |||||
// [10, 100 MHz) to be a HPET would be dangerous because it may actually | |||||
// be faster or RDTSC slower. we have to exclude all other cases and | |||||
// assume it's a HPET - and thus safe - if we get here. | |||||
return true; | |||||
} | |||||
u64 Counter() const | |||||
{ | |||||
// fairly time-critical here, don't check the return value | |||||
// (IsSupported made sure it succeeded initially) | |||||
LARGE_INTEGER qpc_value; | |||||
(void)QueryPerformanceCounter(&qpc_value); | |||||
return qpc_value.QuadPart; | |||||
} | |||||
size_t CounterBits() const | |||||
{ | |||||
// there are reports of incorrect rollover handling in the PMT | |||||
// implementation of QPC (see CounterPMT::IsSafe). however, other | |||||
// counters would be used on those systems, so it's irrelevant. | |||||
// we'll report the full 64 bits. | |||||
return 64; | |||||
} | |||||
double NominalFrequency() const | |||||
{ | |||||
return (double)m_frequency; | |||||
} | |||||
double Resolution() const | |||||
{ | |||||
return 1.0 / m_frequency; | |||||
} | |||||
private: | |||||
// used in several places and QPF is a bit slow+cumbersome. | |||||
// (i64 allows easier conversion to double) | |||||
i64 m_frequency; | |||||
}; | |||||
ICounter* CreateCounterQPC(void* address, size_t size) | |||||
{ | |||||
ENSURE(sizeof(CounterQPC) <= size); | |||||
return new(address) CounterQPC(); | |||||
} |
Wildfire Games · Phabricator
Can it be used? Since it uses QPC.