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