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:
Binary file not shown.
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user