/hrtimer.cpp

https://github.com/weidai11/cryptopp · C++ · 174 lines · 148 code · 22 blank · 4 comment · 18 complexity · 8fae088ff5512131e81ed98d3dc6cbce MD5 · raw file

  1. // hrtimer.cpp - originally written and placed in the public domain by Wei Dai
  2. #include "pch.h"
  3. #include "hrtimer.h"
  4. #include "misc.h"
  5. #include <stddef.h> // for NULL
  6. #include <time.h>
  7. #if defined(CRYPTOPP_WIN32_AVAILABLE)
  8. #define WIN32_LEAN_AND_MEAN
  9. #include <windows.h>
  10. # if ((WINVER >= 0x0602 /*_WIN32_WINNT_WIN8*/) || (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/))
  11. # include <processthreadsapi.h>
  12. # if defined(WINAPI_FAMILY)
  13. # if (WINAPI_FAMILY_PARTITION(WINAPI_FAMILY_PHONE_APP))
  14. # include <profileapi.h>
  15. # endif
  16. # endif
  17. #endif
  18. #endif
  19. #if defined(CRYPTOPP_UNIX_AVAILABLE)
  20. #include <sys/time.h>
  21. #include <sys/times.h>
  22. #include <unistd.h>
  23. #endif
  24. #include "trap.h"
  25. NAMESPACE_BEGIN(CryptoPP)
  26. #if defined(CRYPTOPP_WIN32_AVAILABLE)
  27. static TimerWord InitializePerformanceCounterFrequency()
  28. {
  29. LARGE_INTEGER freq = {0,0};
  30. if (!QueryPerformanceFrequency(&freq))
  31. throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceFrequency failed with error " + IntToString(GetLastError()));
  32. return freq.QuadPart;
  33. }
  34. inline TimerWord PerformanceCounterFrequency()
  35. {
  36. static const word64 freq = InitializePerformanceCounterFrequency();
  37. return freq;
  38. }
  39. #endif
  40. #ifndef CRYPTOPP_IMPORTS
  41. double TimerBase::ConvertTo(TimerWord t, Unit unit)
  42. {
  43. static unsigned long unitsPerSecondTable[] = {1, 1000, 1000*1000, 1000*1000*1000};
  44. // When 'unit' is an enum 'Unit', a Clang warning is generated.
  45. CRYPTOPP_ASSERT(static_cast<unsigned int>(unit) < COUNTOF(unitsPerSecondTable));
  46. return static_cast<double>(t) * unitsPerSecondTable[unit] / TicksPerSecond();
  47. }
  48. void TimerBase::StartTimer()
  49. {
  50. m_last = m_start = GetCurrentTimerValue();
  51. m_started = true;
  52. }
  53. double TimerBase::ElapsedTimeAsDouble()
  54. {
  55. if (m_stuckAtZero)
  56. return 0;
  57. if (m_started)
  58. {
  59. TimerWord now = GetCurrentTimerValue();
  60. if (m_last < now) // protect against OS bugs where time goes backwards
  61. m_last = now;
  62. return ConvertTo(m_last - m_start, m_timerUnit);
  63. }
  64. StartTimer();
  65. return 0;
  66. }
  67. unsigned long TimerBase::ElapsedTime()
  68. {
  69. double elapsed = ElapsedTimeAsDouble();
  70. CRYPTOPP_ASSERT(elapsed <= (double)ULONG_MAX);
  71. return (unsigned long)elapsed;
  72. }
  73. TimerWord Timer::GetCurrentTimerValue()
  74. {
  75. #if defined(CRYPTOPP_WIN32_AVAILABLE)
  76. // Use the first union member to avoid an uninitialized warning
  77. LARGE_INTEGER now = {0,0};
  78. if (!QueryPerformanceCounter(&now))
  79. throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceCounter failed with error " + IntToString(GetLastError()));
  80. return now.QuadPart;
  81. #elif defined(CRYPTOPP_UNIX_AVAILABLE)
  82. timeval now;
  83. gettimeofday(&now, NULLPTR);
  84. return (TimerWord)now.tv_sec * 1000000 + now.tv_usec;
  85. #else
  86. // clock_t now;
  87. return clock();
  88. #endif
  89. }
  90. TimerWord Timer::TicksPerSecond()
  91. {
  92. #if defined(CRYPTOPP_WIN32_AVAILABLE)
  93. return PerformanceCounterFrequency();
  94. #elif defined(CRYPTOPP_UNIX_AVAILABLE)
  95. return 1000000;
  96. #else
  97. return CLOCKS_PER_SEC;
  98. #endif
  99. }
  100. #endif // #ifndef CRYPTOPP_IMPORTS
  101. TimerWord ThreadUserTimer::GetCurrentTimerValue()
  102. {
  103. #if defined(CRYPTOPP_WIN32_AVAILABLE) && defined(THREAD_TIMER_AVAILABLE)
  104. static bool getCurrentThreadImplemented = true;
  105. if (getCurrentThreadImplemented)
  106. {
  107. FILETIME now, ignored;
  108. if (!GetThreadTimes(GetCurrentThread(), &ignored, &ignored, &ignored, &now))
  109. {
  110. const DWORD lastError = GetLastError();
  111. if (lastError == ERROR_CALL_NOT_IMPLEMENTED)
  112. {
  113. getCurrentThreadImplemented = false;
  114. goto GetCurrentThreadNotImplemented;
  115. }
  116. throw Exception(Exception::OTHER_ERROR, "ThreadUserTimer: GetThreadTimes failed with error " + IntToString(lastError));
  117. }
  118. return now.dwLowDateTime + ((TimerWord)now.dwHighDateTime << 32);
  119. }
  120. GetCurrentThreadNotImplemented:
  121. return (TimerWord)clock() * (10*1000*1000 / CLOCKS_PER_SEC);
  122. #elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(THREAD_TIMER_AVAILABLE)
  123. LARGE_INTEGER now;
  124. if (!QueryPerformanceCounter(&now))
  125. {
  126. const DWORD lastError = GetLastError();
  127. throw Exception(Exception::OTHER_ERROR, "ThreadUserTimer: QueryPerformanceCounter failed with error " + IntToString(lastError));
  128. }
  129. return now.QuadPart;
  130. #elif defined(CRYPTOPP_UNIX_AVAILABLE)
  131. tms now;
  132. times(&now);
  133. return now.tms_utime;
  134. #else
  135. return clock();
  136. #endif
  137. }
  138. TimerWord ThreadUserTimer::TicksPerSecond()
  139. {
  140. #if defined(CRYPTOPP_WIN32_AVAILABLE) && defined(THREAD_TIMER_AVAILABLE)
  141. return 10*1000*1000;
  142. #elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(THREAD_TIMER_AVAILABLE)
  143. static const TimerWord ticksPerSecond = PerformanceCounterFrequency();
  144. return ticksPerSecond;
  145. #elif defined(CRYPTOPP_UNIX_AVAILABLE)
  146. static const long ticksPerSecond = sysconf(_SC_CLK_TCK);
  147. return ticksPerSecond;
  148. #else
  149. return CLOCKS_PER_SEC;
  150. #endif
  151. }
  152. NAMESPACE_END