aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/include/pg_config.h.in3
-rw-r--r--src/include/pg_config.h.win323
-rw-r--r--src/include/portability/instr_time.h102
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 */