| /*------------------------------------------------------------------------- |
| * |
| * instr_time.h |
| * portable high-precision interval timing |
| * |
| * This file provides an abstraction layer to hide portability issues in |
| * interval timing. On Unix we use clock_gettime(), and on Windows we use |
| * QueryPerformanceCounter(). 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 |
| * unspecified reference time) or an interval. The operations provided |
| * for it are: |
| * |
| * INSTR_TIME_IS_ZERO(t) is t equal to zero? |
| * |
| * INSTR_TIME_SET_ZERO(t) set t to zero (memset is acceptable too) |
| * |
| * INSTR_TIME_SET_CURRENT(t) set t to current time |
| * |
| * INSTR_TIME_SET_CURRENT_LAZY(t) set t to current time if t is zero, |
| * evaluates to whether t changed |
| * |
| * INSTR_TIME_ADD(x, y) x += y |
| * |
| * INSTR_TIME_SUBTRACT(x, y) x -= y |
| * |
| * INSTR_TIME_ACCUM_DIFF(x, y, z) x += (y - z) |
| * |
| * INSTR_TIME_GET_DOUBLE(t) convert t to double (in seconds) |
| * |
| * INSTR_TIME_GET_MILLISEC(t) convert t to double (in milliseconds) |
| * |
| * 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. |
| * |
| * When summing multiple measurements, it's recommended to leave the |
| * running sum in instr_time form (ie, use INSTR_TIME_ADD or |
| * INSTR_TIME_ACCUM_DIFF) and convert to a result format only at the end. |
| * |
| * Beware of multiple evaluations of the macro arguments. |
| * |
| * |
| * Copyright (c) 2001-2023, PostgreSQL Global Development Group |
| * |
| * src/include/portability/instr_time.h |
| * |
| *------------------------------------------------------------------------- |
| */ |
| #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 <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 |
| |
| /* helper for INSTR_TIME_SET_CURRENT */ |
| static inline instr_time |
| pg_clock_gettime_ns(void) |
| { |
| instr_time now; |
| struct timespec tmp; |
| |
| clock_gettime(PG_INSTR_CLOCK, &tmp); |
| now.ticks = tmp.tv_sec * NS_PER_S + tmp.tv_nsec; |
| |
| return now; |
| } |
| |
| #define INSTR_TIME_SET_CURRENT(t) \ |
| ((t) = pg_clock_gettime_ns()) |
| |
| #define INSTR_TIME_SET_CURRENT_COARSE(t) INSTR_TIME_SET_CURRENT(t) |
| |
| |
| #define INSTR_TIME_ASSIGN(x,y) ((x).ticks = (y).ticks) |
| |
| #define INSTR_TIME_GET_NANOSEC(t) \ |
| ((int64) (t).ticks) |
| |
| |
| #else /* WIN32 */ |
| |
| |
| /* Use QueryPerformanceCounter() */ |
| |
| /* helper for INSTR_TIME_SET_CURRENT */ |
| static inline instr_time |
| pg_query_performance_counter(void) |
| { |
| instr_time now; |
| LARGE_INTEGER tmp; |
| |
| QueryPerformanceCounter(&tmp); |
| now.ticks = tmp.QuadPart; |
| return now; |
| } |
| |
| #define INSTR_TIME_SET_ZERO(t) ((t).QuadPart = 0) |
| |
| #define INSTR_TIME_SET_CURRENT(t) QueryPerformanceCounter(&(t)) |
| |
| #define INSTR_TIME_SET_CURRENT_COARSE(t) INSTR_TIME_SET_CURRENT(t) |
| |
| #define INSTR_TIME_ASSIGN(x,y) ((x).QuadPart = (y).QuadPart) |
| |
| #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())) |
| |
| |
| static inline double |
| GetTimerFrequency(void) |
| { |
| LARGE_INTEGER f; |
| |
| QueryPerformanceFrequency(&f); |
| 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 */ |
| |
| |
| /* |
| * 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_COARSE(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 */ |