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