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