diff --git a/bin/release/redis-2.8.17.zip b/bin/release/redis-2.8.17.zip index 19ddf7ad..939c356b 100644 Binary files a/bin/release/redis-2.8.17.zip and b/bin/release/redis-2.8.17.zip differ diff --git a/src/Win32_Interop/Win32_QFork.cpp b/src/Win32_Interop/Win32_QFork.cpp index f8d8776c..0acdf086 100644 --- a/src/Win32_Interop/Win32_QFork.cpp +++ b/src/Win32_Interop/Win32_QFork.cpp @@ -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) { diff --git a/src/Win32_Interop/win32_wsiocp.c b/src/Win32_Interop/win32_wsiocp.c index 21d6147e..c518469e 100644 --- a/src/Win32_Interop/win32_wsiocp.c +++ b/src/Win32_Interop/win32_wsiocp.c @@ -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; } diff --git a/src/Win32_Interop/win32fixes.c b/src/Win32_Interop/win32fixes.c index 1455c734..97afe223 100644 --- a/src/Win32_Interop/win32fixes.c +++ b/src/Win32_Interop/win32fixes.c @@ -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; diff --git a/src/Win32_Interop/win32fixes.h b/src/Win32_Interop/win32fixes.h index 8a314022..fc47b0eb 100644 --- a/src/Win32_Interop/win32fixes.h +++ b/src/Win32_Interop/win32fixes.h @@ -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); diff --git a/src/dict.c b/src/dict.c index dfd6aea4..56a0ab15 100644 --- a/src/dict.c +++ b/src/dict.c @@ -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; diff --git a/src/redis-benchmark.c b/src/redis-benchmark.c index 77b85253..d911680b 100644 --- a/src/redis-benchmark.c +++ b/src/redis-benchmark.c @@ -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; } diff --git a/src/redis-cli.c b/src/redis-cli.c index 9fb4481e..88565d43 100644 --- a/src/redis-cli.c +++ b/src/redis-cli.c @@ -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) { diff --git a/src/ziplist.c b/src/ziplist.c index 6b2c9b92..44c46bcf 100644 --- a/src/ziplist.c +++ b/src/ziplist.c @@ -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) {