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-2017, 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