PostgreSQL Source Code git master
Loading...
Searching...
No Matches
instrument.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * instrument.c
4 * functions for instrumentation of plan execution
5 *
6 *
7 * Copyright (c) 2001-2026, PostgreSQL Global Development Group
8 *
9 * IDENTIFICATION
10 * src/backend/executor/instrument.c
11 *
12 *-------------------------------------------------------------------------
13 */
14#include "postgres.h"
15
16#include <unistd.h>
17
18#include "executor/instrument.h"
19
24
25static void BufferUsageAdd(BufferUsage *dst, const BufferUsage *add);
26static void WalUsageAdd(WalUsage *dst, WalUsage *add);
27
28
29/* Allocate new instrumentation structure(s) */
31InstrAlloc(int n, int instrument_options, bool async_mode)
32{
33 Instrumentation *instr;
34
35 /* initialize all fields to zeroes, then modify as needed */
36 instr = palloc0(n * sizeof(Instrumentation));
37 if (instrument_options & (INSTRUMENT_BUFFERS | INSTRUMENT_TIMER | INSTRUMENT_WAL))
38 {
39 bool need_buffers = (instrument_options & INSTRUMENT_BUFFERS) != 0;
40 bool need_wal = (instrument_options & INSTRUMENT_WAL) != 0;
41 bool need_timer = (instrument_options & INSTRUMENT_TIMER) != 0;
42 int i;
43
44 for (i = 0; i < n; i++)
45 {
47 instr[i].need_walusage = need_wal;
48 instr[i].need_timer = need_timer;
49 instr[i].async_mode = async_mode;
50 }
51 }
52
53 return instr;
54}
55
56/* Initialize a pre-allocated instrumentation structure. */
57void
58InstrInit(Instrumentation *instr, int instrument_options)
59{
60 memset(instr, 0, sizeof(Instrumentation));
61 instr->need_bufusage = (instrument_options & INSTRUMENT_BUFFERS) != 0;
62 instr->need_walusage = (instrument_options & INSTRUMENT_WAL) != 0;
63 instr->need_timer = (instrument_options & INSTRUMENT_TIMER) != 0;
64}
65
66/* Entry to a plan node */
67void
69{
70 if (instr->need_timer &&
72 elog(ERROR, "InstrStartNode called twice in a row");
73
74 /* save buffer usage totals at node entry, if needed */
75 if (instr->need_bufusage)
77
78 if (instr->need_walusage)
80}
81
82/* Exit from a plan node */
83void
84InstrStopNode(Instrumentation *instr, double nTuples)
85{
86 double save_tuplecount = instr->tuplecount;
88
89 /* count the returned tuples */
90 instr->tuplecount += nTuples;
91
92 /* let's update the time only if the timer was requested */
93 if (instr->need_timer)
94 {
95 if (INSTR_TIME_IS_ZERO(instr->starttime))
96 elog(ERROR, "InstrStopNode called without start");
97
100
102 }
103
104 /* Add delta of buffer usage since entry to node's totals */
105 if (instr->need_bufusage)
107 &pgBufferUsage, &instr->bufusage_start);
108
109 if (instr->need_walusage)
111 &pgWalUsage, &instr->walusage_start);
112
113 /* Is this the first tuple of this cycle? */
114 if (!instr->running)
115 {
116 instr->running = true;
117 instr->firsttuple = instr->counter;
118 }
119 else
120 {
121 /*
122 * In async mode, if the plan node hadn't emitted any tuples before,
123 * this might be the first tuple
124 */
125 if (instr->async_mode && save_tuplecount < 1.0)
126 instr->firsttuple = instr->counter;
127 }
128}
129
130/* Update tuple count */
131void
133{
134 /* count the returned tuples */
135 instr->tuplecount += nTuples;
136}
137
138/* Finish a run cycle for a plan node */
139void
141{
142 /* Skip if nothing has happened, or already shut down */
143 if (!instr->running)
144 return;
145
146 if (!INSTR_TIME_IS_ZERO(instr->starttime))
147 elog(ERROR, "InstrEndLoop called on running node");
148
149 /* Accumulate per-cycle statistics into totals */
150 INSTR_TIME_ADD(instr->startup, instr->firsttuple);
151 INSTR_TIME_ADD(instr->total, instr->counter);
152 instr->ntuples += instr->tuplecount;
153 instr->nloops += 1;
154
155 /* Reset for next cycle (if any) */
156 instr->running = false;
160 instr->tuplecount = 0;
161}
162
163/* aggregate instrumentation information */
164void
166{
167 if (!dst->running && add->running)
168 {
169 dst->running = true;
170 dst->firsttuple = add->firsttuple;
171 }
172 else if (dst->running && add->running &&
173 INSTR_TIME_LT(dst->firsttuple, add->firsttuple))
174 dst->firsttuple = add->firsttuple;
175
176 INSTR_TIME_ADD(dst->counter, add->counter);
177
178 dst->tuplecount += add->tuplecount;
179 INSTR_TIME_ADD(dst->startup, add->startup);
180 INSTR_TIME_ADD(dst->total, add->total);
181 dst->ntuples += add->ntuples;
182 dst->ntuples2 += add->ntuples2;
183 dst->nloops += add->nloops;
184 dst->nfiltered1 += add->nfiltered1;
185 dst->nfiltered2 += add->nfiltered2;
186
187 /* Add delta of buffer usage since entry to node's totals */
188 if (dst->need_bufusage)
189 BufferUsageAdd(&dst->bufusage, &add->bufusage);
190
191 if (dst->need_walusage)
192 WalUsageAdd(&dst->walusage, &add->walusage);
193}
194
195/* note current values during parallel executor startup */
196void
202
203/* report usage after parallel executor shutdown */
204void
206{
207 memset(bufusage, 0, sizeof(BufferUsage));
209 memset(walusage, 0, sizeof(WalUsage));
211}
212
213/* accumulate work done by workers in leader's stats */
214void
216{
217 BufferUsageAdd(&pgBufferUsage, bufusage);
218 WalUsageAdd(&pgWalUsage, walusage);
219}
220
221/* dst += add */
222static void
224{
225 dst->shared_blks_hit += add->shared_blks_hit;
226 dst->shared_blks_read += add->shared_blks_read;
227 dst->shared_blks_dirtied += add->shared_blks_dirtied;
228 dst->shared_blks_written += add->shared_blks_written;
229 dst->local_blks_hit += add->local_blks_hit;
230 dst->local_blks_read += add->local_blks_read;
231 dst->local_blks_dirtied += add->local_blks_dirtied;
232 dst->local_blks_written += add->local_blks_written;
233 dst->temp_blks_read += add->temp_blks_read;
234 dst->temp_blks_written += add->temp_blks_written;
235 INSTR_TIME_ADD(dst->shared_blk_read_time, add->shared_blk_read_time);
236 INSTR_TIME_ADD(dst->shared_blk_write_time, add->shared_blk_write_time);
237 INSTR_TIME_ADD(dst->local_blk_read_time, add->local_blk_read_time);
238 INSTR_TIME_ADD(dst->local_blk_write_time, add->local_blk_write_time);
239 INSTR_TIME_ADD(dst->temp_blk_read_time, add->temp_blk_read_time);
240 INSTR_TIME_ADD(dst->temp_blk_write_time, add->temp_blk_write_time);
241}
242
243/* dst += add - sub */
244void
246 const BufferUsage *add,
247 const BufferUsage *sub)
248{
249 dst->shared_blks_hit += add->shared_blks_hit - sub->shared_blks_hit;
250 dst->shared_blks_read += add->shared_blks_read - sub->shared_blks_read;
251 dst->shared_blks_dirtied += add->shared_blks_dirtied - sub->shared_blks_dirtied;
252 dst->shared_blks_written += add->shared_blks_written - sub->shared_blks_written;
253 dst->local_blks_hit += add->local_blks_hit - sub->local_blks_hit;
254 dst->local_blks_read += add->local_blks_read - sub->local_blks_read;
255 dst->local_blks_dirtied += add->local_blks_dirtied - sub->local_blks_dirtied;
256 dst->local_blks_written += add->local_blks_written - sub->local_blks_written;
257 dst->temp_blks_read += add->temp_blks_read - sub->temp_blks_read;
258 dst->temp_blks_written += add->temp_blks_written - sub->temp_blks_written;
259 INSTR_TIME_ACCUM_DIFF(dst->shared_blk_read_time,
260 add->shared_blk_read_time, sub->shared_blk_read_time);
261 INSTR_TIME_ACCUM_DIFF(dst->shared_blk_write_time,
262 add->shared_blk_write_time, sub->shared_blk_write_time);
263 INSTR_TIME_ACCUM_DIFF(dst->local_blk_read_time,
264 add->local_blk_read_time, sub->local_blk_read_time);
265 INSTR_TIME_ACCUM_DIFF(dst->local_blk_write_time,
266 add->local_blk_write_time, sub->local_blk_write_time);
267 INSTR_TIME_ACCUM_DIFF(dst->temp_blk_read_time,
268 add->temp_blk_read_time, sub->temp_blk_read_time);
269 INSTR_TIME_ACCUM_DIFF(dst->temp_blk_write_time,
270 add->temp_blk_write_time, sub->temp_blk_write_time);
271}
272
273/* helper functions for WAL usage accumulation */
274static void
276{
277 dst->wal_bytes += add->wal_bytes;
278 dst->wal_records += add->wal_records;
279 dst->wal_fpi += add->wal_fpi;
280 dst->wal_fpi_bytes += add->wal_fpi_bytes;
281 dst->wal_buffers_full += add->wal_buffers_full;
282}
283
284void
286{
287 dst->wal_bytes += add->wal_bytes - sub->wal_bytes;
288 dst->wal_records += add->wal_records - sub->wal_records;
289 dst->wal_fpi += add->wal_fpi - sub->wal_fpi;
290 dst->wal_fpi_bytes += add->wal_fpi_bytes - sub->wal_fpi_bytes;
291 dst->wal_buffers_full += add->wal_buffers_full - sub->wal_buffers_full;
292}
#define ERROR
Definition elog.h:39
#define elog(elevel,...)
Definition elog.h:226
#define INSTR_TIME_SET_CURRENT(t)
Definition instr_time.h:122
#define INSTR_TIME_ADD(x, y)
Definition instr_time.h:178
#define INSTR_TIME_IS_ZERO(t)
Definition instr_time.h:169
#define INSTR_TIME_LT(x, y)
Definition instr_time.h:187
#define INSTR_TIME_SET_CURRENT_LAZY(t)
Definition instr_time.h:174
#define INSTR_TIME_SET_ZERO(t)
Definition instr_time.h:172
#define INSTR_TIME_ACCUM_DIFF(x, y, z)
Definition instr_time.h:184
void InstrUpdateTupleCount(Instrumentation *instr, double nTuples)
Definition instrument.c:132
void InstrAccumParallelQuery(BufferUsage *bufusage, WalUsage *walusage)
Definition instrument.c:215
void InstrEndLoop(Instrumentation *instr)
Definition instrument.c:140
Instrumentation * InstrAlloc(int n, int instrument_options, bool async_mode)
Definition instrument.c:31
static void BufferUsageAdd(BufferUsage *dst, const BufferUsage *add)
Definition instrument.c:223
void InstrAggNode(Instrumentation *dst, Instrumentation *add)
Definition instrument.c:165
static BufferUsage save_pgBufferUsage
Definition instrument.c:21
void InstrEndParallelQuery(BufferUsage *bufusage, WalUsage *walusage)
Definition instrument.c:205
static WalUsage save_pgWalUsage
Definition instrument.c:23
static void WalUsageAdd(WalUsage *dst, WalUsage *add)
Definition instrument.c:275
WalUsage pgWalUsage
Definition instrument.c:22
void WalUsageAccumDiff(WalUsage *dst, const WalUsage *add, const WalUsage *sub)
Definition instrument.c:285
void InstrStartParallelQuery(void)
Definition instrument.c:197
BufferUsage pgBufferUsage
Definition instrument.c:20
void InstrInit(Instrumentation *instr, int instrument_options)
Definition instrument.c:58
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition instrument.c:245
void InstrStartNode(Instrumentation *instr)
Definition instrument.c:68
void InstrStopNode(Instrumentation *instr, double nTuples)
Definition instrument.c:84
@ INSTRUMENT_TIMER
Definition instrument.h:63
@ INSTRUMENT_BUFFERS
Definition instrument.h:64
@ INSTRUMENT_WAL
Definition instrument.h:66
int i
Definition isn.c:77
void * palloc0(Size size)
Definition mcxt.c:1417
static int fb(int x)
instr_time local_blk_read_time
Definition instrument.h:38
int64 shared_blks_dirtied
Definition instrument.h:28
int64 local_blks_hit
Definition instrument.h:30
instr_time temp_blk_write_time
Definition instrument.h:41
instr_time shared_blk_read_time
Definition instrument.h:36
instr_time shared_blk_write_time
Definition instrument.h:37
int64 local_blks_written
Definition instrument.h:33
instr_time temp_blk_read_time
Definition instrument.h:40
instr_time local_blk_write_time
Definition instrument.h:39
int64 temp_blks_read
Definition instrument.h:34
int64 shared_blks_read
Definition instrument.h:27
int64 shared_blks_written
Definition instrument.h:29
int64 temp_blks_written
Definition instrument.h:35
int64 local_blks_read
Definition instrument.h:31
int64 local_blks_dirtied
Definition instrument.h:32
int64 shared_blks_hit
Definition instrument.h:26
BufferUsage bufusage_start
Definition instrument.h:83
WalUsage walusage
Definition instrument.h:94
instr_time total
Definition instrument.h:87
BufferUsage bufusage
Definition instrument.h:93
instr_time starttime
Definition instrument.h:79
instr_time counter
Definition instrument.h:80
WalUsage walusage_start
Definition instrument.h:84
instr_time firsttuple
Definition instrument.h:81
double tuplecount
Definition instrument.h:82
instr_time startup
Definition instrument.h:86
int64 wal_buffers_full
Definition instrument.h:57
uint64 wal_bytes
Definition instrument.h:55
int64 wal_fpi
Definition instrument.h:54
uint64 wal_fpi_bytes
Definition instrument.h:56
int64 wal_records
Definition instrument.h:53