[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

timing.hxx
Go to the documentation of this file.
1 /************************************************************************/
2 /* */
3 /* Copyright 2008-2011 by Ullrich Koethe */
4 /* Cognitive Systems Group, University of Hamburg, Germany */
5 /* */
6 /* This file is part of the VIGRA computer vision library. */
7 /* The VIGRA Website is */
8 /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */
9 /* Please direct questions, bug reports, and contributions to */
10 /* ullrich.koethe@iwr.uni-heidelberg.de or */
11 /* vigra@informatik.uni-hamburg.de */
12 /* */
13 /* Permission is hereby granted, free of charge, to any person */
14 /* obtaining a copy of this software and associated documentation */
15 /* files (the "Software"), to deal in the Software without */
16 /* restriction, including without limitation the rights to use, */
17 /* copy, modify, merge, publish, distribute, sublicense, and/or */
18 /* sell copies of the Software, and to permit persons to whom the */
19 /* Software is furnished to do so, subject to the following */
20 /* conditions: */
21 /* */
22 /* The above copyright notice and this permission notice shall be */
23 /* included in all copies or substantial portions of the */
24 /* Software. */
25 /* */
26 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
27 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
28 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
29 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
30 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
31 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
32 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
33 /* OTHER DEALINGS IN THE SOFTWARE. */
34 /* */
35 /************************************************************************/
36 
37 
38 #ifndef VIGRA_TIMING_HXX
39 #define VIGRA_TIMING_HXX
40 #ifndef VIGRA_NO_TIMING
41 
42 #include <iostream>
43 #include <sstream>
44 #include <vector>
45 
46 /*! \page TimingMacros Timing macros for runtime measurements
47 
48  <b>\#include</b> <vigra/timing.hxx>
49 
50  These macros allow to perform execution speed measurements. Results are reported
51  in <i>milliseconds</i>.
52  However, note that timings below 1 msec are generally subject to round-off errors.
53  Under LINUX, you can \#define VIGRA_HIRES_TIMING to get better
54  accuracy, but this requires linking against librt.
55 
56 Basic usage:
57 \code
58  void time_it()
59  {
60  USETICTOC
61 
62  TIC
63  ... code to be timed
64  TOC
65  ... untimed code
66  TIC
67  ... other code to be timed
68  TOC
69  }
70 \endcode
71 
72  Instead of TOC, which outputs the time difference to std::cerr,
73  you may use TOCN (the time difference in <i>msec</i> as a double)
74  or TOCS (the time difference as a std::string).
75 
76  Alternatively, you can perform nested timing like so:
77 \code
78  void time_it()
79  {
80  USE_NESTED_TICTOC
81 
82  TICPUSH
83  ... code to be timed
84  TICPUSH
85  ... nested code to be timed
86  TOC print time for nested code
87  ... more code to be timed
88  TOC print total time
89  }
90 \endcode
91 
92 */
93 
94 /*! \file timing.hxx Timing macros for runtime measurements
95 
96  This header defines timing macros for runtime measurements. See \ref TimingMacros for examples.
97 
98  \def USETICTOC
99  Enable timing using TIC/TOC* pairs. This macro defines temporary storage for the timing data, so it needs to precede the TIC/TOC macros in their context.
100  \hideinitializer
101 
102  \def USE_NESTED_TICTOC
103  Enable timing using TICPUSH/TOC* pairs. This macro defines temporary storage for the timing data, so it needs to precede the TIC/TOC macros in their context.
104  \hideinitializer
105 
106  \def TIC
107  Start timing. Requires USE_TICTOC to be defined in the current context.
108  \hideinitializer
109 
110  \def TOC
111  Stop timing and output result (the time difference w.r.t. the last TIC or TICPUSH
112  instance) to std::cerr.
113  \hideinitializer
114 
115  \def TICPUSH
116  Start timing, possibly a nested block of code within some other timed code block.
117  Requires USE_NESTED_TICTOC to be defined once in the current context.
118  \hideinitializer
119 
120  \def TOCN
121  Stop timing. This macro evaluates to the time difference (w.r.t. the last TIC
122  or TICPUSH) in msec as a double.
123  \hideinitializer
124 
125  \def TOCS
126  Stop timing. This macro evaluates to the time difference (w.r.t. the last TIC
127  or TICPUSH) as a std::string (including units).
128  \hideinitializer
129 
130  \def TICTOCLOOP_BEGIN(inner_repetitions,outer_repetitions)
131  Executes the code block up to TICTOCLOOP_END outer_repetitions x
132  inner_repetitions times. The measurement is averaged over the
133  inner_repetitions, and the best result of the outer_repetitions is
134  reported to std::cerr.
135  \hideinitializer
136 
137  \def TICTOCLOOP_END
138  Ends the timing loop started with the TICTOCLOOP_BEGIN macro
139  and outputs the result.
140  \hideinitializer
141 */
142 
143 
144 #ifdef _WIN32
145 
146  #include "windows.h"
147 
148  namespace {
149 
150  inline double queryTimerUnit()
151  {
152  LARGE_INTEGER frequency;
153  QueryPerformanceFrequency(&frequency);
154  return 1000.0 / frequency.QuadPart;
155  }
156 
157  inline double tic_toc_diff_num(LARGE_INTEGER const & tic)
158  {
159  LARGE_INTEGER toc;
160  QueryPerformanceCounter(&toc);
161  static double unit = queryTimerUnit();
162  return ((toc.QuadPart - tic.QuadPart) * unit);
163  }
164 
165  inline std::string tic_toc_diff_string(LARGE_INTEGER const & tic)
166  {
167  double diff = tic_toc_diff_num(tic);
168  std::stringstream s;
169  s << diff << " msec";
170  return s.str();
171  }
172 
173  inline void tic_toc_diff(LARGE_INTEGER const & tic)
174  {
175  double diff = tic_toc_diff_num(tic);
176  std::cerr << diff << " msec" << std::endl;
177  }
178 
179  inline double tic_toc_diff_num(std::vector<LARGE_INTEGER> & tic)
180  {
181  double res = tic_toc_diff_num(tic.back());
182  tic.pop_back();
183  return res;
184  }
185 
186  inline std::string tic_toc_diff_string(std::vector<LARGE_INTEGER> & tic)
187  {
188  std::string res = tic_toc_diff_string(tic.back());
189  tic.pop_back();
190  return res;
191  }
192 
193  inline void tic_toc_diff(std::vector<LARGE_INTEGER> & tic)
194  {
195  tic_toc_diff(tic.back());
196  tic.pop_back();
197  }
198 
199  } // unnamed namespace
200 
201  #define USETICTOC LARGE_INTEGER tic_timer;
202  #define USE_NESTED_TICTOC std::vector<LARGE_INTEGER> tic_timer;
203  #define TIC QueryPerformanceCounter(&tic_timer);
204  #define TICPUSH tic_timer.push_back(LARGE_INTEGER());\
205  QueryPerformanceCounter(&(tic_timer.back()));
206  #define TOC tic_toc_diff (tic_timer);
207  #define TOCN tic_toc_diff_num (tic_timer)
208  #define TOCS tic_toc_diff_string(tic_timer)
209 
210 #else
211 
212  #if defined(VIGRA_HIRES_TIMING) && !defined(__CYGWIN__)
213  // requires linking against librt
214 
215  #include <time.h>
216 
217  namespace {
218 
219  inline double tic_toc_diff_num(timespec const & tic)
220  {
221  timespec toc;
222  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &toc);
223  return ((toc.tv_sec*1000.0 + toc.tv_nsec/1000000.0) -
224  (tic.tv_sec*1000.0 + tic.tv_nsec/1000000.0));
225  }
226 
227  inline std::string tic_toc_diff_string(timespec const & tic)
228  {
229  double diff = tic_toc_diff_num(tic);
230  std::stringstream s;
231  s << diff << " msec";
232  return s.str();
233  }
234 
235  inline void tic_toc_diff(timespec const & tic)
236  {
237  std::cerr << tic_toc_diff_string(tic) << std::endl;
238  }
239 
240  inline double tic_toc_diff_num(std::vector<timespec> & tic)
241  {
242  double res = tic_toc_diff_num(tic.back());
243  tic.pop_back();
244  return res;
245  }
246 
247  inline std::string tic_toc_diff_string(std::vector<timespec> & tic)
248  {
249  std::string res = tic_toc_diff_string(tic.back());
250  tic.pop_back();
251  return res;
252  }
253 
254  inline void tic_toc_diff(std::vector<timespec> & tic)
255  {
256  tic_toc_diff(tic.back());
257  tic.pop_back();
258  }
259 
260  } // unnamed namespace
261 
262  #define USETICTOC timespec tic_timer;
263  #define TIC clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tic_timer);
264  #define TOC tic_toc_diff (tic_timer);
265  #define TOCN tic_toc_diff_num (tic_timer)
266  #define TOCS tic_toc_diff_string(tic_timer)
267  #define USE_NESTED_TICTOC std::vector<timespec> tic_timer;
268  #define TICPUSH tic_timer.push_back(timespec());\
269  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(tic_timer.back()));
270 
271  #else
272 
273  #include <sys/time.h>
274 
275  namespace {
276 
277  inline double tic_toc_diff_num(timeval const & tic)
278  {
279  timeval toc;
280  gettimeofday(&toc, NULL);
281  return ((toc.tv_sec*1000.0 + toc.tv_usec/1000.0) -
282  (tic.tv_sec*1000.0 + tic.tv_usec/1000.0));
283  }
284 
285  inline std::string tic_toc_diff_string(timeval const & tic)
286  {
287  double diff = tic_toc_diff_num(tic);
288  std::stringstream s;
289  s << diff << " msec";
290  return s.str();
291  }
292 
293  inline void tic_toc_diff(timeval const & tic)
294  {
295  std::cerr << tic_toc_diff_string(tic)<< std::endl;
296  }
297 
298  inline double tic_toc_diff_num(std::vector<timeval> & tic)
299  {
300  double res = tic_toc_diff_num(tic.back());
301  tic.pop_back();
302  return res;
303  }
304 
305  inline std::string tic_toc_diff_string(std::vector<timeval> & tic)
306  {
307  std::string res = tic_toc_diff_string(tic.back());
308  tic.pop_back();
309  return res;
310  }
311 
312  inline void tic_toc_diff(std::vector<timeval> & tic)
313  {
314  tic_toc_diff(tic.back());
315  tic.pop_back();
316  }
317 
318  } // unnamed namespace
319 
320  #define USETICTOC timeval tic_timer;
321  #define TIC gettimeofday (&tic_timer, NULL);
322  #define TOC tic_toc_diff (tic_timer);
323  #define TOCN tic_toc_diff_num (tic_timer)
324  #define TOCS tic_toc_diff_string(tic_timer)
325  #define USE_NESTED_TICTOC std::vector<timeval> tic_timer;
326  #define TICPUSH tic_timer.push_back(timeval());\
327  gettimeofday(&(tic_timer.back()), NULL);
328 
329  #endif // VIGRA_HIRES_TIMING
330 
331 #endif // _WIN32
332 
333 // TICTOCLOOP runs the body inner_repetitions times, and minimizes the result over a number of outer_repetitions runs,
334 // outputting the final minimal average to std::cerr
335 // We enclose the loop in a dummy do { ... } while(false) in order to make this a true single statement
336 // (instead of just a scope).
337 #define TICTOCLOOP_BEGIN(inner_repetitions,outer_repetitions) \
338  do { \
339  USETICTOC \
340  double tictoc_best_, tictoc_inner_repetitions_=inner_repetitions; size_t tictoc_outer_repetitions_=outer_repetitions; \
341  for (size_t tictoccounter_=0; tictoccounter_<tictoc_outer_repetitions_; ++tictoccounter_) { \
342  TIC \
343  for (size_t tictocinnercounter_=0; tictocinnercounter_<inner_repetitions; ++tictocinnercounter_) { \
344 
345 
346 #define TICTOCLOOP_END \
347  } \
348  const double tictoc_cur_ = TOCN; \
349  if ((tictoccounter_==0) || (tictoc_cur_ < tictoc_best_)) \
350  tictoc_best_ = tictoc_cur_; \
351  } \
352  std::cerr << tictoc_best_/tictoc_inner_repetitions_ \
353  << " msec (best-of-" << tictoc_outer_repetitions_ << ")" << std::endl; \
354  } while(false);
355 
356 
357 
358 #else // NDEBUG
359 
360 #define USETICTOC
361 #define TIC
362 #define TOC
363 #define TOCN 0.0
364 #define TICS ""
365 #define USE_NESTED_TICTOC
366 #define TICPUSH
367 #define TICTOCLOOP_BEGIN(inner_repetitions,outer_repetitions) do {
368 #define TICTOCLOOP_END } while(false);
369 #endif // NDEBUG
370 
371 
372 
373 #endif // VIGRA_TIMING_HXX

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.9.0 (Wed Feb 27 2013)