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() if available, else
8 * gettimeofday(). On Windows, gettimeofday() gives a low-precision result
9 * so we must use QueryPerformanceCounter() instead. These macros also give
10 * some breathing room to use other high-precision-timing APIs.
11 *
12 * The basic data type is instr_time, which all callers should treat as an
13 * opaque typedef. instr_time can store either an absolute time (of
14 * unspecified reference time) or an interval. The operations provided
15 * for it are:
16 *
17 * INSTR_TIME_IS_ZERO(t) is t equal to zero?
18 *
19 * INSTR_TIME_SET_ZERO(t) set t to zero (memset is acceptable too)
20 *
21 * INSTR_TIME_SET_CURRENT(t) set t to current time
22 *
23 * INSTR_TIME_ADD(x, y) x += y
24 *
25 * INSTR_TIME_SUBTRACT(x, y) x -= y
26 *
27 * INSTR_TIME_ACCUM_DIFF(x, y, z) x += (y - z)
28 *
29 * INSTR_TIME_GET_DOUBLE(t) convert t to double (in seconds)
30 *
31 * INSTR_TIME_GET_MILLISEC(t) convert t to double (in milliseconds)
32 *
33 * INSTR_TIME_GET_MICROSEC(t) convert t to uint64 (in microseconds)
34 *
35 * Note that INSTR_TIME_SUBTRACT and INSTR_TIME_ACCUM_DIFF convert
36 * absolute times to intervals. The INSTR_TIME_GET_xxx operations are
37 * only useful on intervals.
38 *
39 * When summing multiple measurements, it's recommended to leave the
40 * running sum in instr_time form (ie, use INSTR_TIME_ADD or
41 * INSTR_TIME_ACCUM_DIFF) and convert to a result format only at the end.
42 *
43 * Beware of multiple evaluations of the macro arguments.
44 *
45 *
46 * Copyright (c) 2001-2018, PostgreSQL Global Development Group
47 *
48 * src/include/portability/instr_time.h
49 *
50 *-------------------------------------------------------------------------
51 */
52 #ifndef INSTR_TIME_H
53 #define INSTR_TIME_H
54
55 #ifndef WIN32
56
57 #ifdef HAVE_CLOCK_GETTIME
58
59 /* Use clock_gettime() */
60
61 #include <time.h>
62
63 /*
64 * The best clockid to use according to the POSIX spec is CLOCK_MONOTONIC,
65 * since that will give reliable interval timing even in the face of changes
66 * to the system clock. However, POSIX doesn't require implementations to
67 * provide anything except CLOCK_REALTIME, so fall back to that if we don't
68 * find CLOCK_MONOTONIC.
69 *
70 * Also, some implementations have nonstandard clockids with better properties
71 * than CLOCK_MONOTONIC. In particular, as of macOS 10.12, Apple provides
72 * CLOCK_MONOTONIC_RAW which is both faster to read and higher resolution than
73 * their version of CLOCK_MONOTONIC.
74 */
75 #if defined(__darwin__) && defined(CLOCK_MONOTONIC_RAW)
76 #define PG_INSTR_CLOCK CLOCK_MONOTONIC_RAW
77 #elif defined(CLOCK_MONOTONIC)
78 #define PG_INSTR_CLOCK CLOCK_MONOTONIC
79 #else
80 #define PG_INSTR_CLOCK CLOCK_REALTIME
81 #endif
82
83 typedef struct timespec instr_time;
84
85 #define INSTR_TIME_IS_ZERO(t) ((t).tv_nsec == 0 && (t).tv_sec == 0)
86
87 #define INSTR_TIME_SET_ZERO(t) ((t).tv_sec = 0, (t).tv_nsec = 0)
88
89 #define INSTR_TIME_SET_CURRENT(t) ((void) clock_gettime(PG_INSTR_CLOCK, &(t)))
90
91 #define INSTR_TIME_ADD(x,y) \
92 do { \
93 (x).tv_sec += (y).tv_sec; \
94 (x).tv_nsec += (y).tv_nsec; \
95 /* Normalize */ \
96 while ((x).tv_nsec >= 1000000000) \
97 { \
98 (x).tv_nsec -= 1000000000; \
99 (x).tv_sec++; \
100 } \
101 } while (0)
102
103 #define INSTR_TIME_SUBTRACT(x,y) \
104 do { \
105 (x).tv_sec -= (y).tv_sec; \
106 (x).tv_nsec -= (y).tv_nsec; \
107 /* Normalize */ \
108 while ((x).tv_nsec < 0) \
109 { \
110 (x).tv_nsec += 1000000000; \
111 (x).tv_sec--; \
112 } \
113 } while (0)
114
115 #define INSTR_TIME_ACCUM_DIFF(x,y,z) \
116 do { \
117 (x).tv_sec += (y).tv_sec - (z).tv_sec; \
118 (x).tv_nsec += (y).tv_nsec - (z).tv_nsec; \
119 /* Normalize after each add to avoid overflow/underflow of tv_nsec */ \
120 while ((x).tv_nsec < 0) \
121 { \
122 (x).tv_nsec += 1000000000; \
123 (x).tv_sec--; \
124 } \
125 while ((x).tv_nsec >= 1000000000) \
126 { \
127 (x).tv_nsec -= 1000000000; \
128 (x).tv_sec++; \
129 } \
130 } while (0)
131
132 #define INSTR_TIME_GET_DOUBLE(t) \
133 (((double) (t).tv_sec) + ((double) (t).tv_nsec) / 1000000000.0)
134
135 #define INSTR_TIME_GET_MILLISEC(t) \
136 (((double) (t).tv_sec * 1000.0) + ((double) (t).tv_nsec) / 1000000.0)
137
138 #define INSTR_TIME_GET_MICROSEC(t) \
139 (((uint64) (t).tv_sec * (uint64) 1000000) + (uint64) ((t).tv_nsec / 1000))
140
141 #else /* !HAVE_CLOCK_GETTIME */
142
143 /* Use gettimeofday() */
144
145 #include <sys/time.h>
146
147 typedef struct timeval instr_time;
148
149 #define INSTR_TIME_IS_ZERO(t) ((t).tv_usec == 0 && (t).tv_sec == 0)
150
151 #define INSTR_TIME_SET_ZERO(t) ((t).tv_sec = 0, (t).tv_usec = 0)
152
153 #define INSTR_TIME_SET_CURRENT(t) gettimeofday(&(t), NULL)
154
155 #define INSTR_TIME_ADD(x,y) \
156 do { \
157 (x).tv_sec += (y).tv_sec; \
158 (x).tv_usec += (y).tv_usec; \
159 /* Normalize */ \
160 while ((x).tv_usec >= 1000000) \
161 { \
162 (x).tv_usec -= 1000000; \
163 (x).tv_sec++; \
164 } \
165 } while (0)
166
167 #define INSTR_TIME_SUBTRACT(x,y) \
168 do { \
169 (x).tv_sec -= (y).tv_sec; \
170 (x).tv_usec -= (y).tv_usec; \
171 /* Normalize */ \
172 while ((x).tv_usec < 0) \
173 { \
174 (x).tv_usec += 1000000; \
175 (x).tv_sec--; \
176 } \
177 } while (0)
178
179 #define INSTR_TIME_ACCUM_DIFF(x,y,z) \
180 do { \
181 (x).tv_sec += (y).tv_sec - (z).tv_sec; \
182 (x).tv_usec += (y).tv_usec - (z).tv_usec; \
183 /* Normalize after each add to avoid overflow/underflow of tv_usec */ \
184 while ((x).tv_usec < 0) \
185 { \
186 (x).tv_usec += 1000000; \
187 (x).tv_sec--; \
188 } \
189 while ((x).tv_usec >= 1000000) \
190 { \
191 (x).tv_usec -= 1000000; \
192 (x).tv_sec++; \
193 } \
194 } while (0)
195
196 #define INSTR_TIME_GET_DOUBLE(t) \
197 (((double) (t).tv_sec) + ((double) (t).tv_usec) / 1000000.0)
198
199 #define INSTR_TIME_GET_MILLISEC(t) \
200 (((double) (t).tv_sec * 1000.0) + ((double) (t).tv_usec) / 1000.0)
201
202 #define INSTR_TIME_GET_MICROSEC(t) \
203 (((uint64) (t).tv_sec * (uint64) 1000000) + (uint64) (t).tv_usec)
204
205 #endif /* HAVE_CLOCK_GETTIME */
206
207 #else /* WIN32 */
208
209 /* Use QueryPerformanceCounter() */
210
211 typedef LARGE_INTEGER instr_time;
212
213 #define INSTR_TIME_IS_ZERO(t) ((t).QuadPart == 0)
214
215 #define INSTR_TIME_SET_ZERO(t) ((t).QuadPart = 0)
216
217 #define INSTR_TIME_SET_CURRENT(t) QueryPerformanceCounter(&(t))
218
219 #define INSTR_TIME_ADD(x,y) \
220 ((x).QuadPart += (y).QuadPart)
221
222 #define INSTR_TIME_SUBTRACT(x,y) \
223 ((x).QuadPart -= (y).QuadPart)
224
225 #define INSTR_TIME_ACCUM_DIFF(x,y,z) \
226 ((x).QuadPart += (y).QuadPart - (z).QuadPart)
227
228 #define INSTR_TIME_GET_DOUBLE(t) \
229 (((double) (t).QuadPart) / GetTimerFrequency())
230
231 #define INSTR_TIME_GET_MILLISEC(t) \
232 (((double) (t).QuadPart * 1000.0) / GetTimerFrequency())
233
234 #define INSTR_TIME_GET_MICROSEC(t) \
235 ((uint64) (((double) (t).QuadPart * 1000000.0) / GetTimerFrequency()))
236
237 static inline double
GetTimerFrequency(void)238 GetTimerFrequency(void)
239 {
240 LARGE_INTEGER f;
241
242 QueryPerformanceFrequency(&f);
243 return (double) f.QuadPart;
244 }
245
246 #endif /* WIN32 */
247
248 #endif /* INSTR_TIME_H */
249