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