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

vigra/timing.hxx |

Go to the documentation of this file.

    00001 /************************************************************************/
    00002 /*                                                                      */
    00003 /*               Copyright 2008-2011 by Ullrich Koethe                  */
    00004 /*       Cognitive Systems Group, University of Hamburg, Germany        */
    00005 /*                                                                      */
    00006 /*    This file is part of the VIGRA computer vision library.           */
    00007 /*    The VIGRA Website is                                              */
    00008 /*        http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/      */
    00009 /*    Please direct questions, bug reports, and contributions to        */
    00010 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
    00011 /*        vigra@informatik.uni-hamburg.de                               */
    00012 /*                                                                      */
    00013 /*    Permission is hereby granted, free of charge, to any person       */
    00014 /*    obtaining a copy of this software and associated documentation    */
    00015 /*    files (the "Software"), to deal in the Software without           */
    00016 /*    restriction, including without limitation the rights to use,      */
    00017 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
    00018 /*    sell copies of the Software, and to permit persons to whom the    */
    00019 /*    Software is furnished to do so, subject to the following          */
    00020 /*    conditions:                                                       */
    00021 /*                                                                      */
    00022 /*    The above copyright notice and this permission notice shall be    */
    00023 /*    included in all copies or substantial portions of the             */
    00024 /*    Software.                                                         */
    00025 /*                                                                      */
    00026 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
    00027 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
    00028 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
    00029 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
    00030 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
    00031 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
    00032 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
    00033 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
    00034 /*                                                                      */
    00035 /************************************************************************/
    00036
    00037
    00038 #ifndef VIGRA_TIMING_HXX
    00039 #define VIGRA_TIMING_HXX
    00040 #ifndef VIGRA_NO_TIMING
    00041
    00042 #include <iostream>
    00043 #include <sstream>
    00044 #include <vector>
    00045
    00046 /*! \page TimingMacros  Timing macros for runtime measurements
    00047
    00048     <b>\#include</b> <vigra/timing.hxx>
    00049
    00050     These macros allow to perform execution speed measurements. Results are reported
    00051     in <i>milliseconds</i>.
    00052     However, note that timings below 1 msec are generally subject to round-off errors.
    00053     Under LINUX, you can \#define VIGRA_HIRES_TIMING to get better
    00054     accuracy, but this requires linking against librt.
    00055
    00056 Basic usage:
    00057 \code
    00058    void time_it()
    00059    {
    00060        USETICTOC
    00061
    00062        TIC
    00063         ...    code to be timed
    00064        TOC
    00065         ...    untimed code
    00066        TIC
    00067         ...    other code to be timed
    00068        TOC
    00069    }
    00070 \endcode
    00071
    00072    Instead of TOC, which outputs the time difference to std::cerr,
    00073    you may use TOCN (the time difference in <i>msec</i> as a double)
    00074    or TOCS (the time difference as a std::string).
    00075
    00076    Alternatively, you can perform nested timing like so:
    00077 \code
    00078    void time_it()
    00079    {
    00080        USE_NESTED_TICTOC
    00081
    00082        TICPUSH
    00083         ...         code to be timed
    00084            TICPUSH
    00085             ...         nested code to be timed
    00086            TOC          print time for nested code
    00087         ...         more code to be timed
    00088        TOC          print total time
    00089    }
    00090 \endcode
    00091
    00092 */
    00093
    00094 /*! \file timing.hxx  Timing macros for runtime measurements
    00095
    00096   This header defines timing macros for runtime measurements. See \ref TimingMacros for examples.
    00097
    00098   \def USETICTOC
    00099   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.
    00100   \hideinitializer
    00101
    00102   \def USE_NESTED_TICTOC
    00103   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.
    00104   \hideinitializer
    00105
    00106   \def TIC
    00107   Start timing. Requires USE_TICTOC to be defined in the current context.
    00108   \hideinitializer
    00109
    00110   \def TOC
    00111   Stop timing and output result (the time difference w.r.t. the last TIC or TICPUSH
    00112   instance) to std::cerr.
    00113   \hideinitializer
    00114
    00115   \def TICPUSH
    00116   Start timing, possibly a nested block of code within some other timed code block.
    00117   Requires USE_NESTED_TICTOC to be defined once in the current context.
    00118   \hideinitializer
    00119
    00120   \def TOCN
    00121   Stop timing. This macro evaluates to the time difference (w.r.t. the last TIC
    00122   or TICPUSH) in msec as a double.
    00123   \hideinitializer
    00124
    00125   \def TOCS
    00126   Stop timing. This macro evaluates to the time difference (w.r.t. the last TIC
    00127   or TICPUSH) as a std::string (including units).
    00128   \hideinitializer
    00129
    00130   \def TICTOCLOOP_BEGIN(inner_repetitions,outer_repetitions)
    00131   Executes the code block up to TICTOCLOOP_END outer_repetitions x
    00132   inner_repetitions times. The measurement is averaged over the
    00133   inner_repetitions, and the best result of the outer_repetitions is
    00134   reported to std::cerr.
    00135   \hideinitializer
    00136
    00137   \def TICTOCLOOP_END
    00138   Ends the timing loop started with the TICTOCLOOP_BEGIN macro
    00139   and outputs the result.
    00140   \hideinitializer
    00141 */
    00142
    00143
    00144 #ifdef _WIN32
    00145
    00146     #include "windows.h"
    00147
    00148     namespace {
    00149
    00150     inline double queryTimerUnit()
    00151     {
    00152         LARGE_INTEGER frequency;
    00153         QueryPerformanceFrequency(&frequency);
    00154         return 1000.0 / frequency.QuadPart;
    00155     }
    00156
    00157     inline double tic_toc_diff_num(LARGE_INTEGER const & tic)
    00158     {
    00159         LARGE_INTEGER toc;
    00160         QueryPerformanceCounter(&toc);
    00161         static double unit = queryTimerUnit();
    00162         return ((toc.QuadPart - tic.QuadPart) * unit);
    00163     }
    00164
    00165     inline std::string tic_toc_diff_string(LARGE_INTEGER const & tic)
    00166     {
    00167         double diff = tic_toc_diff_num(tic);
    00168         std::stringstream s;
    00169         s << diff << " msec";
    00170         return s.str();
    00171     }
    00172
    00173     inline void tic_toc_diff(LARGE_INTEGER const & tic)
    00174     {
    00175         double diff = tic_toc_diff_num(tic);
    00176         std::cerr << diff << " msec" << std::endl;
    00177     }
    00178
    00179     inline double tic_toc_diff_num(std::vector<LARGE_INTEGER> & tic)
    00180     {
    00181         double res = tic_toc_diff_num(tic.back());
    00182         tic.pop_back();
    00183         return res;
    00184     }
    00185
    00186     inline std::string tic_toc_diff_string(std::vector<LARGE_INTEGER> & tic)
    00187     {
    00188         std::string res = tic_toc_diff_string(tic.back());
    00189         tic.pop_back();
    00190         return res;
    00191     }
    00192
    00193     inline void tic_toc_diff(std::vector<LARGE_INTEGER> & tic)
    00194     {
    00195         tic_toc_diff(tic.back());
    00196         tic.pop_back();
    00197     }
    00198
    00199     } // unnamed namespace
    00200
    00201     #define USETICTOC LARGE_INTEGER tic_timer;
    00202     #define USE_NESTED_TICTOC std::vector<LARGE_INTEGER> tic_timer;
    00203     #define TIC QueryPerformanceCounter(&tic_timer);
    00204     #define TICPUSH tic_timer.push_back(LARGE_INTEGER());\
    00205                     QueryPerformanceCounter(&(tic_timer.back()));
    00206     #define TOC  tic_toc_diff       (tic_timer);
    00207     #define TOCN tic_toc_diff_num   (tic_timer)
    00208     #define TOCS tic_toc_diff_string(tic_timer)
    00209
    00210 #else
    00211
    00212     #if defined(VIGRA_HIRES_TIMING) && !defined(__CYGWIN__)
    00213         // requires linking against librt
    00214
    00215         #include <time.h>
    00216
    00217         namespace {
    00218
    00219         inline double tic_toc_diff_num(timespec const & tic)
    00220         {
    00221             timespec toc;
    00222             clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &toc);
    00223             return ((toc.tv_sec*1000.0 + toc.tv_nsec/1000000.0) -
    00224                   (tic.tv_sec*1000.0 + tic.tv_nsec/1000000.0));
    00225         }
    00226
    00227         inline std::string tic_toc_diff_string(timespec const & tic)
    00228         {
    00229             double diff = tic_toc_diff_num(tic);
    00230             std::stringstream s;
    00231             s << diff << " msec";
    00232             return s.str();
    00233         }
    00234
    00235         inline void tic_toc_diff(timespec const & tic)
    00236         {
    00237             std::cerr << tic_toc_diff_string(tic) << std::endl;
    00238         }
    00239
    00240         inline double tic_toc_diff_num(std::vector<timespec> & tic)
    00241         {
    00242             double res = tic_toc_diff_num(tic.back());
    00243             tic.pop_back();
    00244             return res;
    00245         }
    00246
    00247         inline std::string tic_toc_diff_string(std::vector<timespec> & tic)
    00248         {
    00249             std::string res = tic_toc_diff_string(tic.back());
    00250             tic.pop_back();
    00251             return res;
    00252         }
    00253
    00254         inline void tic_toc_diff(std::vector<timespec> & tic)
    00255         {
    00256             tic_toc_diff(tic.back());
    00257             tic.pop_back();
    00258         }
    00259
    00260         } // unnamed namespace
    00261
    00262         #define USETICTOC timespec tic_timer;
    00263         #define TIC clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tic_timer);
    00264         #define TOC  tic_toc_diff       (tic_timer);
    00265         #define TOCN tic_toc_diff_num   (tic_timer)
    00266         #define TOCS tic_toc_diff_string(tic_timer)
    00267         #define USE_NESTED_TICTOC std::vector<timespec> tic_timer;
    00268         #define TICPUSH tic_timer.push_back(timespec());\
    00269                         clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(tic_timer.back()));
    00270
    00271     #else
    00272
    00273         #include <sys/time.h>
    00274
    00275         namespace {
    00276
    00277         inline double tic_toc_diff_num(timeval const & tic)
    00278         {
    00279             timeval toc;
    00280             gettimeofday(&toc, NULL);
    00281             return  ((toc.tv_sec*1000.0 + toc.tv_usec/1000.0) -
    00282                         (tic.tv_sec*1000.0 + tic.tv_usec/1000.0));
    00283         }
    00284
    00285         inline std::string tic_toc_diff_string(timeval const & tic)
    00286         {
    00287             double diff = tic_toc_diff_num(tic);
    00288             std::stringstream s;
    00289             s << diff << " msec";
    00290             return s.str();
    00291         }
    00292
    00293         inline void tic_toc_diff(timeval const & tic)
    00294         {
    00295             std::cerr << tic_toc_diff_string(tic)<< std::endl;
    00296         }
    00297
    00298         inline double tic_toc_diff_num(std::vector<timeval> & tic)
    00299         {
    00300             double res = tic_toc_diff_num(tic.back());
    00301             tic.pop_back();
    00302             return res;
    00303         }
    00304
    00305         inline std::string tic_toc_diff_string(std::vector<timeval> & tic)
    00306         {
    00307             std::string res = tic_toc_diff_string(tic.back());
    00308             tic.pop_back();
    00309             return res;
    00310         }
    00311
    00312         inline void tic_toc_diff(std::vector<timeval> & tic)
    00313         {
    00314             tic_toc_diff(tic.back());
    00315             tic.pop_back();
    00316         }
    00317
    00318         } // unnamed namespace
    00319
    00320         #define USETICTOC timeval tic_timer;
    00321         #define TIC  gettimeofday       (&tic_timer, NULL);
    00322         #define TOC  tic_toc_diff       (tic_timer);
    00323         #define TOCN tic_toc_diff_num   (tic_timer)
    00324         #define TOCS tic_toc_diff_string(tic_timer)
    00325         #define USE_NESTED_TICTOC std::vector<timeval> tic_timer;
    00326         #define TICPUSH tic_timer.push_back(timeval());\
    00327                         gettimeofday(&(tic_timer.back()), NULL);
    00328
    00329     #endif // VIGRA_HIRES_TIMING
    00330
    00331 #endif // _WIN32
    00332
    00333 // TICTOCLOOP runs the body inner_repetitions times, and minimizes the result over a number of outer_repetitions runs,
    00334 //  outputting the final minimal average to std::cerr
    00335 // We enclose the loop in a dummy do { ... } while(false) in order to make this a true single statement
    00336 //  (instead of just a scope).
    00337 #define TICTOCLOOP_BEGIN(inner_repetitions,outer_repetitions) \
    00338     do { \
    00339     USETICTOC \
    00340         double tictoc_best_, tictoc_inner_repetitions_=inner_repetitions; size_t tictoc_outer_repetitions_=outer_repetitions; \
    00341         for (size_t tictoccounter_=0; tictoccounter_<tictoc_outer_repetitions_; ++tictoccounter_) { \
    00342         TIC \
    00343         for (size_t tictocinnercounter_=0; tictocinnercounter_<inner_repetitions; ++tictocinnercounter_) { \
    00344
    00345
    00346 #define TICTOCLOOP_END \
    00347                 } \
    00348         const double tictoc_cur_ = TOCN; \
    00349                 if ((tictoccounter_==0) || (tictoc_cur_ < tictoc_best_)) \
    00350             tictoc_best_ = tictoc_cur_; \
    00351         } \
    00352         std::cerr << tictoc_best_/tictoc_inner_repetitions_ \
    00353              << " msec (best-of-" << tictoc_outer_repetitions_ << ")" << std::endl; \
    00354     } while(false);
    00355
    00356
    00357
    00358 #else // NDEBUG
    00359
    00360 #define USETICTOC
    00361 #define TIC
    00362 #define TOC
    00363 #define TOCN 0.0
    00364 #define TICS ""
    00365 #define USE_NESTED_TICTOC
    00366 #define TICPUSH
    00367 #define TICTOCLOOP_BEGIN(inner_repetitions,outer_repetitions)  do {
    00368 #define TICTOCLOOP_END } while(false);
    00369 #endif // NDEBUG
    00370
    00371
    00372
    00373 #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 (Tue Nov 6 2012)