diff --git a/configure b/configure index 0f143a0fad..e5dd6fb789 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 b9831bc340..77aa3b41d7 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 42a3fc862e..b9dfdd41c1 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 header file. */ #undef HAVE_CRTDEFS_H diff --git a/src/include/pg_config.h.win32 b/src/include/pg_config.h.win32 index ceb8b7956e..199668c187 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 16caf6eee3..b10d6f019f 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 + +/* + * 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 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 */