diff --git a/configure b/configure
index 0f143a0fad7a72e7c13943ee733cefdccba3efc7..e5dd6fb789d0421c50700c44229a33dfb36658b7 100755
--- a/configure
+++ b/configure
@@ -9055,6 +9055,62 @@ if test "$ac_res" != no; then :
 
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
+$as_echo_n "checking for library containing clock_gettime... " >&6; }
+if ${ac_cv_search_clock_gettime+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+  ;
+  return 0;
+}
+_ACEOF
+for ac_lib in '' rt posix4; do
+  if test -z "$ac_lib"; then
+    ac_res="none required"
+  else
+    ac_res=-l$ac_lib
+    LIBS="-l$ac_lib  $ac_func_search_save_LIBS"
+  fi
+  if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_search_clock_gettime=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext
+  if ${ac_cv_search_clock_gettime+:} false; then :
+  break
+fi
+done
+if ${ac_cv_search_clock_gettime+:} false; then :
+
+else
+  ac_cv_search_clock_gettime=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
+$as_echo "$ac_cv_search_clock_gettime" >&6; }
+ac_res=$ac_cv_search_clock_gettime
+if test "$ac_res" != no; then :
+  test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
 # Solaris:
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing fdatasync" >&5
 $as_echo_n "checking for library containing fdatasync... " >&6; }
@@ -12520,7 +12576,7 @@ fi
 LIBS_including_readline="$LIBS"
 LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
 
-for ac_func in cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l
+for ac_func in cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
 ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/configure.in b/configure.in
index b9831bc3408552ab1ca91804a48424c4fd32f805..77aa3b41d75337bb31da01f0e92bb297761e63b4 100644
--- a/configure.in
+++ b/configure.in
@@ -1016,6 +1016,7 @@ AC_SEARCH_LIBS(getopt_long, [getopt gnugetopt])
 AC_SEARCH_LIBS(crypt, crypt)
 AC_SEARCH_LIBS(shm_open, rt)
 AC_SEARCH_LIBS(shm_unlink, rt)
+AC_SEARCH_LIBS(clock_gettime, [rt posix4])
 # Solaris:
 AC_SEARCH_LIBS(fdatasync, [rt posix4])
 # Required for thread_test.c on Solaris
@@ -1415,7 +1416,7 @@ PGAC_FUNC_WCSTOMBS_L
 LIBS_including_readline="$LIBS"
 LIBS=`echo "$LIBS" | sed -e 's/-ledit//g' -e 's/-lreadline//g'`
 
-AC_CHECK_FUNCS([cbrt dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l])
+AC_CHECK_FUNCS([cbrt clock_gettime dlopen fdatasync getifaddrs getpeerucred getrlimit mbstowcs_l memmove poll pstat pthread_is_threaded_np readlink setproctitle setsid shm_open symlink sync_file_range towlower utime utimes wcstombs wcstombs_l])
 
 AC_REPLACE_FUNCS(fseeko)
 case $host_os in
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 42a3fc862e9665e1e4f5af66353ee73b3434a81a..b9dfdd41c1a3f3e74f0e919f4bfd4d829817d287 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 ceb8b7956eee08d40aa105a6cb4ddaa2b84369dc..199668c18764025dd78d222469327f0269839531 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 16caf6eee3dcc0353c3f8ddeca403c0f030bbf74..b10d6f019f9eb612363d3a83030536072b7fedfa 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 */