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