#ifndef ET_TIMER_H #define ET_TIMER_H #include #include #include #include /** * \file Timer.h A flexible toolset for timing pieces of code. */ #ifdef _MSC_VER # include # pragma intrinsic(__rdtsc) #endif #ifndef ET_TIMER_RESULT_VAR #error undefined ET_TIMER_RESULT_VAR /** * This macro provides the name of a result variable to the Timer tools. * The user must define it BEFORE including et/Timer.h. E.g. * ~~~ #define ET_TIMER_RESULT_VAR_TYPE float* #define ET_TIMER_RESULT_VAR a * ~~~ */ #define ET_TIMER_RESULT_VAR #endif #ifndef ET_TIMER_RESULT_VAR_TYPE #error undefined ET_TIMER_RESULT_VAR_TYPE /** * The user must define this macro to provide the type of the result variable * (#ET_TIMER_RESULT_VAR) to the Timer tools. * ~~~ #define ET_TIMER_RESULT_VAR_TYPE float* #define ET_TIMER_RESULT_VAR a * ~~~ */ #define ET_TIMER_RESULT_VAR_TYPE #endif #ifdef DEBUG # pragma message("DEBUG DEFINED") # define NEVER_TRUE k%kPrint==0 #else # define NEVER_TRUE k%kPrint==-1 #endif /** * Convenient macro to time a piece of code. * Use this macro to time a piece of code and print the results * \param TITLE descriptive string for the piece of code to be timed * \param CODE code to be timed * \param NREPS request timing for NREPS repetitions of CODE * \param PRINT timing results are printed if PRINT is convertible to true * * E.g. this times a for loop that writes "Hello" ten times, repeating it 100 times, and prints * results with title "10 x Hello": ~~~ ET_TIME_THIS( "10 x Hello", , for(int i=0; i<10; ++i) { std::cout << "Hello" << std::endl; } , 100 , true ) ~~~ \remark If the macro ET_NO_TIMING is defined the code is not timed, only executed. */ #ifndef ET_NO_TIMING #define ET_TIME_THIS( TITLE, CODE, NREPS, PRINT ) \ { \ ET::Timer timer; \ size_t kPrint=( NREPS<10 ? 1 : NREPS/10 ); \ if( NREPS>1 ) { \ timer.start(); \ for( int k=0; k chrono_start_, chrono_end_; static std::vector title_list; // title of each run static std::vector cycles_list; // #cycles of each run static std::vector seconds_list; // #seconds of each run static std::vector repeats_list; // #repetitions of each run }; //----------------------------------------------------------------------------- void Timer::print_i( int i, std::ostream & o, int iSpeedupRef ) { o<< title_list[i]<<" : " << cycles_list[i]/repeats_list[i]<<" cycles/repetition, "<cycles() ); seconds_list.push_back( this->seconds() ); repeats_list.push_back( nreps ); } //----------------------------------------------------------------------------- double Timer::GHz( int i ) { return 1.e-9*cycles_list[i]/seconds_list[i]; } //----------------------------------------------------------------------------- void Timer::reset() { title_list.clear(); cycles_list.clear(); seconds_list.clear(); repeats_list.clear(); } //----------------------------------------------------------------------------- inline void Timer::start() { this->chrono_start_ = std::chrono::system_clock::now(); #ifdef VC_IMPL_MIC asm volatile("xor %%eax,%%eax\n\tcpuid\n\trdtsc" : "=a"(m_start.b[0]), "=d"(m_start.b[1]) :: "ebx", "ecx" ); #elif defined _MSC_VER unsigned int tmp; m_start.a = __rdtscp(&tmp); #else asm volatile("rdtscp" : "=a"(m_start.b[0]), "=d"(m_start.b[1]) :: "ecx" ); #endif } inline void Timer::stop() { #ifdef VC_IMPL_MIC asm volatile("xor %%eax,%%eax\n\tcpuid\n\trdtsc" : "=a"(m_end.b[0]), "=d"(m_end.b[1]) :: "ebx", "ecx" ); #elif defined _MSC_VER unsigned int tmp; m_end.a = __rdtscp(&tmp); #else asm volatile("rdtscp" : "=a"(m_end.b[0]), "=d"(m_end.b[1]) :: "ecx" ); #endif this->chrono_end_ = std::chrono::system_clock::now(); } inline unsigned long long Timer::cycles() const { return m_end.a - m_start.a; } inline double Timer::seconds() const { std::chrono::duration duration = this->chrono_end_ - this->chrono_start_; return duration.count(); } //----------------------------------------------------------------------------- // should be in a .cpp file actually, but then it should become a library. std::vector Timer::title_list; std::vector Timer::cycles_list; std::vector Timer::seconds_list; std::vector Timer::repeats_list; size_t Timer::speedupReference = 0; //----------------------------------------------------------------------------- } #endif /* ET_TIMER_H */