/toonz/sources/common/tcore/tstopwatch.cpp

https://github.com/opentoonz/opentoonz · C++ · 402 lines · 291 code · 76 blank · 35 comment · 33 complexity · 74ad0adaf253b50f6fec3126d7009752 MD5 · raw file

  1. #include "tstopwatch.h"
  2. #include <sstream>
  3. #ifdef _WIN32
  4. #include <stdlib.h>
  5. #else //_WIN32
  6. #include <unistd.h>
  7. #include <limits.h>
  8. #include <sys/times.h>
  9. #include <sys/types.h>
  10. #include <time.h>
  11. #ifndef STW_TICKS_PER_SECOND
  12. #ifndef _WIN32
  13. extern "C" long sysconf(int);
  14. #define STW_TICKS_PER_SECOND sysconf(_SC_CLK_TCK)
  15. #else
  16. #define STW_TICKS_PER_SECOND CLK_TCK
  17. #endif
  18. #endif
  19. #endif
  20. #define MAXSWNAMELENGHT 40
  21. #define MAXSWTIMELENGHT 12
  22. TStopWatch TStopWatch::StopWatch[10];
  23. enum TimerType { TTUUnknown, TTUHiRes, TTUTickCount };
  24. static void determineTimer();
  25. #ifdef _WIN32
  26. static TimerType timerToUse = TTUUnknown;
  27. static LARGE_INTEGER perfFreq; // ticks per second
  28. static int perfFreqAdjust = 0; // in case Freq is too big
  29. static int overheadTicks = 0; // overhead in calling timer
  30. #else
  31. static TimerType timerToUse = TTUTickCount;
  32. #endif
  33. using namespace std;
  34. //-----------------------------------------------------------
  35. TStopWatch::TStopWatch(std::string name)
  36. : m_name(name), m_active(false), m_isRunning(false) {
  37. if (timerToUse == TTUUnknown) determineTimer();
  38. m_start = 0;
  39. #ifdef _WIN32
  40. m_startUser.dwHighDateTime = m_startUser.dwLowDateTime = 0;
  41. m_startSystem.dwHighDateTime = m_startSystem.dwLowDateTime = 0;
  42. #else
  43. m_startUser = 0;
  44. m_startSystem = 0;
  45. #endif //_WIN32
  46. m_tm = 0;
  47. m_tmUser = 0;
  48. m_tmSystem = 0;
  49. }
  50. //-----------------------------------------------------------
  51. TStopWatch::~TStopWatch() { m_active = false; }
  52. //-----------------------------------------------------------
  53. void TStopWatch::setStartToCurrentTime() {
  54. #ifdef _WIN32
  55. FILETIME creationTime, exitTime;
  56. BOOL ret =
  57. GetProcessTimes(GetCurrentProcess(), // specifies the process of interest
  58. &creationTime, &exitTime, &m_startSystem, &m_startUser);
  59. if (timerToUse == TTUTickCount) {
  60. m_start = GetTickCount();
  61. } else {
  62. QueryPerformanceCounter(&m_hrStart);
  63. }
  64. #else
  65. struct tms clk;
  66. m_start = times(&clk);
  67. m_startUser = clk.tms_utime;
  68. m_startSystem = clk.tms_stime;
  69. #endif //_WIN32
  70. }
  71. //-----------------------------------------------------------
  72. void TStopWatch::reset() {
  73. m_tm = 0;
  74. m_tmUser = 0;
  75. m_tmSystem = 0;
  76. setStartToCurrentTime();
  77. }
  78. //-----------------------------------------------------------
  79. void TStopWatch::start(bool resetFlag) {
  80. if (resetFlag) reset();
  81. if (m_isRunning) return;
  82. m_active = true;
  83. m_isRunning = true;
  84. setStartToCurrentTime();
  85. }
  86. //-----------------------------------------------------------
  87. #ifdef _WIN32
  88. inline __int64 FileTimeToInt64(LPFILETIME pFileTime) {
  89. __int64 val;
  90. val = pFileTime->dwHighDateTime;
  91. val <<= 32;
  92. val |= pFileTime->dwLowDateTime;
  93. return val;
  94. }
  95. #endif //_WIN32
  96. //-----------------------------------------------------------
  97. //
  98. // Aggiunge il tempo trascorso fra start(startUser, startSystem) e l'istante
  99. // corrente
  100. // a tm(tmUser, tmSystem)
  101. //
  102. static void checkTime(START start, START_USER startUser,
  103. START_SYSTEM startSystem, TM_TOTAL &tm, TM_USER &tmUser,
  104. TM_SYSTEM &tmSystem) {
  105. assert(timerToUse == TTUTickCount);
  106. #ifdef _WIN32
  107. DWORD tm_stop;
  108. FILETIME creationTime, exitTime, stopSystem, stopUser;
  109. BOOL ret =
  110. GetProcessTimes(GetCurrentProcess(), // specifies the process of interest
  111. &creationTime, &exitTime, &stopSystem, &stopUser);
  112. tm_stop = GetTickCount();
  113. assert(tm_stop >= start);
  114. tm += tm_stop - start; // total elapsed time
  115. tmUser += FileTimeToInt64(&stopUser) -
  116. FileTimeToInt64(&startUser); // user elapsed time
  117. tmSystem += FileTimeToInt64(&stopSystem) -
  118. FileTimeToInt64(&startSystem); // system elapsed time
  119. #else // _WIN32
  120. struct tms clk;
  121. clock_t tm_stop;
  122. tm_stop = times(&clk);
  123. assert(tm_stop >= start);
  124. tm += tm_stop - start;
  125. tmUser += clk.tms_utime - startUser;
  126. tmSystem += clk.tms_stime - startSystem;
  127. #endif // _WIN32
  128. }
  129. //-----------------------------------------------------------
  130. #ifdef _WIN32
  131. //
  132. // come checkTime, ma usa i timer ad alta risoluzione
  133. //
  134. namespace {
  135. //-----------------------------------------------------------
  136. void hrCheckTime(LARGE_INTEGER start, START_USER startUser,
  137. START_SYSTEM startSystem, TM_TOTAL &tm, TM_USER &tmUser,
  138. TM_SYSTEM &tmSystem) {
  139. assert(timerToUse != TTUTickCount);
  140. LARGE_INTEGER hrTm_stop;
  141. FILETIME creationTime, exitTime, stopSystem, stopUser;
  142. BOOL ret =
  143. GetProcessTimes(GetCurrentProcess(), // specifies the process of interest
  144. &creationTime, &exitTime, &stopSystem, &stopUser);
  145. QueryPerformanceCounter(&hrTm_stop);
  146. assert(hrTm_stop.HighPart > start.HighPart ||
  147. hrTm_stop.HighPart == start.HighPart &&
  148. hrTm_stop.LowPart >= start.LowPart);
  149. LARGE_INTEGER Freq = perfFreq;
  150. int Oht = overheadTicks;
  151. LARGE_INTEGER dtime;
  152. // faccio "a mano" la differenza dtime = m_tStop - m_tStart
  153. dtime.HighPart = hrTm_stop.HighPart - start.HighPart;
  154. if (hrTm_stop.LowPart >= start.LowPart)
  155. dtime.LowPart = hrTm_stop.LowPart - start.LowPart;
  156. else {
  157. assert(dtime.HighPart > 0);
  158. dtime.HighPart--;
  159. dtime.LowPart = hrTm_stop.LowPart + ~start.LowPart + 1;
  160. }
  161. int shift = 0;
  162. if (Freq.HighPart > 0) {
  163. int h = Freq.HighPart;
  164. while (h > 0) {
  165. h >>= 1;
  166. shift++;
  167. }
  168. }
  169. if ((dtime.HighPart >> shift) > 0) {
  170. int h = dtime.HighPart >> shift;
  171. while (h > 0) {
  172. h >>= 1;
  173. shift++;
  174. }
  175. }
  176. if (shift > 0) {
  177. dtime.QuadPart = Int64ShrlMod32(dtime.QuadPart, shift);
  178. Freq.QuadPart = Int64ShrlMod32(Freq.QuadPart, shift);
  179. }
  180. assert(Freq.HighPart == 0);
  181. assert(dtime.HighPart == 0);
  182. double totalTime = 1000.0 * dtime.LowPart / Freq.LowPart;
  183. tm += troundp(totalTime);
  184. tmUser += FileTimeToInt64(&stopUser) -
  185. FileTimeToInt64(&startUser); // user elapsed time
  186. tmSystem += FileTimeToInt64(&stopSystem) -
  187. FileTimeToInt64(&startSystem); // system elapsed time
  188. }
  189. //-----------------------------------------------------------
  190. } // namespace
  191. #endif // _WIN32
  192. //-----------------------------------------------------------
  193. void TStopWatch::stop() {
  194. if (!m_isRunning) return;
  195. m_isRunning = false;
  196. #ifdef _WIN32
  197. if (timerToUse == TTUTickCount)
  198. checkTime(m_start, m_startUser, m_startSystem, m_tm, m_tmUser, m_tmSystem);
  199. else
  200. hrCheckTime(m_hrStart, m_startUser, m_startSystem, m_tm, m_tmUser,
  201. m_tmSystem);
  202. #else
  203. checkTime(m_start, m_startUser, m_startSystem, m_tm, m_tmUser, m_tmSystem);
  204. #endif
  205. }
  206. //-----------------------------------------------------------
  207. void TStopWatch::getElapsedTime(TM_TOTAL &tm, TM_USER &user,
  208. TM_SYSTEM &system) {
  209. if (m_isRunning) {
  210. TM_TOTAL cur_tm = 0;
  211. TM_USER cur_tmUser = 0;
  212. TM_SYSTEM cur_tmSystem = 0;
  213. #ifdef _WIN32
  214. if (timerToUse == TTUTickCount)
  215. checkTime(m_start, m_startUser, m_startSystem, cur_tm, cur_tmUser,
  216. cur_tmSystem);
  217. else
  218. hrCheckTime(m_hrStart, m_startUser, m_startSystem, cur_tm, cur_tmUser,
  219. cur_tmSystem);
  220. #else
  221. checkTime(m_start, m_startUser, m_startSystem, cur_tm, cur_tmUser,
  222. cur_tmSystem);
  223. #endif
  224. tm = m_tm + cur_tm;
  225. user = m_tmUser + cur_tmUser;
  226. system = m_tmSystem + cur_tmSystem;
  227. } else {
  228. tm = m_tm;
  229. user = m_tmUser;
  230. system = m_tmSystem;
  231. }
  232. }
  233. //-----------------------------------------------------------
  234. TUINT32 TStopWatch::getTotalTime() {
  235. TM_TOTAL tm;
  236. TM_USER user;
  237. TM_SYSTEM system;
  238. getElapsedTime(tm, user, system);
  239. #ifdef _WIN32
  240. return tm;
  241. #else
  242. return (TINT32)(tm * 1000) / STW_TICKS_PER_SECOND;
  243. #endif //_WIN32
  244. }
  245. //-----------------------------------------------------------
  246. TUINT32 TStopWatch::getUserTime() {
  247. TM_TOTAL tm;
  248. TM_USER user;
  249. TM_SYSTEM system;
  250. getElapsedTime(tm, user, system);
  251. #ifdef _WIN32
  252. return (TINT32)(user / 10000);
  253. #else
  254. return (TINT32)(user * 1000) / STW_TICKS_PER_SECOND;
  255. #endif //_WIN32
  256. }
  257. //-----------------------------------------------------------
  258. TUINT32 TStopWatch::getSystemTime() {
  259. TM_TOTAL tm;
  260. TM_USER user;
  261. TM_SYSTEM system;
  262. getElapsedTime(tm, user, system);
  263. #ifdef _WIN32
  264. return (TINT32)(system / 10000);
  265. #else
  266. return (TINT32)(system * 1000) / STW_TICKS_PER_SECOND;
  267. #endif //_WIN32
  268. }
  269. //-----------------------------------------------------------
  270. TStopWatch::operator string() {
  271. ostringstream out;
  272. out << m_name.c_str() << ": " << (int)getTotalTime() << " u"
  273. << (int)getUserTime() << " s" << (TINT32)getSystemTime();
  274. return out.str();
  275. }
  276. //------------------------------------------------------------
  277. void TStopWatch::print() { print(cout); }
  278. //-------------------------------------------------------------------------------------------
  279. void TStopWatch::print(ostream &out) {
  280. string s(*this);
  281. out << s.c_str() << endl;
  282. }
  283. //-------------------------------------------------------------------------------------------
  284. void TStopWatch::printGlobals(ostream &out) {
  285. const int n = sizeof(StopWatch) / sizeof(StopWatch[0]);
  286. for (int i = 0; i < n; i++)
  287. if (StopWatch[i].m_active) StopWatch[i].print(out);
  288. }
  289. //-------------------------------------------------------------------------------------------
  290. void TStopWatch::printGlobals() { printGlobals(cout); }
  291. //-----------------------------------------------------------
  292. #ifdef _WIN32
  293. static void dummyFunction() {
  294. // It's used just to calculate the overhead
  295. return;
  296. }
  297. void determineTimer() {
  298. void (*pFunc)() = dummyFunction;
  299. // cout << "DETERMINE TIMER" << endl;
  300. // Assume the worst
  301. timerToUse = TTUTickCount;
  302. if (QueryPerformanceFrequency(&perfFreq)) {
  303. // We can use hires timer, determine overhead
  304. timerToUse = TTUHiRes;
  305. overheadTicks = 200;
  306. for (int i = 0; i < 20; i++) {
  307. LARGE_INTEGER b, e;
  308. int Ticks;
  309. QueryPerformanceCounter(&b);
  310. (*pFunc)();
  311. QueryPerformanceCounter(&e);
  312. Ticks = e.LowPart - b.LowPart;
  313. if (Ticks >= 0 && Ticks < overheadTicks) overheadTicks = Ticks;
  314. }
  315. // See if Freq fits in 32 bits; if not lose some precision
  316. perfFreqAdjust = 0;
  317. int High32 = perfFreq.HighPart;
  318. while (High32) {
  319. High32 >>= 1;
  320. perfFreqAdjust++;
  321. }
  322. }
  323. }
  324. #else
  325. void determineTimer() {}
  326. #endif