STIR 6.4.0
HighResWallClockTimer.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2000 PARAPET partners
3 Copyright (C) 2000- 2008, Hammersmith Imanet Ltd
4 Copyright (C) 2023 University College London
5 This file is part of STIR.
6
7 SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license
8
9 See STIR/LICENSE.txt for details
10*/
11
21/*
22 Modification history:
23
24 <TT>
25 Sep 2023 -- Kris Thielemans -- fixed WIN32 version
26 May 2015 -- Kris Thielemans -- removed overflow when using gettimeofday and reinstated AZ's WIN32 version (as MS had
27 get_nanosec() wrong) May 2008 -- Kris Thielemans -- renamed PTimer to HighResWallClockTimer and renamed functions to by
28 compatible with stir::Timer 18 Aug 99 -- Mustapha Sadki -- corrected the formula for HighResWallClockTimer::stop() &
29 HighResWallClockTimer::GetTime() for WIN32\n 08 Jul 99 -- Mustapha Sadki -- added global Ptimers and #define manipulations\n 10
30 Apr 99 -- Alexey Zverovich -- Ported to Linux\n 19 Oct 98 -- Alexey Zverovich -- Ported to Win32;\n 19 Oct 98 -- Alexey Zverovich
31 -- Slightly reorganised HighResWallClockTimer::start() to reduce overhead\n 16 Oct 98 -- Alexey Zverovich -- created
32 </TT>
33
34*/
35
36#ifndef __stir_HIGHRESWALLCLOCKTIMER_H__
37#define __stir_HIGHRESWALLCLOCKTIMER_H__
38
39#if defined(WIN32)
40# include <windows.h>
41#else
42# include <sys/time.h>
43#endif
44
45#include <assert.h>
46
47namespace stir
48{
49
74
76{
77public:
79 inline HighResWallClockTimer(void);
81 inline virtual ~HighResWallClockTimer(void);
82
83 // Default copy ctor & assignment op are just fine
84
86 inline void start(bool bReset = false);
88 inline void stop(void);
90 inline void reset(void);
92 inline bool is_running(void);
93
95 inline int get_sec(void);
97 inline int get_nanosec(void);
99 inline double value(void);
100
102 static int get_resolution_in_nanosecs(void); // in nanoseconds
103
104protected:
105private:
106 bool m_bRunning;
107 int m_Secs;
108 int m_Nanosecs;
109
110#if defined(_AIX)
111 timebasestruct_t m_Start;
112 timebasestruct_t m_Finish;
113#elif defined(__sun)
114 hrtime_t m_Start;
115 hrtime_t m_Finish;
116#elif defined(WIN32)
117 LARGE_INTEGER m_Start;
118 LARGE_INTEGER m_Finish;
119#else
120// default to using gettimeofday which is on most unix (and all Linux) systems
121# define STIR_HRWCT_Use_gettimeofday
122 timeval m_Start;
123 timeval m_Finish;
124#endif
125};
126
129 : m_bRunning(false)
130{
131 reset();
132};
133
136{
137 assert(!m_bRunning);
138};
139
144inline void
145HighResWallClockTimer::start(bool bReset /* = false */)
146{
147 if (bReset)
148 reset();
149 m_bRunning = true;
150#if defined(_AIX)
151 read_real_time(&m_Start, TIMEBASE_SZ);
152#elif defined(__sun)
153 m_Start = gethrtime();
154#elif defined(WIN32)
155# ifndef NDEBUG
156 BOOL Result =
157# endif
158 QueryPerformanceCounter(&m_Start);
159 assert(Result); // if failed, high-resolution timers are not supported by this hardware
160#elif defined(STIR_HRWCT_Use_gettimeofday)
161 // TODO: what will happen if the time gets changed?
162# ifndef NDEBUG
163 int Result =
164# endif
165 gettimeofday(&m_Start, NULL);
166 assert(Result == 0);
167#endif
168};
169
174inline void
176{
177 assert(m_bRunning);
178
179#if defined(_AIX)
180
181 read_real_time(&m_Finish, TIMEBASE_SZ);
182
183 time_base_to_time(&m_Start, TIMEBASE_SZ);
184 time_base_to_time(&m_Finish, TIMEBASE_SZ);
185
186 int Secs = m_Finish.tb_high - m_Start.tb_high;
187 int Nanosecs = m_Finish.tb_low - m_Start.tb_low;
188
189 // If there was a carry from low-order to high-order during
190 // the measurement, we may have to undo it.
191
192 if (Nanosecs < 0)
193 {
194 Secs--;
195 Nanosecs += 1000000000;
196 };
197
198 m_Secs += Secs;
199 m_Nanosecs += Nanosecs;
200 if (m_Nanosecs >= 1000000000)
201 {
202 m_Secs++;
203 m_Nanosecs -= 1000000000;
204 };
205
206#elif defined(__sun)
207
208 m_Finish = gethrtime();
209
210 m_Secs += (m_Finish - m_Start) / 1000000000;
211 m_Nanosecs += (m_Finish - m_Start) % 1000000000;
212 if (m_Nanosecs >= 1000000000)
213 {
214 m_Secs++;
215 m_Nanosecs -= 1000000000;
216 };
217
218#elif defined(WIN32)
219
220 BOOL Result = QueryPerformanceCounter(&m_Finish);
221 assert(Result); // if failed, high-resolution timers are not supported by this hardware
222
223 LONGLONG Delta = m_Finish.QuadPart - m_Start.QuadPart;
224 LARGE_INTEGER Freq;
225 Result = QueryPerformanceFrequency(&Freq);
226 assert(Result); // if failed, high-resolution timers are not supported by this hardware
227 const auto DeltaSecs = Delta / Freq.QuadPart;
228 m_Secs += static_cast<int>(DeltaSecs);
229 // handle remainder
230 Delta -= DeltaSecs * Freq.QuadPart;
231 // convert to nano-secs
232 Delta *= 1000000000;
233 Delta /= Freq.QuadPart;
234 m_Nanosecs += static_cast<int>(Delta);
235 if (m_Nanosecs >= 1000000000)
236 {
237 m_Secs++;
238 m_Nanosecs -= 1000000000;
239 }
240
241#elif defined(STIR_HRWCT_Use_gettimeofday)
242
243# ifndef NDEBUG
244 int Result =
245# endif
246 gettimeofday(&m_Finish, NULL);
247 assert(Result == 0);
248 m_Secs += (m_Finish.tv_sec - m_Start.tv_sec);
249 int Microsecs = (m_Finish.tv_usec - m_Start.tv_usec);
250 if (Microsecs < 0)
251 {
252 m_Secs--;
253 Microsecs += 1000000;
254 };
255
256 m_Nanosecs += (Microsecs * 1000);
257 if (m_Nanosecs >= 1000000000)
258 {
259 m_Secs++;
260 m_Nanosecs -= 1000000000;
261 };
262
263#endif
264
265 assert(m_Secs >= 0);
266 assert(m_Nanosecs >= 0 && m_Nanosecs < 1000000000);
267
268 m_bRunning = false;
269};
270
272inline void
274{
275 assert(!m_bRunning);
276 m_Secs = m_Nanosecs = 0;
277};
278
280inline bool
282{
283 return m_bRunning;
284};
285
287inline int
289{
290 assert(!m_bRunning);
291 return m_Secs;
292};
293
295inline int
297{
298 assert(!m_bRunning);
299 return m_Nanosecs;
300};
301
303inline double
305{
306 return get_sec() + double(get_nanosec()) / 1e9;
307}
308
309// HighResWallClockTimer.cxx -- high-resolution timers implementation
310
311// Modification history:
312//
313// 19 Oct 98 -- Alexey Zverovich -- created
314
326
327inline int
329{
330
331 /*static*/ int Resolution = -1; // cached resolution
332
333 if (Resolution > 0)
334 return Resolution;
335
336#if defined(_AIX)
337
338 timebasestruct_t Start;
339 timebasestruct_t Current;
340
341 read_real_time(&Start, TIMEBASE_SZ);
342 time_base_to_time(&Start, TIMEBASE_SZ);
343
344 int MinSecs = -1; // no minimum yet
345 int MinNanosecs = -1;
346 int SecondsElapsed = 0;
347
348 do
349 {
350 timebasestruct_t Times[2];
351
352 read_real_time(&Times[0], TIMEBASE_SZ);
353 do
354 {
355 read_real_time(&Times[1], TIMEBASE_SZ);
356 assert(Times[1].flag == Times[0].flag);
357 } while (Times[1].tb_high == Times[0].tb_high && Times[1].tb_low == Times[0].tb_low);
358
359 time_base_to_time(&Times[0], TIMEBASE_SZ);
360 time_base_to_time(&Times[1], TIMEBASE_SZ);
361
362 int Secs = Times[1].tb_high - Times[0].tb_high;
363 int Nanosecs = Times[1].tb_low - Times[0].tb_low;
364
365 // If there was a carry from low-order to high-order during
366 // the measurement, we may have to undo it.
367
368 if (Nanosecs < 0)
369 {
370 Secs--;
371 Nanosecs += 1000000000;
372 };
373
374 assert(Secs >= 0 && Nanosecs >= 0 && Nanosecs < 1000000000);
375 assert(Secs != 0 || Nanosecs != 0); // shouldn't be the same as we checked in the 'do' loop
376
377 // cout << "[" << Secs << " " << Nanosecs << "]" << endl;
378
379 if (MinSecs < 0 || Secs < MinSecs || (Secs == MinSecs && Nanosecs < MinNanosecs))
380 {
381 MinSecs = Secs;
382 MinNanosecs = Nanosecs;
383 };
384
385 read_real_time(&Current, TIMEBASE_SZ);
386 time_base_to_time(&Current, TIMEBASE_SZ);
387
388 SecondsElapsed = Current.tb_high - Start.tb_high;
389 if (Current.tb_low < Start.tb_low)
390 SecondsElapsed--;
391 } while (SecondsElapsed < 1);
392
393 assert(MinSecs < 2); // otherwise it's too coarse for this measurement
394
395 Resolution = MinSecs * 1000000000 + MinNanosecs;
396
397#elif defined(__sun)
398
399 hrtime_t Start = gethrtime();
400 hrtime_t Current;
401
402 hrtime_t MinNanosecs = -1;
403
404 do
405 {
406 hrtime_t Times[2];
407
408 Times[0] = gethrtime();
409
410 while ((Times[1] = gethrtime()) == Times[0]) /* do nothing */
411 ;
412
413 hrtime_t Nanosecs = Times[1] - Times[0];
414
415 assert(Nanosecs > 0);
416
417 if (MinNanosecs < 0 || Nanosecs < MinNanosecs)
418 {
419 MinNanosecs = Nanosecs;
420 };
421
422 Current = gethrtime();
423 } while (Current - Start < 1000000000); // 1 second
424
425 assert(MinNanosecs < 2000000000); // otherwise it's too coarse for this measurement
426
427 Resolution = static_cast<int>(MinNanosecs);
428
429#elif defined(WIN32)
430
431 LARGE_INTEGER Freq;
432 BOOL Result;
433
434 Result = QueryPerformanceFrequency(&Freq);
435 assert(Result); // if failed, high-resolution timers are not supported by this hardware
436
437 Resolution = static_cast<int>(1000000000 / Freq.QuadPart);
438
439#elif defined(STIR_HRWCT_Use_gettimeofday)
440
441 // TODO
442
443#endif
444
445 assert(Resolution > 0);
446
447 return Resolution;
448};
449
450} // namespace stir
451
452#endif // __HIGHRESWALLCLOCKTIMER_H__
int get_nanosec(void)
Returns the number of nanoseconds that elapsed on top of whatever get_sec() returned.
Definition HighResWallClockTimer.h:296
HighResWallClockTimer(void)
Create a timer.
Definition HighResWallClockTimer.h:128
void stop(void)
Stop a running timer.
Definition HighResWallClockTimer.h:175
bool is_running(void)
Check if a timer is running.
Definition HighResWallClockTimer.h:281
virtual ~HighResWallClockTimer(void)
Destroy a timer.
Definition HighResWallClockTimer.h:135
double value(void)
Returns the elapsed time (in seconds)
Definition HighResWallClockTimer.h:304
int get_sec(void)
Returns the number of whole seconds elapsed.
Definition HighResWallClockTimer.h:288
static int get_resolution_in_nanosecs(void)
Attempts to guess the timer resolution.
Definition HighResWallClockTimer.h:328
void start(bool bReset=false)
Start a timer.
Definition HighResWallClockTimer.h:145
void reset(void)
Reset a timer.
Definition HighResWallClockTimer.h:273
Namespace for the STIR library (and some/most of its applications)
Definition General_Reconstruction.h:19