#include "tstopwatch.h" #include #ifdef _WIN32 #include #else //_WIN32 #if defined(__APPLE_CC__) #include #else #include #endif #include #include #include #include #ifndef STW_TICKS_PER_SECOND #ifndef _WIN32 extern "C" long sysconf(int); #define STW_TICKS_PER_SECOND sysconf(_SC_CLK_TCK) #else #define STW_TICKS_PER_SECOND CLK_TCK #endif #endif #endif #define MAXSWNAMELENGHT 40 #define MAXSWTIMELENGHT 12 TStopWatch TStopWatch::StopWatch[10]; enum TimerType { TTUUnknown, TTUHiRes, TTUTickCount }; static void determineTimer(); #ifdef _WIN32 static TimerType timerToUse = TTUUnknown; static LARGE_INTEGER perfFreq; // ticks per second static int perfFreqAdjust = 0; // in case Freq is too big static int overheadTicks = 0; // overhead in calling timer #else static TimerType timerToUse = TTUTickCount; #endif using namespace std; //----------------------------------------------------------- TStopWatch::TStopWatch(std::string name) : m_name(name), m_active(false), m_isRunning(false) { if (timerToUse == TTUUnknown) determineTimer(); m_start = 0; #ifdef _WIN32 m_startUser.dwHighDateTime = m_startUser.dwLowDateTime = 0; m_startSystem.dwHighDateTime = m_startSystem.dwLowDateTime = 0; #else m_startUser = 0; m_startSystem = 0; #endif //_WIN32 m_tm = 0; m_tmUser = 0; m_tmSystem = 0; } //----------------------------------------------------------- TStopWatch::~TStopWatch() { m_active = false; } //----------------------------------------------------------- void TStopWatch::setStartToCurrentTime() { #ifdef _WIN32 FILETIME creationTime, exitTime; BOOL ret = GetProcessTimes(GetCurrentProcess(), // specifies the process of interest &creationTime, &exitTime, &m_startSystem, &m_startUser); if (timerToUse == TTUTickCount) { m_start = GetTickCount(); } else { QueryPerformanceCounter(&m_hrStart); } #else struct tms clk; m_start = times(&clk); m_startUser = clk.tms_utime; m_startSystem = clk.tms_stime; #endif //_WIN32 } //----------------------------------------------------------- void TStopWatch::reset() { m_tm = 0; m_tmUser = 0; m_tmSystem = 0; setStartToCurrentTime(); } //----------------------------------------------------------- void TStopWatch::start(bool resetFlag) { if (resetFlag) reset(); if (m_isRunning) return; m_active = true; m_isRunning = true; setStartToCurrentTime(); } //----------------------------------------------------------- #ifdef _WIN32 inline __int64 FileTimeToInt64(LPFILETIME pFileTime) { __int64 val; val = pFileTime->dwHighDateTime; val <<= 32; val |= pFileTime->dwLowDateTime; return val; } #endif //_WIN32 //----------------------------------------------------------- // // Aggiunge il tempo trascorso fra start(startUser, startSystem) e l'istante // corrente // a tm(tmUser, tmSystem) // static void checkTime(START start, START_USER startUser, START_SYSTEM startSystem, TM_TOTAL &tm, TM_USER &tmUser, TM_SYSTEM &tmSystem) { assert(timerToUse == TTUTickCount); #ifdef _WIN32 DWORD tm_stop; FILETIME creationTime, exitTime, stopSystem, stopUser; BOOL ret = GetProcessTimes(GetCurrentProcess(), // specifies the process of interest &creationTime, &exitTime, &stopSystem, &stopUser); tm_stop = GetTickCount(); assert(tm_stop >= start); tm += tm_stop - start; // total elapsed time tmUser += FileTimeToInt64(&stopUser) - FileTimeToInt64(&startUser); // user elapsed time tmSystem += FileTimeToInt64(&stopSystem) - FileTimeToInt64(&startSystem); // system elapsed time #else // _WIN32 struct tms clk; clock_t tm_stop; tm_stop = times(&clk); assert(tm_stop >= start); tm += tm_stop - start; tmUser += clk.tms_utime - startUser; tmSystem += clk.tms_stime - startSystem; #endif // _WIN32 } //----------------------------------------------------------- #ifdef _WIN32 // // come checkTime, ma usa i timer ad alta risoluzione // namespace { //----------------------------------------------------------- void hrCheckTime(LARGE_INTEGER start, START_USER startUser, START_SYSTEM startSystem, TM_TOTAL &tm, TM_USER &tmUser, TM_SYSTEM &tmSystem) { assert(timerToUse != TTUTickCount); LARGE_INTEGER hrTm_stop; FILETIME creationTime, exitTime, stopSystem, stopUser; BOOL ret = GetProcessTimes(GetCurrentProcess(), // specifies the process of interest &creationTime, &exitTime, &stopSystem, &stopUser); QueryPerformanceCounter(&hrTm_stop); assert(hrTm_stop.HighPart > start.HighPart || hrTm_stop.HighPart == start.HighPart && hrTm_stop.LowPart >= start.LowPart); LARGE_INTEGER Freq = perfFreq; int Oht = overheadTicks; LARGE_INTEGER dtime; // faccio "a mano" la differenza dtime = m_tStop - m_tStart dtime.HighPart = hrTm_stop.HighPart - start.HighPart; if (hrTm_stop.LowPart >= start.LowPart) dtime.LowPart = hrTm_stop.LowPart - start.LowPart; else { assert(dtime.HighPart > 0); dtime.HighPart--; dtime.LowPart = hrTm_stop.LowPart + ~start.LowPart + 1; } int shift = 0; if (Freq.HighPart > 0) { int h = Freq.HighPart; while (h > 0) { h >>= 1; shift++; } } if ((dtime.HighPart >> shift) > 0) { int h = dtime.HighPart >> shift; while (h > 0) { h >>= 1; shift++; } } if (shift > 0) { dtime.QuadPart = Int64ShrlMod32(dtime.QuadPart, shift); Freq.QuadPart = Int64ShrlMod32(Freq.QuadPart, shift); } assert(Freq.HighPart == 0); assert(dtime.HighPart == 0); double totalTime = 1000.0 * dtime.LowPart / Freq.LowPart; tm += troundp(totalTime); tmUser += FileTimeToInt64(&stopUser) - FileTimeToInt64(&startUser); // user elapsed time tmSystem += FileTimeToInt64(&stopSystem) - FileTimeToInt64(&startSystem); // system elapsed time } //----------------------------------------------------------- } // namespace #endif // _WIN32 //----------------------------------------------------------- void TStopWatch::stop() { if (!m_isRunning) return; m_isRunning = false; #ifdef _WIN32 if (timerToUse == TTUTickCount) checkTime(m_start, m_startUser, m_startSystem, m_tm, m_tmUser, m_tmSystem); else hrCheckTime(m_hrStart, m_startUser, m_startSystem, m_tm, m_tmUser, m_tmSystem); #else checkTime(m_start, m_startUser, m_startSystem, m_tm, m_tmUser, m_tmSystem); #endif } //----------------------------------------------------------- void TStopWatch::getElapsedTime(TM_TOTAL &tm, TM_USER &user, TM_SYSTEM &system) { if (m_isRunning) { TM_TOTAL cur_tm = 0; TM_USER cur_tmUser = 0; TM_SYSTEM cur_tmSystem = 0; #ifdef _WIN32 if (timerToUse == TTUTickCount) checkTime(m_start, m_startUser, m_startSystem, cur_tm, cur_tmUser, cur_tmSystem); else hrCheckTime(m_hrStart, m_startUser, m_startSystem, cur_tm, cur_tmUser, cur_tmSystem); #else checkTime(m_start, m_startUser, m_startSystem, cur_tm, cur_tmUser, cur_tmSystem); #endif tm = m_tm + cur_tm; user = m_tmUser + cur_tmUser; system = m_tmSystem + cur_tmSystem; } else { tm = m_tm; user = m_tmUser; system = m_tmSystem; } } //----------------------------------------------------------- TUINT32 TStopWatch::getTotalTime() { TM_TOTAL tm; TM_USER user; TM_SYSTEM system; getElapsedTime(tm, user, system); #ifdef _WIN32 return tm; #else return (TINT32)(tm * 1000) / STW_TICKS_PER_SECOND; #endif //_WIN32 } //----------------------------------------------------------- TUINT32 TStopWatch::getUserTime() { TM_TOTAL tm; TM_USER user; TM_SYSTEM system; getElapsedTime(tm, user, system); #ifdef _WIN32 return (TINT32)(user / 10000); #else return (TINT32)(user * 1000) / STW_TICKS_PER_SECOND; #endif //_WIN32 } //----------------------------------------------------------- TUINT32 TStopWatch::getSystemTime() { TM_TOTAL tm; TM_USER user; TM_SYSTEM system; getElapsedTime(tm, user, system); #ifdef _WIN32 return (TINT32)(system / 10000); #else return (TINT32)(system * 1000) / STW_TICKS_PER_SECOND; #endif //_WIN32 } //----------------------------------------------------------- TStopWatch::operator string() { ostringstream out; out << m_name.c_str() << ": " << (int)getTotalTime() << " u" << (int)getUserTime() << " s" << (TINT32)getSystemTime(); return out.str(); } //------------------------------------------------------------ void TStopWatch::print() { print(cout); } //------------------------------------------------------------------------------------------- void TStopWatch::print(ostream &out) { string s(*this); out << s.c_str() << endl; } //------------------------------------------------------------------------------------------- void TStopWatch::printGlobals(ostream &out) { const int n = sizeof(StopWatch) / sizeof(StopWatch[0]); for (int i = 0; i < n; i++) if (StopWatch[i].m_active) StopWatch[i].print(out); } //------------------------------------------------------------------------------------------- void TStopWatch::printGlobals() { printGlobals(cout); } //----------------------------------------------------------- #ifdef _WIN32 void dummyFunction() { // It's used just to calculate the overhead return; } void determineTimer() { void (*pFunc)() = dummyFunction; // cout << "DETERMINE TIMER" << endl; // Assume the worst timerToUse = TTUTickCount; if (QueryPerformanceFrequency(&perfFreq)) { // We can use hires timer, determine overhead timerToUse = TTUHiRes; overheadTicks = 200; for (int i = 0; i < 20; i++) { LARGE_INTEGER b, e; int Ticks; QueryPerformanceCounter(&b); (*pFunc)(); QueryPerformanceCounter(&e); Ticks = e.LowPart - b.LowPart; if (Ticks >= 0 && Ticks < overheadTicks) overheadTicks = Ticks; } // See if Freq fits in 32 bits; if not lose some precision perfFreqAdjust = 0; int High32 = perfFreq.HighPart; while (High32) { High32 >>= 1; perfFreqAdjust++; } } } #else void determineTimer() {} #endif