diff --git a/src/include/portability/instr_time.h b/src/include/portability/instr_time.h index 9ea1a68bd9..cc85138e21 100644 --- a/src/include/portability/instr_time.h +++ b/src/include/portability/instr_time.h @@ -34,6 +34,8 @@ * * INSTR_TIME_GET_MICROSEC(t) convert t to uint64 (in microseconds) * + * INSTR_TIME_GET_NANOSEC(t) convert t to uint64 (in nanoseconds) + * * Note that INSTR_TIME_SUBTRACT and INSTR_TIME_ACCUM_DIFF convert * absolute times to intervals. The INSTR_TIME_GET_xxx operations are * only useful on intervals. @@ -54,8 +56,32 @@ #ifndef INSTR_TIME_H #define INSTR_TIME_H + +/* + * We store interval times as an int64 integer on all platforms, as int64 is + * cheap to add/subtract, the most common operation for instr_time. The + * acquisition of time and converting to specific units of time is platform + * specific. + * + * To avoid users of the API relying on the integer representation, we wrap + * the 64bit integer in a struct. + */ +typedef struct instr_time +{ + int64 ticks; /* in platforms specific unit */ +} instr_time; + + +/* helpers macros used in platform specific code below */ + +#define NS_PER_S INT64CONST(1000000000) +#define NS_PER_MS INT64CONST(1000000) +#define NS_PER_US INT64CONST(1000) + + #ifndef WIN32 + /* Use clock_gettime() */ #include @@ -80,93 +106,43 @@ #define PG_INSTR_CLOCK CLOCK_REALTIME #endif -typedef struct timespec instr_time; +/* helper for INSTR_TIME_SET_CURRENT */ +static inline instr_time +pg_clock_gettime_ns(void) +{ + instr_time now; + struct timespec tmp; -#define INSTR_TIME_IS_ZERO(t) ((t).tv_nsec == 0 && (t).tv_sec == 0) + clock_gettime(PG_INSTR_CLOCK, &tmp); + now.ticks = tmp.tv_sec * NS_PER_S + tmp.tv_nsec; -#define INSTR_TIME_SET_ZERO(t) ((t).tv_sec = 0, (t).tv_nsec = 0) + return now; +} -#define INSTR_TIME_SET_CURRENT(t) ((void) clock_gettime(PG_INSTR_CLOCK, &(t))) +#define INSTR_TIME_SET_CURRENT(t) \ + ((t) = pg_clock_gettime_ns()) -#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_GET_NANOSEC(t) \ + ((int64) (t).ticks) -#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 /* WIN32 */ + /* Use QueryPerformanceCounter() */ -typedef LARGE_INTEGER instr_time; +/* helper for INSTR_TIME_SET_CURRENT */ +static inline instr_time +pg_query_performance_counter(void) +{ + instr_time now; + LARGE_INTEGER tmp; -#define INSTR_TIME_IS_ZERO(t) ((t).QuadPart == 0) + QueryPerformanceCounter(&tmp); + now.ticks = tmp.QuadPart; -#define INSTR_TIME_SET_ZERO(t) ((t).QuadPart = 0) - -#define INSTR_TIME_SET_CURRENT(t) QueryPerformanceCounter(&(t)) - -#define INSTR_TIME_ADD(x,y) \ - ((x).QuadPart += (y).QuadPart) - -#define INSTR_TIME_SUBTRACT(x,y) \ - ((x).QuadPart -= (y).QuadPart) - -#define INSTR_TIME_ACCUM_DIFF(x,y,z) \ - ((x).QuadPart += (y).QuadPart - (z).QuadPart) - -#define INSTR_TIME_GET_DOUBLE(t) \ - (((double) (t).QuadPart) / GetTimerFrequency()) - -#define INSTR_TIME_GET_MILLISEC(t) \ - (((double) (t).QuadPart * 1000.0) / GetTimerFrequency()) - -#define INSTR_TIME_GET_MICROSEC(t) \ - ((uint64) (((double) (t).QuadPart * 1000000.0) / GetTimerFrequency())) + return now; +} static inline double GetTimerFrequency(void) @@ -177,11 +153,45 @@ GetTimerFrequency(void) return (double) f.QuadPart; } +#define INSTR_TIME_SET_CURRENT(t) \ + ((t) = pg_query_performance_counter()) + +#define INSTR_TIME_GET_NANOSEC(t) \ + ((int64) ((t).ticks * ((double) NS_PER_S / GetTimerFrequency()))) + #endif /* WIN32 */ -/* same macro on all platforms */ + +/* + * Common macros + */ + +#define INSTR_TIME_IS_ZERO(t) ((t).ticks == 0) + + +#define INSTR_TIME_SET_ZERO(t) ((t).ticks = 0) #define INSTR_TIME_SET_CURRENT_LAZY(t) \ (INSTR_TIME_IS_ZERO(t) ? INSTR_TIME_SET_CURRENT(t), true : false) + +#define INSTR_TIME_ADD(x,y) \ + ((x).ticks += (y).ticks) + +#define INSTR_TIME_SUBTRACT(x,y) \ + ((x).ticks -= (y).ticks) + +#define INSTR_TIME_ACCUM_DIFF(x,y,z) \ + ((x).ticks += (y).ticks - (z).ticks) + + +#define INSTR_TIME_GET_DOUBLE(t) \ + ((double) INSTR_TIME_GET_NANOSEC(t) / NS_PER_S) + +#define INSTR_TIME_GET_MILLISEC(t) \ + ((double) INSTR_TIME_GET_NANOSEC(t) / NS_PER_MS) + +#define INSTR_TIME_GET_MICROSEC(t) \ + (INSTR_TIME_GET_NANOSEC(t) / NS_PER_US) + #endif /* INSTR_TIME_H */