232 строки
5.3 KiB
C++
232 строки
5.3 KiB
C++
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT license.
|
|
|
|
#ifndef _STTIMER_H
|
|
#define _STTIMER_H
|
|
|
|
class STTIMER
|
|
{
|
|
public:
|
|
|
|
STTIMER()
|
|
: _pTimer( NULL )
|
|
{
|
|
}
|
|
|
|
virtual
|
|
~STTIMER()
|
|
{
|
|
if ( _pTimer )
|
|
{
|
|
CancelTimer();
|
|
|
|
CloseThreadpoolTimer( _pTimer );
|
|
|
|
_pTimer = NULL;
|
|
}
|
|
}
|
|
|
|
HRESULT
|
|
InitializeTimer(
|
|
PTP_TIMER_CALLBACK pfnCallback,
|
|
VOID * pContext,
|
|
DWORD dwInitialWait = 0,
|
|
DWORD dwPeriod = 0
|
|
)
|
|
{
|
|
_pTimer = CreateThreadpoolTimer( pfnCallback,
|
|
pContext,
|
|
NULL );
|
|
|
|
if ( !_pTimer )
|
|
{
|
|
return HRESULT_FROM_WIN32( GetLastError() );
|
|
}
|
|
|
|
if ( dwInitialWait )
|
|
{
|
|
SetTimer( dwInitialWait,
|
|
dwPeriod );
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
VOID
|
|
SetTimer(
|
|
DWORD dwInitialWait,
|
|
DWORD dwPeriod = 0
|
|
)
|
|
{
|
|
FILETIME ftInitialWait;
|
|
|
|
if ( dwInitialWait == 0 && dwPeriod == 0 )
|
|
{
|
|
//
|
|
// Special case. We are preventing new callbacks
|
|
// from being queued. Any existing callbacks in the
|
|
// queue will still run.
|
|
//
|
|
// This effectively disables the timer. It can be
|
|
// re-enabled by setting non-zero initial wait or
|
|
// period values.
|
|
//
|
|
|
|
SetThreadpoolTimer( _pTimer, NULL, 0, 0 );
|
|
return;
|
|
}
|
|
|
|
InitializeRelativeFileTime( &ftInitialWait, dwInitialWait );
|
|
|
|
SetThreadpoolTimer( _pTimer,
|
|
&ftInitialWait,
|
|
dwPeriod,
|
|
0 );
|
|
}
|
|
|
|
VOID
|
|
CancelTimer()
|
|
{
|
|
//
|
|
// Disable the timer
|
|
//
|
|
|
|
SetTimer( 0 );
|
|
|
|
//
|
|
// Wait until any callbacks queued prior to disabling
|
|
// have completed.
|
|
//
|
|
|
|
WaitForThreadpoolTimerCallbacks( _pTimer, TRUE );
|
|
}
|
|
|
|
private:
|
|
|
|
VOID
|
|
InitializeRelativeFileTime(
|
|
FILETIME * pft,
|
|
DWORD dwMilliseconds
|
|
)
|
|
{
|
|
LARGE_INTEGER li;
|
|
|
|
//
|
|
// The pftDueTime parameter expects the time to be
|
|
// expressed as the number of 100 nanosecond intervals
|
|
// times -1.
|
|
//
|
|
// To convert from milliseconds, we'll multiply by
|
|
// -10000
|
|
//
|
|
|
|
li.QuadPart = (LONGLONG)dwMilliseconds * -10000;
|
|
|
|
pft->dwHighDateTime = li.HighPart;
|
|
pft->dwLowDateTime = li.LowPart;
|
|
};
|
|
|
|
TP_TIMER * _pTimer;
|
|
};
|
|
|
|
class STELAPSED
|
|
{
|
|
public:
|
|
|
|
STELAPSED()
|
|
: _dwInitTime( 0 ),
|
|
_dwInitTickCount( 0 ),
|
|
_dwPerfCountsPerMillisecond( 0 ),
|
|
_fUsingHighResolution( FALSE )
|
|
{
|
|
LARGE_INTEGER li;
|
|
BOOL fResult;
|
|
|
|
_dwInitTickCount = GetTickCount64();
|
|
|
|
fResult = QueryPerformanceFrequency( &li );
|
|
|
|
if ( !fResult )
|
|
{
|
|
goto Finished;
|
|
}
|
|
|
|
_dwPerfCountsPerMillisecond = li.QuadPart / 1000;
|
|
|
|
fResult = QueryPerformanceCounter( &li );
|
|
|
|
if ( !fResult )
|
|
{
|
|
goto Finished;
|
|
}
|
|
|
|
_dwInitTime = li.QuadPart / _dwPerfCountsPerMillisecond;
|
|
|
|
_fUsingHighResolution = TRUE;
|
|
|
|
Finished:
|
|
|
|
return;
|
|
}
|
|
|
|
virtual
|
|
~STELAPSED()
|
|
{
|
|
}
|
|
|
|
LONGLONG
|
|
QueryElapsedTime()
|
|
{
|
|
LARGE_INTEGER li;
|
|
|
|
if ( _fUsingHighResolution && QueryPerformanceCounter( &li ) )
|
|
{
|
|
DWORD64 dwCurrentTime = li.QuadPart / _dwPerfCountsPerMillisecond;
|
|
|
|
if ( dwCurrentTime < _dwInitTime )
|
|
{
|
|
//
|
|
// It's theoretically possible that QueryPerformanceCounter
|
|
// may return slightly different values on different CPUs.
|
|
// In this case, we don't want to return an unexpected value
|
|
// so we'll return zero. This is acceptable because
|
|
// presumably such a case would only happen for a very short
|
|
// time window.
|
|
//
|
|
// It would be possible to prevent this by ensuring processor
|
|
// affinity for all calls to QueryPerformanceCounter, but that
|
|
// would be undesirable in the general case because it could
|
|
// introduce unnecessary context switches and potentially a
|
|
// CPU bottleneck.
|
|
//
|
|
// Note that this issue also applies to callers doing rapid
|
|
// calls to this function. If a caller wants to mitigate
|
|
// that, they could enforce the affinitization, or they
|
|
// could implement a similar sanity check when comparing
|
|
// returned values from this function.
|
|
//
|
|
|
|
return 0;
|
|
}
|
|
|
|
return dwCurrentTime - _dwInitTime;
|
|
}
|
|
|
|
return GetTickCount64() - _dwInitTickCount;
|
|
}
|
|
|
|
BOOL
|
|
QueryUsingHighResolution()
|
|
{
|
|
return _fUsingHighResolution;
|
|
}
|
|
|
|
private:
|
|
|
|
DWORD64 _dwInitTime;
|
|
DWORD64 _dwInitTickCount;
|
|
DWORD64 _dwPerfCountsPerMillisecond;
|
|
BOOL _fUsingHighResolution;
|
|
};
|
|
|
|
#endif // _STTIMER_H
|