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