v7-0004-fixup-show-prefetch-stats-for-SeqScan.patch
text/x-patch
Filename: v7-0004-fixup-show-prefetch-stats-for-SeqScan.patch
Type: text/x-patch
Part: 3
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v7-0004
Subject: fixup: show prefetch stats for SeqScan
| File | + | − |
|---|---|---|
| src/backend/commands/explain.c | 14 | 15 |
| src/backend/executor/execParallel.c | 8 | 8 |
| src/backend/executor/nodeSeqscan.c | 66 | 28 |
From 0b19891ca39f986492d5079dc6406de454bc3511 Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tomas@vondra.me>
Date: Wed, 1 Apr 2026 20:20:57 +0200
Subject: [PATCH v7 4/6] fixup: show prefetch stats for SeqScan
---
src/backend/commands/explain.c | 29 +++++----
src/backend/executor/execParallel.c | 16 ++---
src/backend/executor/nodeSeqscan.c | 94 ++++++++++++++++++++---------
3 files changed, 88 insertions(+), 51 deletions(-)
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index f91e9d0048e..20c5d720516 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -4053,21 +4053,26 @@ static void
show_scan_io_usage(ScanState *planstate, ExplainState *es)
{
Plan *plan = planstate->ps.plan;
- IOStats stats;
+ IOStats stats = {0};
if (!es->io)
return;
- /* scan not started or no prefetch stats */
- if (!(planstate &&
- planstate->ss_currentScanDesc &&
- planstate->ss_currentScanDesc->rs_instrument))
- return;
-
/*
- * Initialize counters with stats from the local process first, then
- * accumulate data from parallel workers.
+ * Initialize counters with stats from the local process first.
+ *
+ * The scan descriptor may not exist, e.g. if the scan did not start,
+ * or because of debug_parallel_query=regress. We still want to collect
+ * data from workers.
*/
+ if (planstate &&
+ planstate->ss_currentScanDesc &&
+ planstate->ss_currentScanDesc->rs_instrument)
+ {
+ stats = planstate->ss_currentScanDesc->rs_instrument->io;
+ }
+
+ /* accumulate data from parallel workers */
switch (nodeTag(plan))
{
case T_SeqScan:
@@ -4075,9 +4080,6 @@ show_scan_io_usage(ScanState *planstate, ExplainState *es)
SharedSeqScanInstrumentation *sinstrument
= ((SeqScanState *) planstate)->sinstrument;
- /* collect prefetch statistics from the read stream */
- stats = planstate->ss_currentScanDesc->rs_instrument->io;
-
/* get the sum of the counters set within each and every process */
if (sinstrument)
{
@@ -4096,9 +4098,6 @@ show_scan_io_usage(ScanState *planstate, ExplainState *es)
SharedBitmapHeapInstrumentation *sinstrument
= ((BitmapHeapScanState *) planstate)->sinstrument;
- /* collect prefetch statistics from the read stream */
- stats = planstate->ss_currentScanDesc->rs_instrument->io;
-
/*
* get the sum of the counters set within each and every
* process
diff --git a/src/backend/executor/execParallel.c b/src/backend/executor/execParallel.c
index d1747993df0..c6f7ee292dd 100644
--- a/src/backend/executor/execParallel.c
+++ b/src/backend/executor/execParallel.c
@@ -250,9 +250,9 @@ ExecParallelEstimate(PlanState *planstate, ExecParallelEstimateContext *e)
switch (nodeTag(planstate))
{
case T_SeqScanState:
- if (planstate->plan->parallel_aware)
- ExecSeqScanEstimate((SeqScanState *) planstate,
- e->pcxt);
+ /* even when not parallel-aware, for EXPLAIN ANALYZE */
+ ExecSeqScanEstimate((SeqScanState *) planstate,
+ e->pcxt);
break;
case T_IndexScanState:
/* even when not parallel-aware, for EXPLAIN ANALYZE */
@@ -484,9 +484,9 @@ ExecParallelInitializeDSM(PlanState *planstate,
switch (nodeTag(planstate))
{
case T_SeqScanState:
- if (planstate->plan->parallel_aware)
- ExecSeqScanInitializeDSM((SeqScanState *) planstate,
- d->pcxt);
+ /* even when not parallel-aware, for EXPLAIN ANALYZE */
+ ExecSeqScanInitializeDSM((SeqScanState *) planstate,
+ d->pcxt);
break;
case T_IndexScanState:
/* even when not parallel-aware, for EXPLAIN ANALYZE */
@@ -1366,8 +1366,8 @@ ExecParallelInitializeWorker(PlanState *planstate, ParallelWorkerContext *pwcxt)
switch (nodeTag(planstate))
{
case T_SeqScanState:
- if (planstate->plan->parallel_aware)
- ExecSeqScanInitializeWorker((SeqScanState *) planstate, pwcxt);
+ /* even when not parallel-aware, for EXPLAIN ANALYZE */
+ ExecSeqScanInitializeWorker((SeqScanState *) planstate, pwcxt);
break;
case T_IndexScanState:
/* even when not parallel-aware, for EXPLAIN ANALYZE */
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 032f3dc5efc..2e4a6138eae 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -387,17 +387,25 @@ ExecSeqScanEstimate(SeqScanState *node,
ParallelContext *pcxt)
{
EState *estate = node->ss.ps.state;
+ bool instrument = node->ss.ps.instrument != NULL;
+ bool parallel_aware = node->ss.ps.plan->parallel_aware;
Size size;
+ if (!instrument && !parallel_aware)
+ {
+ /* No DSM required by the scan */
+ return;
+ }
+
size = table_parallelscan_estimate(node->ss.ss_currentRelation,
- estate->es_snapshot);
+ estate->es_snapshot);
node->pscan_len = size;
/* make sure the instrumentation is properly aligned */
size = MAXALIGN(size);
/* account for instrumentation, if required */
- if (node->ss.ps.instrument && pcxt->nworkers > 0)
+ if (instrument && pcxt->nworkers > 0)
{
size = add_size(size, offsetof(SharedSeqScanInstrumentation, sinstrument));
size = add_size(size, mul_size(pcxt->nworkers, sizeof(SeqScanInstrumentation)));
@@ -420,13 +428,20 @@ ExecSeqScanInitializeDSM(SeqScanState *node,
EState *estate = node->ss.ps.state;
ParallelTableScanDesc pscan;
SharedSeqScanInstrumentation *sinstrument = NULL;
+ bool instrument = node->ss.ps.instrument != NULL;
+ bool parallel_aware = node->ss.ps.plan->parallel_aware;
Size size;
- char *ptr;
uint32 flags = SO_NONE;
+ if (!instrument && !parallel_aware)
+ {
+ /* No DSM required by the scan */
+ return;
+ }
+
/* Recalculate the size. This needs to match ExecSeqScanEstimate. */
size = MAXALIGN(node->pscan_len);
- if (node->ss.ps.instrument && pcxt->nworkers > 0)
+ if (instrument && pcxt->nworkers > 0)
{
size = add_size(size, offsetof(SharedSeqScanInstrumentation, sinstrument));
size = add_size(size, mul_size(pcxt->nworkers, sizeof(SeqScanInstrumentation)));
@@ -440,31 +455,38 @@ ExecSeqScanInitializeDSM(SeqScanState *node,
estate->es_snapshot);
shm_toc_insert(pcxt->toc, node->ss.ps.plan->plan_node_id, pscan);
- if (ScanRelIsReadOnly(&node->ss))
- flags |= SO_HINT_REL_READ_ONLY;
-
- if (estate->es_instrument)
- flags |= SO_SCAN_INSTRUMENT;
+ /* initialize the shared instrumentation (with correct alignment) */
+ if (instrument && pcxt->nworkers > 0)
+ {
+ char *ptr = (char *) pscan;
- node->ss.ss_currentScanDesc =
- table_beginscan_parallel(node->ss.ss_currentRelation, pscan, flags);
+ ptr += MAXALIGN(node->pscan_len);
- /* initialize the shared instrumentation (with correct alignment) */
- ptr = (char *) pscan;
- ptr += MAXALIGN(node->pscan_len);
- if (node->ss.ps.instrument && pcxt->nworkers > 0)
sinstrument = (SharedSeqScanInstrumentation *) ptr;
- if (sinstrument)
- {
sinstrument->num_workers = pcxt->nworkers;
/* ensure any unfilled slots will contain zeroes */
memset(sinstrument->sinstrument, 0,
pcxt->nworkers * sizeof(SeqScanInstrumentation));
+
+ node->sinstrument = sinstrument;
+ }
+
+ if (!parallel_aware)
+ {
+ /* Only here to set up worker node's shared instrumentation */
+ return;
}
- node->sinstrument = sinstrument;
+ if (ScanRelIsReadOnly(&node->ss))
+ flags |= SO_HINT_REL_READ_ONLY;
+
+ if (estate->es_instrument)
+ flags |= SO_SCAN_INSTRUMENT;
+
+ node->ss.ss_currentScanDesc =
+ table_beginscan_parallel(node->ss.ss_currentRelation, pscan, flags);
}
/* ----------------------------------------------------------------
@@ -493,27 +515,43 @@ void
ExecSeqScanInitializeWorker(SeqScanState *node,
ParallelWorkerContext *pwcxt)
{
- EState *estate = node->ss.ps.state;
ParallelTableScanDesc pscan;
- char *ptr;
+ EState *estate = node->ss.ps.state;
+ bool instrument = node->ss.ps.instrument != NULL;
+ bool parallel_aware = node->ss.ps.plan->parallel_aware;
uint32 flags = SO_NONE;
+ if (!instrument && !parallel_aware)
+ {
+ /* No DSM required by the scan */
+ return;
+ }
+
+ pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
+
+ /* set pointer to the shared instrumentation */
+ if (instrument)
+ {
+ char *ptr = (char *) pscan;
+ ptr += MAXALIGN(pscan->phs_len);
+
+ node->sinstrument = (SharedSeqScanInstrumentation *) ptr;
+ }
+
+ if (!parallel_aware)
+ {
+ /* Only here to set up worker node's SharedInfo */
+ return;
+ }
+
if (ScanRelIsReadOnly(&node->ss))
flags |= SO_HINT_REL_READ_ONLY;
if (estate->es_instrument)
flags |= SO_SCAN_INSTRUMENT;
- pscan = shm_toc_lookup(pwcxt->toc, node->ss.ps.plan->plan_node_id, false);
node->ss.ss_currentScanDesc =
table_beginscan_parallel(node->ss.ss_currentRelation, pscan, flags);
-
- /* set pointer to the shared instrumentation */
- ptr = (char *) pscan;
- ptr += MAXALIGN(pscan->phs_len);
-
- if (node->ss.ps.instrument)
- node->sinstrument = (SharedSeqScanInstrumentation *) ptr;
}
/* ----------------------------------------------------------------
--
2.53.0