STIR  6.2.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 
47 namespace stir
48 {
49 
76 {
77 public:
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 
104 protected:
105 private:
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 
144 inline void
145 HighResWallClockTimer::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 
174 inline 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 
272 inline void
274 {
275  assert(!m_bRunning);
276  m_Secs = m_Nanosecs = 0;
277 };
278 
280 inline bool
282 {
283  return m_bRunning;
284 };
285 
287 inline int
289 {
290  assert(!m_bRunning);
291  return m_Secs;
292 };
293 
295 inline int
297 {
298  assert(!m_bRunning);
299  return m_Nanosecs;
300 };
301 
303 inline 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 
327 inline 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__
Namespace for the STIR library (and some/most of its applications)
Definition: General_Reconstruction.cxx:6
int get_nanosec(void)
Returns the number of nanoseconds that elapsed on top of whatever get_sec() returned.
Definition: HighResWallClockTimer.h:296
void start(bool bReset=false)
Start a timer.
Definition: HighResWallClockTimer.h:145
double value(void)
Returns the elapsed time (in seconds)
Definition: HighResWallClockTimer.h:304
static int get_resolution_in_nanosecs(void)
Attempts to guess the timer resolution.
Definition: HighResWallClockTimer.h:328
HighResWallClockTimer(void)
Create a timer.
Definition: HighResWallClockTimer.h:128
int get_sec(void)
Returns the number of whole seconds elapsed.
Definition: HighResWallClockTimer.h:288
bool is_running(void)
Check if a timer is running.
Definition: HighResWallClockTimer.h:281
virtual ~HighResWallClockTimer(void)
Destroy a timer.
Definition: HighResWallClockTimer.h:135
High-resolution timer.
Definition: HighResWallClockTimer.h:75
void reset(void)
Reset a timer.
Definition: HighResWallClockTimer.h:273
void stop(void)
Stop a running timer.
Definition: HighResWallClockTimer.h:175