PostgreSQL Source Code  git master
instr_time.h
Go to the documentation of this file.
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 
86 typedef 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 
150 typedef 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 
214 typedef 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 
240 static inline double
241 GetTimerFrequency(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 */
struct timeval instr_time
Definition: instr_time.h:150