From c01361e32cbc4bc82a88c0568fa93a1a1565032b Mon Sep 17 00:00:00 2001
From: Michael Paquier <michael@paquier.xyz>
Date: Tue, 8 Oct 2024 16:26:13 +0900
Subject: [PATCH v4 3/3] Introduce two more counters in pg_stat_statements

These track if a query has used parallelism at execution time, and if
parallelism was actually initially planned or not, incrementing
dedicated counters when reaching the executor path.
---
 src/include/nodes/execnodes.h                 |  1 +
 src/backend/executor/execUtils.c              |  1 +
 src/backend/executor/nodeGather.c             |  3 ++
 src/backend/executor/nodeGatherMerge.c        |  2 +
 doc/src/sgml/pgstatstatements.sgml            | 18 +++++++++
 .../expected/oldextversions.out               |  2 +
 .../pg_stat_statements/expected/parallel.out  | 10 +++--
 .../pg_stat_statements--1.11--1.12.sql        |  2 +
 .../pg_stat_statements/pg_stat_statements.c   | 38 +++++++++++++++----
 contrib/pg_stat_statements/sql/parallel.sql   |  4 +-
 10 files changed, 68 insertions(+), 13 deletions(-)

diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index e4698a28c4..2a81fb1ead 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -707,6 +707,7 @@ typedef struct EState
 	struct EPQState *es_epq_active;
 
 	bool		es_use_parallel_mode;	/* can we use parallel workers? */
+	bool		es_used_parallel_mode;	/* was executed in parallel */
 
 	int			es_parallel_workers_to_launch;	/* number of workers to
 												 * launch. */
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 6712302ec8..f06d4eefd3 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -158,6 +158,7 @@ CreateExecutorState(void)
 	estate->es_sourceText = NULL;
 
 	estate->es_use_parallel_mode = false;
+	estate->es_used_parallel_mode = false;
 	estate->es_parallel_workers_to_launch = 0;
 	estate->es_parallel_workers_launched = 0;
 
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index 7f7edc7f9f..f33c837304 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -182,6 +182,9 @@ ExecGather(PlanState *pstate)
 			/* We save # workers launched for the benefit of EXPLAIN */
 			node->nworkers_launched = pcxt->nworkers_launched;
 
+			if (pcxt->nworkers_launched > 0)
+				estate->es_used_parallel_mode = true;
+
 			/*
 			 * Count number of workers originally wanted and actually
 			 * launched.
diff --git a/src/backend/executor/nodeGatherMerge.c b/src/backend/executor/nodeGatherMerge.c
index bc99c0b448..671d6edb04 100644
--- a/src/backend/executor/nodeGatherMerge.c
+++ b/src/backend/executor/nodeGatherMerge.c
@@ -222,6 +222,8 @@ ExecGatherMerge(PlanState *pstate)
 			LaunchParallelWorkers(pcxt);
 			/* We save # workers launched for the benefit of EXPLAIN */
 			node->nworkers_launched = pcxt->nworkers_launched;
+			 if (pcxt->nworkers_launched > 0)
+				 estate->es_used_parallel_mode = true;
 
 			/*
 			 * Count number of workers originally wanted and actually
diff --git a/doc/src/sgml/pgstatstatements.sgml b/doc/src/sgml/pgstatstatements.sgml
index 501b468e9a..4af09837cf 100644
--- a/doc/src/sgml/pgstatstatements.sgml
+++ b/doc/src/sgml/pgstatstatements.sgml
@@ -545,6 +545,24 @@
       </para></entry>
      </row>
 
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>parallel_queries_planned</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of times the statement was planned to use parallelism.
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>parallel_queries_launched</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of times that the statement was executed using parallelism
+      </para></entry>
+     </row>
+
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>stats_since</structfield> <type>timestamp with time zone</type>
diff --git a/contrib/pg_stat_statements/expected/oldextversions.out b/contrib/pg_stat_statements/expected/oldextversions.out
index 0c60fc8127..84e3f04d5f 100644
--- a/contrib/pg_stat_statements/expected/oldextversions.out
+++ b/contrib/pg_stat_statements/expected/oldextversions.out
@@ -397,6 +397,8 @@ AlTER EXTENSION pg_stat_statements UPDATE TO '1.12';
  jit_deform_time            | double precision         |           |          | 
  parallel_workers_to_launch | bigint                   |           |          | 
  parallel_workers_launched  | bigint                   |           |          | 
+ parallel_queries_planned   | bigint                   |           |          | 
+ parallel_queries_launched  | bigint                   |           |          | 
  stats_since                | timestamp with time zone |           |          | 
  minmax_stats_since         | timestamp with time zone |           |          | 
 
diff --git a/contrib/pg_stat_statements/expected/parallel.out b/contrib/pg_stat_statements/expected/parallel.out
index 8af3bd2c91..c9b1a1e339 100644
--- a/contrib/pg_stat_statements/expected/parallel.out
+++ b/contrib/pg_stat_statements/expected/parallel.out
@@ -22,13 +22,15 @@ SELECT count(*) FROM pgss_parallel_tab;
 
 SELECT query,
   parallel_workers_to_launch > 0 AS has_workers_to_launch,
-  parallel_workers_launched > 0 AS has_workers_launched
+  parallel_workers_launched > 0 AS has_workers_launched,
+  parallel_queries_planned > 0 AS has_queries_planned,
+  parallel_queries_launched > 0 AS has_queries_launched
   FROM pg_stat_statements
   WHERE query ~ 'SELECT count'
   ORDER BY query COLLATE "C";
-                 query                  | has_workers_to_launch | has_workers_launched 
-----------------------------------------+-----------------------+----------------------
- SELECT count(*) FROM pgss_parallel_tab | t                     | t
+                 query                  | has_workers_to_launch | has_workers_launched | has_queries_planned | has_queries_launched 
+----------------------------------------+-----------------------+----------------------+---------------------+----------------------
+ SELECT count(*) FROM pgss_parallel_tab | t                     | t                    | t                   | t
 (1 row)
 
 DROP TABLE pgss_parallel_tab;
diff --git a/contrib/pg_stat_statements/pg_stat_statements--1.11--1.12.sql b/contrib/pg_stat_statements/pg_stat_statements--1.11--1.12.sql
index 80e6be2544..3a3964a998 100644
--- a/contrib/pg_stat_statements/pg_stat_statements--1.11--1.12.sql
+++ b/contrib/pg_stat_statements/pg_stat_statements--1.11--1.12.sql
@@ -62,6 +62,8 @@ CREATE FUNCTION pg_stat_statements(IN showtext boolean,
     OUT jit_deform_time float8,
     OUT parallel_workers_to_launch int8,
     OUT parallel_workers_launched int8,
+    OUT parallel_queries_planned int8,
+    OUT parallel_queries_launched int8,
     OUT stats_since timestamp with time zone,
     OUT minmax_stats_since timestamp with time zone
 )
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 773b821911..072db1281e 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -209,6 +209,10 @@ typedef struct Counters
 											 * be launched */
 	int64       parallel_workers_launched;	/* # of parallel workers actually
 											 * launched */
+	int64       parallel_queries_planned;	/* # of times query was planned
+												 * to use parallelism */
+	int64       parallel_queries_launched;	/* # of times query was executed
+												 * using parallelism */
 } Counters;
 
 /*
@@ -355,7 +359,9 @@ static void pgss_store(const char *query, uint64 queryId,
 					   const struct JitInstrumentation *jitusage,
 					   JumbleState *jstate,
 					   int parallel_workers_to_launch,
-					   int parallel_workers_launched);
+					   int parallel_workers_launched,
+					   bool parallel_queries_planned,
+					   bool parallel_queries_launched);
 static void pg_stat_statements_internal(FunctionCallInfo fcinfo,
 										pgssVersion api_version,
 										bool showtext);
@@ -877,7 +883,9 @@ pgss_post_parse_analyze(ParseState *pstate, Query *query, JumbleState *jstate)
 				   NULL,
 				   jstate,
 				   0,
-				   0);
+				   0,
+				   false,
+				   false);
 }
 
 /*
@@ -957,7 +965,9 @@ pgss_planner(Query *parse,
 				   NULL,
 				   NULL,
 				   0,
-				   0);
+				   0,
+				   false,
+				   false);
 	}
 	else
 	{
@@ -1092,7 +1102,9 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
 				   queryDesc->estate->es_jit ? &queryDesc->estate->es_jit->instr : NULL,
 				   NULL,
 				   queryDesc->estate->es_parallel_workers_to_launch,
-				   queryDesc->estate->es_parallel_workers_launched);
+				   queryDesc->estate->es_parallel_workers_launched,
+				   queryDesc->plannedstmt->parallelModeNeeded,
+				   queryDesc->estate->es_used_parallel_mode);
 	}
 
 	if (prev_ExecutorEnd)
@@ -1225,7 +1237,9 @@ pgss_ProcessUtility(PlannedStmt *pstmt, const char *queryString,
 				   NULL,
 				   NULL,
 				   0,
-				   0);
+				   0,
+				   false,
+				   false);
 	}
 	else
 	{
@@ -1288,7 +1302,9 @@ pgss_store(const char *query, uint64 queryId,
 		   const struct JitInstrumentation *jitusage,
 		   JumbleState *jstate,
 		   int parallel_workers_to_launch,
-		   int parallel_workers_launched)
+		   int parallel_workers_launched,
+		   bool parallel_queries_planned,
+		   bool parallel_queries_launched)
 {
 	pgssHashKey key;
 	pgssEntry  *entry;
@@ -1494,6 +1510,10 @@ pgss_store(const char *query, uint64 queryId,
 		/* parallel worker counters */
 		entry->counters.parallel_workers_to_launch += parallel_workers_to_launch;
 		entry->counters.parallel_workers_launched += parallel_workers_launched;
+		if (parallel_queries_planned)
+			entry->counters.parallel_queries_planned += 1;
+		if (parallel_queries_launched)
+			entry->counters.parallel_queries_launched += 1;
 
 		SpinLockRelease(&entry->mutex);
 	}
@@ -1561,8 +1581,8 @@ pg_stat_statements_reset(PG_FUNCTION_ARGS)
 #define PG_STAT_STATEMENTS_COLS_V1_9	33
 #define PG_STAT_STATEMENTS_COLS_V1_10	43
 #define PG_STAT_STATEMENTS_COLS_V1_11	49
-#define PG_STAT_STATEMENTS_COLS_V1_12	51
-#define PG_STAT_STATEMENTS_COLS			51	/* maximum of above */
+#define PG_STAT_STATEMENTS_COLS_V1_12	53
+#define PG_STAT_STATEMENTS_COLS			53	/* maximum of above */
 
 /*
  * Retrieve statement statistics.
@@ -1974,6 +1994,8 @@ pg_stat_statements_internal(FunctionCallInfo fcinfo,
 		{
 			values[i++] = Int64GetDatumFast(tmp.parallel_workers_to_launch);
 			values[i++] = Int64GetDatumFast(tmp.parallel_workers_launched);
+			values[i++] = Int64GetDatumFast(tmp.parallel_queries_planned);
+			values[i++] = Int64GetDatumFast(tmp.parallel_queries_launched);
 		}
 		if (api_version >= PGSS_V1_11)
 		{
diff --git a/contrib/pg_stat_statements/sql/parallel.sql b/contrib/pg_stat_statements/sql/parallel.sql
index 4ce1573d13..74a5bb5195 100644
--- a/contrib/pg_stat_statements/sql/parallel.sql
+++ b/contrib/pg_stat_statements/sql/parallel.sql
@@ -18,7 +18,9 @@ SELECT count(*) FROM pgss_parallel_tab;
 
 SELECT query,
   parallel_workers_to_launch > 0 AS has_workers_to_launch,
-  parallel_workers_launched > 0 AS has_workers_launched
+  parallel_workers_launched > 0 AS has_workers_launched,
+  parallel_queries_planned > 0 AS has_queries_planned,
+  parallel_queries_launched > 0 AS has_queries_launched
   FROM pg_stat_statements
   WHERE query ~ 'SELECT count'
   ORDER BY query COLLATE "C";
-- 
2.45.2

