prefetch-distance-explain-v2.patch
text/x-patch
Filename: prefetch-distance-explain-v2.patch
Type: text/x-patch
Part: 2
Message:
Re: index prefetching
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: unified
Series: patch v2
| File | + | − |
|---|---|---|
| src/backend/access/index/indexam.c | 12 | 6 |
| src/backend/commands/explain.c | 47 | 0 |
| src/backend/executor/nodeIndexscan.c | 13 | 0 |
| src/backend/storage/aio/read_stream.c | 51 | 0 |
| src/include/access/genam.h | 1 | 0 |
| src/include/nodes/execnodes.h | 6 | 0 |
| src/include/storage/read_stream.h | 3 | 0 |
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 4835c48b448..b0e50307a0e 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -407,12 +407,6 @@ index_beginscan_internal(Relation indexRelation,
scan->parallel_scan = pscan;
scan->xs_temp_snap = temp_snap;
- /*
- * No batching by default, so set it to NULL. Will be initialized later if
- * batching is requested and AM supports it.
- */
- scan->xs_batches = NULL;
-
return scan;
}
@@ -463,6 +457,17 @@ index_rescan(IndexScanDesc scan,
orderbys, norderbys);
}
+void
+index_get_prefetch_stats(IndexScanDesc scan, int *accum, int *count, int *stalls, int *resets, int *skips)
+{
+ /* ugly */
+ if (scan->xs_heapfetch->rs != NULL)
+ {
+ read_stream_prefetch_stats(scan->xs_heapfetch->rs,
+ accum, count, stalls, resets, skips);
+ }
+}
+
/* ----------------
* index_endscan - end a scan
* ----------------
@@ -1883,6 +1888,7 @@ index_scan_stream_read_next(ReadStream *stream,
/* same block as before, don't need to read it */
if (scan->xs_batches->lastBlock == ItemPointerGetBlockNumber(tid))
{
+ read_stream_skip_block(stream);
DEBUG_LOG("index_scan_stream_read_next: skip block (lastBlock)");
continue;
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 7e2792ead71..9c95b4e2878 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -136,6 +136,7 @@ static void show_memoize_info(MemoizeState *mstate, List *ancestors,
ExplainState *es);
static void show_hashagg_info(AggState *aggstate, ExplainState *es);
static void show_indexsearches_info(PlanState *planstate, ExplainState *es);
+static void show_indexprefetch_info(PlanState *planstate, ExplainState *es);
static void show_tidbitmap_info(BitmapHeapScanState *planstate,
ExplainState *es);
static void show_instrumentation_count(const char *qlabel, int which,
@@ -1966,6 +1967,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
show_instrumentation_count("Rows Removed by Filter", 1,
planstate, es);
show_indexsearches_info(planstate, es);
+ show_indexprefetch_info(planstate, es);
break;
case T_IndexOnlyScan:
show_scan_qual(((IndexOnlyScan *) plan)->indexqual,
@@ -1983,6 +1985,7 @@ ExplainNode(PlanState *planstate, List *ancestors,
ExplainPropertyFloat("Heap Fetches", NULL,
planstate->instrument->ntuples2, 0, es);
show_indexsearches_info(planstate, es);
+ show_indexprefetch_info(planstate, es);
break;
case T_BitmapIndexScan:
show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig,
@@ -3889,6 +3892,50 @@ show_indexsearches_info(PlanState *planstate, ExplainState *es)
ExplainPropertyUInteger("Index Searches", NULL, nsearches, es);
}
+static void
+show_indexprefetch_info(PlanState *planstate, ExplainState *es)
+{
+ Plan *plan = planstate->plan;
+
+ int count = 0,
+ accum = 0,
+ stalls = 0,
+ resets = 0,
+ skips = 0;
+
+ if (!es->analyze)
+ return;
+
+ /* Initialize counters with stats from the local process first */
+ switch (nodeTag(plan))
+ {
+ case T_IndexScan:
+ {
+ IndexScanState *indexstate = ((IndexScanState *) planstate);
+
+ count = indexstate->iss_PrefetchCount;
+ accum = indexstate->iss_PrefetchAccum;
+ stalls = indexstate->iss_PrefetchStalls;
+ resets = indexstate->iss_ResetCount;
+ skips = indexstate->iss_SkipCount;
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (count > 0)
+ {
+ ExplainPropertyFloat("Prefetch Distance", NULL, (accum * 1.0 / count), 3, es);
+ ExplainPropertyUInteger("Prefetch Count", NULL, count, es);
+ ExplainPropertyUInteger("Prefetch Stalls", NULL, stalls, es);
+ ExplainPropertyUInteger("Prefetch Skips", NULL, skips, es);
+ ExplainPropertyUInteger("Prefetch Resets", NULL, resets, es);
+ }
+}
+
+
/*
* Show exact/lossy pages for a BitmapHeapScan node
*/
diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c
index 7fcaa37fe62..707badc4fdc 100644
--- a/src/backend/executor/nodeIndexscan.c
+++ b/src/backend/executor/nodeIndexscan.c
@@ -125,6 +125,13 @@ IndexNext(IndexScanState *node)
node->iss_OrderByKeys, node->iss_NumOrderByKeys);
}
+ index_get_prefetch_stats(scandesc,
+ &node->iss_PrefetchAccum,
+ &node->iss_PrefetchCount,
+ &node->iss_PrefetchStalls,
+ &node->iss_ResetCount,
+ &node->iss_SkipCount);
+
/*
* ok, now that we have what we need, fetch the next tuple.
*/
@@ -1088,6 +1095,12 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
indexstate->iss_RuntimeContext = NULL;
}
+ indexstate->iss_PrefetchAccum = 0;
+ indexstate->iss_PrefetchCount = 0;
+ indexstate->iss_PrefetchStalls = 0;
+ indexstate->iss_ResetCount = 0;
+ indexstate->iss_SkipCount = 0;
+
/*
* all done.
*/
diff --git a/src/backend/storage/aio/read_stream.c b/src/backend/storage/aio/read_stream.c
index 0e7f5557f5c..e41189f6612 100644
--- a/src/backend/storage/aio/read_stream.c
+++ b/src/backend/storage/aio/read_stream.c
@@ -106,6 +106,12 @@ struct ReadStream
bool advice_enabled;
bool temporary;
+ int distance_accum;
+ int distance_count;
+ int distance_stalls;
+ int reset_count;
+ int skip_count;
+
/*
* One-block buffer to support 'ungetting' a block number, to resolve flow
* control problems when I/Os are split.
@@ -180,6 +186,16 @@ read_stream_get_block(ReadStream *stream, void *per_buffer_data)
{
BlockNumber blocknum;
+ if (stream->distance > 1)
+ {
+ stream->distance_accum += stream->distance;
+ stream->distance_count += 1;
+ }
+ else
+ {
+ stream->distance_stalls += 1;
+ }
+
blocknum = stream->buffered_blocknum;
if (blocknum != InvalidBlockNumber)
stream->buffered_blocknum = InvalidBlockNumber;
@@ -681,6 +697,12 @@ read_stream_begin_impl(int flags,
stream->seq_until_processed = InvalidBlockNumber;
stream->temporary = SmgrIsTemp(smgr);
+ stream->distance_accum = 0;
+ stream->distance_count = 0;
+ stream->distance_stalls = 0;
+ stream->reset_count = 0;
+ stream->skip_count = 0;
+
/*
* Skip the initial ramp-up phase if the caller says we're going to be
* reading the whole relation. This way we start out assuming we'll be
@@ -771,6 +793,17 @@ read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
{
Buffer buffer;
int16 oldest_buffer_index;
+/*
+ if (stream->distance > 0)
+ {
+ stream->distance_accum += stream->distance;
+ stream->distance_count += 1;
+ }
+ else
+ {
+ stream->distance_stalls += 1;
+ }
+*/
#ifndef READ_STREAM_DISABLE_FAST_PATH
@@ -1046,6 +1079,8 @@ read_stream_reset(ReadStream *stream)
/* Start off assuming data is cached. */
stream->distance = 1;
+
+ stream->reset_count += 1;
}
/*
@@ -1057,3 +1092,19 @@ read_stream_end(ReadStream *stream)
read_stream_reset(stream);
pfree(stream);
}
+
+void
+read_stream_prefetch_stats(ReadStream *stream, int *accum, int *count, int *stalls, int *resets, int *skips)
+{
+ *accum = stream->distance_accum;
+ *count = stream->distance_count;
+ *stalls = stream->distance_stalls;
+ *resets = stream->reset_count;
+ *skips = stream->skip_count;
+}
+
+void
+read_stream_skip_block(ReadStream *stream)
+{
+ stream->skip_count++;
+}
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 3a3a44be3a5..f1e5fdfd478 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -235,6 +235,7 @@ extern bytea *index_opclass_options(Relation indrel, AttrNumber attnum,
Datum attoptions, bool validate);
extern IndexScanBatch index_batch_alloc(int maxitems, bool want_itup);
+extern void index_get_prefetch_stats(IndexScanDesc scan, int *accum, int *count, int *stalls, int *resets, int *skips);
/*
* index access method support routines (in genam.c)
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index e107d6e5f81..e91bc7ea35f 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1722,6 +1722,12 @@ typedef struct IndexScanState
IndexScanInstrumentation iss_Instrument;
SharedIndexScanInstrumentation *iss_SharedInfo;
+ int iss_PrefetchAccum;
+ int iss_PrefetchCount;
+ int iss_PrefetchStalls;
+ int iss_ResetCount;
+ int iss_SkipCount;
+
/* These are needed for re-checking ORDER BY expr ordering */
pairingheap *iss_ReorderQueue;
bool iss_ReachedEnd;
diff --git a/src/include/storage/read_stream.h b/src/include/storage/read_stream.h
index 9b0d65161d0..34e184a1690 100644
--- a/src/include/storage/read_stream.h
+++ b/src/include/storage/read_stream.h
@@ -102,4 +102,7 @@ extern ReadStream *read_stream_begin_smgr_relation(int flags,
extern void read_stream_reset(ReadStream *stream);
extern void read_stream_end(ReadStream *stream);
+extern void read_stream_prefetch_stats(ReadStream *stream, int *accum, int *count, int *stalls, int *resets, int *skips);
+extern void read_stream_skip_block(ReadStream *stream);
+
#endif /* READ_STREAM_H */