Home | History | Annotate | Download | only in bench
      1 // This file is part of Eigen, a lightweight C++ template library
      2 // for linear algebra.
      3 //
      4 // Copyright (C) 2008-2010 Gael Guennebaud <gael.guennebaud (at) inria.fr>
      5 // Copyright (C) 2009 Benoit Jacob <jacob.benoit.1 (at) gmail.com>
      6 //
      7 // This Source Code Form is subject to the terms of the Mozilla
      8 // Public License v. 2.0. If a copy of the MPL was not distributed
      9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
     10 
     11 #ifndef EIGEN_BENCH_TIMERR_H
     12 #define EIGEN_BENCH_TIMERR_H
     13 
     14 #if defined(_WIN32) || defined(__CYGWIN__)
     15 # ifndef NOMINMAX
     16 #   define NOMINMAX
     17 #   define EIGEN_BT_UNDEF_NOMINMAX
     18 # endif
     19 # ifndef WIN32_LEAN_AND_MEAN
     20 #   define WIN32_LEAN_AND_MEAN
     21 #   define EIGEN_BT_UNDEF_WIN32_LEAN_AND_MEAN
     22 # endif
     23 # include <windows.h>
     24 #elif defined(__APPLE__)
     25 #include <mach/mach_time.h>
     26 #else
     27 # include <unistd.h>
     28 #endif
     29 
     30 static void escape(void *p) {
     31   asm volatile("" : : "g"(p) : "memory");
     32 }
     33 
     34 static void clobber() {
     35   asm volatile("" : : : "memory");
     36 }
     37 
     38 #include <Eigen/Core>
     39 
     40 namespace Eigen
     41 {
     42 
     43 enum {
     44   CPU_TIMER = 0,
     45   REAL_TIMER = 1
     46 };
     47 
     48 /** Elapsed time timer keeping the best try.
     49   *
     50   * On POSIX platforms we use clock_gettime with CLOCK_PROCESS_CPUTIME_ID.
     51   * On Windows we use QueryPerformanceCounter
     52   *
     53   * Important: on linux, you must link with -lrt
     54   */
     55 class BenchTimer
     56 {
     57 public:
     58 
     59   BenchTimer()
     60   {
     61 #if defined(_WIN32) || defined(__CYGWIN__)
     62     LARGE_INTEGER freq;
     63     QueryPerformanceFrequency(&freq);
     64     m_frequency = (double)freq.QuadPart;
     65 #endif
     66     reset();
     67   }
     68 
     69   ~BenchTimer() {}
     70 
     71   inline void reset()
     72   {
     73     m_bests.fill(1e9);
     74     m_worsts.fill(0);
     75     m_totals.setZero();
     76   }
     77   inline void start()
     78   {
     79     m_starts[CPU_TIMER]  = getCpuTime();
     80     m_starts[REAL_TIMER] = getRealTime();
     81   }
     82   inline void stop()
     83   {
     84     m_times[CPU_TIMER] = getCpuTime() - m_starts[CPU_TIMER];
     85     m_times[REAL_TIMER] = getRealTime() - m_starts[REAL_TIMER];
     86     #if EIGEN_VERSION_AT_LEAST(2,90,0)
     87     m_bests = m_bests.cwiseMin(m_times);
     88     m_worsts = m_worsts.cwiseMax(m_times);
     89     #else
     90     m_bests(0) = std::min(m_bests(0),m_times(0));
     91     m_bests(1) = std::min(m_bests(1),m_times(1));
     92     m_worsts(0) = std::max(m_worsts(0),m_times(0));
     93     m_worsts(1) = std::max(m_worsts(1),m_times(1));
     94     #endif
     95     m_totals += m_times;
     96   }
     97 
     98   /** Return the elapsed time in seconds between the last start/stop pair
     99     */
    100   inline double value(int TIMER = CPU_TIMER) const
    101   {
    102     return m_times[TIMER];
    103   }
    104 
    105   /** Return the best elapsed time in seconds
    106     */
    107   inline double best(int TIMER = CPU_TIMER) const
    108   {
    109     return m_bests[TIMER];
    110   }
    111 
    112   /** Return the worst elapsed time in seconds
    113     */
    114   inline double worst(int TIMER = CPU_TIMER) const
    115   {
    116     return m_worsts[TIMER];
    117   }
    118 
    119   /** Return the total elapsed time in seconds.
    120     */
    121   inline double total(int TIMER = CPU_TIMER) const
    122   {
    123     return m_totals[TIMER];
    124   }
    125 
    126   inline double getCpuTime() const
    127   {
    128 #ifdef _WIN32
    129     LARGE_INTEGER query_ticks;
    130     QueryPerformanceCounter(&query_ticks);
    131     return query_ticks.QuadPart/m_frequency;
    132 #elif __APPLE__
    133     return double(mach_absolute_time())*1e-9;
    134 #else
    135     timespec ts;
    136     clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
    137     return double(ts.tv_sec) + 1e-9 * double(ts.tv_nsec);
    138 #endif
    139   }
    140 
    141   inline double getRealTime() const
    142   {
    143 #ifdef _WIN32
    144     SYSTEMTIME st;
    145     GetSystemTime(&st);
    146     return (double)st.wSecond + 1.e-3 * (double)st.wMilliseconds;
    147 #elif __APPLE__
    148     return double(mach_absolute_time())*1e-9;
    149 #else
    150     timespec ts;
    151     clock_gettime(CLOCK_REALTIME, &ts);
    152     return double(ts.tv_sec) + 1e-9 * double(ts.tv_nsec);
    153 #endif
    154   }
    155 
    156 protected:
    157 #if defined(_WIN32) || defined(__CYGWIN__)
    158   double m_frequency;
    159 #endif
    160   Vector2d m_starts;
    161   Vector2d m_times;
    162   Vector2d m_bests;
    163   Vector2d m_worsts;
    164   Vector2d m_totals;
    165 
    166 public:
    167   EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    168 };
    169 
    170 #define BENCH(TIMER,TRIES,REP,CODE) { \
    171     TIMER.reset(); \
    172     for(int uglyvarname1=0; uglyvarname1<TRIES; ++uglyvarname1){ \
    173       TIMER.start(); \
    174       for(int uglyvarname2=0; uglyvarname2<REP; ++uglyvarname2){ \
    175         CODE; \
    176       } \
    177       TIMER.stop(); \
    178       clobber(); \
    179     } \
    180   }
    181 
    182 }
    183 
    184 // clean #defined tokens
    185 #ifdef EIGEN_BT_UNDEF_NOMINMAX
    186 # undef EIGEN_BT_UNDEF_NOMINMAX
    187 # undef NOMINMAX
    188 #endif
    189 
    190 #ifdef EIGEN_BT_UNDEF_WIN32_LEAN_AND_MEAN
    191 # undef EIGEN_BT_UNDEF_WIN32_LEAN_AND_MEAN
    192 # undef WIN32_LEAN_AND_MEAN
    193 #endif
    194 
    195 #endif // EIGEN_BENCH_TIMERR_H
    196