PostgreSQL Source Code git master
Loading...
Searching...
No Matches
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 x86 we use the RDTSC/RDTSCP instruction directly in
8 * certain cases, or alternatively clock_gettime() on Unix-like systems and
9 * QueryPerformanceCounter() on Windows. These macros also give some breathing
10 * 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_FAST(t) set t to current time without waiting
22 * for instructions in out-of-order window
23 *
24 * INSTR_TIME_SET_CURRENT(t) set t to current time while waiting for
25 * instructions in OOO to retire
26 *
27 *
28 * INSTR_TIME_ADD(x, y) x += y
29 *
30 * INSTR_TIME_ADD_NANOSEC(t, n) t += n in nanoseconds (converts to ticks)
31 *
32 * INSTR_TIME_SUBTRACT(x, y) x -= y
33 *
34 * INSTR_TIME_ACCUM_DIFF(x, y, z) x += (y - z)
35 *
36 * INSTR_TIME_GT(x, y) x > y
37 *
38 * INSTR_TIME_GET_DOUBLE(t) convert t to double (in seconds)
39 *
40 * INSTR_TIME_GET_MILLISEC(t) convert t to double (in milliseconds)
41 *
42 * INSTR_TIME_GET_MICROSEC(t) convert t to int64 (in microseconds)
43 *
44 * INSTR_TIME_GET_NANOSEC(t) convert t to int64 (in nanoseconds)
45 *
46 * Note that INSTR_TIME_SUBTRACT and INSTR_TIME_ACCUM_DIFF convert
47 * absolute times to intervals. The INSTR_TIME_GET_xxx operations are
48 * only useful on intervals.
49 *
50 * When summing multiple measurements, it's recommended to leave the
51 * running sum in instr_time form (ie, use INSTR_TIME_ADD or
52 * INSTR_TIME_ACCUM_DIFF) and convert to a result format only at the end.
53 *
54 * Beware of multiple evaluations of the macro arguments.
55 *
56 *
57 * Copyright (c) 2001-2026, PostgreSQL Global Development Group
58 *
59 * src/include/portability/instr_time.h
60 *
61 *-------------------------------------------------------------------------
62 */
63#ifndef INSTR_TIME_H
64#define INSTR_TIME_H
65
66
67/*
68 * We store interval times as an int64 integer on all platforms, as int64 is
69 * cheap to add/subtract, the most common operation for instr_time. The
70 * acquisition of time and converting to specific units of time is platform
71 * specific.
72 *
73 * To avoid users of the API relying on the integer representation, we wrap
74 * the 64bit integer in a struct.
75 */
76typedef struct instr_time
77{
78 int64 ticks; /* in platforms specific unit */
80
81
82/* helpers macros used in platform specific code below */
83
84#define NS_PER_S INT64CONST(1000000000)
85#define NS_PER_MS INT64CONST(1000000)
86#define NS_PER_US INT64CONST(1000)
87
88/* Shift amount for fixed-point ticks-to-nanoseconds conversion. */
89#define TICKS_TO_NS_SHIFT 14
90
91/*
92 * PG_INSTR_TICKS_TO_NS controls whether pg_ticks_to_ns/pg_ns_to_ticks needs to
93 * check ticks_per_ns_scaled and potentially convert ticks <=> nanoseconds.
94 *
95 * PG_INSTR_TSC_CLOCK controls whether the TSC clock source is compiled in, and
96 * potentially used based on timing_tsc_enabled.
97 */
98#if defined(__x86_64__) || defined(_M_X64)
99#define PG_INSTR_TICKS_TO_NS 1
100#define PG_INSTR_TSC_CLOCK 1
101#elif defined(WIN32)
102#define PG_INSTR_TICKS_TO_NS 1
103#define PG_INSTR_TSC_CLOCK 0
104#else
105#define PG_INSTR_TICKS_TO_NS 0
106#define PG_INSTR_TSC_CLOCK 0
107#endif
108
109/*
110 * Variables used to translate ticks to nanoseconds, initialized by
111 * pg_initialize_timing and adjusted by pg_set_timing_clock_source calls or
112 * changes of the "timing_clock_source" GUC.
113 *
114 * Note that changing these values after setting an instr_time and before
115 * reading/converting it will lead to incorrect results. This is technically
116 * possible because the GUC can be changed at runtime, but unlikely, and we
117 * allow changing this at runtime to simplify testing of different sources.
118 */
122
131
133
134/*
135 * Initialize timing infrastructure
136 *
137 * This must be called at least once before using INSTR_TIME_SET_CURRENT*
138 * macros.
139 *
140 * If you want to use the TSC clock source in a client program,
141 * pg_set_timing_clock_source() needs to also be called.
142 */
143extern void pg_initialize_timing(void);
144
145/*
146 * Sets the time source to be used. Mainly intended for frontend programs,
147 * the backend should set it via the timing_clock_source GUC instead.
148 *
149 * Returns false if the clock source could not be set, for example when TSC
150 * is not available despite being explicitly set.
151 */
153
154/* Whether to actually use TSC based on availability and GUC settings. */
156
157/*
158 * TSC frequency in kHz, set during initialization.
159 *
160 * -1 = not yet initialized, 0 = TSC not usable, >0 = frequency in kHz.
161 */
163
164#if PG_INSTR_TSC_CLOCK
165
166extern void pg_initialize_timing_tsc(void);
167
168typedef struct TscClockSourceInfo
169{
170 int32 frequency_khz; /* from CPUID or calibration */
171 int32 calibrated_frequency_khz; /* from calibration */
172 char frequency_source[128]; /* describes how frequency was
173 * determined */
175
177
178#endif /* PG_INSTR_TSC_CLOCK */
179
180/*
181 * Returns the current timing clock source effectively in use, resolving
182 * TIMING_CLOCK_SOURCE_AUTO to either TIMING_CLOCK_SOURCE_SYSTEM or
183 * TIMING_CLOCK_SOURCE_TSC.
184 */
185static inline TimingClockSourceType
187{
188#if PG_INSTR_TSC_CLOCK
191#endif
193}
194
195#ifndef WIN32
196
197/* On POSIX, use clock_gettime() for system clock source */
198
199#include <time.h>
200
201/*
202 * The best clockid to use according to the POSIX spec is CLOCK_MONOTONIC,
203 * since that will give reliable interval timing even in the face of changes
204 * to the system clock. However, POSIX doesn't require implementations to
205 * provide anything except CLOCK_REALTIME, so fall back to that if we don't
206 * find CLOCK_MONOTONIC.
207 *
208 * Also, some implementations have nonstandard clockids with better properties
209 * than CLOCK_MONOTONIC. In particular, as of macOS 10.12, Apple provides
210 * CLOCK_MONOTONIC_RAW which is both faster to read and higher resolution than
211 * their version of CLOCK_MONOTONIC.
212 *
213 * Note this does not get used in case the TSC clock source logic is used,
214 * which directly calls architecture specific timing instructions (e.g. RDTSC).
215 */
216#if defined(__darwin__) && defined(CLOCK_MONOTONIC_RAW)
217#define PG_INSTR_SYSTEM_CLOCK CLOCK_MONOTONIC_RAW
218#define PG_INSTR_SYSTEM_CLOCK_NAME "clock_gettime (CLOCK_MONOTONIC_RAW)"
219#elif defined(CLOCK_MONOTONIC)
220#define PG_INSTR_SYSTEM_CLOCK CLOCK_MONOTONIC
221#define PG_INSTR_SYSTEM_CLOCK_NAME "clock_gettime (CLOCK_MONOTONIC)"
222#else
223#define PG_INSTR_SYSTEM_CLOCK CLOCK_REALTIME
224#define PG_INSTR_SYSTEM_CLOCK_NAME "clock_gettime (CLOCK_REALTIME)"
225#endif
226
227static inline instr_time
229{
231 struct timespec tmp;
232
234
236 now.ticks = tmp.tv_sec * NS_PER_S + tmp.tv_nsec;
237
238 return now;
239}
240
241#else /* WIN32 */
242
243/* On Windows, use QueryPerformanceCounter() for system clock source */
244
245#define PG_INSTR_SYSTEM_CLOCK_NAME "QueryPerformanceCounter"
246static inline instr_time
248{
250 LARGE_INTEGER tmp;
251
253
255 now.ticks = tmp.QuadPart;
256
257 return now;
258}
259
260#endif /* WIN32 */
261
262static inline int64
264{
265#if PG_INSTR_TICKS_TO_NS
266 int64 ns = 0;
267
269
270 /*
271 * Avoid doing work if we don't use scaled ticks, e.g. system clock on
272 * Unix (in that case ticks is counted in nanoseconds)
273 */
274 if (ticks_per_ns_scaled == 0)
275 return ticks;
276
277 /*
278 * Would multiplication overflow? If so perform computation in two parts.
279 */
280 if (unlikely(ticks > (int64) max_ticks_no_overflow))
281 {
282 /*
283 * To avoid overflow, first scale total ticks down by the fixed
284 * factor, and *afterwards* multiply them by the frequency-based scale
285 * factor.
286 *
287 * The remaining ticks can follow the regular formula, since they
288 * won't overflow.
289 */
290 int64 count = ticks >> TICKS_TO_NS_SHIFT;
291
292 ns = count * ticks_per_ns_scaled;
293 ticks -= (count << TICKS_TO_NS_SHIFT);
294 }
295
296 ns += (ticks * ticks_per_ns_scaled) >> TICKS_TO_NS_SHIFT;
297
298 return ns;
299#else
301
302 return ticks;
303#endif /* PG_INSTR_TICKS_TO_NS */
304}
305
306static inline int64
308{
309#if PG_INSTR_TICKS_TO_NS
310 int64 ticks = 0;
311
313
314 /*
315 * If ticks_per_ns_scaled is zero, ticks are already in nanoseconds (e.g.
316 * system clock on Unix).
317 */
318 if (ticks_per_ns_scaled == 0)
319 return ns;
320
321 /*
322 * The reverse of pg_ticks_to_ns to avoid a similar overflow problem.
323 */
324 if (unlikely(ns > (INT64_MAX >> TICKS_TO_NS_SHIFT)))
325 {
326 int64 count = ns / ticks_per_ns_scaled;
327
328 ticks = count << TICKS_TO_NS_SHIFT;
329 ns -= count * ticks_per_ns_scaled;
330 }
331
332 ticks += (ns << TICKS_TO_NS_SHIFT) / ticks_per_ns_scaled;
333
334 return ticks;
335#else
337
338 return ns;
339#endif /* PG_INSTR_TICKS_TO_NS */
340}
341
342#if PG_INSTR_TSC_CLOCK
343
344#define PG_INSTR_TSC_CLOCK_NAME_FAST "RDTSC"
345#define PG_INSTR_TSC_CLOCK_NAME "RDTSCP"
346
347#ifdef _MSC_VER
348#include <intrin.h>
349#endif /* defined(_MSC_VER) */
350
351/* Helpers to abstract compiler differences for reading the x86 TSC. */
352static inline int64
353pg_rdtsc(void)
354{
355#ifdef _MSC_VER
356 return __rdtsc();
357#else
358 return __builtin_ia32_rdtsc();
359#endif /* defined(_MSC_VER) */
360}
361
362static inline int64
363pg_rdtscp(void)
364{
365 uint32 unused;
366
367#ifdef _MSC_VER
368 return __rdtscp(&unused);
369#else
370 return __builtin_ia32_rdtscp(&unused);
371#endif /* defined(_MSC_VER) */
372}
373
374/*
375 * Marked always_inline due to a shortcoming in gcc's heuristics leading to
376 * only inlining the function partially.
377 * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124795
378 */
380pg_get_ticks(void)
381{
383 {
385
386 now.ticks = pg_rdtscp();
387 return now;
388 }
389
390 return pg_get_ticks_system();
391}
392
395{
397 {
399
400 now.ticks = pg_rdtsc();
401 return now;
402 }
403
404 return pg_get_ticks_system();
405}
406
407#else
408
411{
412 return pg_get_ticks_system();
413}
414
417{
418 return pg_get_ticks_system();
419}
420
421#endif /* PG_INSTR_TSC_CLOCK */
422
423/*
424 * Common macros
425 */
426
427#define INSTR_TIME_IS_ZERO(t) ((t).ticks == 0)
428
429#define INSTR_TIME_SET_ZERO(t) ((t).ticks = 0)
430
431#define INSTR_TIME_SET_CURRENT_FAST(t) \
432 ((t) = pg_get_ticks_fast())
433
434#define INSTR_TIME_SET_CURRENT(t) \
435 ((t) = pg_get_ticks())
436
437
438#define INSTR_TIME_ADD(x,y) \
439 ((x).ticks += (y).ticks)
440
441#define INSTR_TIME_ADD_NANOSEC(t, n) \
442 ((t).ticks += pg_ns_to_ticks(n))
443
444#define INSTR_TIME_SUBTRACT(x,y) \
445 ((x).ticks -= (y).ticks)
446
447#define INSTR_TIME_ACCUM_DIFF(x,y,z) \
448 ((x).ticks += (y).ticks - (z).ticks)
449
450#define INSTR_TIME_GT(x,y) \
451 ((x).ticks > (y).ticks)
452
453#define INSTR_TIME_GET_NANOSEC(t) \
454 (pg_ticks_to_ns((t).ticks))
455
456#define INSTR_TIME_GET_DOUBLE(t) \
457 ((double) INSTR_TIME_GET_NANOSEC(t) / NS_PER_S)
458
459#define INSTR_TIME_GET_MILLISEC(t) \
460 ((double) INSTR_TIME_GET_NANOSEC(t) / NS_PER_MS)
461
462#define INSTR_TIME_GET_MICROSEC(t) \
463 (INSTR_TIME_GET_NANOSEC(t) / NS_PER_US)
464
465#endif /* INSTR_TIME_H */
Datum now(PG_FUNCTION_ARGS)
Definition timestamp.c:1613
#define PGDLLIMPORT
Definition c.h:1421
#define likely(x)
Definition c.h:437
#define Assert(condition)
Definition c.h:943
int64_t int64
Definition c.h:621
#define pg_attribute_always_inline
Definition c.h:305
int32_t int32
Definition c.h:620
uint64_t uint64
Definition c.h:625
#define unlikely(x)
Definition c.h:438
uint32_t uint32
Definition c.h:624
static pg_attribute_always_inline instr_time pg_get_ticks_fast(void)
Definition instr_time.h:416
#define TICKS_TO_NS_SHIFT
Definition instr_time.h:89
PGDLLIMPORT int timing_clock_source
Definition instr_time.c:64
#define PG_INSTR_SYSTEM_CLOCK
Definition instr_time.h:223
PGDLLIMPORT uint64 max_ticks_no_overflow
Definition instr_time.c:62
void pg_initialize_timing(void)
Definition instr_time.c:84
static instr_time pg_get_ticks_system(void)
Definition instr_time.h:228
PGDLLIMPORT bool timing_initialized
Definition instr_time.c:63
#define NS_PER_S
Definition instr_time.h:84
static TimingClockSourceType pg_current_timing_clock_source(void)
Definition instr_time.h:186
PGDLLIMPORT bool timing_tsc_enabled
Definition instr_time.c:66
static int64 pg_ns_to_ticks(int64 ns)
Definition instr_time.h:307
static int64 pg_ticks_to_ns(int64 ticks)
Definition instr_time.h:263
TimingClockSourceType
Definition instr_time.h:124
@ TIMING_CLOCK_SOURCE_SYSTEM
Definition instr_time.h:126
@ TIMING_CLOCK_SOURCE_AUTO
Definition instr_time.h:125
PGDLLIMPORT uint64 ticks_per_ns_scaled
Definition instr_time.c:61
PGDLLIMPORT int32 timing_tsc_frequency_khz
Definition instr_time.c:67
bool pg_set_timing_clock_source(TimingClockSourceType source)
Definition instr_time.c:94
static pg_attribute_always_inline instr_time pg_get_ticks(void)
Definition instr_time.h:410
static rewind_source * source
Definition pg_rewind.c:89
static int fb(int x)
int64 ticks
Definition instr_time.h:78