[ 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 #include "vigra/windows.h"
146
147 namespace {
148
149 inline double queryTimerUnit()
150 {
151 LARGE_INTEGER frequency;
152 QueryPerformanceFrequency(&frequency);
153 return 1000.0 / frequency.QuadPart;
154 }
155
156 static const double timerUnit = queryTimerUnit();
157
158 inline double tic_toc_diff_num(LARGE_INTEGER const & tic)
159 {
160 LARGE_INTEGER toc;
161 QueryPerformanceCounter(&toc);
162 return ((toc.QuadPart - tic.QuadPart) * timerUnit);
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.12.2