Coverage Report

Created: 2024-11-21 07:03

/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