// hrtimer.cpp - originally written and placed in the public domain by Wei Dai #include "pch.h" #include "hrtimer.h" #include "misc.h" #include // for NULL #include #if defined(CRYPTOPP_WIN32_AVAILABLE) #define WIN32_LEAN_AND_MEAN #include # if ((WINVER >= 0x0602 /*_WIN32_WINNT_WIN8*/) || (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/)) # include # if defined(WINAPI_FAMILY) # if (WINAPI_FAMILY_PARTITION(WINAPI_FAMILY_PHONE_APP)) # include # endif # endif #endif #endif #if defined(CRYPTOPP_UNIX_AVAILABLE) #include #include #include #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(unit) < COUNTOF(unitsPerSecondTable)); return static_cast(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