Revisit time functions

Addressing https://github.com/MSOpenTech/redis/issues/188

- Made gettimeofday use GetSystemTimePreciseAsFileTime when available
- Introduced definitions for gettimeofday_fast and gettimeofday_precise,
  so that calls can be specialized based on specific usage requirements
- Introduced GetHighResRelativeTime, for high-resolution relative time
  measurements on all Windows versions.
This commit is contained in:
Alexis Campailla
2014-12-04 18:26:53 +01:00
parent 7827f41357
commit 08e4226e59
9 changed files with 113 additions and 40 deletions
Binary file not shown.
+2
View File
@@ -57,6 +57,7 @@ using namespace std;
const long long cSentinelHeapSize = 30 * 1024 * 1024;
extern "C" int checkForSentinelMode(int argc, char **argv);
extern "C" void InitTimeFunctions();
extern "C"
{
@@ -1274,6 +1275,7 @@ extern "C"
// Redis will allocate.
int main(int argc, char* argv[]) {
try {
InitTimeFunctions();
ParseCommandLineArguments(argc, argv);
SetupLogging();
} catch (system_error syserr) {
+2 -7
View File
@@ -443,15 +443,12 @@ int aeWinSocketAttach(int fd) {
void aeShutdown(int fd) {
char rbuf[100];
struct timeval timenow;
long long waitmsecs = 50; /* wait up to 50 millisecs */
long long endms;
long long nowms;
/* wait for last item to complete up to tosecs seconds*/
gettimeofday(&timenow, NULL);
endms = ((long long)timenow.tv_sec * 1000) +
((long long)timenow.tv_usec / 1000) + waitmsecs;
endms = GetHighResRelativeTime(1000) + waitmsecs;
if (shutdown(fd, SD_SEND) != SOCKET_ERROR) {
/* read data until no more or error to ensure shutdown completed */
@@ -460,9 +457,7 @@ void aeShutdown(int fd) {
if (rc == 0 || rc == SOCKET_ERROR)
break;
else {
gettimeofday(&timenow, NULL);
nowms = ((long long)timenow.tv_sec * 1000) +
((long long)timenow.tv_usec / 1000);
nowms = GetHighResRelativeTime(1000);
if (nowms > endms)
break;
}
+86 -1
View File
@@ -401,6 +401,56 @@ struct timezone
int tz_dsttime; /* type of dst correction */
};
static VOID (WINAPI *fnGetSystemTimePreciseAsFileTime)(LPFILETIME);
/* Interval (in seconds) of the high-resolution clock. */
static double highResTimeInterval = 0;
void InitTimeFunctions()
{
FARPROC fp;
HMODULE module;
LARGE_INTEGER perfFrequency;
/* Use GetSystemTimeAsFileTime as fallbcak where GetSystemTimePreciseAsFileTime is not available */
fnGetSystemTimePreciseAsFileTime = GetSystemTimeAsFileTime;
module = GetModuleHandleA("kernel32.dll");
if (module) {
fp = GetProcAddress(module, "GetSystemTimePreciseAsFileTime");
if (fp) {
fnGetSystemTimePreciseAsFileTime = (VOID (WINAPI*)(LPFILETIME)) fp;
}
}
/* Retrieve high-resolution timer frequency
* and precompute its reciprocal.
*/
if (QueryPerformanceFrequency(&perfFrequency)) {
highResTimeInterval = 1.0 / perfFrequency.QuadPart;
} else {
highResTimeInterval = 0;
}
}
unsigned long long GetHighResRelativeTime(double scale) {
LARGE_INTEGER counter;
/* If the performance interval is zero, there's no support. */
if (highResTimeInterval == 0) {
return 0;
}
if (!QueryPerformanceCounter(&counter)) {
return 0;
}
/* Because we have no guarantee about the order of magnitude of the
* performance counter interval, integer math could cause this computation
* to overflow. Therefore we resort to floating point math.
*/
return (unsigned long long) ((double)counter.QuadPart * highResTimeInterval * scale);
}
time_t gettimeofdaysecs(unsigned int *usec)
{
FILETIME ft;
@@ -419,7 +469,7 @@ time_t gettimeofdaysecs(unsigned int *usec)
return (tmpres / 1000000UL);
}
int gettimeofday(struct timeval *tv, struct timezone *tz)
int gettimeofday_fast(struct timeval *tv, struct timezone *tz)
{
FILETIME ft;
unsigned __int64 tmpres = 0;
@@ -454,6 +504,41 @@ int gettimeofday(struct timeval *tv, struct timezone *tz)
return 0;
}
int gettimeofday_highres(struct timeval *tv, struct timezone *tz)
{
FILETIME ft;
unsigned __int64 tmpres = 0;
static int tzflag;
if (NULL != tv)
{
fnGetSystemTimePreciseAsFileTime(&ft);
tmpres |= ft.dwHighDateTime;
tmpres <<= 32;
tmpres |= ft.dwLowDateTime;
/*converting file time to unix epoch*/
tmpres /= 10; /*convert into microseconds*/
tmpres -= DELTA_EPOCH_IN_MICROSECS;
tv->tv_sec = (long)(tmpres / 1000000UL);
tv->tv_usec = (long)(tmpres % 1000000UL);
}
if (NULL != tz)
{
if (!tzflag)
{
_tzset();
tzflag++;
}
tz->tz_minuteswest = _timezone / 60;
tz->tz_dsttime = _daylight;
}
return 0;
}
static _locale_t clocale = NULL;
double wstrtod(const char *nptr, char **eptr) {
double d;
+5 -1
View File
@@ -268,8 +268,12 @@ int w32initWinSock(void);
void *mmap(void *start, size_t length, int prot, int flags, int fd, off offset);
int munmap(void *start, size_t length);
int gettimeofday(struct timeval *tv, struct timezone *tz);
void InitTimeFunctions();
unsigned long long GetHighResRelativeTime(double scale);
int gettimeofday_fast(struct timeval *tv, struct timezone *tz);
int gettimeofday_highres(struct timeval *tv, struct timezone *tz);
time_t gettimeofdaysecs(unsigned int *usec);
#define gettimeofday gettimeofday_highres
char *ctime_r(const time_t *clock, char *buf);
+1 -1
View File
@@ -326,7 +326,7 @@ int dictRehash(dict *d, int n) {
long long timeInMilliseconds(void) {
#ifdef _WIN32
return GetTickCount();
return GetHighResRelativeTime(1000);
#else
struct timeval tv;
+9 -30
View File
@@ -107,30 +107,12 @@ typedef struct _client {
static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask);
static void createMissingClients(client c);
#ifdef _WIN32
/*acquires high resolution time stamps on windows, more details can be found here http://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx */
static long long getQPCTimeStamp()
{
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
return time.QuadPart;
}
static long long getQPCElapsedMicroSeconds(long long startime, long long endtime)
{
long long elapsedMicroseconds = endtime - startime;
LARGE_INTEGER Frequency;
QueryPerformanceFrequency(&Frequency);
// To guard against loss-of-precision, we convert
// to microseconds *before* dividing by ticks-per-second.
elapsedMicroseconds *= 1000000;
elapsedMicroseconds /= Frequency.QuadPart;
return elapsedMicroseconds;
}
#endif
/* Implementation */
static long long ustime(void) {
#ifdef _WIN32
return GetHighResRelativeTime(1000000);
#else
struct timeval tv;
long long ust;
@@ -138,9 +120,13 @@ static long long ustime(void) {
ust = ((long)tv.tv_sec)*1000000;
ust += tv.tv_usec;
return ust;
#endif
}
static long long mstime(void) {
#ifdef _WIN32
return GetHighResRelativeTime(1000);
#else
struct timeval tv;
long long mst;
@@ -148,6 +134,7 @@ static long long mstime(void) {
mst = ((long long)tv.tv_sec)*1000;
mst += tv.tv_usec/1000;
return mst;
#endif
}
static void freeClient(client c) {
@@ -234,11 +221,7 @@ static void readHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
* is not part of the latency, so calculate it only once, here. */
if (c->latency < 0)
{
#ifdef _WIN32
c->latency = getQPCElapsedMicroSeconds(c->start, getQPCTimeStamp());
#else
c->latency = ustime() - (c->start);
#endif
}
#ifdef WIN32_IOCP
@@ -334,11 +317,7 @@ static void writeHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
/* Really initialize: randomize keys and set start time. */
if (config.randomkeys) randomizeClientKey(c);
#ifdef _WIN32
c->start = getQPCTimeStamp();
#else
c->start = ustime();
#endif
c->start = ustime();
c->latency = -1;
}
+4
View File
@@ -134,6 +134,9 @@ char *redisGitDirty(void);
*--------------------------------------------------------------------------- */
static long long ustime(void) {
#ifdef _WIN32
return GetHighResRelativeTime(1000000);
#else
struct timeval tv;
long long ust;
@@ -141,6 +144,7 @@ static long long ustime(void) {
ust = ((long long)tv.tv_sec)*1000000;
ust += tv.tv_usec;
return ust;
#endif
}
static long long mstime(void) {
+4
View File
@@ -991,9 +991,13 @@ unsigned char *createIntList() {
}
long long usec(void) {
#ifdef _WIN32
return GetHighResRelativeTime(1000000);
#else
struct timeval tv;
gettimeofday(&tv,NULL);
return (((long long)tv.tv_sec)*1000000)+tv.tv_usec;
#endif
}
void stress(int pos, int num, int maxsize, int dnum) {