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