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-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 */
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
112 {
113  instr_time now;
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 */
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 */
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1608
int64_t int64
Definition: c.h:482
#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