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-2021, 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
GetTimerFrequency(void)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 */
257