PerfTimer.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. // CPerfTimer - a simple Win32 performance counter wrapper
  2. // by Dean Wyant [email protected]
  3. /*
  4. This class is simple to use. Just declare a variable(s) as type CPerfTimer,
  5. call Start() to start timimg and call Stop() to stop timimg. You can pause a
  6. timer by calling Stop() and then you can call Start() to resume. Retrieve the
  7. elapsed time by calling an Elapsed..() function. Assignment, addition,
  8. subtraction and comparison are supported. There are a few information calls
  9. available also. All calls except Start and Stop can be performed on a timer
  10. without stopping it.
  11. */
  12. #ifndef __PERFTIMER_H__
  13. #define __PERFTIMER_H__
  14. class CPerfTimer
  15. {
  16. public:
  17. CPerfTimer(BOOL bStart = FALSE) {Init(bStart);}
  18. CPerfTimer(const CPerfTimer& Src);
  19. virtual ~CPerfTimer() {;}
  20. void Start(BOOL bReset = FALSE); // Start from current value or optionally from 0
  21. void Stop(); // Stop timing. Use Start afterwards to continue.
  22. BOOL IsRunning(); // Returns FALSE if stopped.
  23. BOOL IsSupported(); // Returns FALSE if performance counter not supported.
  24. // Call after constructing at least one CPerfTimer
  25. const double Resolution(); // Returns timer resolution in seconds
  26. const double Resolutionms(); // Returns timer resolution in milliseconds
  27. const double Resolutionus(); // Returns timer resolution in microseconds
  28. const double Elapsed(); // Returns elapsed time in seconds
  29. const double Elapsedms(); // Returns elapsed time in milliseconds
  30. const double Elapsedus(); // Returns elapsed time in microseconds
  31. const CPerfTimer& operator=(const CPerfTimer& Src); // Assignment operator
  32. // Math operators
  33. CPerfTimer operator+(const CPerfTimer& Src) const;
  34. CPerfTimer operator-(const CPerfTimer& Src) const;
  35. const CPerfTimer& operator+=(const CPerfTimer& Src);
  36. const CPerfTimer& operator-=(const CPerfTimer& Src);
  37. // For time in seconds
  38. CPerfTimer operator+(const double Secs) const;
  39. CPerfTimer operator-(const double Secs) const;
  40. const CPerfTimer& operator+=(const double Secs);
  41. const CPerfTimer& operator-=(const double Secs);
  42. // Boolean comparison operators
  43. BOOL operator<(const CPerfTimer& Src);
  44. BOOL operator>(const CPerfTimer& Src);
  45. BOOL operator<=(const CPerfTimer& Src);
  46. BOOL operator>=(const CPerfTimer& Src);
  47. // For time in seconds
  48. BOOL operator<(const double Secs);
  49. BOOL operator>(const double Secs);
  50. BOOL operator<=(const double Secs);
  51. BOOL operator>=(const double Secs);
  52. virtual void Lock() const {;} // Override for thread safe operation
  53. virtual void Unlock() const {;} // Override for thread safe operation
  54. protected:
  55. void Init(BOOL bStart);
  56. void Copy(const CPerfTimer& Src);
  57. private:
  58. __int64 m_Start;
  59. static __int64 m_Freq; // does not change while system is running
  60. static __int64 m_Adjust; // Adjustment time it takes to Start and Stop
  61. };
  62. class CPerfTimerT : public CPerfTimer
  63. { // You only need to use types of this class if a timer is going to be shared between threads
  64. public:
  65. CPerfTimerT(BOOL bStart = FALSE)
  66. {
  67. m_hMutex = CreateMutex(NULL, FALSE, _T(""));
  68. Init(bStart);
  69. }
  70. CPerfTimerT(const CPerfTimerT& Src)
  71. {
  72. m_hMutex = CreateMutex(NULL,FALSE,_T(""));
  73. Copy(Src);
  74. }
  75. CPerfTimerT(const CPerfTimer& Src)
  76. {
  77. m_hMutex = CreateMutex(NULL,FALSE,_T(""));
  78. Copy(Src);
  79. }
  80. virtual ~CPerfTimerT()
  81. { CloseHandle(m_hMutex); }
  82. const CPerfTimerT& operator=(const CPerfTimerT& Src) // Assignment operator
  83. {
  84. Copy(Src);
  85. return *this;
  86. }
  87. virtual void Lock() const { WaitForSingleObject(m_hMutex,10000); }
  88. virtual void Unlock() const { ReleaseMutex(m_hMutex); }
  89. private:
  90. HANDLE m_hMutex;
  91. };
  92. inline void CPerfTimer::Init(BOOL bStart)
  93. {
  94. if (!m_Freq)
  95. { // Initialization should only run once
  96. QueryPerformanceFrequency((LARGE_INTEGER *)&m_Freq);
  97. if (!m_Freq)
  98. m_Freq = 1; // Timer will be useless but will not cause divide by zero
  99. m_Start = 0;
  100. m_Adjust = 0;
  101. Start(); // Time a Stop
  102. Stop();
  103. m_Adjust = m_Start;
  104. }
  105. // This is the only part that normally runs
  106. m_Start = 0;
  107. if (bStart)
  108. Start();
  109. }
  110. inline CPerfTimer::CPerfTimer(const CPerfTimer& Src)
  111. {
  112. Copy(Src);
  113. }
  114. inline void CPerfTimer::Copy(const CPerfTimer& Src)
  115. {
  116. if (&Src == this)
  117. return; // avoid deadlock if someone tries to copy it to itself
  118. Src.Lock();
  119. Lock();
  120. m_Start = Src.m_Start;
  121. Unlock();
  122. Src.Unlock();
  123. }
  124. inline void CPerfTimer::Start(BOOL bReset)
  125. { // Start from current value or optionally from 0
  126. __int64 i;
  127. QueryPerformanceCounter((LARGE_INTEGER *)&i);
  128. Lock();
  129. if ((!bReset) && (m_Start < 0))
  130. m_Start += i; // We are starting with an accumulated time
  131. else
  132. m_Start = i; // Starting from 0
  133. Unlock();
  134. }
  135. inline void CPerfTimer::Stop()
  136. { // Stop timing. Use Start afterwards to continue
  137. Lock();
  138. if (m_Start <= 0)
  139. {
  140. Unlock();
  141. return; // Was not running
  142. }
  143. __int64 i;
  144. QueryPerformanceCounter((LARGE_INTEGER *)&i);
  145. m_Start += -i; // Stopped timer keeps elapsed timer ticks as a negative
  146. if (m_Start < m_Adjust) // Do not overflow
  147. m_Start -= m_Adjust; // Adjust for time timer code takes to run
  148. else
  149. m_Start = 0; // Stop must have been called directly after Start
  150. Unlock();
  151. }
  152. inline BOOL CPerfTimer::IsRunning()
  153. { // Returns FALSE if stopped.
  154. Lock();
  155. BOOL bRet = (m_Start > 0); // When < 0, holds elpased clicks
  156. Unlock();
  157. return bRet;
  158. }
  159. inline const double CPerfTimer::Elapsed()
  160. { // Returns elapsed time in seconds
  161. CPerfTimer Result(*this);
  162. Result.Stop();
  163. return (double)(-Result.m_Start)/(double)m_Freq;
  164. }
  165. inline const double CPerfTimer::Elapsedms()
  166. { // Returns elapsed time in milliseconds
  167. CPerfTimer Result(*this);
  168. Result.Stop();
  169. return (-Result.m_Start*1000.0)/(double)m_Freq;
  170. }
  171. inline const double CPerfTimer::Elapsedus()
  172. { // Returns elapsed time in microseconds
  173. CPerfTimer Result(*this);
  174. Result.Stop();
  175. return (-Result.m_Start * 1000000.0)/(double)m_Freq;
  176. }
  177. // Assignment operator
  178. inline const CPerfTimer& CPerfTimer::operator=(const CPerfTimer& Src)
  179. {
  180. Copy(Src);
  181. return *this;
  182. }
  183. // Math operators
  184. inline CPerfTimer CPerfTimer::operator+(const CPerfTimer& Src) const
  185. {
  186. CPerfTimer Result(*this);
  187. Result += Src;
  188. return Result;
  189. }
  190. inline CPerfTimer CPerfTimer::operator-(const CPerfTimer& Src) const
  191. {
  192. CPerfTimer Result(*this);
  193. Result -= Src;
  194. return Result;
  195. }
  196. inline const CPerfTimer& CPerfTimer::operator+=(const CPerfTimer& Src)
  197. {
  198. CPerfTimer SrcStop(Src); // Temp is necessary in case Src is not stopped
  199. SrcStop.Stop();
  200. Lock();
  201. m_Start += SrcStop.m_Start;
  202. Unlock();
  203. return *this;
  204. }
  205. inline const CPerfTimer& CPerfTimer::operator-=(const CPerfTimer& Src)
  206. {
  207. CPerfTimer SrcStop(Src); // Temp is necessary in case Src is not stopped
  208. SrcStop.Stop();
  209. Lock();
  210. m_Start -= SrcStop.m_Start;
  211. Unlock();
  212. return *this;
  213. }
  214. // For time in seconds
  215. inline CPerfTimer CPerfTimer::operator+(const double Secs) const
  216. {
  217. CPerfTimer Result(*this);
  218. Result += Secs;
  219. return Result;
  220. }
  221. inline CPerfTimer CPerfTimer::operator-(const double Secs) const
  222. {
  223. CPerfTimer Result(*this);
  224. Result += Secs;
  225. return Result;
  226. }
  227. inline const CPerfTimer& CPerfTimer::operator+=(const double Secs)
  228. {
  229. Lock();
  230. m_Start -= (__int64)(Secs*(double)m_Freq);
  231. Unlock();
  232. return *this;
  233. }
  234. inline const CPerfTimer& CPerfTimer::operator-=(const double Secs)
  235. {
  236. Lock();
  237. m_Start += (__int64)(Secs*(double)m_Freq);
  238. Unlock();
  239. return *this;
  240. }
  241. // Boolean comparison operators
  242. inline BOOL CPerfTimer::operator<(const CPerfTimer& Src)
  243. {
  244. BOOL bRet;
  245. CPerfTimer Temp(Src);
  246. Lock();
  247. if (m_Start <= 0)
  248. {
  249. Temp.Stop();
  250. bRet = (m_Start > Temp.m_Start);
  251. Unlock();
  252. return bRet;
  253. }
  254. else
  255. if (Temp.m_Start > 0)
  256. {
  257. bRet = (m_Start < Temp.m_Start);
  258. Unlock();
  259. return bRet;
  260. }
  261. else
  262. {
  263. Unlock();
  264. CPerfTimer ThisStop(*this);
  265. ThisStop.Stop();
  266. return (ThisStop.m_Start > Temp.m_Start);
  267. }
  268. }
  269. inline BOOL CPerfTimer::operator>(const CPerfTimer& Src)
  270. {
  271. BOOL bRet;
  272. CPerfTimer Temp(Src);
  273. Lock();
  274. if (m_Start <= 0)
  275. {
  276. Temp.Stop();
  277. bRet = (m_Start < Temp.m_Start);
  278. Unlock();
  279. return bRet;
  280. }
  281. else
  282. if (Temp.m_Start > 0)
  283. {
  284. bRet = (m_Start > Temp.m_Start);
  285. Unlock();
  286. return bRet;
  287. }
  288. else
  289. {
  290. Unlock();
  291. CPerfTimer ThisStop(*this);
  292. ThisStop.Stop();
  293. return (ThisStop.m_Start < Temp.m_Start);
  294. }
  295. }
  296. inline BOOL CPerfTimer::operator<=(const CPerfTimer& Src)
  297. {
  298. return !(*this > Src);
  299. }
  300. inline BOOL CPerfTimer::operator>=(const CPerfTimer& Src)
  301. {
  302. return !(*this < Src);
  303. }
  304. // For time in seconds
  305. inline BOOL CPerfTimer::operator<(const double Secs)
  306. {
  307. BOOL bRet;
  308. Lock();
  309. if (m_Start <= 0)
  310. {
  311. bRet = (m_Start > (__int64)(-Secs*(double)m_Freq));
  312. Unlock();
  313. return bRet;
  314. }
  315. else
  316. {
  317. Unlock();
  318. CPerfTimer ThisStop(*this);
  319. ThisStop.Stop();
  320. return (ThisStop.m_Start > (__int64)(-Secs*(double)m_Freq));
  321. }
  322. }
  323. inline BOOL CPerfTimer::operator>(const double Secs)
  324. {
  325. BOOL bRet;
  326. Lock();
  327. if (m_Start <= 0)
  328. {
  329. bRet = (m_Start < (__int64)(-Secs*(double)m_Freq));
  330. Unlock();
  331. return bRet;
  332. }
  333. else
  334. {
  335. Unlock();
  336. CPerfTimer ThisStop(*this);
  337. ThisStop.Stop();
  338. return (ThisStop.m_Start < (__int64)(-Secs*(double)m_Freq));
  339. }
  340. }
  341. inline BOOL CPerfTimer::operator<=(const double Secs)
  342. {
  343. return !(*this > Secs);
  344. }
  345. inline BOOL CPerfTimer::operator>=(const double Secs)
  346. {
  347. return !(*this < Secs);
  348. }
  349. #endif //__PERFTIMER_H__