[ 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 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.0 (Fri May 19 2017)