diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/pg_config.h.in | 3 | ||||
-rw-r--r-- | src/include/pg_config.h.win32 | 3 | ||||
-rw-r--r-- | src/include/portability/instr_time.h | 102 |
3 files changed, 104 insertions, 4 deletions
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index 42a3fc862e9..b9dfdd41c1a 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -105,6 +105,9 @@ /* Define to 1 if you have the `class' function. */ #undef HAVE_CLASS +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + /* Define to 1 if you have the <crtdefs.h> header file. */ #undef HAVE_CRTDEFS_H diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32 index ceb8b7956ee..199668c1876 100644 --- a/src/include/pg_config.h.win32 +++ b/src/include/pg_config.h.win32 @@ -75,6 +75,9 @@ /* Define to 1 if you have the `class' function. */ /* #undef HAVE_CLASS */ +/* Define to 1 if you have the `clock_gettime' function. */ +/* #undef HAVE_CLOCK_GETTIME */ + /* Define to 1 if you have the `crypt' function. */ /* #undef HAVE_CRYPT */ diff --git a/src/include/portability/instr_time.h b/src/include/portability/instr_time.h index 16caf6eee3d..b10d6f019f9 100644 --- a/src/include/portability/instr_time.h +++ b/src/include/portability/instr_time.h @@ -4,10 +4,10 @@ * portable high-precision interval timing * * This file provides an abstraction layer to hide portability issues in - * interval timing. On Unix we use gettimeofday(), but on Windows that - * gives a low-precision result so we must use QueryPerformanceCounter() - * instead. These macros also give some breathing room to use other - * high-precision-timing APIs on yet other platforms. + * interval timing. On Unix we use clock_gettime() if available, else + * gettimeofday(). On Windows, gettimeofday() gives a low-precision result + * so we must use QueryPerformanceCounter() instead. These macros also give + * some breathing room to use other high-precision-timing APIs. * * The basic data type is instr_time, which all callers should treat as an * opaque typedef. instr_time can store either an absolute time (of @@ -54,6 +54,94 @@ #ifndef WIN32 +#ifdef HAVE_CLOCK_GETTIME + +/* Use clock_gettime() */ + +#include <time.h> + +/* + * The best clockid to use according to the POSIX spec is CLOCK_MONOTONIC, + * since that will give reliable interval timing even in the face of changes + * to the system clock. However, POSIX doesn't require implementations to + * provide anything except CLOCK_REALTIME, so fall back to that if we don't + * find CLOCK_MONOTONIC. + * + * Also, some implementations have nonstandard clockids with better properties + * than CLOCK_MONOTONIC. In particular, as of macOS 10.12, Apple provides + * CLOCK_MONOTONIC_RAW which is both faster to read and higher resolution than + * their version of CLOCK_MONOTONIC. + */ +#if defined(__darwin__) && defined(CLOCK_MONOTONIC_RAW) +#define PG_INSTR_CLOCK CLOCK_MONOTONIC_RAW +#elif defined(CLOCK_MONOTONIC) +#define PG_INSTR_CLOCK CLOCK_MONOTONIC +#else +#define PG_INSTR_CLOCK CLOCK_REALTIME +#endif + +typedef struct timespec instr_time; + +#define INSTR_TIME_IS_ZERO(t) ((t).tv_nsec == 0 && (t).tv_sec == 0) + +#define INSTR_TIME_SET_ZERO(t) ((t).tv_sec = 0, (t).tv_nsec = 0) + +#define INSTR_TIME_SET_CURRENT(t) ((void) clock_gettime(PG_INSTR_CLOCK, &(t))) + +#define INSTR_TIME_ADD(x,y) \ + do { \ + (x).tv_sec += (y).tv_sec; \ + (x).tv_nsec += (y).tv_nsec; \ + /* Normalize */ \ + while ((x).tv_nsec >= 1000000000) \ + { \ + (x).tv_nsec -= 1000000000; \ + (x).tv_sec++; \ + } \ + } while (0) + +#define INSTR_TIME_SUBTRACT(x,y) \ + do { \ + (x).tv_sec -= (y).tv_sec; \ + (x).tv_nsec -= (y).tv_nsec; \ + /* Normalize */ \ + while ((x).tv_nsec < 0) \ + { \ + (x).tv_nsec += 1000000000; \ + (x).tv_sec--; \ + } \ + } while (0) + +#define INSTR_TIME_ACCUM_DIFF(x,y,z) \ + do { \ + (x).tv_sec += (y).tv_sec - (z).tv_sec; \ + (x).tv_nsec += (y).tv_nsec - (z).tv_nsec; \ + /* Normalize after each add to avoid overflow/underflow of tv_nsec */ \ + while ((x).tv_nsec < 0) \ + { \ + (x).tv_nsec += 1000000000; \ + (x).tv_sec--; \ + } \ + while ((x).tv_nsec >= 1000000000) \ + { \ + (x).tv_nsec -= 1000000000; \ + (x).tv_sec++; \ + } \ + } while (0) + +#define INSTR_TIME_GET_DOUBLE(t) \ + (((double) (t).tv_sec) + ((double) (t).tv_nsec) / 1000000000.0) + +#define INSTR_TIME_GET_MILLISEC(t) \ + (((double) (t).tv_sec * 1000.0) + ((double) (t).tv_nsec) / 1000000.0) + +#define INSTR_TIME_GET_MICROSEC(t) \ + (((uint64) (t).tv_sec * (uint64) 1000000) + (uint64) ((t).tv_nsec / 1000)) + +#else /* !HAVE_CLOCK_GETTIME */ + +/* Use gettimeofday() */ + #include <sys/time.h> typedef struct timeval instr_time; @@ -113,8 +201,13 @@ typedef struct timeval instr_time; #define INSTR_TIME_GET_MICROSEC(t) \ (((uint64) (t).tv_sec * (uint64) 1000000) + (uint64) (t).tv_usec) + +#endif /* HAVE_CLOCK_GETTIME */ + #else /* WIN32 */ +/* Use QueryPerformanceCounter() */ + typedef LARGE_INTEGER instr_time; #define INSTR_TIME_IS_ZERO(t) ((t).QuadPart == 0) @@ -149,6 +242,7 @@ GetTimerFrequency(void) QueryPerformanceFrequency(&f); return (double) f.QuadPart; } + #endif /* WIN32 */ #endif /* INSTR_TIME_H */ |