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 19NAMESPACE_BEGIN(CryptoPP) 20 21#ifndef CRYPTOPP_IMPORTS 22 23double 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 31void TimerBase::StartTimer() 32{ 33 m_last = m_start = GetCurrentTimerValue(); 34 m_started = true; 35} 36 37double 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 54unsigned long TimerBase::ElapsedTime() 55{ 56 double elapsed = ElapsedTimeAsDouble(); 57 assert(elapsed <= ULONG_MAX); 58 return (unsigned long)elapsed; 59} 60 61TimerWord 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 78TimerWord 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 97TimerWord 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 } 116GetCurrentThreadNotImplemented: 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 127TimerWord 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 139NAMESPACE_END 140