/util/chrono.cpp

https://github.com/ftk/niceamx · C++ · 289 lines · 237 code · 41 blank · 11 comment · 47 complexity · c8e23828d8130ce25796ab9be6f1135a MD5 · raw file

  1. #include "config.h"
  2. #include "chrono.hpp"
  3. #ifdef WIN32
  4. #define VC_EXTRALEAN
  5. #define WIN32_LEAN_AND_MEAN
  6. #include <windows.h>
  7. // workaround for mingw 4.7
  8. #if defined _WIN32_WINNT && _WIN32_WINNT >= 0x6000 && defined __GNUC__ && (__GNUC__ * 100 + __GNUC_MINOR__) < 408
  9. extern "C" WINBASEAPI ULONGLONG WINAPI GetTickCount64(VOID);
  10. #endif
  11. #else
  12. #include <unistd.h>
  13. #include <sys/time.h>
  14. #include <pthread.h>
  15. #endif
  16. #include <utility>
  17. #include <cassert>
  18. #include <ctime>
  19. namespace chrono {
  20. #ifdef WIN32
  21. long long fast_steady_clock::freq = 0LL;
  22. #endif
  23. fast_steady_clock::time_point fast_steady_clock::now() noexcept
  24. {
  25. #ifndef WIN32
  26. timespec ts;
  27. if(clock_gettime(CLOCK_MONOTONIC/*_COARSE*/, &ts))
  28. {
  29. assert(false && "clock_gettime(CLOCK_MONOTONIC) failed");
  30. }
  31. nanoseconds dur((static_cast<rep>(ts.tv_sec)*1000000000) + (ts.tv_nsec));
  32. #else
  33. static_assert(sizeof(long long) == sizeof(_LARGE_INTEGER), "fixme:wrong llong size");
  34. long long cnt;
  35. if(!QueryPerformanceCounter(reinterpret_cast<PLARGE_INTEGER>(&cnt)))
  36. {
  37. assert(false && "QPC failed");
  38. }
  39. if(!freq)
  40. {
  41. if(!QueryPerformanceFrequency(reinterpret_cast<PLARGE_INTEGER>(&freq))) // ticks per second
  42. {
  43. assert(false && "QPF failed");
  44. }
  45. freq /= 1000000LL; // ticks per microsecond
  46. }
  47. microseconds dur(cnt / freq);
  48. #endif
  49. return time_point(std::move(dur));
  50. }
  51. fast_realtime_clock::time_point fast_realtime_clock::now() noexcept
  52. {
  53. #ifndef WIN32
  54. timespec ts;
  55. if(clock_gettime(CLOCK_REALTIME/*_COARSE*/, &ts))
  56. {
  57. assert(false && "clock_gettime(CLOCK_REALTIME) failed");
  58. }
  59. nanoseconds dur((static_cast<rep>(ts.tv_sec)*1000000000) + (ts.tv_nsec));
  60. #elif defined _WIN32_WINNT && _WIN32_WINNT >= 0x6000
  61. milliseconds dur(GetTickCount64());
  62. #else
  63. milliseconds dur(GetTickCount());
  64. #endif
  65. return time_point(std::move(dur));
  66. }
  67. process_real_cpu_clock::time_point process_real_cpu_clock::now() noexcept
  68. {
  69. clock_t c = ::clock();
  70. if(c == clock_t(-1)) // error
  71. {
  72. assert(false && "clock() failed");
  73. }
  74. typedef std::ratio_divide<std::giga, std::ratio<CLOCKS_PER_SEC> >::type R;
  75. return time_point(
  76. duration(static_cast<rep>(c)*R::num/R::den)
  77. );
  78. }
  79. #ifdef WIN32
  80. process_user_cpu_clock::time_point process_user_cpu_clock::now() noexcept
  81. {
  82. // note that Windows uses 100 nanosecond ticks for FILETIME
  83. _FILETIME creation, exit, user_time, system_time;
  84. if (GetProcessTimes(
  85. GetCurrentProcess(), &creation, &exit,
  86. &system_time, &user_time ))
  87. {
  88. return time_point(duration(
  89. ((static_cast<process_user_cpu_clock::rep>(user_time.dwHighDateTime) << 32)
  90. | user_time.dwLowDateTime) * 100
  91. ));
  92. }
  93. else
  94. {
  95. assert(false && "GetProcessTimes failed");
  96. return time_point();
  97. }
  98. }
  99. process_system_cpu_clock::time_point process_system_cpu_clock::now() noexcept
  100. {
  101. // note that Windows uses 100 nanosecond ticks for FILETIME
  102. _FILETIME creation, exit, user_time, system_time;
  103. if (GetProcessTimes(
  104. GetCurrentProcess(), &creation, &exit,
  105. &system_time, &user_time))
  106. {
  107. return time_point(duration(
  108. ((static_cast<process_system_cpu_clock::rep>(system_time.dwHighDateTime) << 32)
  109. | system_time.dwLowDateTime) * 100
  110. ));
  111. }
  112. else
  113. {
  114. assert(false && "GetProcessTimes failed");
  115. return time_point();
  116. }
  117. }
  118. thread_clock::time_point thread_clock::now() noexcept
  119. {
  120. // note that Windows uses 100 nanosecond ticks for FILETIME
  121. _FILETIME creation, exit, user_time, system_time;
  122. if (GetThreadTimes(
  123. GetCurrentThread(), &creation, &exit,
  124. &system_time, &user_time))
  125. {
  126. duration user = duration(
  127. ((static_cast<duration::rep>(user_time.dwHighDateTime) << 32)
  128. | user_time.dwLowDateTime) * 100 );
  129. duration system = duration(
  130. ((static_cast<duration::rep>(system_time.dwHighDateTime) << 32)
  131. | system_time.dwLowDateTime) * 100 );
  132. return time_point(system+user);
  133. }
  134. else
  135. {
  136. assert(false && "GetThreadTimes failed");
  137. return time_point();
  138. }
  139. }
  140. #else
  141. // posix
  142. static inline long tick_factor() // multiplier to convert ticks
  143. // to nanoseconds; -1 if unknown
  144. {
  145. static long factor = 0;
  146. if ( !factor )
  147. {
  148. if ((factor = ::sysconf( _SC_CLK_TCK )) <= 0)
  149. factor = -1;
  150. else
  151. {
  152. assert( factor <= 1000000000l ); // doesn't handle large ticks
  153. factor = 1000000000l / factor; // compute factor
  154. if ( !factor ) factor = -1;
  155. }
  156. }
  157. return factor;
  158. }
  159. process_real_cpu_clock::time_point process_real_cpu_clock::now() noexcept
  160. {
  161. tms tm;
  162. clock_t c = ::times( &tm );
  163. if (c == clock_t(-1)) // error
  164. {
  165. assert(false && "times() failed");
  166. }
  167. else
  168. {
  169. if(tick_factor() != -1)
  170. {
  171. return time_point(
  172. nanoseconds(c*chrono_detail::tick_factor()));
  173. }
  174. else
  175. {
  176. assert(false && "CLK_TCK failed");
  177. }
  178. }
  179. return time_point();
  180. }
  181. process_user_cpu_clock::time_point process_user_cpu_clock::now() noexcept
  182. {
  183. tms tm;
  184. clock_t c = ::times( &tm );
  185. if (c == clock_t(-1)) // error
  186. {
  187. assert(false && "times() failed");
  188. }
  189. else
  190. {
  191. if(tick_factor() != -1)
  192. {
  193. return time_point(
  194. nanoseconds((tm.tms_utime + tm.tms_cutime)*tick_factor()));
  195. }
  196. else
  197. {
  198. assert(false && "CLK_TCK failed");
  199. }
  200. }
  201. return time_point();
  202. }
  203. process_system_cpu_clock::time_point process_system_cpu_clock::now() noexcept
  204. {
  205. tms tm;
  206. clock_t c = ::times( &tm );
  207. if (c == clock_t(-1)) // error
  208. {
  209. assert(false && "times() failed");
  210. }
  211. else
  212. {
  213. if(tick_factor() != -1)
  214. {
  215. return time_point(
  216. nanoseconds((tm.tms_stime + tm.tms_cstime)*tick_factor()));
  217. }
  218. else
  219. {
  220. assert(false && "CLK_TCK failed");
  221. }
  222. }
  223. return time_point();
  224. }
  225. thread_clock::time_point thread_clock::now( ) BOOST_NOEXCEPT
  226. {
  227. struct timespec ts;
  228. #if defined CLOCK_THREAD_CPUTIME_ID
  229. // get the timespec associated to the thread clock
  230. if(::clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts))
  231. #else
  232. // get the current thread
  233. pthread_t pth = pthread_self();
  234. // get the clock_id associated to the current thread
  235. clockid_t clock_id;
  236. pthread_getcpuclockid(pth, &clock_id);
  237. // get the timespec associated to the thread clock
  238. if(::clock_gettime(clock_id, &ts))
  239. #endif
  240. {
  241. assert(false && "clock_gettime failed")
  242. }
  243. // transform to nanoseconds
  244. return time_point(duration(
  245. static_cast<thread_clock::rep>( ts.tv_sec ) * 1000000000 + ts.tv_nsec));
  246. }
  247. #endif
  248. } //chrono