PostgreSQL Source Code git master
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 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 int64 (in microseconds)
36 *
37 * INSTR_TIME_GET_NANOSEC(t) convert t to int64 (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-2025, 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 */
69typedef struct instr_time
70{
71 int64 ticks; /* in platforms specific unit */
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 */
110static inline instr_time
112{
114 struct timespec tmp;
115
116 clock_gettime(PG_INSTR_CLOCK, &tmp);
117 now.ticks = tmp.tv_sec * NS_PER_S + tmp.tv_nsec;
118
119 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 */
135static inline instr_time
136pg_query_performance_counter(void)
137{
139 LARGE_INTEGER tmp;
140
141 QueryPerformanceCounter(&tmp);
142 now.ticks = tmp.QuadPart;
143
144 return now;
145}
146
147static inline double
148GetTimerFrequency(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 */
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1608
int64_t int64
Definition: c.h:499
#define NS_PER_S
Definition: instr_time.h:77
#define PG_INSTR_CLOCK
Definition: instr_time.h:106
struct instr_time instr_time
static instr_time pg_clock_gettime_ns(void)
Definition: instr_time.h:111
int64 ticks
Definition: instr_time.h:71