Line data Source code
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(), and on Windows we use
8 : * QueryPerformanceCounter(). These macros also give some breathing room to
9 : * use other high-precision-timing APIs.
10 : *
11 : * The basic data type is instr_time, which all callers should treat as an
12 : * opaque typedef. instr_time can store either an absolute time (of
13 : * unspecified reference time) or an interval. The operations provided
14 : * for it are:
15 : *
16 : * INSTR_TIME_IS_ZERO(t) is t equal to zero?
17 : *
18 : * INSTR_TIME_SET_ZERO(t) set t to zero (memset is acceptable too)
19 : *
20 : * INSTR_TIME_SET_CURRENT(t) set t to current time
21 : *
22 : *
23 : * INSTR_TIME_ADD(x, y) x += y
24 : *
25 : * INSTR_TIME_ADD_NANOSEC(t, n) x += y in nanoseconds (converts to ticks)
26 : *
27 : * INSTR_TIME_SUBTRACT(x, y) x -= y
28 : *
29 : * INSTR_TIME_ACCUM_DIFF(x, y, z) x += (y - z)
30 : *
31 : * INSTR_TIME_GT(x, y) x > y
32 : *
33 : * INSTR_TIME_GET_DOUBLE(t) convert t to double (in seconds)
34 : *
35 : * INSTR_TIME_GET_MILLISEC(t) convert t to double (in milliseconds)
36 : *
37 : * INSTR_TIME_GET_MICROSEC(t) convert t to int64 (in microseconds)
38 : *
39 : * INSTR_TIME_GET_NANOSEC(t) convert t to int64 (in nanoseconds)
40 : *
41 : * Note that INSTR_TIME_SUBTRACT and INSTR_TIME_ACCUM_DIFF convert
42 : * absolute times to intervals. The INSTR_TIME_GET_xxx operations are
43 : * only useful on intervals.
44 : *
45 : * When summing multiple measurements, it's recommended to leave the
46 : * running sum in instr_time form (ie, use INSTR_TIME_ADD or
47 : * INSTR_TIME_ACCUM_DIFF) and convert to a result format only at the end.
48 : *
49 : * Beware of multiple evaluations of the macro arguments.
50 : *
51 : *
52 : * Copyright (c) 2001-2026, PostgreSQL Global Development Group
53 : *
54 : * src/include/portability/instr_time.h
55 : *
56 : *-------------------------------------------------------------------------
57 : */
58 : #ifndef INSTR_TIME_H
59 : #define INSTR_TIME_H
60 :
61 :
62 : /*
63 : * We store interval times as an int64 integer on all platforms, as int64 is
64 : * cheap to add/subtract, the most common operation for instr_time. The
65 : * acquisition of time and converting to specific units of time is platform
66 : * specific.
67 : *
68 : * To avoid users of the API relying on the integer representation, we wrap
69 : * the 64bit integer in a struct.
70 : */
71 : typedef struct instr_time
72 : {
73 : int64 ticks; /* in platforms specific unit */
74 : } instr_time;
75 :
76 :
77 : /* helpers macros used in platform specific code below */
78 :
79 : #define NS_PER_S INT64CONST(1000000000)
80 : #define NS_PER_MS INT64CONST(1000000)
81 : #define NS_PER_US INT64CONST(1000)
82 :
83 :
84 : #ifndef WIN32
85 :
86 :
87 : /* Use clock_gettime() */
88 :
89 : #include <time.h>
90 :
91 : /*
92 : * The best clockid to use according to the POSIX spec is CLOCK_MONOTONIC,
93 : * since that will give reliable interval timing even in the face of changes
94 : * to the system clock. However, POSIX doesn't require implementations to
95 : * provide anything except CLOCK_REALTIME, so fall back to that if we don't
96 : * find CLOCK_MONOTONIC.
97 : *
98 : * Also, some implementations have nonstandard clockids with better properties
99 : * than CLOCK_MONOTONIC. In particular, as of macOS 10.12, Apple provides
100 : * CLOCK_MONOTONIC_RAW which is both faster to read and higher resolution than
101 : * their version of CLOCK_MONOTONIC.
102 : */
103 : #if defined(__darwin__) && defined(CLOCK_MONOTONIC_RAW)
104 : #define PG_INSTR_CLOCK CLOCK_MONOTONIC_RAW
105 : #elif defined(CLOCK_MONOTONIC)
106 : #define PG_INSTR_CLOCK CLOCK_MONOTONIC
107 : #else
108 : #define PG_INSTR_CLOCK CLOCK_REALTIME
109 : #endif
110 :
111 : /* helper for INSTR_TIME_SET_CURRENT */
112 : static inline instr_time
113 24737867 : pg_clock_gettime_ns(void)
114 : {
115 : instr_time now;
116 : struct timespec tmp;
117 :
118 24737867 : clock_gettime(PG_INSTR_CLOCK, &tmp);
119 24737867 : now.ticks = tmp.tv_sec * NS_PER_S + tmp.tv_nsec;
120 :
121 24737867 : return now;
122 : }
123 :
124 : #define INSTR_TIME_SET_CURRENT(t) \
125 : ((t) = pg_clock_gettime_ns())
126 :
127 : #define INSTR_TIME_GET_NANOSEC(t) \
128 : ((int64) (t).ticks)
129 :
130 : #define INSTR_TIME_ADD_NANOSEC(t, n) \
131 : ((t).ticks += (n))
132 :
133 :
134 : #else /* WIN32 */
135 :
136 :
137 : /* Use QueryPerformanceCounter() */
138 :
139 : /* helper for INSTR_TIME_SET_CURRENT */
140 : static inline instr_time
141 : pg_query_performance_counter(void)
142 : {
143 : instr_time now;
144 : LARGE_INTEGER tmp;
145 :
146 : QueryPerformanceCounter(&tmp);
147 : now.ticks = tmp.QuadPart;
148 :
149 : return now;
150 : }
151 :
152 : static inline double
153 : GetTimerFrequency(void)
154 : {
155 : LARGE_INTEGER f;
156 :
157 : QueryPerformanceFrequency(&f);
158 : return (double) f.QuadPart;
159 : }
160 :
161 : #define INSTR_TIME_SET_CURRENT(t) \
162 : ((t) = pg_query_performance_counter())
163 :
164 : #define INSTR_TIME_GET_NANOSEC(t) \
165 : ((int64) ((t).ticks * ((double) NS_PER_S / GetTimerFrequency())))
166 :
167 : #define INSTR_TIME_ADD_NANOSEC(t, n) \
168 : ((t).ticks += ((n) / ((double) NS_PER_S / GetTimerFrequency())))
169 :
170 : #endif /* WIN32 */
171 :
172 :
173 : /*
174 : * Common macros
175 : */
176 :
177 : #define INSTR_TIME_IS_ZERO(t) ((t).ticks == 0)
178 :
179 : #define INSTR_TIME_SET_ZERO(t) ((t).ticks = 0)
180 :
181 :
182 : #define INSTR_TIME_ADD(x,y) \
183 : ((x).ticks += (y).ticks)
184 :
185 : #define INSTR_TIME_SUBTRACT(x,y) \
186 : ((x).ticks -= (y).ticks)
187 :
188 : #define INSTR_TIME_ACCUM_DIFF(x,y,z) \
189 : ((x).ticks += (y).ticks - (z).ticks)
190 :
191 : #define INSTR_TIME_GT(x,y) \
192 : ((x).ticks > (y).ticks)
193 :
194 : #define INSTR_TIME_GET_DOUBLE(t) \
195 : ((double) INSTR_TIME_GET_NANOSEC(t) / NS_PER_S)
196 :
197 : #define INSTR_TIME_GET_MILLISEC(t) \
198 : ((double) INSTR_TIME_GET_NANOSEC(t) / NS_PER_MS)
199 :
200 : #define INSTR_TIME_GET_MICROSEC(t) \
201 : (INSTR_TIME_GET_NANOSEC(t) / NS_PER_US)
202 :
203 : #endif /* INSTR_TIME_H */
|