github.com/platonnetwork/platon-go@v0.7.6/cases/tool/win/bls_win/include/cybozu/benchmark.hpp (about) 1 #pragma once 2 /** 3 @file 4 @brief measure exec time of function 5 @author MITSUNARI Shigeo 6 */ 7 #if defined(_MSC_VER) && (MSC_VER <= 1500) 8 #include <cybozu/inttype.hpp> 9 #else 10 #include <stdint.h> 11 #endif 12 #include <stdio.h> 13 14 #ifdef __EMSCRIPTEN__ 15 #define CYBOZU_BENCH_USE_GETTIMEOFDAY 16 #endif 17 18 #ifdef CYBOZU_BENCH_USE_GETTIMEOFDAY 19 #include <sys/time.h> 20 #elif !defined(CYBOZU_BENCH_DONT_USE_RDTSC) 21 #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) 22 #define CYBOZU_BENCH_USE_RDTSC 23 #define CYBOZU_BENCH_USE_CPU_TIMER 24 #endif 25 #if defined(__GNUC__) && defined(__ARM_ARCH_7A__) 26 // #define CYBOZU_BENCH_USE_MRC 27 // #define CYBOZU_BENCH_USE_CPU_TIMER 28 #endif 29 #endif 30 31 32 #include <assert.h> 33 #include <time.h> 34 #ifdef _MSC_VER 35 #include <intrin.h> 36 #include <sys/timeb.h> 37 #else 38 #endif 39 40 #ifndef CYBOZU_UNUSED 41 #ifdef __GNUC__ 42 #define CYBOZU_UNUSED __attribute__((unused)) 43 #else 44 #define CYBOZU_UNUSED 45 #endif 46 #endif 47 48 namespace cybozu { 49 50 namespace bench { 51 52 static void (*g_putCallback)(double); 53 54 static inline void setPutCallback(void (*f)(double)) 55 { 56 g_putCallback = f; 57 } 58 59 } // cybozu::bench 60 61 class CpuClock { 62 public: 63 static inline uint64_t getCpuClk() 64 { 65 #ifdef CYBOZU_BENCH_USE_RDTSC 66 #ifdef _MSC_VER 67 return __rdtsc(); 68 #else 69 unsigned int eax, edx; 70 __asm__ volatile("rdtsc" : "=a"(eax), "=d"(edx)); 71 return ((uint64_t)edx << 32) | eax; 72 #endif 73 #elif defined(CYBOZU_BENCH_USE_MRC) 74 uint32_t clk; 75 __asm__ volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(clk)); 76 return clk; 77 #else 78 #ifdef _MSC_VER 79 struct _timeb timeb; 80 _ftime_s(&timeb); 81 return uint64_t(timeb.time) * 1000000000 + timeb.millitm * 1000000; 82 #elif defined(CYBOZU_BENCH_USE_GETTIMEOFDAY) 83 struct timeval tv; 84 int ret CYBOZU_UNUSED = gettimeofday(&tv, 0); 85 assert(ret == 0); 86 return uint64_t(tv.tv_sec) * 1000000000 + tv.tv_usec * 1000; 87 #else 88 struct timespec tp; 89 int ret CYBOZU_UNUSED = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); 90 assert(ret == 0); 91 return uint64_t(tp.tv_sec) * 1000000000 + tp.tv_nsec; 92 #endif 93 #endif 94 } 95 CpuClock() 96 : clock_(0) 97 , count_(0) 98 { 99 } 100 void begin() 101 { 102 clock_ -= getCpuClk(); 103 } 104 void end() 105 { 106 clock_ += getCpuClk(); 107 count_++; 108 } 109 int getCount() const { return count_; } 110 uint64_t getClock() const { return clock_; } 111 void clear() { count_ = 0; clock_ = 0; } 112 void put(const char *msg = 0, int N = 1) const 113 { 114 double t = getClock() / double(getCount()) / N; 115 if (msg && *msg) printf("%s ", msg); 116 if (bench::g_putCallback) { 117 bench::g_putCallback(t); 118 return; 119 } 120 #ifdef CYBOZU_BENCH_USE_CPU_TIMER 121 if (t > 1e6) { 122 printf("%7.3fMclk", t * 1e-6); 123 } else if (t > 1e3) { 124 printf("%7.3fKclk", t * 1e-3); 125 } else { 126 printf("%6.2f clk", t); 127 } 128 #else 129 if (t > 1e6) { 130 printf("%7.3fmsec", t * 1e-6); 131 } else if (t > 1e3) { 132 printf("%7.3fusec", t * 1e-3); 133 } else { 134 printf("%6.2fnsec", t); 135 } 136 #endif 137 if (msg && *msg) printf("\n"); 138 } 139 // adhoc constatns for CYBOZU_BENCH 140 #ifdef CYBOZU_BENCH_USE_CPU_TIMER 141 static const int loopN1 = 1000; 142 static const int loopN2 = 100; 143 static const uint64_t maxClk = (uint64_t)1e8; 144 #else 145 static const int loopN1 = 100; 146 static const int loopN2 = 100; 147 static const uint64_t maxClk = (uint64_t)1e8; 148 #endif 149 private: 150 uint64_t clock_; 151 int count_; 152 }; 153 154 namespace bench { 155 156 static CpuClock g_clk; 157 static int CYBOZU_UNUSED g_loopNum; 158 159 } // cybozu::bench 160 /* 161 loop counter is automatically determined 162 CYBOZU_BENCH(<msg>, <func>, <param1>, <param2>, ...); 163 if msg == "" then only set g_clk, g_loopNum 164 */ 165 #define CYBOZU_BENCH(msg, func, ...) \ 166 { \ 167 const uint64_t _cybozu_maxClk = cybozu::CpuClock::maxClk; \ 168 cybozu::CpuClock _cybozu_clk; \ 169 for (int _cybozu_i = 0; _cybozu_i < cybozu::CpuClock::loopN2; _cybozu_i++) { \ 170 _cybozu_clk.begin(); \ 171 for (int _cybozu_j = 0; _cybozu_j < cybozu::CpuClock::loopN1; _cybozu_j++) { func(__VA_ARGS__); } \ 172 _cybozu_clk.end(); \ 173 if (_cybozu_clk.getClock() > _cybozu_maxClk) break; \ 174 } \ 175 if (msg && *msg) _cybozu_clk.put(msg, cybozu::CpuClock::loopN1); \ 176 cybozu::bench::g_clk = _cybozu_clk; cybozu::bench::g_loopNum = cybozu::CpuClock::loopN1; \ 177 } 178 179 /* 180 double clk; 181 CYBOZU_BENCH_T(clk, <func>, <param1>, <param2>, ...); 182 clk is set by CYBOZU_BENCH_T 183 */ 184 #define CYBOZU_BENCH_T(clk, func, ...) \ 185 { \ 186 const uint64_t _cybozu_maxClk = cybozu::CpuClock::maxClk; \ 187 cybozu::CpuClock _cybozu_clk; \ 188 for (int _cybozu_i = 0; _cybozu_i < cybozu::CpuClock::loopN2; _cybozu_i++) { \ 189 _cybozu_clk.begin(); \ 190 for (int _cybozu_j = 0; _cybozu_j < cybozu::CpuClock::loopN1; _cybozu_j++) { func(__VA_ARGS__); } \ 191 _cybozu_clk.end(); \ 192 if (_cybozu_clk.getClock() > _cybozu_maxClk) break; \ 193 } \ 194 clk = _cybozu_clk.getClock() / (double)_cybozu_clk.getCount() / cybozu::CpuClock::loopN1; \ 195 } 196 197 /* 198 loop counter N is given 199 CYBOZU_BENCH_C(<msg>, <counter>, <func>, <param1>, <param2>, ...); 200 if msg == "" then only set g_clk, g_loopNum 201 */ 202 #define CYBOZU_BENCH_C(msg, _N, func, ...) \ 203 { \ 204 cybozu::CpuClock _cybozu_clk; \ 205 _cybozu_clk.begin(); \ 206 for (int _cybozu_j = 0; _cybozu_j < _N; _cybozu_j++) { func(__VA_ARGS__); } \ 207 _cybozu_clk.end(); \ 208 if (msg && *msg) _cybozu_clk.put(msg, _N); \ 209 cybozu::bench::g_clk = _cybozu_clk; cybozu::bench::g_loopNum = _N; \ 210 } 211 212 } // cybozu