// CPerfTimer - a simple Win32 performance counter wrapper
|
// by Dean Wyant dwyant@mindspring.com
|
|
/*
|
This class is simple to use. Just declare a variable(s) as type CPerfTimer,
|
call Start() to start timimg and call Stop() to stop timimg. You can pause a
|
timer by calling Stop() and then you can call Start() to resume. Retrieve the
|
elapsed time by calling an Elapsed..() function. Assignment, addition,
|
subtraction and comparison are supported. There are a few information calls
|
available also. All calls except Start and Stop can be performed on a timer
|
without stopping it.
|
*/
|
|
#ifndef __PERFTIMER_H__
|
#define __PERFTIMER_H__
|
|
class CPerfTimer
|
{
|
public:
|
void Trace( LPCTSTR lpsz );
|
CPerfTimer(BOOL bStart = FALSE) {Init(bStart);}
|
|
CPerfTimer(const CPerfTimer& Src);
|
|
virtual ~CPerfTimer() {;}
|
|
void Start(BOOL bReset = FALSE); // Start from current value or optionally from 0
|
void Stop(); // Stop timing. Use Start afterwards to continue.
|
|
BOOL IsRunning(); // Returns FALSE if stopped.
|
|
BOOL IsSupported(); // Returns FALSE if performance counter not supported.
|
// Call after constructing at least one CPerfTimer
|
|
const double Resolution(); // Returns timer resolution in seconds
|
const double Resolutionms(); // Returns timer resolution in milliseconds
|
const double Resolutionus(); // Returns timer resolution in microseconds
|
|
const double Elapsed(); // Returns elapsed time in seconds
|
const double Elapsedms(); // Returns elapsed time in milliseconds
|
const double Elapsedus(); // Returns elapsed time in microseconds
|
|
const CPerfTimer& operator=(const CPerfTimer& Src); // Assignment operator
|
|
// Math operators
|
CPerfTimer operator+(const CPerfTimer& Src) const;
|
CPerfTimer operator-(const CPerfTimer& Src) const;
|
const CPerfTimer& operator+=(const CPerfTimer& Src);
|
const CPerfTimer& operator-=(const CPerfTimer& Src);
|
// For time in seconds
|
CPerfTimer operator+(const double Secs) const;
|
CPerfTimer operator-(const double Secs) const;
|
const CPerfTimer& operator+=(const double Secs);
|
const CPerfTimer& operator-=(const double Secs);
|
|
// Boolean comparison operators
|
BOOL operator<(const CPerfTimer& Src);
|
BOOL operator>(const CPerfTimer& Src);
|
BOOL operator<=(const CPerfTimer& Src);
|
BOOL operator>=(const CPerfTimer& Src);
|
// For time in seconds
|
BOOL operator<(const double Secs);
|
BOOL operator>(const double Secs);
|
BOOL operator<=(const double Secs);
|
BOOL operator>=(const double Secs);
|
|
virtual void Lock() const {;} // Override for thread safe operation
|
virtual void Unlock() const {;} // Override for thread safe operation
|
protected:
|
void Init(BOOL bStart);
|
void Copy(const CPerfTimer& Src);
|
|
private:
|
__int64 m_Start;
|
static __int64 m_Freq; // does not change while system is running
|
static __int64 m_Adjust; // Adjustment time it takes to Start and Stop
|
};
|
|
class CPerfTimerT : public CPerfTimer
|
{ // You only need to use types of this class if a timer is going to be shared between threads
|
public:
|
void Trace(LPCTSTR lpsz);
|
CPerfTimerT(BOOL bStart = FALSE)
|
{
|
m_hMutex = CreateMutex(NULL,FALSE,_T(""));
|
Init(bStart);
|
}
|
|
CPerfTimerT(const CPerfTimerT& Src)
|
{
|
m_hMutex = CreateMutex(NULL,FALSE,_T(""));
|
Copy(Src);
|
}
|
|
CPerfTimerT(const CPerfTimer& Src)
|
{
|
m_hMutex = CreateMutex(NULL,FALSE,_T(""));
|
Copy(Src);
|
}
|
|
virtual ~CPerfTimerT()
|
{ CloseHandle(m_hMutex); }
|
|
const CPerfTimerT& operator=(const CPerfTimerT& Src) // Assignment operator
|
{
|
Copy(Src);
|
return *this;
|
}
|
|
virtual void Lock() const { WaitForSingleObject(m_hMutex,10000); }
|
virtual void Unlock() const { ReleaseMutex(m_hMutex); }
|
private:
|
HANDLE m_hMutex;
|
};
|
|
inline void CPerfTimer::Init(BOOL bStart)
|
{
|
if (!m_Freq)
|
{ // Initialization should only run once
|
QueryPerformanceFrequency((LARGE_INTEGER *)&m_Freq);
|
if (!m_Freq)
|
m_Freq = 1; // Timer will be useless but will not cause divide by zero
|
m_Start = 0;
|
m_Adjust = 0;
|
Start(); // Time a Stop
|
Stop();
|
m_Adjust = m_Start;
|
}
|
// This is the only part that normally runs
|
m_Start = 0;
|
if (bStart)
|
Start();
|
}
|
|
inline CPerfTimer::CPerfTimer(const CPerfTimer& Src)
|
{
|
Copy(Src);
|
}
|
|
inline void CPerfTimer::Copy(const CPerfTimer& Src)
|
{
|
if (&Src == this)
|
return; // avoid deadlock if someone tries to copy it to itself
|
Src.Lock();
|
Lock();
|
m_Start = Src.m_Start;
|
Unlock();
|
Src.Unlock();
|
}
|
|
inline void CPerfTimer::Start(BOOL bReset)
|
{ // Start from current value or optionally from 0
|
__int64 i;
|
QueryPerformanceCounter((LARGE_INTEGER *)&i);
|
Lock();
|
if ((!bReset) && (m_Start < 0))
|
m_Start += i; // We are starting with an accumulated time
|
else
|
m_Start = i; // Starting from 0
|
Unlock();
|
}
|
|
inline void CPerfTimer::Stop()
|
{ // Stop timing. Use Start afterwards to continue
|
Lock();
|
if (m_Start <= 0)
|
{
|
Unlock();
|
return; // Was not running
|
}
|
__int64 i;
|
QueryPerformanceCounter((LARGE_INTEGER *)&i);
|
m_Start += -i; // Stopped timer keeps elapsed timer ticks as a negative
|
if (m_Start < m_Adjust) // Do not overflow
|
m_Start -= m_Adjust; // Adjust for time timer code takes to run
|
else
|
m_Start = 0; // Stop must have been called directly after Start
|
Unlock();
|
}
|
|
inline BOOL CPerfTimer::IsRunning()
|
{ // Returns FALSE if stopped.
|
Lock();
|
BOOL bRet = (m_Start > 0); // When < 0, holds elpased clicks
|
Unlock();
|
return bRet;
|
}
|
inline const double CPerfTimer::Elapsed()
|
{ // Returns elapsed time in seconds
|
CPerfTimer Result(*this);
|
Result.Stop();
|
return (double)(-Result.m_Start)/(double)m_Freq;
|
}
|
|
inline const double CPerfTimer::Elapsedms()
|
{ // Returns elapsed time in milliseconds
|
CPerfTimer Result(*this);
|
Result.Stop();
|
return (-Result.m_Start*1000.0)/(double)m_Freq;
|
}
|
|
inline const double CPerfTimer::Elapsedus()
|
{ // Returns elapsed time in microseconds
|
CPerfTimer Result(*this);
|
Result.Stop();
|
return (-Result.m_Start * 1000000.0)/(double)m_Freq;
|
}
|
|
|
// Assignment operator
|
inline const CPerfTimer& CPerfTimer::operator=(const CPerfTimer& Src)
|
{
|
Copy(Src);
|
return *this;
|
}
|
|
|
// Math operators
|
inline CPerfTimer CPerfTimer::operator+(const CPerfTimer& Src) const
|
{
|
CPerfTimer Result(*this);
|
Result += Src;
|
return Result;
|
}
|
|
inline CPerfTimer CPerfTimer::operator-(const CPerfTimer& Src) const
|
{
|
CPerfTimer Result(*this);
|
Result -= Src;
|
return Result;
|
}
|
|
inline const CPerfTimer& CPerfTimer::operator+=(const CPerfTimer& Src)
|
{
|
CPerfTimer SrcStop(Src); // Temp is necessary in case Src is not stopped
|
SrcStop.Stop();
|
Lock();
|
m_Start += SrcStop.m_Start;
|
Unlock();
|
return *this;
|
}
|
|
inline const CPerfTimer& CPerfTimer::operator-=(const CPerfTimer& Src)
|
{
|
CPerfTimer SrcStop(Src); // Temp is necessary in case Src is not stopped
|
SrcStop.Stop();
|
Lock();
|
m_Start -= SrcStop.m_Start;
|
Unlock();
|
return *this;
|
}
|
|
// For time in seconds
|
inline CPerfTimer CPerfTimer::operator+(const double Secs) const
|
{
|
CPerfTimer Result(*this);
|
Result += Secs;
|
return Result;
|
}
|
|
inline CPerfTimer CPerfTimer::operator-(const double Secs) const
|
{
|
CPerfTimer Result(*this);
|
Result += Secs;
|
return Result;
|
}
|
|
inline const CPerfTimer& CPerfTimer::operator+=(const double Secs)
|
{
|
Lock();
|
m_Start -= (__int64)(Secs*(double)m_Freq);
|
Unlock();
|
return *this;
|
}
|
|
inline const CPerfTimer& CPerfTimer::operator-=(const double Secs)
|
{
|
Lock();
|
m_Start += (__int64)(Secs*(double)m_Freq);
|
Unlock();
|
return *this;
|
}
|
|
|
|
// Boolean comparison operators
|
inline BOOL CPerfTimer::operator<(const CPerfTimer& Src)
|
{
|
BOOL bRet;
|
CPerfTimer Temp(Src);
|
Lock();
|
if (m_Start <= 0)
|
{
|
Temp.Stop();
|
bRet = (m_Start > Temp.m_Start);
|
Unlock();
|
return bRet;
|
}
|
else
|
if (Temp.m_Start > 0)
|
{
|
bRet = (m_Start < Temp.m_Start);
|
Unlock();
|
return bRet;
|
}
|
else
|
{
|
Unlock();
|
CPerfTimer ThisStop(*this);
|
ThisStop.Stop();
|
return (ThisStop.m_Start > Temp.m_Start);
|
}
|
}
|
|
inline BOOL CPerfTimer::operator>(const CPerfTimer& Src)
|
{
|
BOOL bRet;
|
CPerfTimer Temp(Src);
|
Lock();
|
if (m_Start <= 0)
|
{
|
Temp.Stop();
|
bRet = (m_Start < Temp.m_Start);
|
Unlock();
|
return bRet;
|
}
|
else
|
if (Temp.m_Start > 0)
|
{
|
bRet = (m_Start > Temp.m_Start);
|
Unlock();
|
return bRet;
|
}
|
else
|
{
|
Unlock();
|
CPerfTimer ThisStop(*this);
|
ThisStop.Stop();
|
return (ThisStop.m_Start < Temp.m_Start);
|
}
|
}
|
|
inline BOOL CPerfTimer::operator<=(const CPerfTimer& Src)
|
{
|
return !(*this > Src);
|
}
|
|
inline BOOL CPerfTimer::operator>=(const CPerfTimer& Src)
|
{
|
return !(*this < Src);
|
}
|
|
// For time in seconds
|
inline BOOL CPerfTimer::operator<(const double Secs)
|
{
|
BOOL bRet;
|
Lock();
|
if (m_Start <= 0)
|
{
|
bRet = (m_Start > (__int64)(-Secs*(double)m_Freq));
|
Unlock();
|
return bRet;
|
}
|
else
|
{
|
Unlock();
|
CPerfTimer ThisStop(*this);
|
ThisStop.Stop();
|
return (ThisStop.m_Start > (__int64)(-Secs*(double)m_Freq));
|
}
|
}
|
|
inline BOOL CPerfTimer::operator>(const double Secs)
|
{
|
BOOL bRet;
|
Lock();
|
if (m_Start <= 0)
|
{
|
bRet = (m_Start < (__int64)(-Secs*(double)m_Freq));
|
Unlock();
|
return bRet;
|
}
|
else
|
{
|
Unlock();
|
CPerfTimer ThisStop(*this);
|
ThisStop.Stop();
|
return (ThisStop.m_Start < (__int64)(-Secs*(double)m_Freq));
|
}
|
}
|
|
inline BOOL CPerfTimer::operator<=(const double Secs)
|
{
|
return !(*this > Secs);
|
}
|
|
inline BOOL CPerfTimer::operator>=(const double Secs)
|
{
|
return !(*this < Secs);
|
}
|
|
|
#endif //__PERFTIMER_H__
|