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

timing.hxx VIGRA

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