[ 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  std::cerr << tic_toc_diff_string(tic) <<std::endl;
176  }
177 
178  inline double tic_toc_diff_num(std::vector<LARGE_INTEGER> & tic)
179  {
180  double res = tic_toc_diff_num(tic.back());
181  tic.pop_back();
182  return res;
183  }
184 
185  inline std::string tic_toc_diff_string(std::vector<LARGE_INTEGER> & tic)
186  {
187  std::string res = tic_toc_diff_string(tic.back());
188  tic.pop_back();
189  return res;
190  }
191 
192  inline void tic_toc_diff(std::vector<LARGE_INTEGER> & tic)
193  {
194  tic_toc_diff(tic.back());
195  tic.pop_back();
196  }
197 
198  } // unnamed namespace
199 
200  #define USETICTOC LARGE_INTEGER tic_timer;
201  #define USE_NESTED_TICTOC std::vector<LARGE_INTEGER> tic_timer;
202  #define TIC QueryPerformanceCounter(&tic_timer);
203  #define TICPUSH tic_timer.push_back(LARGE_INTEGER());\
204  QueryPerformanceCounter(&(tic_timer.back()));
205  #define TOC tic_toc_diff (tic_timer);
206  #define TOCN tic_toc_diff_num (tic_timer)
207  #define TOCS tic_toc_diff_string(tic_timer)
208 
209 #else
210 
211  #if defined(VIGRA_HIRES_TIMING) && !defined(__CYGWIN__)
212  // requires linking against librt
213 
214  #include <time.h>
215 
216  namespace {
217 
218  inline double tic_toc_diff_num(timespec const & tic)
219  {
220  timespec toc;
221  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &toc);
222  return ((toc.tv_sec*1000.0 + toc.tv_nsec/1000000.0) -
223  (tic.tv_sec*1000.0 + tic.tv_nsec/1000000.0));
224  }
225 
226  inline std::string tic_toc_diff_string(timespec const & tic)
227  {
228  double diff = tic_toc_diff_num(tic);
229  std::stringstream s;
230  s << diff << " msec";
231  return s.str();
232  }
233 
234  inline void tic_toc_diff(timespec const & tic)
235  {
236  std::cerr << tic_toc_diff_string(tic) << std::endl;
237  }
238 
239  inline double tic_toc_diff_num(std::vector<timespec> & tic)
240  {
241  double res = tic_toc_diff_num(tic.back());
242  tic.pop_back();
243  return res;
244  }
245 
246  inline std::string tic_toc_diff_string(std::vector<timespec> & tic)
247  {
248  std::string res = tic_toc_diff_string(tic.back());
249  tic.pop_back();
250  return res;
251  }
252 
253  inline void tic_toc_diff(std::vector<timespec> & tic)
254  {
255  tic_toc_diff(tic.back());
256  tic.pop_back();
257  }
258 
259  } // unnamed namespace
260 
261  #define USETICTOC timespec tic_timer;
262  #define TIC clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tic_timer);
263  #define TOC tic_toc_diff (tic_timer);
264  #define TOCN tic_toc_diff_num (tic_timer)
265  #define TOCS tic_toc_diff_string(tic_timer)
266  #define USE_NESTED_TICTOC std::vector<timespec> tic_timer;
267  #define TICPUSH tic_timer.push_back(timespec());\
268  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(tic_timer.back()));
269 
270  #else
271 
272  #include <sys/time.h>
273 
274  namespace {
275 
276  inline double tic_toc_diff_num(timeval const & tic)
277  {
278  timeval toc;
279  gettimeofday(&toc, NULL);
280  return ((toc.tv_sec*1000.0 + toc.tv_usec/1000.0) -
281  (tic.tv_sec*1000.0 + tic.tv_usec/1000.0));
282  }
283 
284  inline std::string tic_toc_diff_string(timeval const & tic)
285  {
286  double diff = tic_toc_diff_num(tic);
287  std::stringstream s;
288  s << diff << " msec";
289  return s.str();
290  }
291 
292  inline void tic_toc_diff(timeval const & tic)
293  {
294  std::cerr << tic_toc_diff_string(tic)<< std::endl;
295  }
296 
297  inline double tic_toc_diff_num(std::vector<timeval> & tic)
298  {
299  double res = tic_toc_diff_num(tic.back());
300  tic.pop_back();
301  return res;
302  }
303 
304  inline std::string tic_toc_diff_string(std::vector<timeval> & tic)
305  {
306  std::string res = tic_toc_diff_string(tic.back());
307  tic.pop_back();
308  return res;
309  }
310 
311  inline void tic_toc_diff(std::vector<timeval> & tic)
312  {
313  tic_toc_diff(tic.back());
314  tic.pop_back();
315  }
316 
317  } // unnamed namespace
318 
319  #define USETICTOC timeval tic_timer;
320  #define TIC gettimeofday (&tic_timer, NULL);
321  #define TOC tic_toc_diff (tic_timer);
322  #define TOCN tic_toc_diff_num (tic_timer)
323  #define TOCS tic_toc_diff_string(tic_timer)
324  #define USE_NESTED_TICTOC std::vector<timeval> tic_timer;
325  #define TICPUSH tic_timer.push_back(timeval());\
326  gettimeofday(&(tic_timer.back()), NULL);
327 
328  #endif // VIGRA_HIRES_TIMING
329 
330 #endif // WIN32
331 
332 // TICTOCLOOP runs the body inner_repetitions times, and minimizes the result over a number of outer_repetitions runs,
333 // outputting the final minimal average to std::cerr
334 #define TICTOCLOOP_BEGIN(inner_repetitions,outer_repetitions) \
335  { \
336  USETICTOC \
337  double tictoc_best_, tictoc_inner_repetitions_=inner_repetitions; size_t tictoc_outer_repetitions_=outer_repetitions; \
338  for (size_t tictoccounter_=0; tictoccounter_<tictoc_outer_repetitions_; ++tictoccounter_) { \
339  TIC \
340  for (size_t tictocinnercounter_=0; tictocinnercounter_<inner_repetitions; ++tictocinnercounter_) { \
341 
342 
343 #define TICTOCLOOP_END \
344  } \
345  const double tictoc_cur_ = TOCN; \
346  if ((tictoccounter_==0) || (tictoc_cur_ < tictoc_best_)) \
347  tictoc_best_ = tictoc_cur_; \
348  } \
349  std::cerr << tictoc_best_/tictoc_inner_repetitions_ \
350  << " msec (best-of-" << tictoc_outer_repetitions_ << ")" << std::endl; \
351  }\
352 
353 
354 
355 #else // NDEBUG
356 
357 #define USETICTOC
358 #define TIC
359 #define TOC
360 #define TOCN 0.0
361 #define TICS ""
362 #define USE_NESTED_TICTOC
363 #define TICPUSH
364 #define TICTOCLOOP_BEGIN {
365 #define TICTOCLOOP_END }
366 #endif // NDEBUG
367 
368 
369 
370 #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.8.0 (Wed Sep 26 2012)