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