1
This commit is contained in:
254
unittests/ihvtest1/sys_clock.cpp
Normal file
254
unittests/ihvtest1/sys_clock.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#pragma optimize( "", off )
|
||||
|
||||
#pragma pack( push, thing )
|
||||
#pragma pack( 4 )
|
||||
static long g_cw, g_single_cw, g_highchop_cw, g_full_cw, g_ceil_cw, g_pushed_cw;
|
||||
static struct
|
||||
{
|
||||
long dummy[8];
|
||||
} g_fpenv;
|
||||
#pragma pack( pop, thing )
|
||||
|
||||
|
||||
void __declspec ( naked ) MaskExceptions()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
fnstenv ds:dword ptr[g_fpenv]
|
||||
or ds:dword ptr[g_fpenv],03Fh
|
||||
fldenv ds:dword ptr[g_fpenv]
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec ( naked ) Sys_SetFPCW()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
fnstcw ds:word ptr[g_cw]
|
||||
mov eax,ds:dword ptr[g_cw]
|
||||
and ah,0F0h
|
||||
or ah,003h
|
||||
mov ds:dword ptr[g_full_cw],eax
|
||||
mov ds:dword ptr[g_highchop_cw],eax
|
||||
and ah,0F0h
|
||||
or ah,00Ch
|
||||
mov ds:dword ptr[g_single_cw],eax
|
||||
and ah,0F0h
|
||||
or ah,008h
|
||||
mov ds:dword ptr[g_ceil_cw],eax
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec ( naked ) Sys_PushFPCW_SetHigh()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
fnstcw ds:word ptr[g_pushed_cw]
|
||||
fldcw ds:word ptr[g_full_cw]
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec ( naked ) Sys_PopFPCW()
|
||||
{
|
||||
_asm
|
||||
{
|
||||
fldcw ds:word ptr[g_pushed_cw]
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#pragma optimize( "", on )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Implements high precision clock
|
||||
// TODO: Make into an interface?
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSysClock
|
||||
{
|
||||
public:
|
||||
// Construction
|
||||
CSysClock( void );
|
||||
|
||||
// Initialization
|
||||
void Init( void );
|
||||
void SetStartTime( void );
|
||||
|
||||
// Sample the clock
|
||||
double GetTime( void );
|
||||
|
||||
private:
|
||||
// High performance clock frequency
|
||||
double m_dClockFrequency;
|
||||
// Current accumulated time
|
||||
double m_dCurrentTime;
|
||||
// How many bits to shift raw 64 bit sample count by
|
||||
int m_nTimeSampleShift;
|
||||
// Previous 32 bit sample count
|
||||
unsigned int m_uiPreviousTime;
|
||||
|
||||
bool m_bInitialized;
|
||||
};
|
||||
|
||||
static CSysClock g_Clock;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
CSysClock::CSysClock( void )
|
||||
{
|
||||
m_bInitialized = false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initialize the clock
|
||||
//-----------------------------------------------------------------------------
|
||||
void CSysClock::Init( void )
|
||||
{
|
||||
BOOL success;
|
||||
LARGE_INTEGER PerformanceFreq;
|
||||
unsigned int lowpart, highpart;
|
||||
|
||||
MaskExceptions ();
|
||||
Sys_SetFPCW ();
|
||||
|
||||
// Start clock at zero
|
||||
m_dCurrentTime = 0.0;
|
||||
|
||||
success = QueryPerformanceFrequency( &PerformanceFreq );
|
||||
assert( success );
|
||||
|
||||
// get 32 out of the 64 time bits such that we have around
|
||||
// 1 microsecond resolution
|
||||
lowpart = (unsigned int)PerformanceFreq.LowPart;
|
||||
highpart = (unsigned int)PerformanceFreq.HighPart;
|
||||
|
||||
m_nTimeSampleShift = 0;
|
||||
|
||||
while ( highpart || ( lowpart > 2000000.0 ) )
|
||||
{
|
||||
m_nTimeSampleShift++;
|
||||
lowpart >>= 1;
|
||||
lowpart |= (highpart & 1) << 31;
|
||||
highpart >>= 1;
|
||||
}
|
||||
|
||||
m_dClockFrequency = 1.0 / (double)lowpart;
|
||||
|
||||
// Get initial sample
|
||||
unsigned int temp;
|
||||
LARGE_INTEGER PerformanceCount;
|
||||
QueryPerformanceCounter( &PerformanceCount );
|
||||
if ( !m_nTimeSampleShift )
|
||||
{
|
||||
temp = (unsigned int)PerformanceCount.LowPart;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rotate counter to right by m_nTimeSampleShift places
|
||||
temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) |
|
||||
((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift));
|
||||
}
|
||||
|
||||
// Set first time stamp
|
||||
m_uiPreviousTime = temp;
|
||||
|
||||
m_bInitialized = true;
|
||||
|
||||
SetStartTime();
|
||||
}
|
||||
|
||||
void CSysClock::SetStartTime( void )
|
||||
{
|
||||
GetTime();
|
||||
|
||||
m_dCurrentTime = 0.0;
|
||||
|
||||
m_uiPreviousTime = ( unsigned int )m_dCurrentTime;
|
||||
}
|
||||
|
||||
double CSysClock::GetTime( void )
|
||||
{
|
||||
LARGE_INTEGER PerformanceCount;
|
||||
unsigned int temp, t2;
|
||||
double time;
|
||||
|
||||
if ( !m_bInitialized )
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
Sys_PushFPCW_SetHigh();
|
||||
|
||||
// Get sample counter
|
||||
QueryPerformanceCounter( &PerformanceCount );
|
||||
|
||||
if ( !m_nTimeSampleShift )
|
||||
{
|
||||
temp = (unsigned int)PerformanceCount.LowPart;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rotate counter to right by m_nTimeSampleShift places
|
||||
temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) |
|
||||
((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift));
|
||||
}
|
||||
|
||||
// check for turnover or backward time
|
||||
if ( ( temp <= m_uiPreviousTime ) &&
|
||||
( ( m_uiPreviousTime - temp ) < 0x10000000) )
|
||||
{
|
||||
m_uiPreviousTime = temp; // so we can't get stuck
|
||||
}
|
||||
else
|
||||
{
|
||||
// gap in performance clocks
|
||||
t2 = temp - m_uiPreviousTime;
|
||||
|
||||
// Convert to time using frequencey of clock
|
||||
time = (double)t2 * m_dClockFrequency;
|
||||
|
||||
// Remember old time
|
||||
m_uiPreviousTime = temp;
|
||||
|
||||
// Increment clock
|
||||
m_dCurrentTime += time;
|
||||
}
|
||||
|
||||
Sys_PopFPCW();
|
||||
|
||||
// Convert to float
|
||||
return m_dCurrentTime;
|
||||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sample the high-precision clock
|
||||
// Output : double
|
||||
//-----------------------------------------------------------------------------
|
||||
double Sys_FloatTime( void )
|
||||
{
|
||||
return g_Clock.GetTime();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Initialize high-precision clock
|
||||
//-----------------------------------------------------------------------------
|
||||
void Sys_InitFloatTime( void )
|
||||
{
|
||||
g_Clock.Init();
|
||||
}
|
Reference in New Issue
Block a user