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