You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
4.7 KiB
175 lines
4.7 KiB
4 years ago
|
// hrtimer.cpp - originally written and placed in the public domain by Wei Dai
|
||
|
|
||
|
#include "pch.h"
|
||
|
#include "hrtimer.h"
|
||
|
#include "misc.h"
|
||
|
|
||
|
#include <stddef.h> // for NULL
|
||
|
#include <time.h>
|
||
|
|
||
|
#if defined(CRYPTOPP_WIN32_AVAILABLE)
|
||
|
#define WIN32_LEAN_AND_MEAN
|
||
|
#include <windows.h>
|
||
|
# if ((WINVER >= 0x0602 /*_WIN32_WINNT_WIN8*/) || (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/))
|
||
|
# include <processthreadsapi.h>
|
||
|
# if defined(WINAPI_FAMILY)
|
||
|
# if (WINAPI_FAMILY_PARTITION(WINAPI_FAMILY_PHONE_APP))
|
||
|
# include <profileapi.h>
|
||
|
# endif
|
||
|
# endif
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#if defined(CRYPTOPP_UNIX_AVAILABLE)
|
||
|
#include <sys/time.h>
|
||
|
#include <sys/times.h>
|
||
|
#include <unistd.h>
|
||
|
#endif
|
||
|
|
||
|
#include "trap.h"
|
||
|
|
||
|
NAMESPACE_BEGIN(CryptoPP)
|
||
|
|
||
|
#if defined(CRYPTOPP_WIN32_AVAILABLE)
|
||
|
static TimerWord InitializePerformanceCounterFrequency()
|
||
|
{
|
||
|
LARGE_INTEGER freq = {0,0};
|
||
|
if (!QueryPerformanceFrequency(&freq))
|
||
|
throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceFrequency failed with error " + IntToString(GetLastError()));
|
||
|
return freq.QuadPart;
|
||
|
}
|
||
|
|
||
|
inline TimerWord PerformanceCounterFrequency()
|
||
|
{
|
||
|
static const word64 freq = InitializePerformanceCounterFrequency();
|
||
|
return freq;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifndef CRYPTOPP_IMPORTS
|
||
|
|
||
|
double TimerBase::ConvertTo(TimerWord t, Unit unit)
|
||
|
{
|
||
|
static unsigned long unitsPerSecondTable[] = {1, 1000, 1000*1000, 1000*1000*1000};
|
||
|
|
||
|
// When 'unit' is an enum 'Unit', a Clang warning is generated.
|
||
|
CRYPTOPP_ASSERT(static_cast<unsigned int>(unit) < COUNTOF(unitsPerSecondTable));
|
||
|
return static_cast<double>(t) * unitsPerSecondTable[unit] / TicksPerSecond();
|
||
|
}
|
||
|
|
||
|
void TimerBase::StartTimer()
|
||
|
{
|
||
|
m_last = m_start = GetCurrentTimerValue();
|
||
|
m_started = true;
|
||
|
}
|
||
|
|
||
|
double TimerBase::ElapsedTimeAsDouble()
|
||
|
{
|
||
|
if (m_stuckAtZero)
|
||
|
return 0;
|
||
|
|
||
|
if (m_started)
|
||
|
{
|
||
|
TimerWord now = GetCurrentTimerValue();
|
||
|
if (m_last < now) // protect against OS bugs where time goes backwards
|
||
|
m_last = now;
|
||
|
return ConvertTo(m_last - m_start, m_timerUnit);
|
||
|
}
|
||
|
|
||
|
StartTimer();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
unsigned long TimerBase::ElapsedTime()
|
||
|
{
|
||
|
double elapsed = ElapsedTimeAsDouble();
|
||
|
CRYPTOPP_ASSERT(elapsed <= (double)ULONG_MAX);
|
||
|
return (unsigned long)elapsed;
|
||
|
}
|
||
|
|
||
|
TimerWord Timer::GetCurrentTimerValue()
|
||
|
{
|
||
|
#if defined(CRYPTOPP_WIN32_AVAILABLE)
|
||
|
// Use the first union member to avoid an uninitialized warning
|
||
|
LARGE_INTEGER now = {0,0};
|
||
|
if (!QueryPerformanceCounter(&now))
|
||
|
throw Exception(Exception::OTHER_ERROR, "Timer: QueryPerformanceCounter failed with error " + IntToString(GetLastError()));
|
||
|
return now.QuadPart;
|
||
|
#elif defined(CRYPTOPP_UNIX_AVAILABLE)
|
||
|
timeval now;
|
||
|
gettimeofday(&now, NULLPTR);
|
||
|
return (TimerWord)now.tv_sec * 1000000 + now.tv_usec;
|
||
|
#else
|
||
|
// clock_t now;
|
||
|
return clock();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
TimerWord Timer::TicksPerSecond()
|
||
|
{
|
||
|
#if defined(CRYPTOPP_WIN32_AVAILABLE)
|
||
|
return PerformanceCounterFrequency();
|
||
|
#elif defined(CRYPTOPP_UNIX_AVAILABLE)
|
||
|
return 1000000;
|
||
|
#else
|
||
|
return CLOCKS_PER_SEC;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
#endif // #ifndef CRYPTOPP_IMPORTS
|
||
|
|
||
|
TimerWord ThreadUserTimer::GetCurrentTimerValue()
|
||
|
{
|
||
|
#if defined(CRYPTOPP_WIN32_AVAILABLE) && defined(THREAD_TIMER_AVAILABLE)
|
||
|
static bool getCurrentThreadImplemented = true;
|
||
|
if (getCurrentThreadImplemented)
|
||
|
{
|
||
|
FILETIME now, ignored;
|
||
|
if (!GetThreadTimes(GetCurrentThread(), &ignored, &ignored, &ignored, &now))
|
||
|
{
|
||
|
const DWORD lastError = GetLastError();
|
||
|
if (lastError == ERROR_CALL_NOT_IMPLEMENTED)
|
||
|
{
|
||
|
getCurrentThreadImplemented = false;
|
||
|
goto GetCurrentThreadNotImplemented;
|
||
|
}
|
||
|
throw Exception(Exception::OTHER_ERROR, "ThreadUserTimer: GetThreadTimes failed with error " + IntToString(lastError));
|
||
|
}
|
||
|
return now.dwLowDateTime + ((TimerWord)now.dwHighDateTime << 32);
|
||
|
}
|
||
|
GetCurrentThreadNotImplemented:
|
||
|
return (TimerWord)clock() * (10*1000*1000 / CLOCKS_PER_SEC);
|
||
|
#elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(THREAD_TIMER_AVAILABLE)
|
||
|
LARGE_INTEGER now;
|
||
|
if (!QueryPerformanceCounter(&now))
|
||
|
{
|
||
|
const DWORD lastError = GetLastError();
|
||
|
throw Exception(Exception::OTHER_ERROR, "ThreadUserTimer: QueryPerformanceCounter failed with error " + IntToString(lastError));
|
||
|
}
|
||
|
return now.QuadPart;
|
||
|
#elif defined(CRYPTOPP_UNIX_AVAILABLE)
|
||
|
tms now;
|
||
|
times(&now);
|
||
|
return now.tms_utime;
|
||
|
#else
|
||
|
return clock();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
TimerWord ThreadUserTimer::TicksPerSecond()
|
||
|
{
|
||
|
#if defined(CRYPTOPP_WIN32_AVAILABLE) && defined(THREAD_TIMER_AVAILABLE)
|
||
|
return 10*1000*1000;
|
||
|
#elif defined(CRYPTOPP_WIN32_AVAILABLE) && !defined(THREAD_TIMER_AVAILABLE)
|
||
|
static const TimerWord ticksPerSecond = PerformanceCounterFrequency();
|
||
|
return ticksPerSecond;
|
||
|
#elif defined(CRYPTOPP_UNIX_AVAILABLE)
|
||
|
static const long ticksPerSecond = sysconf(_SC_CLK_TCK);
|
||
|
return ticksPerSecond;
|
||
|
#else
|
||
|
return CLOCKS_PER_SEC;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
NAMESPACE_END
|