Line data Source code
1 : /*------------------------------------------------------------------------- 2 : * 3 : * instr_time.h 4 : * portable high-precision interval timing 5 : * 6 : * This file provides an abstraction layer to hide portability issues in 7 : * interval timing. On Unix we use clock_gettime(), and on Windows we use 8 : * QueryPerformanceCounter(). These macros also give some breathing room to 9 : * use other high-precision-timing APIs. 10 : * 11 : * The basic data type is instr_time, which all callers should treat as an 12 : * opaque typedef. instr_time can store either an absolute time (of 13 : * unspecified reference time) or an interval. The operations provided 14 : * for it are: 15 : * 16 : * INSTR_TIME_IS_ZERO(t) is t equal to zero? 17 : * 18 : * INSTR_TIME_SET_ZERO(t) set t to zero (memset is acceptable too) 19 : * 20 : * INSTR_TIME_SET_CURRENT(t) set t to current time 21 : * 22 : * INSTR_TIME_SET_CURRENT_LAZY(t) set t to current time if t is zero, 23 : * evaluates to whether t changed 24 : * 25 : * INSTR_TIME_ADD(x, y) x += y 26 : * 27 : * INSTR_TIME_SUBTRACT(x, y) x -= y 28 : * 29 : * INSTR_TIME_ACCUM_DIFF(x, y, z) x += (y - z) 30 : * 31 : * INSTR_TIME_GET_DOUBLE(t) convert t to double (in seconds) 32 : * 33 : * INSTR_TIME_GET_MILLISEC(t) convert t to double (in milliseconds) 34 : * 35 : * INSTR_TIME_GET_MICROSEC(t) convert t to int64 (in microseconds) 36 : * 37 : * INSTR_TIME_GET_NANOSEC(t) convert t to int64 (in nanoseconds) 38 : * 39 : * Note that INSTR_TIME_SUBTRACT and INSTR_TIME_ACCUM_DIFF convert 40 : * absolute times to intervals. The INSTR_TIME_GET_xxx operations are 41 : * only useful on intervals. 42 : * 43 : * When summing multiple measurements, it's recommended to leave the 44 : * running sum in instr_time form (ie, use INSTR_TIME_ADD or 45 : * INSTR_TIME_ACCUM_DIFF) and convert to a result format only at the end. 46 : * 47 : * Beware of multiple evaluations of the macro arguments. 48 : * 49 : * 50 : * Copyright (c) 2001-2024, PostgreSQL Global Development Group 51 : * 52 : * src/include/portability/instr_time.h 53 : * 54 : *------------------------------------------------------------------------- 55 : */ 56 : #ifndef INSTR_TIME_H 57 : #define INSTR_TIME_H 58 : 59 : 60 : /* 61 : * We store interval times as an int64 integer on all platforms, as int64 is 62 : * cheap to add/subtract, the most common operation for instr_time. The 63 : * acquisition of time and converting to specific units of time is platform 64 : * specific. 65 : * 66 : * To avoid users of the API relying on the integer representation, we wrap 67 : * the 64bit integer in a struct. 68 : */ 69 : typedef struct instr_time 70 : { 71 : int64 ticks; /* in platforms specific unit */ 72 : } instr_time; 73 : 74 : 75 : /* helpers macros used in platform specific code below */ 76 : 77 : #define NS_PER_S INT64CONST(1000000000) 78 : #define NS_PER_MS INT64CONST(1000000) 79 : #define NS_PER_US INT64CONST(1000) 80 : 81 : 82 : #ifndef WIN32 83 : 84 : 85 : /* Use clock_gettime() */ 86 : 87 : #include <time.h> 88 : 89 : /* 90 : * The best clockid to use according to the POSIX spec is CLOCK_MONOTONIC, 91 : * since that will give reliable interval timing even in the face of changes 92 : * to the system clock. However, POSIX doesn't require implementations to 93 : * provide anything except CLOCK_REALTIME, so fall back to that if we don't 94 : * find CLOCK_MONOTONIC. 95 : * 96 : * Also, some implementations have nonstandard clockids with better properties 97 : * than CLOCK_MONOTONIC. In particular, as of macOS 10.12, Apple provides 98 : * CLOCK_MONOTONIC_RAW which is both faster to read and higher resolution than 99 : * their version of CLOCK_MONOTONIC. 100 : */ 101 : #if defined(__darwin__) && defined(CLOCK_MONOTONIC_RAW) 102 : #define PG_INSTR_CLOCK CLOCK_MONOTONIC_RAW 103 : #elif defined(CLOCK_MONOTONIC) 104 : #define PG_INSTR_CLOCK CLOCK_MONOTONIC 105 : #else 106 : #define PG_INSTR_CLOCK CLOCK_REALTIME 107 : #endif 108 : 109 : /* helper for INSTR_TIME_SET_CURRENT */ 110 : static inline instr_time 111 21736732 : pg_clock_gettime_ns(void) 112 : { 113 : instr_time now; 114 : struct timespec tmp; 115 : 116 21736732 : clock_gettime(PG_INSTR_CLOCK, &tmp); 117 21736732 : now.ticks = tmp.tv_sec * NS_PER_S + tmp.tv_nsec; 118 : 119 21736732 : return now; 120 : } 121 : 122 : #define INSTR_TIME_SET_CURRENT(t) \ 123 : ((t) = pg_clock_gettime_ns()) 124 : 125 : #define INSTR_TIME_GET_NANOSEC(t) \ 126 : ((int64) (t).ticks) 127 : 128 : 129 : #else /* WIN32 */ 130 : 131 : 132 : /* Use QueryPerformanceCounter() */ 133 : 134 : /* helper for INSTR_TIME_SET_CURRENT */ 135 : static inline instr_time 136 : pg_query_performance_counter(void) 137 : { 138 : instr_time now; 139 : LARGE_INTEGER tmp; 140 : 141 : QueryPerformanceCounter(&tmp); 142 : now.ticks = tmp.QuadPart; 143 : 144 : return now; 145 : } 146 : 147 : static inline double 148 : GetTimerFrequency(void) 149 : { 150 : LARGE_INTEGER f; 151 : 152 : QueryPerformanceFrequency(&f); 153 : return (double) f.QuadPart; 154 : } 155 : 156 : #define INSTR_TIME_SET_CURRENT(t) \ 157 : ((t) = pg_query_performance_counter()) 158 : 159 : #define INSTR_TIME_GET_NANOSEC(t) \ 160 : ((int64) ((t).ticks * ((double) NS_PER_S / GetTimerFrequency()))) 161 : 162 : #endif /* WIN32 */ 163 : 164 : 165 : /* 166 : * Common macros 167 : */ 168 : 169 : #define INSTR_TIME_IS_ZERO(t) ((t).ticks == 0) 170 : 171 : 172 : #define INSTR_TIME_SET_ZERO(t) ((t).ticks = 0) 173 : 174 : #define INSTR_TIME_SET_CURRENT_LAZY(t) \ 175 : (INSTR_TIME_IS_ZERO(t) ? INSTR_TIME_SET_CURRENT(t), true : false) 176 : 177 : 178 : #define INSTR_TIME_ADD(x,y) \ 179 : ((x).ticks += (y).ticks) 180 : 181 : #define INSTR_TIME_SUBTRACT(x,y) \ 182 : ((x).ticks -= (y).ticks) 183 : 184 : #define INSTR_TIME_ACCUM_DIFF(x,y,z) \ 185 : ((x).ticks += (y).ticks - (z).ticks) 186 : 187 : 188 : #define INSTR_TIME_GET_DOUBLE(t) \ 189 : ((double) INSTR_TIME_GET_NANOSEC(t) / NS_PER_S) 190 : 191 : #define INSTR_TIME_GET_MILLISEC(t) \ 192 : ((double) INSTR_TIME_GET_NANOSEC(t) / NS_PER_MS) 193 : 194 : #define INSTR_TIME_GET_MICROSEC(t) \ 195 : (INSTR_TIME_GET_NANOSEC(t) / NS_PER_US) 196 : 197 : #endif /* INSTR_TIME_H */