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