6464#include "access/xlog.h"
6565#include "access/xloginsert.h"
6666#include "catalog/index.h"
67+ #include "executor/instrument.h"
6768#include "miscadmin.h"
6869#include "pgstat.h"
6970#include "storage/smgr.h"
7879#define PARALLEL_KEY_TUPLESORT UINT64CONST(0xA000000000000002)
7980#define PARALLEL_KEY_TUPLESORT_SPOOL2 UINT64CONST(0xA000000000000003)
8081#define PARALLEL_KEY_QUERY_TEXT UINT64CONST(0xA000000000000004)
82+ #define PARALLEL_KEY_BUFFER_USAGE UINT64CONST(0xA000000000000005)
8183
8284/*
8385 * DISABLE_LEADER_PARTICIPATION disables the leader's participation in
@@ -192,6 +194,7 @@ typedef struct BTLeader
192194Sharedsort * sharedsort ;
193195Sharedsort * sharedsort2 ;
194196Snapshot snapshot ;
197+ BufferUsage * bufferusage ;
195198}BTLeader ;
196199
197200/*
@@ -1240,6 +1243,7 @@ _bt_begin_parallel(BTBuildState *buildstate, bool isconcurrent, int request)
12401243Sharedsort * sharedsort2 ;
12411244BTSpool * btspool = buildstate -> spool ;
12421245BTLeader * btleader = (BTLeader * )palloc0 (sizeof (BTLeader ));
1246+ BufferUsage * bufferusage ;
12431247bool leaderparticipates = true;
12441248char * sharedquery ;
12451249int querylen ;
@@ -1292,6 +1296,17 @@ _bt_begin_parallel(BTBuildState *buildstate, bool isconcurrent, int request)
12921296shm_toc_estimate_keys (& pcxt -> estimator ,3 );
12931297}
12941298
1299+ /*
1300+ * Estimate space for BufferUsage -- PARALLEL_KEY_BUFFER_USAGE.
1301+ *
1302+ * If there are no extensions loaded that care, we could skip this. We
1303+ * have no way of knowing whether anyone's looking at pgBufferUsage, so do
1304+ * it unconditionally.
1305+ */
1306+ shm_toc_estimate_chunk (& pcxt -> estimator ,
1307+ mul_size (sizeof (BufferUsage ),pcxt -> nworkers ));
1308+ shm_toc_estimate_keys (& pcxt -> estimator ,1 );
1309+
12951310/* Finally, estimate PARALLEL_KEY_QUERY_TEXT space */
12961311querylen = strlen (debug_query_string );
12971312shm_toc_estimate_chunk (& pcxt -> estimator ,querylen + 1 );
@@ -1361,6 +1376,11 @@ _bt_begin_parallel(BTBuildState *buildstate, bool isconcurrent, int request)
13611376memcpy (sharedquery ,debug_query_string ,querylen + 1 );
13621377shm_toc_insert (pcxt -> toc ,PARALLEL_KEY_QUERY_TEXT ,sharedquery );
13631378
1379+ /* Allocate space for each worker's BufferUsage; no need to initialize */
1380+ bufferusage = shm_toc_allocate (pcxt -> toc ,
1381+ mul_size (sizeof (BufferUsage ),pcxt -> nworkers ));
1382+ shm_toc_insert (pcxt -> toc ,PARALLEL_KEY_BUFFER_USAGE ,bufferusage );
1383+
13641384/* Launch workers, saving status for leader/caller */
13651385LaunchParallelWorkers (pcxt );
13661386btleader -> pcxt = pcxt ;
@@ -1371,6 +1391,7 @@ _bt_begin_parallel(BTBuildState *buildstate, bool isconcurrent, int request)
13711391btleader -> sharedsort = sharedsort ;
13721392btleader -> sharedsort2 = sharedsort2 ;
13731393btleader -> snapshot = snapshot ;
1394+ btleader -> bufferusage = bufferusage ;
13741395
13751396/* If no workers were successfully launched, back out (do serial build) */
13761397if (pcxt -> nworkers_launched == 0 )
@@ -1399,8 +1420,18 @@ _bt_begin_parallel(BTBuildState *buildstate, bool isconcurrent, int request)
13991420static void
14001421_bt_end_parallel (BTLeader * btleader )
14011422{
1423+ int i ;
1424+
14021425/* Shutdown worker processes */
14031426WaitForParallelWorkersToFinish (btleader -> pcxt );
1427+
1428+ /*
1429+ * Next, accumulate buffer usage. (This must wait for the workers to
1430+ * finish, or we might get incomplete data.)
1431+ */
1432+ for (i = 0 ;i < btleader -> pcxt -> nworkers_launched ;i ++ )
1433+ InstrAccumParallelQuery (& btleader -> bufferusage [i ]);
1434+
14041435/* Free last reference to MVCC snapshot, if one was used */
14051436if (IsMVCCSnapshot (btleader -> snapshot ))
14061437UnregisterSnapshot (btleader -> snapshot );
@@ -1537,6 +1568,7 @@ _bt_parallel_build_main(dsm_segment *seg, shm_toc *toc)
15371568Relation indexRel ;
15381569LOCKMODE heapLockmode ;
15391570LOCKMODE indexLockmode ;
1571+ BufferUsage * bufferusage ;
15401572int sortmem ;
15411573
15421574#ifdef BTREE_BUILD_STATS
@@ -1598,11 +1630,18 @@ _bt_parallel_build_main(dsm_segment *seg, shm_toc *toc)
15981630tuplesort_attach_shared (sharedsort2 ,seg );
15991631}
16001632
1633+ /* Prepare to track buffer usage during parallel execution */
1634+ InstrStartParallelQuery ();
1635+
16011636/* Perform sorting of spool, and possibly a spool2 */
16021637sortmem = maintenance_work_mem /btshared -> scantuplesortstates ;
16031638_bt_parallel_scan_and_sort (btspool ,btspool2 ,btshared ,sharedsort ,
16041639sharedsort2 ,sortmem );
16051640
1641+ /* Report buffer usage during parallel execution */
1642+ bufferusage = shm_toc_lookup (toc ,PARALLEL_KEY_BUFFER_USAGE , false);
1643+ InstrEndParallelQuery (& bufferusage [ParallelWorkerNumber ]);
1644+
16061645#ifdef BTREE_BUILD_STATS
16071646if (log_btree_build_stats )
16081647{