Introduce a new view for checkpointer related stats

Started by Bharath Rupireddyabout 3 years ago39 messages
#1Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
1 attachment(s)

Hi,

pg_stat_bgwriter view currently reports checkpointer stats as well. It
is that way because historically checkpointer was part of bgwriter
until the commits 806a2ae and bf405ba, that went into PG 9.2,
separated them out. I think it is time for us to separate checkpointer
stats to its own view. I discussed it in another thread [1]/messages/by-id/20221116181433.y2hq2pirtbqmmndt@awork3.anarazel.de /messages/by-id/CA+TgmoYCu6RpuJ3cZz0e7cZSfaVb=cr6iVcgGMGd5dxX0MYNRA@mail.gmail.com and it
seems like there's an unequivocal agreement for the proposal.

I'm attaching a patch introducing a new pg_stat_checkpointer view,
with this change the pg_stat_bgwriter view only focuses on bgwriter
related stats. The patch does mostly mechanical changes. I'll add it
to CF in a bit.

Thoughts?

[1]: /messages/by-id/20221116181433.y2hq2pirtbqmmndt@awork3.anarazel.de /messages/by-id/CA+TgmoYCu6RpuJ3cZz0e7cZSfaVb=cr6iVcgGMGd5dxX0MYNRA@mail.gmail.com
/messages/by-id/20221116181433.y2hq2pirtbqmmndt@awork3.anarazel.de
/messages/by-id/CA+TgmoYCu6RpuJ3cZz0e7cZSfaVb=cr6iVcgGMGd5dxX0MYNRA@mail.gmail.com

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v1-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchapplication/x-patch; name=v1-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchDownload
From 707b3f0e0e7cf55b48a09709b070341d23ad03b8 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Thu, 17 Nov 2022 12:20:13 +0000
Subject: [PATCH v1] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as well.
It is that way because historically checkpointer was part of
bgwriter until the commits 806a2ae and bf405ba, that went into
PG 9.2, separated them out.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

Bump catalog version.
---
 doc/src/sgml/monitoring.sgml                  | 108 +++++++++++++-----
 src/backend/catalog/system_views.sql          |  18 +--
 .../utils/activity/pgstat_checkpointer.c      |   1 +
 src/backend/utils/adt/pgstatfuncs.c           |  19 +--
 src/include/catalog/pg_proc.dat               |  22 ++--
 src/include/pgstat.h                          |   1 +
 src/test/recovery/t/029_stats_restart.pl      |   6 +-
 src/test/regress/expected/rules.out           |  15 +--
 src/test/regress/expected/stats.out           |  21 +++-
 src/test/regress/sql/stats.sql                |  12 +-
 10 files changed, 154 insertions(+), 69 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index e5d622d514..52c3118727 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -448,6 +448,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_wal</structname><indexterm><primary>pg_stat_wal</primary></indexterm></entry>
       <entry>One row only, showing statistics about WAL activity. See
@@ -3647,97 +3656,138 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
     <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+       <structfield>buffers_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of buffers written by the background writer
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_req</structfield> <type>bigint</type>
+       <structfield>maxwritten_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of times the background writer stopped a cleaning
+       scan because it had written too many buffers
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+       <structfield>buffers_alloc</structfield> <type>bigint</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       Number of buffers allocated
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       Time at which these statistics were last reset
       </para></entry>
      </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
+
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
+
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
 
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing global data for the cluster.
+  </para>
+
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+       Column Type
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Description
+      </para></entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of scheduled checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_clean</structfield> <type>bigint</type>
+       <structfield>checkpoints_req</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written by the background writer
+       Number of requested checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>maxwritten_clean</structfield> <type>bigint</type>
+       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of times the background writer stopped a cleaning
-       scan because it had written too many buffers
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend</structfield> <type>bigint</type>
+       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of buffers written directly by a backend
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
+       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times a backend had to execute its own
-       <function>fsync</function> call (normally the background writer handles those
-       even when the backend does its own write)
+       Number of buffers written during checkpoints
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_alloc</structfield> <type>bigint</type>
+       <structfield>buffers_backend</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers allocated
+       Number of buffers written directly by a backend
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of times a backend had to execute its own
+       <function>fsync</function> call (normally the checkpointer handles those
+       even when the backend does its own write)
       </para></entry>
      </row>
 
@@ -5387,8 +5437,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>wal</literal> to reset all the counters shown in the
         <structname>pg_stat_wal</structname> view or
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2d8104b090..131d949dfb 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1105,18 +1105,22 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_written_backend() AS buffers_backend,
-        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+        pg_stat_get_requested_checkpoints() AS checkpoints_req,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_wal AS
     SELECT
         w.wal_records,
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index af8d513e7b..2757a10b7e 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -89,6 +89,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index ae3365d917..38a2595cdd 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1662,19 +1662,19 @@ pg_stat_get_db_sessions_killed(PG_FUNCTION_ARGS)
 }
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_requested_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_buf_written_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
 }
@@ -1707,6 +1707,12 @@ pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
 					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
 }
 
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
+}
+
 Datum
 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 {
@@ -2082,14 +2088,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "recovery_prefetch") == 0)
 		XLogPrefetchResetStats();
 	else if (strcmp(target, "wal") == 0)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 9dbe9ec801..605801c19b 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5602,20 +5602,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_timed_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_timed_checkpoints' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_requested_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_requested_checkpoints' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_buf_written_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_buf_written_checkpoints' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 9e2ce6f011..e23d80bba8 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -274,6 +274,7 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter buf_written_checkpoints;
 	PgStat_Counter buf_written_backend;
 	PgStat_Counter buf_fsync_backend;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 typedef struct PgStat_StatDBEntry
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 1bf7b568cc..f4e262a4bf 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset     = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 624d0e5aae..4496619271 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1811,17 +1811,18 @@ pg_stat_archiver| SELECT s.archived_count,
     s.last_failed_time,
     s.stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
+pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+    pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
+    pg_stat_get_buf_alloc() AS buffers_alloc,
+    pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+    pg_stat_get_requested_checkpoints() AS checkpoints_req,
     pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
     pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
-    pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
-    pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
+    pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
     pg_stat_get_buf_written_backend() AS buffers_backend,
     pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
-    pg_stat_get_buf_alloc() AS buffers_alloc,
-    pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT d.oid AS datid,
     d.datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 1d84407a03..8ed7f895b2 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -782,8 +782,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -793,7 +793,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -884,6 +884,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index b4d6753c71..c8c24abea8 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -387,8 +387,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -402,7 +402,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -440,6 +440,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#2Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Bharath Rupireddy (#1)
Re: Introduce a new view for checkpointer related stats

Hi,

On 11/17/22 1:51 PM, Bharath Rupireddy wrote:

Hi,

pg_stat_bgwriter view currently reports checkpointer stats as well. It
is that way because historically checkpointer was part of bgwriter
until the commits 806a2ae and bf405ba, that went into PG 9.2,
separated them out. I think it is time for us to separate checkpointer
stats to its own view. I discussed it in another thread [1] and it
seems like there's an unequivocal agreement for the proposal.

I'm attaching a patch introducing a new pg_stat_checkpointer view,
with this change the pg_stat_bgwriter view only focuses on bgwriter
related stats. The patch does mostly mechanical changes. I'll add it
to CF in a bit.

Thoughts?

+1 for the dedicated view.

+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing global data for the cluster.
+  </para>

what about "containing data about checkpointer activity of the cluster"? (to provide more "details" (even if that seems obvious given the name of the view) and be consistent with the pg_stat_wal description too).
And if it makes sense to you, While at it, why not go for "containing data about bgwriter activity of the cluster" for pg_stat_bgwriter too?

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+        pg_stat_get_requested_checkpoints() AS checkpoints_req,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;

I don't think we should keep the checkpoints_ prefix (or _checkpoint suffix) in the column names now that they belong to a dedicated view (also the pg_stat_bgwriter view's columns don't have a
bgwriter prefix/suffix).

And while at it, I'm not sure the wal_ suffix in pg_stat_wal make sense too.

The idea is to have consistent naming between the views and their columns: I'd vote without prefix/suffix.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#3Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Drouvot, Bertrand (#2)
1 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Tue, Nov 22, 2022 at 1:26 PM Drouvot, Bertrand
<bertranddrouvot.pg@gmail.com> wrote:

Hi,

On 11/17/22 1:51 PM, Bharath Rupireddy wrote:

Hi,

pg_stat_bgwriter view currently reports checkpointer stats as well. It
is that way because historically checkpointer was part of bgwriter
until the commits 806a2ae and bf405ba, that went into PG 9.2,
separated them out. I think it is time for us to separate checkpointer
stats to its own view. I discussed it in another thread [1] and it
seems like there's an unequivocal agreement for the proposal.

I'm attaching a patch introducing a new pg_stat_checkpointer view,
with this change the pg_stat_bgwriter view only focuses on bgwriter
related stats. The patch does mostly mechanical changes. I'll add it
to CF in a bit.

Thoughts?

+1 for the dedicated view.

+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing global data for the cluster.
+  </para>

what about "containing data about checkpointer activity of the cluster"? (to provide more "details" (even if that seems obvious given the name of the view) and be consistent with the pg_stat_wal description too).
And if it makes sense to you, While at it, why not go for "containing data about bgwriter activity of the cluster" for pg_stat_bgwriter too?

Nice catch. Modified.

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+        pg_stat_get_requested_checkpoints() AS checkpoints_req,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;

I don't think we should keep the checkpoints_ prefix (or _checkpoint suffix) in the column names now that they belong to a dedicated view (also the pg_stat_bgwriter view's columns don't have a
bgwriter prefix/suffix).

And while at it, I'm not sure the wal_ suffix in pg_stat_wal make sense too.

The idea is to have consistent naming between the views and their columns: I'd vote without prefix/suffix.

-1. If the prefix is removed, some column names become unreadable -
timed, requested, write_time, sync_time, buffers. We might think of
renaming those columns to something more readable, I tend to not do
that as it can break largely the application/service layer/monitoring
tools, of course even with the new pg_stat_checkpointer view, we can't
avoid that, however the changes are less i.e. replace pg_stat_bgwriter
with the new view.

I'm attaching the v2 patch for further review.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v2-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchapplication/x-patch; name=v2-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchDownload
From 724d9bee5bc3bc124dd37909878a6450c4fe1019 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 22 Nov 2022 12:06:20 +0000
Subject: [PATCH v2] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as well.
It is that way because historically checkpointer was part of
bgwriter until the commits 806a2ae and bf405ba, that went into
PG 9.2, separated them out.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

Bump catalog version.
---
 doc/src/sgml/monitoring.sgml                  | 110 +++++++++++++-----
 src/backend/catalog/system_views.sql          |  18 +--
 .../utils/activity/pgstat_checkpointer.c      |   1 +
 src/backend/utils/adt/pgstatfuncs.c           |  19 +--
 src/include/catalog/pg_proc.dat               |  22 ++--
 src/include/pgstat.h                          |   1 +
 src/test/recovery/t/029_stats_restart.pl      |   6 +-
 src/test/regress/expected/rules.out           |  15 +--
 src/test/regress/expected/stats.out           |  21 +++-
 src/test/regress/sql/stats.sql                |  12 +-
 10 files changed, 155 insertions(+), 70 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index e2426f7210..e532c4be08 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -448,6 +448,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_wal</structname><indexterm><primary>pg_stat_wal</primary></indexterm></entry>
       <entry>One row only, showing statistics about WAL activity. See
@@ -3631,7 +3640,7 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
 
   <para>
    The <structname>pg_stat_bgwriter</structname> view will always have a
-   single row, containing global data for the cluster.
+   single row, containing data about the bgwriter of the cluster.
   </para>
 
   <table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
@@ -3651,97 +3660,138 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
     <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+       <structfield>buffers_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of buffers written by the background writer
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_req</structfield> <type>bigint</type>
+       <structfield>maxwritten_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of times the background writer stopped a cleaning
+       scan because it had written too many buffers
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+       <structfield>buffers_alloc</structfield> <type>bigint</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       Number of buffers allocated
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       Time at which these statistics were last reset
       </para></entry>
      </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
+
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
+
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
 
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing data about the checkpointer process of the cluster.
+  </para>
+
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+       Column Type
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Description
       </para></entry>
      </row>
+    </thead>
 
+    <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_clean</structfield> <type>bigint</type>
+       <structfield>checkpoints_timed</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written by the background writer
+       Number of scheduled checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>maxwritten_clean</structfield> <type>bigint</type>
+       <structfield>checkpoints_req</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times the background writer stopped a cleaning
-       scan because it had written too many buffers
+       Number of requested checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend</structfield> <type>bigint</type>
+       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of buffers written directly by a backend
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
+       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of times a backend had to execute its own
-       <function>fsync</function> call (normally the background writer handles those
-       even when the backend does its own write)
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_alloc</structfield> <type>bigint</type>
+       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers allocated
+       Number of buffers written during checkpoints
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_backend</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written directly by a backend
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of times a backend had to execute its own
+       <function>fsync</function> call (normally the checkpointer handles those
+       even when the backend does its own write)
       </para></entry>
      </row>
 
@@ -5391,8 +5441,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>wal</literal> to reset all the counters shown in the
         <structname>pg_stat_wal</structname> view or
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2d8104b090..131d949dfb 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1105,18 +1105,22 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_written_backend() AS buffers_backend,
-        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+        pg_stat_get_requested_checkpoints() AS checkpoints_req,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_wal AS
     SELECT
         w.wal_records,
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index af8d513e7b..2757a10b7e 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -89,6 +89,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index ae3365d917..38a2595cdd 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1662,19 +1662,19 @@ pg_stat_get_db_sessions_killed(PG_FUNCTION_ARGS)
 }
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_requested_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_buf_written_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
 }
@@ -1707,6 +1707,12 @@ pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
 					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
 }
 
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
+}
+
 Datum
 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 {
@@ -2082,14 +2088,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "recovery_prefetch") == 0)
 		XLogPrefetchResetStats();
 	else if (strcmp(target, "wal") == 0)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f15aa2dbb1..ec97c6015e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5628,20 +5628,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_timed_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_timed_checkpoints' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_requested_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_requested_checkpoints' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_buf_written_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_buf_written_checkpoints' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 9e2ce6f011..e23d80bba8 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -274,6 +274,7 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter buf_written_checkpoints;
 	PgStat_Counter buf_written_backend;
 	PgStat_Counter buf_fsync_backend;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 typedef struct PgStat_StatDBEntry
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 1bf7b568cc..f4e262a4bf 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset     = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 624d0e5aae..4496619271 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1811,17 +1811,18 @@ pg_stat_archiver| SELECT s.archived_count,
     s.last_failed_time,
     s.stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
+pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+    pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
+    pg_stat_get_buf_alloc() AS buffers_alloc,
+    pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+    pg_stat_get_requested_checkpoints() AS checkpoints_req,
     pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
     pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
-    pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
-    pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
+    pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
     pg_stat_get_buf_written_backend() AS buffers_backend,
     pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
-    pg_stat_get_buf_alloc() AS buffers_alloc,
-    pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT d.oid AS datid,
     d.datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 1d84407a03..8ed7f895b2 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -782,8 +782,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -793,7 +793,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -884,6 +884,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index b4d6753c71..c8c24abea8 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -387,8 +387,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -402,7 +402,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -440,6 +440,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#4Andres Freund
andres@anarazel.de
In reply to: Bharath Rupireddy (#3)
Re: Introduce a new view for checkpointer related stats

Hi,

On 2022-11-22 18:08:28 +0530, Bharath Rupireddy wrote:

diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2d8104b090..131d949dfb 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1105,18 +1105,22 @@ CREATE VIEW pg_stat_archiver AS

CREATE VIEW pg_stat_bgwriter AS
SELECT
- pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
- pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
- pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
- pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
- pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
- pg_stat_get_buf_written_backend() AS buffers_backend,
- pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
pg_stat_get_buf_alloc() AS buffers_alloc,
pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+        pg_stat_get_requested_checkpoints() AS checkpoints_req,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;

I think we should consider deprecating the pg_stat_bgwriter columns but
leaving them in place for a few years. New stuff should only be added to
pg_stat_checkpointer, but we don't need to break old monitoring queries.

Greetings,

Andres Freund

#5Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Andres Freund (#4)
Re: Introduce a new view for checkpointer related stats

On Wed, Nov 23, 2022 at 2:23 AM Andres Freund <andres@anarazel.de> wrote:

On 2022-11-22 18:08:28 +0530, Bharath Rupireddy wrote:

CREATE VIEW pg_stat_bgwriter AS
SELECT
- pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
- pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
- pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
- pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
- pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
- pg_stat_get_buf_written_backend() AS buffers_backend,
- pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
pg_stat_get_buf_alloc() AS buffers_alloc,
pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;

I think we should consider deprecating the pg_stat_bgwriter columns but
leaving them in place for a few years. New stuff should only be added to
pg_stat_checkpointer, but we don't need to break old monitoring queries.

May I know what it means to deprecate pg_stat_bgwriter columns? Are
you suggesting to add deprecation warnings to corresponding functions
pg_stat_get_bgwriter_buf_written_clean(),
pg_stat_get_bgwriter_maxwritten_clean(), pg_stat_get_buf_alloc() and
pg_stat_get_bgwriter_stat_reset_time() and in the docs? And eventually
do away with the bgwriter stats and the file pgstat_bgwriter.c? Aren't
the bgwriter stats buf_written_clean, maxwritten_clean and buf_alloc
useful?

I think we need to discuss the pg_stat_bgwriter deprecation separately
independent of the patch here, no?

PS: I noticed some discussion here
/messages/by-id/20221121003815.qnwlnz2lhkow2e5w@awork3.anarazel.de,
I haven't spent enough time on it.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#6Andres Freund
andres@anarazel.de
In reply to: Bharath Rupireddy (#5)
Re: Introduce a new view for checkpointer related stats

Hi,

On 2022-11-23 11:39:43 +0530, Bharath Rupireddy wrote:

On Wed, Nov 23, 2022 at 2:23 AM Andres Freund <andres@anarazel.de> wrote:

On 2022-11-22 18:08:28 +0530, Bharath Rupireddy wrote:

CREATE VIEW pg_stat_bgwriter AS
SELECT
- pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
- pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
- pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
- pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
- pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
- pg_stat_get_buf_written_backend() AS buffers_backend,
- pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
pg_stat_get_buf_alloc() AS buffers_alloc,
pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;

I think we should consider deprecating the pg_stat_bgwriter columns but
leaving them in place for a few years. New stuff should only be added to
pg_stat_checkpointer, but we don't need to break old monitoring queries.

May I know what it means to deprecate pg_stat_bgwriter columns?

Add a note to the docs saying that the columns will be removed.

Are
you suggesting to add deprecation warnings to corresponding functions
pg_stat_get_bgwriter_buf_written_clean(),
pg_stat_get_bgwriter_maxwritten_clean(), pg_stat_get_buf_alloc() and
pg_stat_get_bgwriter_stat_reset_time() and in the docs?

I'm thinking of the checkpoint related columns in pg_stat_bgwriter.

If we move, rather than duplicate, the pg_stat_bgwriter columns to
pg_stat_checkpointer, everyone will have to update their monitoring scripts
when upgrading and will need to add version dependency if they monitor
multiple versions. If we instead keep the duplicated columns in
pg_stat_bgwriter for 5 years, users can reloy on pg_stat_checkpointer in all
supported versions.

To be clear, it isn't a very heavy burden for users to make these
adjustments. But if it only costs us a few lines to keep the old columns for a
bit, that seems worth it.

And eventually do away with the bgwriter stats and the file
pgstat_bgwriter.c? Aren't the bgwriter stats buf_written_clean,
maxwritten_clean and buf_alloc useful?

Correct, I don't think we should remove those.

Greetings,

Andres Freund

#7Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Andres Freund (#6)
1 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Sat, Nov 26, 2022 at 4:32 AM Andres Freund <andres@anarazel.de> wrote:

Thanks Andres for reviewing.

May I know what it means to deprecate pg_stat_bgwriter columns?

Add a note to the docs saying that the columns will be removed.

Done.

Are
you suggesting to add deprecation warnings to corresponding functions
pg_stat_get_bgwriter_buf_written_clean(),
pg_stat_get_bgwriter_maxwritten_clean(), pg_stat_get_buf_alloc() and
pg_stat_get_bgwriter_stat_reset_time() and in the docs?

I'm thinking of the checkpoint related columns in pg_stat_bgwriter.

Added note in the docs alongside each deprecated pg_stat_bgwriter's
checkpoint related column.

If we move, rather than duplicate, the pg_stat_bgwriter columns to
pg_stat_checkpointer, everyone will have to update their monitoring scripts
when upgrading and will need to add version dependency if they monitor
multiple versions. If we instead keep the duplicated columns in
pg_stat_bgwriter for 5 years, users can reloy on pg_stat_checkpointer in all
supported versions.

Agree. However, it's a bit difficult to keep track of deprecated
things and come back after 5 years to clean them up unless "some"
postgres hacker/developer/user notices it again. Perhaps, adding a
separate section, say 'Deprecated and To-Be-Removed, in
https://wiki.postgresql.org/wiki/Main_Page is a good idea.

To be clear, it isn't a very heavy burden for users to make these
adjustments. But if it only costs us a few lines to keep the old columns for a
bit, that seems worth it.

Yes.

I'm attaching the v3 patch for further review.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v3-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchapplication/x-patch; name=v3-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchDownload
From ec09bfcde836cb23f090fd6088b89f0fb9a68000 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Mon, 28 Nov 2022 10:07:55 +0000
Subject: [PATCH v3] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as well.
It is that way because historically checkpointer was part of
bgwriter until the commits 806a2ae and bf405ba, that went into
PG 9.2, separated them out.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

For now, we deprecate the use of these checkpointer related fields
under pg_stat_bgwriter view for smoother transitioning.
Eventually, we need to remove them from pg_stat_bgwriter view.

Bump catalog version.

Author: Bharath Rupireddy
Reviewed-by: Andres Freund, Bertrand Drouvot
Discussion: https://www.postgresql.org/message-id/CALj2ACVxX2ii=66RypXRweZe2EsBRiPMj0aHfRfHUeXJcC7kHg@mail.gmail.com
---
 doc/src/sgml/monitoring.sgml                  | 165 +++++++++++++++++-
 src/backend/catalog/system_views.sql          |  17 +-
 .../utils/activity/pgstat_checkpointer.c      |   1 +
 src/backend/utils/adt/pgstatfuncs.c           |  19 +-
 src/include/catalog/pg_proc.dat               |  22 ++-
 src/include/pgstat.h                          |   1 +
 src/test/recovery/t/029_stats_restart.pl      |   6 +-
 src/test/regress/expected/rules.out           |  14 +-
 src/test/regress/expected/stats.out           |  21 ++-
 src/test/regress/sql/stats.sql                |  12 +-
 10 files changed, 236 insertions(+), 42 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 5579b8b9e0..c69d3b21c0 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -448,6 +448,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_wal</structname><indexterm><primary>pg_stat_wal</primary></indexterm></entry>
       <entry>One row only, showing statistics about WAL activity. See
@@ -3654,7 +3663,11 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
        <structfield>checkpoints_timed</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of scheduled checkpoints that have been performed. Use of this
+       field under <structname>pg_stat_bgwriter</structname> view has been
+       deprecated, because the field actually shows checkpointer process
+       activity and is moved to a new view called
+       <structname>pg_stat_checkpointer</structname>.
       </para></entry>
      </row>
 
@@ -3663,7 +3676,11 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
        <structfield>checkpoints_req</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of requested checkpoints that have been performed. Use of this
+       field under <structname>pg_stat_bgwriter</structname> view has been
+       deprecated, because the field actually shows checkpointer process
+       activity and is moved to a new view called
+       <structname>pg_stat_checkpointer</structname>.
       </para></entry>
      </row>
 
@@ -3673,7 +3690,11 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       </para>
       <para>
        Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       checkpoint processing where files are written to disk, in milliseconds.
+       Use of this field under <structname>pg_stat_bgwriter</structname> view
+       has been deprecated, because the field actually shows checkpointer
+       process activity and is moved to a new view called
+       <structname>pg_stat_checkpointer</structname>.
       </para></entry>
      </row>
 
@@ -3684,7 +3705,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       <para>
        Total amount of time that has been spent in the portion of
        checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       milliseconds. Use of this field under
+       <structname>pg_stat_bgwriter</structname> view has been deprecated,
+       because the field actually shows checkpointer process activity and is
+       moved to a new view called <structname>pg_stat_checkpointer</structname>.
       </para></entry>
      </row>
 
@@ -3693,7 +3717,11 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
        <structfield>buffers_checkpoint</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Number of buffers written during checkpoints. Use of this field under
+       <structname>pg_stat_bgwriter</structname> view has been deprecated,
+       because the field actually shows checkpointer process activity and is
+       moved to a new view called
+       <structname>pg_stat_checkpointer</structname>.
       </para></entry>
      </row>
 
@@ -3721,7 +3749,11 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
        <structfield>buffers_backend</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written directly by a backend
+       Number of buffers written directly by a backend. Use of this field
+       under <structname>pg_stat_bgwriter</structname> view has been
+       deprecated, because the field actually shows checkpointer process
+       activity and is moved to a new view called
+       <structname>pg_stat_checkpointer</structname>.
       </para></entry>
      </row>
 
@@ -3732,7 +3764,11 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       <para>
        Number of times a backend had to execute its own
        <function>fsync</function> call (normally the background writer handles those
-       even when the backend does its own write)
+       even when the backend does its own write). Use of this field under
+       <structname>pg_stat_bgwriter</structname> view has been deprecated,
+       because the field actually shows checkpointer process activity and is
+       moved to a new view called
+       <structname>pg_stat_checkpointer</structname>.
       </para></entry>
      </row>
 
@@ -3759,6 +3795,115 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
 
  </sect2>
 
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
+
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
+
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing data about the checkpointer process of the cluster.
+  </para>
+
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       Column Type
+      </para>
+      <para>
+       Description
+      </para></entry>
+     </row>
+    </thead>
+
+    <tbody>
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of scheduled checkpoints that have been performed
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>checkpoints_req</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of requested checkpoints that have been performed
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written during checkpoints
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_backend</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written directly by a backend
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of times a backend had to execute its own
+       <function>fsync</function> call (normally the checkpointer handles those
+       even when the backend does its own write)
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
+      </para>
+      <para>
+       Time at which these statistics were last reset
+      </para></entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
+
  <sect2 id="monitoring-pg-stat-wal-view">
    <title><structname>pg_stat_wal</structname></title>
 
@@ -5391,8 +5536,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>wal</literal> to reset all the counters shown in the
         <structname>pg_stat_wal</structname> view or
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2d8104b090..e4e49efe76 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1105,11 +1105,11 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
+        pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+        pg_stat_get_requested_checkpoints() AS checkpoints_req,
         pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
         pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
         pg_stat_get_buf_written_backend() AS buffers_backend,
@@ -1117,6 +1117,17 @@ CREATE VIEW pg_stat_bgwriter AS
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+        pg_stat_get_requested_checkpoints() AS checkpoints_req,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_wal AS
     SELECT
         w.wal_records,
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index af8d513e7b..2757a10b7e 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -89,6 +89,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index ae3365d917..38a2595cdd 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1662,19 +1662,19 @@ pg_stat_get_db_sessions_killed(PG_FUNCTION_ARGS)
 }
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_requested_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_buf_written_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
 }
@@ -1707,6 +1707,12 @@ pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
 					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
 }
 
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
+}
+
 Datum
 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 {
@@ -2082,14 +2088,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "recovery_prefetch") == 0)
 		XLogPrefetchResetStats();
 	else if (strcmp(target, "wal") == 0)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f9301b2627..1b24969a01 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5628,20 +5628,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_timed_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_timed_checkpoints' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_requested_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_requested_checkpoints' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_buf_written_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_buf_written_checkpoints' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 9e2ce6f011..e23d80bba8 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -274,6 +274,7 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter buf_written_checkpoints;
 	PgStat_Counter buf_written_backend;
 	PgStat_Counter buf_fsync_backend;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 typedef struct PgStat_StatDBEntry
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 1bf7b568cc..f4e262a4bf 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset     = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 37c1c86473..81bb0adfc3 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1814,17 +1814,25 @@ pg_stat_archiver| SELECT s.archived_count,
     s.last_failed_time,
     s.stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
+pg_stat_bgwriter| SELECT pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+    pg_stat_get_requested_checkpoints() AS checkpoints_req,
     pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
     pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
+    pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
     pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
     pg_stat_get_buf_written_backend() AS buffers_backend,
     pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+    pg_stat_get_requested_checkpoints() AS checkpoints_req,
+    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+    pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+    pg_stat_get_buf_written_backend() AS buffers_backend,
+    pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT d.oid AS datid,
     d.datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 1d84407a03..8ed7f895b2 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -782,8 +782,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -793,7 +793,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -884,6 +884,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index b4d6753c71..c8c24abea8 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -387,8 +387,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -402,7 +402,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -440,6 +440,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#8Robert Haas
robertmhaas@gmail.com
In reply to: Andres Freund (#4)
Re: Introduce a new view for checkpointer related stats

On Tue, Nov 22, 2022 at 3:53 PM Andres Freund <andres@anarazel.de> wrote:

I think we should consider deprecating the pg_stat_bgwriter columns but
leaving them in place for a few years. New stuff should only be added to
pg_stat_checkpointer, but we don't need to break old monitoring queries.

I vote to just remove them. I think that most people won't update
their queries until they are forced to do so. I don't think it
matters very much when we force them to do that.

Our track record in following through on deprecations is pretty bad
too, which is another consideration.

--
Robert Haas
EDB: http://www.enterprisedb.com

#9Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Robert Haas (#8)
Re: Introduce a new view for checkpointer related stats

On Mon, Nov 28, 2022 at 11:29 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Nov 22, 2022 at 3:53 PM Andres Freund <andres@anarazel.de> wrote:

I think we should consider deprecating the pg_stat_bgwriter columns but
leaving them in place for a few years. New stuff should only be added to
pg_stat_checkpointer, but we don't need to break old monitoring queries.

I vote to just remove them. I think that most people won't update
their queries until they are forced to do so. I don't think it
matters very much when we force them to do that.

Our track record in following through on deprecations is pretty bad
too, which is another consideration.

Hm. I'm fine with either way. Even if we remove the checkpointer
columns from pg_stat_bgwriter, the changes that one needs to do are so
minimal and straightforward because the column names aren't changed,
just the view name.

Having said that, I don't have a strong opinion here. I'll leave it to
the other hacker's opinion and/or committer's discretion.

FWIW - here's the v2 patch that gets rid of checkpointer columns from
pg_stat_bgwriter
/messages/by-id/CALj2ACX8jFET1C3bs_edz_8JRcMg5nz8Y7ryjGaCsfnVpAYoVQ@mail.gmail.com
and here's the v3 patch that deprecates
/messages/by-id/CALj2ACUjEvPQYGJHmH2FrAj1gmvHskNrOeNUr7xnwjtkYVZvEQ@mail.gmail.com.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#10Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#8)
Re: Introduce a new view for checkpointer related stats

On Mon, Nov 28, 2022 at 11:29 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Nov 22, 2022 at 3:53 PM Andres Freund <andres@anarazel.de> wrote:

I think we should consider deprecating the pg_stat_bgwriter columns but
leaving them in place for a few years. New stuff should only be added to
pg_stat_checkpointer, but we don't need to break old monitoring queries.

I vote to just remove them. I think that most people won't update
their queries until they are forced to do so. I don't think it
matters very much when we force them to do that.

+1.

--
With Regards,
Amit Kapila.

#11Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Robert Haas (#8)
Re: Introduce a new view for checkpointer related stats

Hi,

On 11/28/22 6:58 PM, Robert Haas wrote:

On Tue, Nov 22, 2022 at 3:53 PM Andres Freund <andres@anarazel.de> wrote:

I think we should consider deprecating the pg_stat_bgwriter columns but
leaving them in place for a few years. New stuff should only be added to
pg_stat_checkpointer, but we don't need to break old monitoring queries.

I vote to just remove them. I think that most people won't update
their queries until they are forced to do so. I don't think it
matters very much when we force them to do that.

Our track record in following through on deprecations is pretty bad
too, which is another consideration.

Same point of view.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#12Greg Stark
stark@mit.edu
In reply to: Robert Haas (#8)
Re: Introduce a new view for checkpointer related stats

On Mon, 28 Nov 2022 at 13:00, Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Nov 22, 2022 at 3:53 PM Andres Freund <andres@anarazel.de> wrote:

I vote to just remove them. I think that most people won't update
their queries until they are forced to do so. I don't think it
matters very much when we force them to do that.

I would tend to agree.

If we wanted to have a deprecation period I think the smooth way to do
it would be to introduce two new functions/views with the new split.
Then mark the entire old view as deprecated. That way there isn't a
mix of new and old columns in the same view/function.

I don't think it's really necessary to do that here but there'll
probably be instances where it would be worth doing.

--
greg

#13Andres Freund
andres@anarazel.de
In reply to: Robert Haas (#8)
Re: Introduce a new view for checkpointer related stats

Hi,

On 2022-11-28 12:58:48 -0500, Robert Haas wrote:

On Tue, Nov 22, 2022 at 3:53 PM Andres Freund <andres@anarazel.de> wrote:

I think we should consider deprecating the pg_stat_bgwriter columns but
leaving them in place for a few years. New stuff should only be added to
pg_stat_checkpointer, but we don't need to break old monitoring queries.

I vote to just remove them. I think that most people won't update
their queries until they are forced to do so.

Seems most agree with that... WFM.

But:

I don't think it matters very much when we force them to do that.

I don't think that's true. If we remove the columns when the last version
without pg_stat_checkpointer has gone out of support, users don't need to have
version switches in their monitoring setups.

Greetings,

Andres Freund

#14Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Andres Freund (#13)
1 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Wed, Nov 30, 2022 at 6:01 AM Andres Freund <andres@anarazel.de> wrote:

Hi,

On 2022-11-28 12:58:48 -0500, Robert Haas wrote:

On Tue, Nov 22, 2022 at 3:53 PM Andres Freund <andres@anarazel.de> wrote:

I think we should consider deprecating the pg_stat_bgwriter columns but
leaving them in place for a few years. New stuff should only be added to
pg_stat_checkpointer, but we don't need to break old monitoring queries.

I vote to just remove them. I think that most people won't update
their queries until they are forced to do so.

Seems most agree with that... WFM.

Thanks. I'm attaching the v2 patch from upthread again here as we all
agree to remove checkpointer columns from pg_stat_bgwriter view and
have them in the new view pg_stat_checkpointer.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v2-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchapplication/octet-stream; name=v2-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchDownload
From 724d9bee5bc3bc124dd37909878a6450c4fe1019 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 22 Nov 2022 12:06:20 +0000
Subject: [PATCH v2] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as well.
It is that way because historically checkpointer was part of
bgwriter until the commits 806a2ae and bf405ba, that went into
PG 9.2, separated them out.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

Bump catalog version.
---
 doc/src/sgml/monitoring.sgml                  | 110 +++++++++++++-----
 src/backend/catalog/system_views.sql          |  18 +--
 .../utils/activity/pgstat_checkpointer.c      |   1 +
 src/backend/utils/adt/pgstatfuncs.c           |  19 +--
 src/include/catalog/pg_proc.dat               |  22 ++--
 src/include/pgstat.h                          |   1 +
 src/test/recovery/t/029_stats_restart.pl      |   6 +-
 src/test/regress/expected/rules.out           |  15 +--
 src/test/regress/expected/stats.out           |  21 +++-
 src/test/regress/sql/stats.sql                |  12 +-
 10 files changed, 155 insertions(+), 70 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index e2426f7210..e532c4be08 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -448,6 +448,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_wal</structname><indexterm><primary>pg_stat_wal</primary></indexterm></entry>
       <entry>One row only, showing statistics about WAL activity. See
@@ -3631,7 +3640,7 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
 
   <para>
    The <structname>pg_stat_bgwriter</structname> view will always have a
-   single row, containing global data for the cluster.
+   single row, containing data about the bgwriter of the cluster.
   </para>
 
   <table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
@@ -3651,97 +3660,138 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
     <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+       <structfield>buffers_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of buffers written by the background writer
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_req</structfield> <type>bigint</type>
+       <structfield>maxwritten_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of times the background writer stopped a cleaning
+       scan because it had written too many buffers
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+       <structfield>buffers_alloc</structfield> <type>bigint</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       Number of buffers allocated
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       Time at which these statistics were last reset
       </para></entry>
      </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
+
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
+
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
 
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing data about the checkpointer process of the cluster.
+  </para>
+
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+       Column Type
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Description
       </para></entry>
      </row>
+    </thead>
 
+    <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_clean</structfield> <type>bigint</type>
+       <structfield>checkpoints_timed</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written by the background writer
+       Number of scheduled checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>maxwritten_clean</structfield> <type>bigint</type>
+       <structfield>checkpoints_req</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times the background writer stopped a cleaning
-       scan because it had written too many buffers
+       Number of requested checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend</structfield> <type>bigint</type>
+       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of buffers written directly by a backend
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
+       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of times a backend had to execute its own
-       <function>fsync</function> call (normally the background writer handles those
-       even when the backend does its own write)
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_alloc</structfield> <type>bigint</type>
+       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers allocated
+       Number of buffers written during checkpoints
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_backend</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written directly by a backend
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of times a backend had to execute its own
+       <function>fsync</function> call (normally the checkpointer handles those
+       even when the backend does its own write)
       </para></entry>
      </row>
 
@@ -5391,8 +5441,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>wal</literal> to reset all the counters shown in the
         <structname>pg_stat_wal</structname> view or
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2d8104b090..131d949dfb 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1105,18 +1105,22 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_written_backend() AS buffers_backend,
-        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+        pg_stat_get_requested_checkpoints() AS checkpoints_req,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_wal AS
     SELECT
         w.wal_records,
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index af8d513e7b..2757a10b7e 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -89,6 +89,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index ae3365d917..38a2595cdd 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1662,19 +1662,19 @@ pg_stat_get_db_sessions_killed(PG_FUNCTION_ARGS)
 }
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_requested_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_buf_written_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
 }
@@ -1707,6 +1707,12 @@ pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
 					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
 }
 
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
+}
+
 Datum
 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 {
@@ -2082,14 +2088,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "recovery_prefetch") == 0)
 		XLogPrefetchResetStats();
 	else if (strcmp(target, "wal") == 0)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f15aa2dbb1..ec97c6015e 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5628,20 +5628,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_timed_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_timed_checkpoints' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_requested_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_requested_checkpoints' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_buf_written_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_buf_written_checkpoints' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 9e2ce6f011..e23d80bba8 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -274,6 +274,7 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter buf_written_checkpoints;
 	PgStat_Counter buf_written_backend;
 	PgStat_Counter buf_fsync_backend;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 typedef struct PgStat_StatDBEntry
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 1bf7b568cc..f4e262a4bf 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset     = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 624d0e5aae..4496619271 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1811,17 +1811,18 @@ pg_stat_archiver| SELECT s.archived_count,
     s.last_failed_time,
     s.stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
+pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+    pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
+    pg_stat_get_buf_alloc() AS buffers_alloc,
+    pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+    pg_stat_get_requested_checkpoints() AS checkpoints_req,
     pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
     pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
-    pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
-    pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
+    pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
     pg_stat_get_buf_written_backend() AS buffers_backend,
     pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
-    pg_stat_get_buf_alloc() AS buffers_alloc,
-    pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT d.oid AS datid,
     d.datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 1d84407a03..8ed7f895b2 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -782,8 +782,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -793,7 +793,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -884,6 +884,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index b4d6753c71..c8c24abea8 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -387,8 +387,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -402,7 +402,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -440,6 +440,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#15Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Bharath Rupireddy (#14)
Re: Introduce a new view for checkpointer related stats

Hi,

On 11/30/22 7:34 AM, Bharath Rupireddy wrote:

On Wed, Nov 30, 2022 at 6:01 AM Andres Freund <andres@anarazel.de> wrote:

Hi,

On 2022-11-28 12:58:48 -0500, Robert Haas wrote:

On Tue, Nov 22, 2022 at 3:53 PM Andres Freund <andres@anarazel.de> wrote:

I think we should consider deprecating the pg_stat_bgwriter columns but
leaving them in place for a few years. New stuff should only be added to
pg_stat_checkpointer, but we don't need to break old monitoring queries.

I vote to just remove them. I think that most people won't update
their queries until they are forced to do so.

Seems most agree with that... WFM.

Thanks. I'm attaching the v2 patch from upthread again here as we all
agree to remove checkpointer columns from pg_stat_bgwriter view and
have them in the new view pg_stat_checkpointer.

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+        pg_stat_get_requested_checkpoints() AS checkpoints_req,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+

I still think that having checkpoints_ prefix in a pg_stat_checkpointer view sounds "weird" (made sense when they were part of pg_stat_bgwriter)

maybe we could have something like this instead?

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS num_timed,
+        pg_stat_get_requested_checkpoints() AS num_req,
+        pg_stat_get_checkpoint_write_time() AS total_write_time,
+        pg_stat_get_checkpoint_sync_time() AS total_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+

That's a nit in any case and the patch LGTM.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#16Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Drouvot, Bertrand (#15)
Re: Introduce a new view for checkpointer related stats

On Wed, Nov 30, 2022 at 12:44 PM Drouvot, Bertrand
<bertranddrouvot.pg@gmail.com> wrote:

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS checkpoints_timed,
+        pg_stat_get_requested_checkpoints() AS checkpoints_req,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+

I still think that having checkpoints_ prefix in a pg_stat_checkpointer view sounds "weird" (made sense when they were part of pg_stat_bgwriter)

maybe we could have something like this instead?

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS num_timed,
+        pg_stat_get_requested_checkpoints() AS num_req,
+        pg_stat_get_checkpoint_write_time() AS total_write_time,
+        pg_stat_get_checkpoint_sync_time() AS total_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_checkpoint,
+        pg_stat_get_buf_written_backend() AS buffers_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+

I don't have a strong opinion about changing column names. However, if
we were to change it, I prefer to use names that
PgStat_CheckpointerStats has. BTW, that's what
PgStat_BgWriterStats/pg_stat_bgwriter and
PgStat_ArchiverStats/pg_stat_archiver uses.
typedef struct PgStat_CheckpointerStats
{
PgStat_Counter timed_checkpoints;
PgStat_Counter requested_checkpoints;
PgStat_Counter checkpoint_write_time; /* times in milliseconds */
PgStat_Counter checkpoint_sync_time;
PgStat_Counter buf_written_checkpoints;
PgStat_Counter buf_written_backend;
PgStat_Counter buf_fsync_backend;
TimestampTz stat_reset_timestamp;
} PgStat_CheckpointerStats;

That's a nit in any case and the patch LGTM.

Thanks.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#17Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#16)
1 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Wed, Nov 30, 2022 at 5:15 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

I don't have a strong opinion about changing column names. However, if
we were to change it, I prefer to use names that
PgStat_CheckpointerStats has. BTW, that's what
PgStat_BgWriterStats/pg_stat_bgwriter and
PgStat_ArchiverStats/pg_stat_archiver uses.

After thinking about this a while, I convinced myself to change the
column names to be a bit more meaningful. I still think having
checkpoints in the column names is needed because it also has other
backend related columns. I'm attaching the v4 patch for further
review.
CREATE VIEW pg_stat_checkpointer AS
SELECT
pg_stat_get_timed_checkpoints() AS timed_checkpoints,
pg_stat_get_requested_checkpoints() AS requested_checkpoints,
pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
pg_stat_get_buf_written_backend() AS buffers_written_backend,
pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v4-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchapplication/x-patch; name=v4-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchDownload
From 8280223b2b8fde888dd8540328336421bbf6138c Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Fri, 2 Dec 2022 04:58:46 +0000
Subject: [PATCH v4] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as well.
It is that way because historically checkpointer was part of
bgwriter until the commits 806a2ae and bf405ba, that went into
PG 9.2, separated them out.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

Bump catalog version.
---
 doc/src/sgml/monitoring.sgml                  | 110 +++++++++++++-----
 src/backend/catalog/system_views.sql          |  18 +--
 .../utils/activity/pgstat_checkpointer.c      |   1 +
 src/backend/utils/adt/pgstatfuncs.c           |  19 +--
 src/include/catalog/pg_proc.dat               |  22 ++--
 src/include/pgstat.h                          |   1 +
 src/test/recovery/t/029_stats_restart.pl      |   6 +-
 src/test/regress/expected/rules.out           |  17 +--
 src/test/regress/expected/stats.out           |  21 +++-
 src/test/regress/sql/stats.sql                |  12 +-
 10 files changed, 156 insertions(+), 71 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 11a8ebe5ec..1279b47d27 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -448,6 +448,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_wal</structname><indexterm><primary>pg_stat_wal</primary></indexterm></entry>
       <entry>One row only, showing statistics about WAL activity. See
@@ -3633,7 +3642,7 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
 
   <para>
    The <structname>pg_stat_bgwriter</structname> view will always have a
-   single row, containing global data for the cluster.
+   single row, containing data about the bgwriter of the cluster.
   </para>
 
   <table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
@@ -3653,97 +3662,138 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
     <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+       <structfield>buffers_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of buffers written by the background writer
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_req</structfield> <type>bigint</type>
+       <structfield>maxwritten_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of times the background writer stopped a cleaning
+       scan because it had written too many buffers
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+       <structfield>buffers_alloc</structfield> <type>bigint</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       Number of buffers allocated
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       Time at which these statistics were last reset
       </para></entry>
      </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
+
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
+
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
+
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing data about the checkpointer process of the cluster.
+  </para>
 
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+       Column Type
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Description
       </para></entry>
      </row>
+    </thead>
 
+    <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_clean</structfield> <type>bigint</type>
+       <structfield>timed_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written by the background writer
+       Number of scheduled checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>maxwritten_clean</structfield> <type>bigint</type>
+       <structfield>requested_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times the background writer stopped a cleaning
-       scan because it had written too many buffers
+       Number of requested checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend</structfield> <type>bigint</type>
+       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of buffers written directly by a backend
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
+       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of times a backend had to execute its own
-       <function>fsync</function> call (normally the background writer handles those
-       even when the backend does its own write)
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_alloc</structfield> <type>bigint</type>
+       <structfield>buffers_written_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers allocated
+       Number of buffers written during checkpoints
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_written_backend</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written directly by a backend
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_fsync_backend</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of times a backend had to execute its own
+       <function>fsync</function> call (normally the checkpointer handles those
+       even when the backend does its own write)
       </para></entry>
      </row>
 
@@ -5393,8 +5443,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>wal</literal> to reset all the counters shown in the
         <structname>pg_stat_wal</structname> view or
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2d8104b090..89e40db1c1 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1105,18 +1105,22 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_written_backend() AS buffers_backend,
-        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+        pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+        pg_stat_get_buf_written_backend() AS buffers_written_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_wal AS
     SELECT
         w.wal_records,
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index af8d513e7b..2757a10b7e 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -89,6 +89,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index ae3365d917..38a2595cdd 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1662,19 +1662,19 @@ pg_stat_get_db_sessions_killed(PG_FUNCTION_ARGS)
 }
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_requested_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_buf_written_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
 }
@@ -1707,6 +1707,12 @@ pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
 					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
 }
 
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
+}
+
 Datum
 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 {
@@ -2082,14 +2088,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "recovery_prefetch") == 0)
 		XLogPrefetchResetStats();
 	else if (strcmp(target, "wal") == 0)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f9301b2627..1b24969a01 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5628,20 +5628,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_timed_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_timed_checkpoints' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_requested_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_requested_checkpoints' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_buf_written_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_buf_written_checkpoints' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 9e2ce6f011..e23d80bba8 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -274,6 +274,7 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter buf_written_checkpoints;
 	PgStat_Counter buf_written_backend;
 	PgStat_Counter buf_fsync_backend;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 typedef struct PgStat_StatDBEntry
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 1bf7b568cc..25ae0a36e6 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset     = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT timed_checkpoints + requested_checkpoints FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 37c1c86473..2cf97dcee1 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1814,17 +1814,18 @@ pg_stat_archiver| SELECT s.archived_count,
     s.last_failed_time,
     s.stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
-    pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-    pg_stat_get_buf_written_backend() AS buffers_backend,
-    pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+    pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+    pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+    pg_stat_get_buf_written_backend() AS buffers_written_backend,
+    pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT d.oid AS datid,
     d.datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 1d84407a03..85aaebe7b6 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -782,8 +782,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT requested_checkpoints AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -793,7 +793,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT requested_checkpoints > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -884,6 +884,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index b4d6753c71..e867bc15e3 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -387,8 +387,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT requested_checkpoints AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -402,7 +402,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT requested_checkpoints > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -440,6 +440,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#18sirisha chamarthi
sirichamarthi22@gmail.com
In reply to: Bharath Rupireddy (#17)
Re: Introduce a new view for checkpointer related stats

On Thu, Dec 1, 2022 at 9:50 PM Bharath Rupireddy <
bharath.rupireddyforpostgres@gmail.com> wrote:

On Wed, Nov 30, 2022 at 5:15 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

I don't have a strong opinion about changing column names. However, if
we were to change it, I prefer to use names that
PgStat_CheckpointerStats has. BTW, that's what
PgStat_BgWriterStats/pg_stat_bgwriter and
PgStat_ArchiverStats/pg_stat_archiver uses.

After thinking about this a while, I convinced myself to change the
column names to be a bit more meaningful. I still think having
checkpoints in the column names is needed because it also has other
backend related columns. I'm attaching the v4 patch for further
review.
CREATE VIEW pg_stat_checkpointer AS
SELECT
pg_stat_get_timed_checkpoints() AS timed_checkpoints,
pg_stat_get_requested_checkpoints() AS requested_checkpoints,
pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
pg_stat_get_buf_written_checkpoints() AS
buffers_written_checkpoints,
pg_stat_get_buf_written_backend() AS buffers_written_backend,
pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;

IMO, “buffers_written_checkpoints” is confusing. What do you think?

Show quoted text

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#19Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: sirisha chamarthi (#18)
Re: Introduce a new view for checkpointer related stats

On Fri, Dec 2, 2022 at 12:54 PM sirisha chamarthi
<sirichamarthi22@gmail.com> wrote:

On Thu, Dec 1, 2022 at 9:50 PM Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com> wrote:

On Wed, Nov 30, 2022 at 5:15 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

I don't have a strong opinion about changing column names. However, if
we were to change it, I prefer to use names that
PgStat_CheckpointerStats has. BTW, that's what
PgStat_BgWriterStats/pg_stat_bgwriter and
PgStat_ArchiverStats/pg_stat_archiver uses.

After thinking about this a while, I convinced myself to change the
column names to be a bit more meaningful. I still think having
checkpoints in the column names is needed because it also has other
backend related columns. I'm attaching the v4 patch for further
review.
CREATE VIEW pg_stat_checkpointer AS
SELECT
pg_stat_get_timed_checkpoints() AS timed_checkpoints,
pg_stat_get_requested_checkpoints() AS requested_checkpoints,
pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
pg_stat_get_buf_written_backend() AS buffers_written_backend,
pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;

IMO, “buffers_written_checkpoints” is confusing. What do you think?

Thanks. We can be "more and more" meaningful by naming
buffers_written_by_checkpoints, buffers_written_by_backend,
buffers_fsync_by_backend. However, I don't think that's a good idea
here as names get too long.

Having said that, I'll leave it to the committer's discretion.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#20Drouvot, Bertrand
bertranddrouvot.pg@gmail.com
In reply to: Bharath Rupireddy (#17)
Re: Introduce a new view for checkpointer related stats

Hi,

On 12/2/22 6:50 AM, Bharath Rupireddy wrote:

On Wed, Nov 30, 2022 at 5:15 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

I don't have a strong opinion about changing column names. However, if
we were to change it, I prefer to use names that
PgStat_CheckpointerStats has. BTW, that's what
PgStat_BgWriterStats/pg_stat_bgwriter and
PgStat_ArchiverStats/pg_stat_archiver uses.

After thinking about this a while, I convinced myself to change the
column names to be a bit more meaningful. I still think having
checkpoints in the column names is needed because it also has other
backend related columns. I'm attaching the v4 patch for further
review.
CREATE VIEW pg_stat_checkpointer AS
SELECT
pg_stat_get_timed_checkpoints() AS timed_checkpoints,
pg_stat_get_requested_checkpoints() AS requested_checkpoints,
pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
pg_stat_get_buf_written_backend() AS buffers_written_backend,
pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;

Thanks!

Patch LGTM, marking it as Ready for Committer.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#21Nitin Jadhav
nitinjadhavpostgres@gmail.com
In reply to: Bharath Rupireddy (#17)
Re: Introduce a new view for checkpointer related stats

The patch looks good to me.

Thanks & Regards,
Nitin Jadhav

On Fri, Dec 2, 2022 at 11:20 AM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Show quoted text

On Wed, Nov 30, 2022 at 5:15 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

I don't have a strong opinion about changing column names. However, if
we were to change it, I prefer to use names that
PgStat_CheckpointerStats has. BTW, that's what
PgStat_BgWriterStats/pg_stat_bgwriter and
PgStat_ArchiverStats/pg_stat_archiver uses.

After thinking about this a while, I convinced myself to change the
column names to be a bit more meaningful. I still think having
checkpoints in the column names is needed because it also has other
backend related columns. I'm attaching the v4 patch for further
review.
CREATE VIEW pg_stat_checkpointer AS
SELECT
pg_stat_get_timed_checkpoints() AS timed_checkpoints,
pg_stat_get_requested_checkpoints() AS requested_checkpoints,
pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
pg_stat_get_buf_written_backend() AS buffers_written_backend,
pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#22Nathan Bossart
nathandbossart@gmail.com
In reply to: Drouvot, Bertrand (#20)
Re: Introduce a new view for checkpointer related stats

On Fri, Dec 02, 2022 at 08:36:38AM +0100, Drouvot, Bertrand wrote:

Patch LGTM, marking it as Ready for Committer.

Unfortunately, this patch no longer applies. Bharath, would you mind
posting a rebased version?

--
Nathan Bossart
Amazon Web Services: https://aws.amazon.com

#23Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Drouvot, Bertrand (#20)
1 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Fri, Dec 2, 2022 at 1:07 PM Drouvot, Bertrand
<bertranddrouvot.pg@gmail.com> wrote:

Patch LGTM, marking it as Ready for Committer.

Had to rebase, attached v5 patch for further consideration.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v5-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchapplication/x-patch; name=v5-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchDownload
From e705916c40649d13a66299159cc992d0572960f5 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Fri, 20 Jan 2023 14:20:03 +0000
Subject: [PATCH v5] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as well.
It is that way because historically checkpointer was part of
bgwriter until the commits 806a2ae and bf405ba, that went into
PG 9.2, separated them out.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

Bump catalog version.
---
 doc/src/sgml/monitoring.sgml                  | 110 +++++++++++++-----
 src/backend/catalog/system_views.sql          |  18 +--
 .../utils/activity/pgstat_checkpointer.c      |   1 +
 src/backend/utils/adt/pgstatfuncs.c           |  19 +--
 src/include/catalog/pg_proc.dat               |  22 ++--
 src/include/pgstat.h                          |   1 +
 src/test/recovery/t/029_stats_restart.pl      |   6 +-
 src/test/regress/expected/rules.out           |  17 +--
 src/test/regress/expected/stats.out           |  21 +++-
 src/test/regress/sql/stats.sql                |  12 +-
 10 files changed, 156 insertions(+), 71 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index e3a783abd0..54166d88fc 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -494,6 +494,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_wal</structname><indexterm><primary>pg_stat_wal</primary></indexterm></entry>
       <entry>One row only, showing statistics about WAL activity. See
@@ -3671,7 +3680,7 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
 
   <para>
    The <structname>pg_stat_bgwriter</structname> view will always have a
-   single row, containing global data for the cluster.
+   single row, containing data about the bgwriter of the cluster.
   </para>
 
   <table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
@@ -3691,97 +3700,138 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
     <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+       <structfield>buffers_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of buffers written by the background writer
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_req</structfield> <type>bigint</type>
+       <structfield>maxwritten_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of times the background writer stopped a cleaning
+       scan because it had written too many buffers
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+       <structfield>buffers_alloc</structfield> <type>bigint</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       Number of buffers allocated
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       Time at which these statistics were last reset
       </para></entry>
      </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
+
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
+
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
+
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing data about the checkpointer process of the cluster.
+  </para>
 
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+       Column Type
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Description
       </para></entry>
      </row>
+    </thead>
 
+    <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_clean</structfield> <type>bigint</type>
+       <structfield>timed_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written by the background writer
+       Number of scheduled checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>maxwritten_clean</structfield> <type>bigint</type>
+       <structfield>requested_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times the background writer stopped a cleaning
-       scan because it had written too many buffers
+       Number of requested checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend</structfield> <type>bigint</type>
+       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of buffers written directly by a backend
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
+       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of times a backend had to execute its own
-       <function>fsync</function> call (normally the background writer handles those
-       even when the backend does its own write)
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_alloc</structfield> <type>bigint</type>
+       <structfield>buffers_written_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers allocated
+       Number of buffers written during checkpoints
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_written_backend</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written directly by a backend
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_fsync_backend</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of times a backend had to execute its own
+       <function>fsync</function> call (normally the checkpointer handles those
+       even when the backend does its own write)
       </para></entry>
      </row>
 
@@ -5431,8 +5481,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>wal</literal> to reset all the counters shown in the
         <structname>pg_stat_wal</structname> view or
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 8608e3fa5b..1ac72031fc 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1105,18 +1105,22 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_written_backend() AS buffers_backend,
-        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+        pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+        pg_stat_get_buf_written_backend() AS buffers_written_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_wal AS
     SELECT
         w.wal_records,
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index 3e9ab45103..d9942b64d4 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -89,6 +89,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6737493402..271f19688b 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1176,19 +1176,19 @@ PG_STAT_GET_DBENTRY_FLOAT8(idle_in_transaction_time)
 PG_STAT_GET_DBENTRY_FLOAT8(session_time)
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_requested_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_buf_written_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
 }
@@ -1221,6 +1221,12 @@ pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
 					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
 }
 
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
+}
+
 Datum
 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 {
@@ -1596,14 +1602,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "recovery_prefetch") == 0)
 		XLogPrefetchResetStats();
 	else if (strcmp(target, "wal") == 0)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 86eb8e8c58..decd98c327 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5639,20 +5639,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_timed_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_timed_checkpoints' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_requested_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_requested_checkpoints' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_buf_written_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_buf_written_checkpoints' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 5e3326a3b9..b8d8a3710c 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -274,6 +274,7 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter buf_written_checkpoints;
 	PgStat_Counter buf_written_backend;
 	PgStat_Counter buf_fsync_backend;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 typedef struct PgStat_StatDBEntry
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 83d6647d32..463f29101e 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset     = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT timed_checkpoints + requested_checkpoints FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index e7a2f5856a..1215e0f881 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1814,17 +1814,18 @@ pg_stat_archiver| SELECT archived_count,
     last_failed_time,
     stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
-    pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-    pg_stat_get_buf_written_backend() AS buffers_backend,
-    pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+    pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+    pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+    pg_stat_get_buf_written_backend() AS buffers_written_backend,
+    pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT oid AS datid,
     datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 1d84407a03..85aaebe7b6 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -782,8 +782,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT requested_checkpoints AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -793,7 +793,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT requested_checkpoints > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -884,6 +884,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index b4d6753c71..e867bc15e3 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -387,8 +387,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT requested_checkpoints AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -402,7 +402,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT requested_checkpoints > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -440,6 +440,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#24Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#23)
1 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Sat, Jan 21, 2023 at 5:56 AM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

On Fri, Dec 2, 2022 at 1:07 PM Drouvot, Bertrand
<bertranddrouvot.pg@gmail.com> wrote:

Patch LGTM, marking it as Ready for Committer.

Had to rebase, attached v5 patch for further consideration.

One more rebase due to 28e626bd (pgstat: Infrastructure for more
detailed IO statistics). PSA v6 patch.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v6-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchapplication/x-patch; name=v6-0001-Introduce-a-new-view-for-checkpointer-related-sta.patchDownload
From 87829fec1f51a2ed764c6e48825caf13ef4b2725 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Thu, 9 Feb 2023 06:25:35 +0000
Subject: [PATCH v6] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as well.
It is that way because historically checkpointer was part of
bgwriter until the commits 806a2ae and bf405ba, that went into
PG 9.2, separated them out.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

Bump catalog version.
---
 doc/src/sgml/monitoring.sgml                  | 110 +++++++++++++-----
 src/backend/catalog/system_views.sql          |  18 +--
 .../utils/activity/pgstat_checkpointer.c      |   1 +
 src/backend/utils/adt/pgstatfuncs.c           |  19 +--
 src/include/catalog/pg_proc.dat               |  22 ++--
 src/include/pgstat.h                          |   1 +
 src/test/recovery/t/029_stats_restart.pl      |   6 +-
 src/test/regress/expected/rules.out           |  17 +--
 src/test/regress/expected/stats.out           |  21 +++-
 src/test/regress/sql/stats.sql                |  12 +-
 10 files changed, 156 insertions(+), 71 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index b246ddc634..f53f5769fc 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -494,6 +494,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
       </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_wal</structname><indexterm><primary>pg_stat_wal</primary></indexterm></entry>
       <entry>One row only, showing statistics about WAL activity. See
@@ -3681,7 +3690,7 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
 
   <para>
    The <structname>pg_stat_bgwriter</structname> view will always have a
-   single row, containing global data for the cluster.
+   single row, containing data about the bgwriter of the cluster.
   </para>
 
   <table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
@@ -3701,97 +3710,138 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
     <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+       <structfield>buffers_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of buffers written by the background writer
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_req</structfield> <type>bigint</type>
+       <structfield>maxwritten_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of times the background writer stopped a cleaning
+       scan because it had written too many buffers
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+       <structfield>buffers_alloc</structfield> <type>bigint</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       Number of buffers allocated
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       Time at which these statistics were last reset
       </para></entry>
      </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
+
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
+
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
+
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing data about the checkpointer process of the cluster.
+  </para>
 
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+       Column Type
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Description
       </para></entry>
      </row>
+    </thead>
 
+    <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_clean</structfield> <type>bigint</type>
+       <structfield>timed_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written by the background writer
+       Number of scheduled checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>maxwritten_clean</structfield> <type>bigint</type>
+       <structfield>requested_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times the background writer stopped a cleaning
-       scan because it had written too many buffers
+       Number of requested checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend</structfield> <type>bigint</type>
+       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of buffers written directly by a backend
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
+       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of times a backend had to execute its own
-       <function>fsync</function> call (normally the background writer handles those
-       even when the backend does its own write)
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_alloc</structfield> <type>bigint</type>
+       <structfield>buffers_written_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers allocated
+       Number of buffers written during checkpoints
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_written_backend</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written directly by a backend
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_fsync_backend</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of times a backend had to execute its own
+       <function>fsync</function> call (normally the checkpointer handles those
+       even when the backend does its own write)
       </para></entry>
      </row>
 
@@ -5441,8 +5491,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>io</literal> to reset all the counters shown in the
         <structname>pg_stat_io</structname> view,
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 8608e3fa5b..1ac72031fc 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1105,18 +1105,22 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_written_backend() AS buffers_backend,
-        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+        pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+        pg_stat_get_buf_written_backend() AS buffers_written_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_wal AS
     SELECT
         w.wal_records,
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index 26dec112f6..f949095841 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -94,6 +94,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 924698e6ae..b8a208a5b5 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1176,19 +1176,19 @@ PG_STAT_GET_DBENTRY_FLOAT8(idle_in_transaction_time)
 PG_STAT_GET_DBENTRY_FLOAT8(session_time)
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_requested_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_buf_written_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
 }
@@ -1221,6 +1221,12 @@ pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
 					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
 }
 
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
+}
+
 Datum
 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 {
@@ -1601,14 +1607,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "io") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_IO);
 	else if (strcmp(target, "recovery_prefetch") == 0)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index c0f2a8a77c..97a8c823fc 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5666,20 +5666,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_timed_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_timed_checkpoints' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_requested_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_requested_checkpoints' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_buf_written_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_buf_written_checkpoints' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index db9675884f..98418b7610 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -275,6 +275,7 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter buf_written_checkpoints;
 	PgStat_Counter buf_written_backend;
 	PgStat_Counter buf_fsync_backend;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 83d6647d32..463f29101e 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset     = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT timed_checkpoints + requested_checkpoints FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index e7a2f5856a..1215e0f881 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1814,17 +1814,18 @@ pg_stat_archiver| SELECT archived_count,
     last_failed_time,
     stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
-    pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-    pg_stat_get_buf_written_backend() AS buffers_backend,
-    pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+    pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+    pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+    pg_stat_get_buf_written_backend() AS buffers_written_backend,
+    pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT oid AS datid,
     datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 1d84407a03..85aaebe7b6 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -782,8 +782,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT requested_checkpoints AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -793,7 +793,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT requested_checkpoints > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -884,6 +884,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index b4d6753c71..e867bc15e3 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -387,8 +387,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT requested_checkpoints AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -402,7 +402,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT requested_checkpoints > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -440,6 +440,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#25Andres Freund
andres@anarazel.de
In reply to: Bharath Rupireddy (#24)
Re: Introduce a new view for checkpointer related stats

Hi,

On 2023-02-09 12:21:51 +0530, Bharath Rupireddy wrote:

@@ -1105,18 +1105,22 @@ CREATE VIEW pg_stat_archiver AS

CREATE VIEW pg_stat_bgwriter AS
SELECT
- pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
- pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
- pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
- pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
- pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
- pg_stat_get_buf_written_backend() AS buffers_backend,
- pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
pg_stat_get_buf_alloc() AS buffers_alloc,
pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+        pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+        pg_stat_get_buf_written_backend() AS buffers_written_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+

I don't think the backend written stats belong more accurately in
pg_stat_checkpointer than pg_stat_bgwriter.

I continue to be worried about breaking just about any postgres monitoring
setup.

Greetings,

Andres Freund

#26Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Andres Freund (#25)
Re: Introduce a new view for checkpointer related stats

On Thu, Feb 9, 2023 at 12:33 PM Andres Freund <andres@anarazel.de> wrote:

Hi,

Thanks for looking at this.

On 2023-02-09 12:21:51 +0530, Bharath Rupireddy wrote:

@@ -1105,18 +1105,22 @@ CREATE VIEW pg_stat_archiver AS

CREATE VIEW pg_stat_bgwriter AS
SELECT
- pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
- pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
- pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
- pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
- pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
- pg_stat_get_buf_written_backend() AS buffers_backend,
- pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
pg_stat_get_buf_alloc() AS buffers_alloc,
pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+        pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+        pg_stat_get_buf_written_backend() AS buffers_written_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+

I don't think the backend written stats belong more accurately in
pg_stat_checkpointer than pg_stat_bgwriter.

We accumulate buffers_written_backend and buffers_fsync_backend of all
backends under checkpointer stats to show the aggregated results to
the users. I think this is correct because the checkpointer is the one
that processes fsync requests (of course, backends themselves can
fsync when needed, that's what the buffers_fsync_backend shows),
whereas bgwriter doesn't perform IIUC.

I continue to be worried about breaking just about any postgres monitoring
setup.

Hm. Yes, it requires minimal and straightforward changes in monitoring
scripts. Please note that we separated out bgwriter and checkpointer
in v9.2 12 years ago but we haven't had a chance to separate the stats
so far. We might do it at some point of time, IMHO this is that time.

We did away with promote_trigger_file (cd4329d) very recently. The
agreement was that the changes required to move on to other mechanisms
of promotion are minimal, hence we didn't want it to be first
deprecated and then removed.

From the discussion upthread, it looks like Robert, Amit, Bertrand,
Greg and myself are in favour of not having a deprecated version but
moving them to the new pg_stat_checkpointer view.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#27Andres Freund
andres@anarazel.de
In reply to: Bharath Rupireddy (#26)
Re: Introduce a new view for checkpointer related stats

Hi,

On 2023-02-09 19:00:00 +0530, Bharath Rupireddy wrote:

On Thu, Feb 9, 2023 at 12:33 PM Andres Freund <andres@anarazel.de> wrote:

On 2023-02-09 12:21:51 +0530, Bharath Rupireddy wrote:

@@ -1105,18 +1105,22 @@ CREATE VIEW pg_stat_archiver AS

CREATE VIEW pg_stat_bgwriter AS
SELECT
- pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
- pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
- pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
- pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
- pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
- pg_stat_get_buf_written_backend() AS buffers_backend,
- pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
pg_stat_get_buf_alloc() AS buffers_alloc,
pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+        pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+        pg_stat_get_buf_written_backend() AS buffers_written_backend,
+        pg_stat_get_buf_fsync_backend() AS buffers_fsync_backend,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+

I don't think the backend written stats belong more accurately in
pg_stat_checkpointer than pg_stat_bgwriter.

We accumulate buffers_written_backend and buffers_fsync_backend of all
backends under checkpointer stats to show the aggregated results to
the users. I think this is correct because the checkpointer is the one
that processes fsync requests (of course, backends themselves can
fsync when needed, that's what the buffers_fsync_backend shows),
whereas bgwriter doesn't perform IIUC.

That's true for buffers_fsync_backend, but not true for
buffers_backend/buffers_written_backend.

That isn't tied to checkpointer.

I think if we end up breaking compat, we should just drop that column. The
pg_stat_io patch from Melanie, which I hope to finish committing by tomorrow,
provides that in a more useful way, in a less confusing place.

I'm not sure it's worth having buffers_fsync_backend in pg_stat_checkpointer
in that case. You can get nearly the same information from pg_stat_io as well
(except fsyncs for SLRUs that couldn't be put into the queue, which you'd not
see right now - hard to believe that ever happens at a relelvant frequency).

I continue to be worried about breaking just about any postgres monitoring
setup.

Hm. Yes, it requires minimal and straightforward changes in monitoring
scripts. Please note that we separated out bgwriter and checkpointer
in v9.2 12 years ago but we haven't had a chance to separate the stats
so far. We might do it at some point of time, IMHO this is that time.

We did away with promote_trigger_file (cd4329d) very recently. The
agreement was that the changes required to move on to other mechanisms
of promotion are minimal, hence we didn't want it to be first
deprecated and then removed.

That's not really comparable, because we have had pg_ctl promote for a long
time. You can use it across all supported versions. pg_promote() is nearly
there as well. Whereas there's no way to use same query across all versions.

IME there also exist a lot more hand-rolled monitoring setups
than hand-rolled automatic promotion setups.

From the discussion upthread, it looks like Robert, Amit, Bertrand,
Greg and myself are in favour of not having a deprecated version but
moving them to the new pg_stat_checkpointer view.

Yep, and I think you are all wrong, and that this is just going to cause
unnecessary pain :). I'm not going to try to prevent the patch from going in
because of this, just to be clear.

Greetings,

Andres Freund

#28Michael Paquier
michael@paquier.xyz
In reply to: Andres Freund (#27)
Re: Introduce a new view for checkpointer related stats

On Thu, Feb 09, 2023 at 04:46:04PM -0800, Andres Freund wrote:

I think if we end up breaking compat, we should just drop that
column.

Indeed.

Yep, and I think you are all wrong, and that this is just going to cause
unnecessary pain :). I'm not going to try to prevent the patch from going in
because of this, just to be clear.

Catalog attributes have faced a lot of renames across the years, with
the same potential of breakages for monitoring tools. I am not saying
that all of them are justified, but we have usually done so because it
makes sense to reshape things in the way they are now, thinking
long-term. Splitting pg_stat_bgwriter into two views does not strike
me as something that bad, TBH, because it becomes clearer which stats
are attached to which process (bgwriter or checkpointer). (Note: I
have not checked in details the stats switching to the new view and
how pertinent each choice is.)
--
Michael

#29Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Andres Freund (#27)
3 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Fri, Feb 10, 2023 at 6:16 AM Andres Freund <andres@anarazel.de> wrote:

That's true for buffers_fsync_backend, but not true for
buffers_backend/buffers_written_backend.

That isn't tied to checkpointer.

I think if we end up breaking compat, we should just drop that column. The
pg_stat_io patch from Melanie, which I hope to finish committing by tomorrow,
provides that in a more useful way, in a less confusing place.

On Fri, Feb 10, 2023 at 11:29 AM Michael Paquier <michael@paquier.xyz> wrote:

On Thu, Feb 09, 2023 at 04:46:04PM -0800, Andres Freund wrote:

I think if we end up breaking compat, we should just drop that
column.

Indeed.

Yeah, pg_stat_io is a better place to track the backend IO stats. I
removed buffers_backend, please see the attached 0001 patch.

On Fri, Feb 10, 2023 at 6:16 AM Andres Freund <andres@anarazel.de> wrote:

I'm not sure it's worth having buffers_fsync_backend in pg_stat_checkpointer
in that case. You can get nearly the same information from pg_stat_io as well
(except fsyncs for SLRUs that couldn't be put into the queue, which you'd not
see right now - hard to believe that ever happens at a relelvant frequency).

I think it'd be better to move the SLRU fsync stats during checkpoints
to the pg_stat_slru view, then it can be a one-stop view to track all
SLRU IO stats. This lets us remove buffers_fsync_backend too, please
see the attached 0002 patch. However, one metric we might miss is the
number of times checkpointer missed to absorb the fsync requests. If
needed, this metric can be added to the new pg_stat_checkpointer view.

Yep, and I think you are all wrong, and that this is just going to cause
unnecessary pain :). I'm not going to try to prevent the patch from going in
because of this, just to be clear.

Catalog attributes have faced a lot of renames across the years, with
the same potential of breakages for monitoring tools. I am not saying
that all of them are justified, but we have usually done so because it
makes sense to reshape things in the way they are now, thinking
long-term. Splitting pg_stat_bgwriter into two views does not strike
me as something that bad, TBH, because it becomes clearer which stats
are attached to which process (bgwriter or checkpointer). (Note: I
have not checked in details the stats switching to the new view and
how pertinent each choice is.)

Thanks. FWIW, I've attached the patch introducing pg_stat_checkpointer
as 0003 here.

Please review the attached v7 patch set.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v7-0001-Drop-buffers_backend-column-from-pg_stat_bgwriter.patchapplication/x-patch; name=v7-0001-Drop-buffers_backend-column-from-pg_stat_bgwriter.patchDownload
From edb5ee994b179034273edd42c139aa57c9106922 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Fri, 10 Feb 2023 11:45:14 +0000
Subject: [PATCH v7] Drop buffers_backend column from pg_stat_bgwriter view

---
 doc/src/sgml/monitoring.sgml                  |  9 ---------
 src/backend/catalog/system_views.sql          |  1 -
 src/backend/postmaster/checkpointer.c         | 20 +++++--------------
 .../utils/activity/pgstat_checkpointer.c      |  2 --
 src/backend/utils/adt/pgstatfuncs.c           |  6 ------
 src/include/catalog/pg_proc.dat               |  4 ----
 src/include/pgstat.h                          |  1 -
 src/test/regress/expected/rules.out           |  1 -
 8 files changed, 5 insertions(+), 39 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index b246ddc634..380085eedd 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -3766,15 +3766,6 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       </para></entry>
      </row>
 
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend</structfield> <type>bigint</type>
-      </para>
-      <para>
-       Number of buffers written directly by a backend
-      </para></entry>
-     </row>
-
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 8608e3fa5b..2b1b2bf7c3 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1112,7 +1112,6 @@ CREATE VIEW pg_stat_bgwriter AS
         pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_written_backend() AS buffers_backend,
         pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index aaad5c5228..baadd08044 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -91,17 +91,15 @@
  * requesting backends since the last checkpoint start.  The flags are
  * chosen so that OR'ing is the correct way to combine multiple requests.
  *
- * num_backend_writes is used to count the number of buffer writes performed
- * by user backend processes.  This counter should be wide enough that it
- * can't overflow during a single processing cycle.  num_backend_fsync
- * counts the subset of those writes that also had to do their own fsync,
- * because the checkpointer failed to absorb their request.
+ * num_backend_fsync counts the subset of buffer writes performed by user
+ * backend processes that also had to do their own fsync, because the
+ * checkpointer failed to absorb their request.
  *
  * The requests array holds fsync requests sent by backends and not yet
  * absorbed by the checkpointer.
  *
- * Unlike the checkpoint fields, num_backend_writes, num_backend_fsync, and
- * the requests fields are protected by CheckpointerCommLock.
+ * Unlike the checkpoint fields, num_backend_fsync and the requests fields are
+ * protected by CheckpointerCommLock.
  *----------
  */
 typedef struct
@@ -125,7 +123,6 @@ typedef struct
 	ConditionVariable start_cv; /* signaled when ckpt_started advances */
 	ConditionVariable done_cv;	/* signaled when ckpt_done advances */
 
-	uint32		num_backend_writes; /* counts user backend buffer writes */
 	uint32		num_backend_fsync;	/* counts user backend fsync calls */
 
 	int			num_requests;	/* current # of requests */
@@ -1096,10 +1093,6 @@ ForwardSyncRequest(const FileTag *ftag, SyncRequestType type)
 
 	LWLockAcquire(CheckpointerCommLock, LW_EXCLUSIVE);
 
-	/* Count all backend writes regardless of if they fit in the queue */
-	if (!AmBackgroundWriterProcess())
-		CheckpointerShmem->num_backend_writes++;
-
 	/*
 	 * If the checkpointer isn't running or the request queue is full, the
 	 * backend will have to perform its own fsync request.  But before forcing
@@ -1272,12 +1265,9 @@ AbsorbSyncRequests(void)
 	LWLockAcquire(CheckpointerCommLock, LW_EXCLUSIVE);
 
 	/* Transfer stats counts into pending pgstats message */
-	PendingCheckpointerStats.buf_written_backend
-		+= CheckpointerShmem->num_backend_writes;
 	PendingCheckpointerStats.buf_fsync_backend
 		+= CheckpointerShmem->num_backend_fsync;
 
-	CheckpointerShmem->num_backend_writes = 0;
 	CheckpointerShmem->num_backend_fsync = 0;
 
 	/*
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index 26dec112f6..a048205d6e 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -52,7 +52,6 @@ pgstat_report_checkpointer(void)
 	CHECKPOINTER_ACC(checkpoint_write_time);
 	CHECKPOINTER_ACC(checkpoint_sync_time);
 	CHECKPOINTER_ACC(buf_written_checkpoints);
-	CHECKPOINTER_ACC(buf_written_backend);
 	CHECKPOINTER_ACC(buf_fsync_backend);
 #undef CHECKPOINTER_ACC
 
@@ -120,7 +119,6 @@ pgstat_checkpointer_snapshot_cb(void)
 	CHECKPOINTER_COMP(checkpoint_write_time);
 	CHECKPOINTER_COMP(checkpoint_sync_time);
 	CHECKPOINTER_COMP(buf_written_checkpoints);
-	CHECKPOINTER_COMP(buf_written_backend);
 	CHECKPOINTER_COMP(buf_fsync_backend);
 #undef CHECKPOINTER_COMP
 }
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 924698e6ae..ce16884f1b 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1227,12 +1227,6 @@ pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_bgwriter()->stat_reset_timestamp);
 }
 
-Datum
-pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_backend);
-}
-
 Datum
 pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
 {
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index c0f2a8a77c..3188d9ee1f 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5704,10 +5704,6 @@
   proname => 'pg_stat_get_checkpoint_sync_time', provolatile => 's',
   proparallel => 'r', prorettype => 'float8', proargtypes => '',
   prosrc => 'pg_stat_get_checkpoint_sync_time' },
-{ oid => '2775', descr => 'statistics: number of buffers written by backends',
-  proname => 'pg_stat_get_buf_written_backend', provolatile => 's',
-  proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_buf_written_backend' },
 { oid => '3063',
   descr => 'statistics: number of backend buffer writes that did their own fsync',
   proname => 'pg_stat_get_buf_fsync_backend', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index db9675884f..d1675909db 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -273,7 +273,6 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter checkpoint_write_time;	/* times in milliseconds */
 	PgStat_Counter checkpoint_sync_time;
 	PgStat_Counter buf_written_checkpoints;
-	PgStat_Counter buf_written_backend;
 	PgStat_Counter buf_fsync_backend;
 } PgStat_CheckpointerStats;
 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index e7a2f5856a..c98f9cd747 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1821,7 +1821,6 @@ pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints
     pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
     pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-    pg_stat_get_buf_written_backend() AS buffers_backend,
     pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
-- 
2.34.1

v7-0002-Drop-buffers_backend_fsync-column-from-pg_stat_bg.patchapplication/x-patch; name=v7-0002-Drop-buffers_backend_fsync-column-from-pg_stat_bg.patchDownload
From 8f2ca94acc8773d6c6ff6a4b2a00a4767ec63911 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Fri, 10 Feb 2023 11:51:20 +0000
Subject: [PATCH v7] Drop buffers_backend_fsync column from pg_stat_bgwriter
 view

---
 doc/src/sgml/monitoring.sgml                  | 11 ----------
 src/backend/access/transam/slru.c             |  4 ++++
 src/backend/catalog/system_views.sql          |  1 -
 src/backend/postmaster/checkpointer.c         | 22 ++-----------------
 .../utils/activity/pgstat_checkpointer.c      |  2 --
 src/backend/utils/adt/pgstatfuncs.c           |  6 -----
 src/include/catalog/pg_proc.dat               |  5 -----
 src/include/pgstat.h                          |  1 -
 src/test/regress/expected/rules.out           |  1 -
 9 files changed, 6 insertions(+), 47 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 380085eedd..5fe39b305d 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -3766,17 +3766,6 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       </para></entry>
      </row>
 
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
-      </para>
-      <para>
-       Number of times a backend had to execute its own
-       <function>fsync</function> call (normally the background writer handles those
-       even when the backend does its own write)
-      </para></entry>
-     </row>
-
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>buffers_alloc</structfield> <type>bigint</type>
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5ab86238a9..4ae2040f39 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -1593,10 +1593,14 @@ SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
 int
 SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
 {
+	SlruShared	shared = ctl->shared;
 	int			fd;
 	int			save_errno;
 	int			result;
 
+	/* update the stats counter of flushes */
+	pgstat_count_slru_flush(shared->slru_stats_idx);
+
 	SlruFileName(ctl, path, ftag->segno);
 
 	fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2b1b2bf7c3..7ef3d2ebd4 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1112,7 +1112,6 @@ CREATE VIEW pg_stat_bgwriter AS
         pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index baadd08044..12c92f3de9 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -91,15 +91,11 @@
  * requesting backends since the last checkpoint start.  The flags are
  * chosen so that OR'ing is the correct way to combine multiple requests.
  *
- * num_backend_fsync counts the subset of buffer writes performed by user
- * backend processes that also had to do their own fsync, because the
- * checkpointer failed to absorb their request.
- *
  * The requests array holds fsync requests sent by backends and not yet
  * absorbed by the checkpointer.
  *
- * Unlike the checkpoint fields, num_backend_fsync and the requests fields are
- * protected by CheckpointerCommLock.
+ * Unlike the checkpoint fields, reqquests related fields are protected by
+ * CheckpointerCommLock.
  *----------
  */
 typedef struct
@@ -123,8 +119,6 @@ typedef struct
 	ConditionVariable start_cv; /* signaled when ckpt_started advances */
 	ConditionVariable done_cv;	/* signaled when ckpt_done advances */
 
-	uint32		num_backend_fsync;	/* counts user backend fsync calls */
-
 	int			num_requests;	/* current # of requests */
 	int			max_requests;	/* allocated array size */
 	CheckpointerRequest requests[FLEXIBLE_ARRAY_MEMBER];
@@ -1102,12 +1096,6 @@ ForwardSyncRequest(const FileTag *ftag, SyncRequestType type)
 		(CheckpointerShmem->num_requests >= CheckpointerShmem->max_requests &&
 		 !CompactCheckpointerRequestQueue()))
 	{
-		/*
-		 * Count the subset of writes where backends have to do their own
-		 * fsync
-		 */
-		if (!AmBackgroundWriterProcess())
-			CheckpointerShmem->num_backend_fsync++;
 		LWLockRelease(CheckpointerCommLock);
 		return false;
 	}
@@ -1264,12 +1252,6 @@ AbsorbSyncRequests(void)
 
 	LWLockAcquire(CheckpointerCommLock, LW_EXCLUSIVE);
 
-	/* Transfer stats counts into pending pgstats message */
-	PendingCheckpointerStats.buf_fsync_backend
-		+= CheckpointerShmem->num_backend_fsync;
-
-	CheckpointerShmem->num_backend_fsync = 0;
-
 	/*
 	 * We try to avoid holding the lock for a long time by copying the request
 	 * array, and processing the requests after releasing the lock.
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index a048205d6e..03ed5dddda 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -52,7 +52,6 @@ pgstat_report_checkpointer(void)
 	CHECKPOINTER_ACC(checkpoint_write_time);
 	CHECKPOINTER_ACC(checkpoint_sync_time);
 	CHECKPOINTER_ACC(buf_written_checkpoints);
-	CHECKPOINTER_ACC(buf_fsync_backend);
 #undef CHECKPOINTER_ACC
 
 	pgstat_end_changecount_write(&stats_shmem->changecount);
@@ -119,6 +118,5 @@ pgstat_checkpointer_snapshot_cb(void)
 	CHECKPOINTER_COMP(checkpoint_write_time);
 	CHECKPOINTER_COMP(checkpoint_sync_time);
 	CHECKPOINTER_COMP(buf_written_checkpoints);
-	CHECKPOINTER_COMP(buf_fsync_backend);
 #undef CHECKPOINTER_COMP
 }
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index ce16884f1b..7f4c39f052 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1227,12 +1227,6 @@ pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_bgwriter()->stat_reset_timestamp);
 }
 
-Datum
-pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_fsync_backend);
-}
-
 Datum
 pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
 {
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 3188d9ee1f..84bacd0329 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5704,11 +5704,6 @@
   proname => 'pg_stat_get_checkpoint_sync_time', provolatile => 's',
   proparallel => 'r', prorettype => 'float8', proargtypes => '',
   prosrc => 'pg_stat_get_checkpoint_sync_time' },
-{ oid => '3063',
-  descr => 'statistics: number of backend buffer writes that did their own fsync',
-  proname => 'pg_stat_get_buf_fsync_backend', provolatile => 's',
-  proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_buf_fsync_backend' },
 { oid => '2859', descr => 'statistics: number of buffer allocations',
   proname => 'pg_stat_get_buf_alloc', provolatile => 's', proparallel => 'r',
   prorettype => 'int8', proargtypes => '', prosrc => 'pg_stat_get_buf_alloc' },
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index d1675909db..28fb6292d9 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -273,7 +273,6 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter checkpoint_write_time;	/* times in milliseconds */
 	PgStat_Counter checkpoint_sync_time;
 	PgStat_Counter buf_written_checkpoints;
-	PgStat_Counter buf_fsync_backend;
 } PgStat_CheckpointerStats;
 
 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index c98f9cd747..d32f47cdb0 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1821,7 +1821,6 @@ pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints
     pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
     pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-    pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT oid AS datid,
-- 
2.34.1

v7-0003-Introduce-a-new-view-for-checkpointer-related-sta.patchapplication/x-patch; name=v7-0003-Introduce-a-new-view-for-checkpointer-related-sta.patchDownload
From c7dd583d288add34a7fdb412675d2b6258480f1e Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Fri, 10 Feb 2023 16:04:27 +0000
Subject: [PATCH v7] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as well.
It is that way because historically checkpointer was part of
bgwriter until the commits 806a2ae and bf405ba, that went into
PG 9.2, separated them out.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

Bump catalog version.
---
 doc/src/sgml/monitoring.sgml                  | 98 ++++++++++++++-----
 src/backend/catalog/system_views.sql          | 14 ++-
 .../utils/activity/pgstat_checkpointer.c      |  1 +
 src/backend/utils/adt/pgstatfuncs.c           | 19 ++--
 src/include/catalog/pg_proc.dat               | 22 +++--
 src/include/pgstat.h                          |  1 +
 src/test/recovery/t/029_stats_restart.pl      |  6 +-
 src/test/regress/expected/rules.out           | 13 +--
 src/test/regress/expected/stats.out           | 21 +++-
 src/test/regress/sql/stats.sql                | 12 ++-
 10 files changed, 146 insertions(+), 61 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 5fe39b305d..13f9ded5f3 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -451,6 +451,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_database</structname><indexterm><primary>pg_stat_database</primary></indexterm></entry>
       <entry>One row per database, showing database-wide statistics. See
@@ -3681,7 +3690,7 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
 
   <para>
    The <structname>pg_stat_bgwriter</structname> view will always have a
-   single row, containing global data for the cluster.
+   single row, containing data about the bgwriter of the cluster.
   </para>
 
   <table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
@@ -3701,77 +3710,118 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
     <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+       <structfield>buffers_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of buffers written by the background writer
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_req</structfield> <type>bigint</type>
+       <structfield>maxwritten_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of times the background writer stopped a cleaning
+       scan because it had written too many buffers
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+       <structfield>buffers_alloc</structfield> <type>bigint</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       Number of buffers allocated
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       Time at which these statistics were last reset
       </para></entry>
      </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
 
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
+
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
+
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing data about the checkpointer process of the cluster.
+  </para>
+
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+       Column Type
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Description
       </para></entry>
      </row>
+    </thead>
 
+    <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_clean</structfield> <type>bigint</type>
+       <structfield>timed_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written by the background writer
+       Number of scheduled checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>maxwritten_clean</structfield> <type>bigint</type>
+       <structfield>requested_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times the background writer stopped a cleaning
-       scan because it had written too many buffers
+       Number of requested checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_alloc</structfield> <type>bigint</type>
+       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of buffers allocated
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_written_checkpoints</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written during checkpoints
       </para></entry>
      </row>
 
@@ -5421,8 +5471,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>io</literal> to reset all the counters shown in the
         <structname>pg_stat_io</structname> view,
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 7ef3d2ebd4..8fc8c0908f 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1105,16 +1105,20 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+        pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_wal AS
     SELECT
         w.wal_records,
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index 03ed5dddda..aa0b7d2c06 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -92,6 +92,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 7f4c39f052..1a2390977e 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1176,19 +1176,19 @@ PG_STAT_GET_DBENTRY_FLOAT8(idle_in_transaction_time)
 PG_STAT_GET_DBENTRY_FLOAT8(session_time)
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_requested_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_buf_written_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
 }
@@ -1221,6 +1221,12 @@ pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
 					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
 }
 
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
+}
+
 Datum
 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 {
@@ -1589,14 +1595,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "io") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_IO);
 	else if (strcmp(target, "recovery_prefetch") == 0)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 84bacd0329..e5e716f349 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5666,20 +5666,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_timed_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_timed_checkpoints' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_requested_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_requested_checkpoints' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_buf_written_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_buf_written_checkpoints' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 28fb6292d9..b08928cefc 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -273,6 +273,7 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter checkpoint_write_time;	/* times in milliseconds */
 	PgStat_Counter checkpoint_sync_time;
 	PgStat_Counter buf_written_checkpoints;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 83d6647d32..463f29101e 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset     = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT timed_checkpoints + requested_checkpoints FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index d32f47cdb0..7eae7f4184 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1814,15 +1814,16 @@ pg_stat_archiver| SELECT archived_count,
     last_failed_time,
     stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
-    pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+    pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+    pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT oid AS datid,
     datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 1d84407a03..85aaebe7b6 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -782,8 +782,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT requested_checkpoints AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -793,7 +793,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT requested_checkpoints > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -884,6 +884,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index b4d6753c71..e867bc15e3 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -387,8 +387,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT requested_checkpoints AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -402,7 +402,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT requested_checkpoints > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -440,6 +440,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#30Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#29)
3 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Fri, Feb 10, 2023 at 10:00 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Thanks. FWIW, I've attached the patch introducing pg_stat_checkpointer
as 0003 here.

Please review the attached v7 patch set.

Needed a rebase. Please review the attached v8 patch set.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v8-0001-Drop-buffers_backend-column-from-pg_stat_bgwriter.patchapplication/x-patch; name=v8-0001-Drop-buffers_backend-column-from-pg_stat_bgwriter.patchDownload
From c7d1a10b113c90e3712e5f836c21b5a40f909a24 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Mon, 13 Feb 2023 05:01:52 +0000
Subject: [PATCH v8] Drop buffers_backend column from pg_stat_bgwriter view

---
 doc/src/sgml/monitoring.sgml                  |  9 ---------
 src/backend/catalog/system_views.sql          |  1 -
 src/backend/postmaster/checkpointer.c         | 20 +++++--------------
 .../utils/activity/pgstat_checkpointer.c      |  2 --
 src/backend/utils/adt/pgstatfuncs.c           |  6 ------
 src/include/catalog/pg_proc.dat               |  4 ----
 src/include/pgstat.h                          |  1 -
 src/test/regress/expected/rules.out           |  1 -
 8 files changed, 5 insertions(+), 39 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index dca50707ad..c0cae0f4f3 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -4059,15 +4059,6 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       </para></entry>
      </row>
 
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend</structfield> <type>bigint</type>
-      </para>
-      <para>
-       Number of buffers written directly by a backend
-      </para></entry>
-     </row>
-
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 34ca0e739f..9bb96e27aa 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1112,7 +1112,6 @@ CREATE VIEW pg_stat_bgwriter AS
         pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_written_backend() AS buffers_backend,
         pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index aaad5c5228..baadd08044 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -91,17 +91,15 @@
  * requesting backends since the last checkpoint start.  The flags are
  * chosen so that OR'ing is the correct way to combine multiple requests.
  *
- * num_backend_writes is used to count the number of buffer writes performed
- * by user backend processes.  This counter should be wide enough that it
- * can't overflow during a single processing cycle.  num_backend_fsync
- * counts the subset of those writes that also had to do their own fsync,
- * because the checkpointer failed to absorb their request.
+ * num_backend_fsync counts the subset of buffer writes performed by user
+ * backend processes that also had to do their own fsync, because the
+ * checkpointer failed to absorb their request.
  *
  * The requests array holds fsync requests sent by backends and not yet
  * absorbed by the checkpointer.
  *
- * Unlike the checkpoint fields, num_backend_writes, num_backend_fsync, and
- * the requests fields are protected by CheckpointerCommLock.
+ * Unlike the checkpoint fields, num_backend_fsync and the requests fields are
+ * protected by CheckpointerCommLock.
  *----------
  */
 typedef struct
@@ -125,7 +123,6 @@ typedef struct
 	ConditionVariable start_cv; /* signaled when ckpt_started advances */
 	ConditionVariable done_cv;	/* signaled when ckpt_done advances */
 
-	uint32		num_backend_writes; /* counts user backend buffer writes */
 	uint32		num_backend_fsync;	/* counts user backend fsync calls */
 
 	int			num_requests;	/* current # of requests */
@@ -1096,10 +1093,6 @@ ForwardSyncRequest(const FileTag *ftag, SyncRequestType type)
 
 	LWLockAcquire(CheckpointerCommLock, LW_EXCLUSIVE);
 
-	/* Count all backend writes regardless of if they fit in the queue */
-	if (!AmBackgroundWriterProcess())
-		CheckpointerShmem->num_backend_writes++;
-
 	/*
 	 * If the checkpointer isn't running or the request queue is full, the
 	 * backend will have to perform its own fsync request.  But before forcing
@@ -1272,12 +1265,9 @@ AbsorbSyncRequests(void)
 	LWLockAcquire(CheckpointerCommLock, LW_EXCLUSIVE);
 
 	/* Transfer stats counts into pending pgstats message */
-	PendingCheckpointerStats.buf_written_backend
-		+= CheckpointerShmem->num_backend_writes;
 	PendingCheckpointerStats.buf_fsync_backend
 		+= CheckpointerShmem->num_backend_fsync;
 
-	CheckpointerShmem->num_backend_writes = 0;
 	CheckpointerShmem->num_backend_fsync = 0;
 
 	/*
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index 26dec112f6..a048205d6e 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -52,7 +52,6 @@ pgstat_report_checkpointer(void)
 	CHECKPOINTER_ACC(checkpoint_write_time);
 	CHECKPOINTER_ACC(checkpoint_sync_time);
 	CHECKPOINTER_ACC(buf_written_checkpoints);
-	CHECKPOINTER_ACC(buf_written_backend);
 	CHECKPOINTER_ACC(buf_fsync_backend);
 #undef CHECKPOINTER_ACC
 
@@ -120,7 +119,6 @@ pgstat_checkpointer_snapshot_cb(void)
 	CHECKPOINTER_COMP(checkpoint_write_time);
 	CHECKPOINTER_COMP(checkpoint_sync_time);
 	CHECKPOINTER_COMP(buf_written_checkpoints);
-	CHECKPOINTER_COMP(buf_written_backend);
 	CHECKPOINTER_COMP(buf_fsync_backend);
 #undef CHECKPOINTER_COMP
 }
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 9d707c3521..28075fa6fb 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1227,12 +1227,6 @@ pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_bgwriter()->stat_reset_timestamp);
 }
 
-Datum
-pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_backend);
-}
-
 Datum
 pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
 {
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 66b73c3900..e800fdfd5f 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5704,10 +5704,6 @@
   proname => 'pg_stat_get_checkpoint_sync_time', provolatile => 's',
   proparallel => 'r', prorettype => 'float8', proargtypes => '',
   prosrc => 'pg_stat_get_checkpoint_sync_time' },
-{ oid => '2775', descr => 'statistics: number of buffers written by backends',
-  proname => 'pg_stat_get_buf_written_backend', provolatile => 's',
-  proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_buf_written_backend' },
 { oid => '3063',
   descr => 'statistics: number of backend buffer writes that did their own fsync',
   proname => 'pg_stat_get_buf_fsync_backend', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index db9675884f..d1675909db 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -273,7 +273,6 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter checkpoint_write_time;	/* times in milliseconds */
 	PgStat_Counter checkpoint_sync_time;
 	PgStat_Counter buf_written_checkpoints;
-	PgStat_Counter buf_written_backend;
 	PgStat_Counter buf_fsync_backend;
 } PgStat_CheckpointerStats;
 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 174b725fff..5b4f441245 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1821,7 +1821,6 @@ pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints
     pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
     pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-    pg_stat_get_buf_written_backend() AS buffers_backend,
     pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
-- 
2.34.1

v8-0002-Drop-buffers_backend_fsync-column-from-pg_stat_bg.patchapplication/x-patch; name=v8-0002-Drop-buffers_backend_fsync-column-from-pg_stat_bg.patchDownload
From 09afb4d2da776b863aee9d87f475eb8cd852d44c Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Mon, 13 Feb 2023 05:02:17 +0000
Subject: [PATCH v8] Drop buffers_backend_fsync column from pg_stat_bgwriter
 view

---
 doc/src/sgml/monitoring.sgml                  | 11 ----------
 src/backend/access/transam/slru.c             |  4 ++++
 src/backend/catalog/system_views.sql          |  1 -
 src/backend/postmaster/checkpointer.c         | 22 ++-----------------
 .../utils/activity/pgstat_checkpointer.c      |  2 --
 src/backend/utils/adt/pgstatfuncs.c           |  6 -----
 src/include/catalog/pg_proc.dat               |  5 -----
 src/include/pgstat.h                          |  1 -
 src/test/regress/expected/rules.out           |  1 -
 9 files changed, 6 insertions(+), 47 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index c0cae0f4f3..098ca5999d 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -4059,17 +4059,6 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
       </para></entry>
      </row>
 
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
-      </para>
-      <para>
-       Number of times a backend had to execute its own
-       <function>fsync</function> call (normally the background writer handles those
-       even when the backend does its own write)
-      </para></entry>
-     </row>
-
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>buffers_alloc</structfield> <type>bigint</type>
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5ab86238a9..4ae2040f39 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -1593,10 +1593,14 @@ SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
 int
 SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
 {
+	SlruShared	shared = ctl->shared;
 	int			fd;
 	int			save_errno;
 	int			result;
 
+	/* update the stats counter of flushes */
+	pgstat_count_slru_flush(shared->slru_stats_idx);
+
 	SlruFileName(ctl, path, ftag->segno);
 
 	fd = OpenTransientFile(path, O_RDWR | PG_BINARY);
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 9bb96e27aa..2b8e462532 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1112,7 +1112,6 @@ CREATE VIEW pg_stat_bgwriter AS
         pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index baadd08044..12c92f3de9 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -91,15 +91,11 @@
  * requesting backends since the last checkpoint start.  The flags are
  * chosen so that OR'ing is the correct way to combine multiple requests.
  *
- * num_backend_fsync counts the subset of buffer writes performed by user
- * backend processes that also had to do their own fsync, because the
- * checkpointer failed to absorb their request.
- *
  * The requests array holds fsync requests sent by backends and not yet
  * absorbed by the checkpointer.
  *
- * Unlike the checkpoint fields, num_backend_fsync and the requests fields are
- * protected by CheckpointerCommLock.
+ * Unlike the checkpoint fields, reqquests related fields are protected by
+ * CheckpointerCommLock.
  *----------
  */
 typedef struct
@@ -123,8 +119,6 @@ typedef struct
 	ConditionVariable start_cv; /* signaled when ckpt_started advances */
 	ConditionVariable done_cv;	/* signaled when ckpt_done advances */
 
-	uint32		num_backend_fsync;	/* counts user backend fsync calls */
-
 	int			num_requests;	/* current # of requests */
 	int			max_requests;	/* allocated array size */
 	CheckpointerRequest requests[FLEXIBLE_ARRAY_MEMBER];
@@ -1102,12 +1096,6 @@ ForwardSyncRequest(const FileTag *ftag, SyncRequestType type)
 		(CheckpointerShmem->num_requests >= CheckpointerShmem->max_requests &&
 		 !CompactCheckpointerRequestQueue()))
 	{
-		/*
-		 * Count the subset of writes where backends have to do their own
-		 * fsync
-		 */
-		if (!AmBackgroundWriterProcess())
-			CheckpointerShmem->num_backend_fsync++;
 		LWLockRelease(CheckpointerCommLock);
 		return false;
 	}
@@ -1264,12 +1252,6 @@ AbsorbSyncRequests(void)
 
 	LWLockAcquire(CheckpointerCommLock, LW_EXCLUSIVE);
 
-	/* Transfer stats counts into pending pgstats message */
-	PendingCheckpointerStats.buf_fsync_backend
-		+= CheckpointerShmem->num_backend_fsync;
-
-	CheckpointerShmem->num_backend_fsync = 0;
-
 	/*
 	 * We try to avoid holding the lock for a long time by copying the request
 	 * array, and processing the requests after releasing the lock.
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index a048205d6e..03ed5dddda 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -52,7 +52,6 @@ pgstat_report_checkpointer(void)
 	CHECKPOINTER_ACC(checkpoint_write_time);
 	CHECKPOINTER_ACC(checkpoint_sync_time);
 	CHECKPOINTER_ACC(buf_written_checkpoints);
-	CHECKPOINTER_ACC(buf_fsync_backend);
 #undef CHECKPOINTER_ACC
 
 	pgstat_end_changecount_write(&stats_shmem->changecount);
@@ -119,6 +118,5 @@ pgstat_checkpointer_snapshot_cb(void)
 	CHECKPOINTER_COMP(checkpoint_write_time);
 	CHECKPOINTER_COMP(checkpoint_sync_time);
 	CHECKPOINTER_COMP(buf_written_checkpoints);
-	CHECKPOINTER_COMP(buf_fsync_backend);
 #undef CHECKPOINTER_COMP
 }
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 28075fa6fb..087ba87a86 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1227,12 +1227,6 @@ pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_bgwriter()->stat_reset_timestamp);
 }
 
-Datum
-pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_fsync_backend);
-}
-
 Datum
 pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
 {
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index e800fdfd5f..5ed66af0e3 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5704,11 +5704,6 @@
   proname => 'pg_stat_get_checkpoint_sync_time', provolatile => 's',
   proparallel => 'r', prorettype => 'float8', proargtypes => '',
   prosrc => 'pg_stat_get_checkpoint_sync_time' },
-{ oid => '3063',
-  descr => 'statistics: number of backend buffer writes that did their own fsync',
-  proname => 'pg_stat_get_buf_fsync_backend', provolatile => 's',
-  proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_buf_fsync_backend' },
 { oid => '2859', descr => 'statistics: number of buffer allocations',
   proname => 'pg_stat_get_buf_alloc', provolatile => 's', proparallel => 'r',
   prorettype => 'int8', proargtypes => '', prosrc => 'pg_stat_get_buf_alloc' },
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index d1675909db..28fb6292d9 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -273,7 +273,6 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter checkpoint_write_time;	/* times in milliseconds */
 	PgStat_Counter checkpoint_sync_time;
 	PgStat_Counter buf_written_checkpoints;
-	PgStat_Counter buf_fsync_backend;
 } PgStat_CheckpointerStats;
 
 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 5b4f441245..9c9adb6140 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1821,7 +1821,6 @@ pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints
     pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
     pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-    pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT oid AS datid,
-- 
2.34.1

v8-0003-Introduce-a-new-view-for-checkpointer-related-sta.patchapplication/x-patch; name=v8-0003-Introduce-a-new-view-for-checkpointer-related-sta.patchDownload
From 5b349d6b3a3b8db1498e038aed81909fd1f15fe4 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Mon, 13 Feb 2023 05:05:07 +0000
Subject: [PATCH v8] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as well.
It is that way because historically checkpointer was part of
bgwriter until the commits 806a2ae and bf405ba, that went into
PG 9.2, separated them out.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

Bump catalog version.
---
 doc/src/sgml/monitoring.sgml                  | 98 ++++++++++++++-----
 src/backend/catalog/system_views.sql          | 14 ++-
 .../utils/activity/pgstat_checkpointer.c      |  1 +
 src/backend/utils/adt/pgstatfuncs.c           | 19 ++--
 src/include/catalog/pg_proc.dat               | 22 +++--
 src/include/pgstat.h                          |  1 +
 src/test/recovery/t/029_stats_restart.pl      |  6 +-
 src/test/regress/expected/rules.out           | 13 +--
 src/test/regress/expected/stats.out           | 21 +++-
 src/test/regress/sql/stats.sql                | 12 ++-
 10 files changed, 146 insertions(+), 61 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 098ca5999d..47bf6ff247 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -451,6 +451,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_database</structname><indexterm><primary>pg_stat_database</primary></indexterm></entry>
       <entry>One row per database, showing database-wide statistics. See
@@ -3974,7 +3983,7 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
 
   <para>
    The <structname>pg_stat_bgwriter</structname> view will always have a
-   single row, containing global data for the cluster.
+   single row, containing data about the bgwriter of the cluster.
   </para>
 
   <table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
@@ -3994,77 +4003,118 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
     <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+       <structfield>buffers_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of buffers written by the background writer
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_req</structfield> <type>bigint</type>
+       <structfield>maxwritten_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of times the background writer stopped a cleaning
+       scan because it had written too many buffers
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+       <structfield>buffers_alloc</structfield> <type>bigint</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       Number of buffers allocated
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       Time at which these statistics were last reset
       </para></entry>
      </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
 
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
+
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
+
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing data about the checkpointer process of the cluster.
+  </para>
+
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+       Column Type
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Description
       </para></entry>
      </row>
+    </thead>
 
+    <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_clean</structfield> <type>bigint</type>
+       <structfield>timed_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written by the background writer
+       Number of scheduled checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>maxwritten_clean</structfield> <type>bigint</type>
+       <structfield>requested_checkpoints</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times the background writer stopped a cleaning
-       scan because it had written too many buffers
+       Number of requested checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_alloc</structfield> <type>bigint</type>
+       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of buffers allocated
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_written_checkpoints</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written during checkpoints
       </para></entry>
      </row>
 
@@ -5714,8 +5764,10 @@ SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event i
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>io</literal> to reset all the counters shown in the
         <structname>pg_stat_io</structname> view,
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 2b8e462532..ad2992fd25 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1105,16 +1105,20 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+        pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+        pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_io AS
 SELECT
        b.backend_type,
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index 03ed5dddda..aa0b7d2c06 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -92,6 +92,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 087ba87a86..f2395fc13c 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1176,19 +1176,19 @@ PG_STAT_GET_DBENTRY_FLOAT8(idle_in_transaction_time)
 PG_STAT_GET_DBENTRY_FLOAT8(session_time)
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_timed_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_requested_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_buf_written_checkpoints(PG_FUNCTION_ARGS)
 {
 	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
 }
@@ -1221,6 +1221,12 @@ pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
 					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
 }
 
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
+}
+
 Datum
 pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 {
@@ -1730,14 +1736,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "io") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_IO);
 	else if (strcmp(target, "recovery_prefetch") == 0)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 5ed66af0e3..7030597d67 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5666,20 +5666,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_timed_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_timed_checkpoints' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_requested_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_requested_checkpoints' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_buf_written_checkpoints', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_buf_written_checkpoints' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 28fb6292d9..b08928cefc 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -273,6 +273,7 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter checkpoint_write_time;	/* times in milliseconds */
 	PgStat_Counter checkpoint_sync_time;
 	PgStat_Counter buf_written_checkpoints;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 83d6647d32..463f29101e 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset     = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT timed_checkpoints + requested_checkpoints FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 9c9adb6140..f18c047a42 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1814,15 +1814,16 @@ pg_stat_archiver| SELECT archived_count,
     last_failed_time,
     stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
-    pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_timed_checkpoints() AS timed_checkpoints,
+    pg_stat_get_requested_checkpoints() AS requested_checkpoints,
+    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
+    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
+    pg_stat_get_buf_written_checkpoints() AS buffers_written_checkpoints,
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT oid AS datid,
     datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 937b2101b3..2bbe17ba7d 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -782,8 +782,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT requested_checkpoints AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -793,7 +793,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT requested_checkpoints > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -884,6 +884,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 74e592aa8a..cfc9aa3a37 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -387,8 +387,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT requested_checkpoints AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -402,7 +402,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT requested_checkpoints > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -440,6 +440,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#31Michael Paquier
michael@paquier.xyz
In reply to: Bharath Rupireddy (#30)
Re: Introduce a new view for checkpointer related stats

On Mon, Feb 13, 2023 at 11:31:03AM +0530, Bharath Rupireddy wrote:

Needed a rebase. Please review the attached v8 patch set.

I was looking at this patch, and got a few comments.

FWIW, I kind of agree with the feeling of Bertrand upthread that using
"checkpoint_" in the attribute names for the new view is globally
inconsistent. After 0003, we get:
=# select attname from pg_attribute
where attrelid = 'pg_stat_checkpointer'::regclass
and attnum > 0;
attname
-----------------------------
timed_checkpoints
requested_checkpoints
checkpoint_write_time
checkpoint_sync_time
buffers_written_checkpoints
stats_reset
(6 rows)
=# select attname from pg_attribute
where attrelid = 'pg_stat_bgwriter'::regclass and
attnum > 0;
attname
------------------
buffers_clean
maxwritten_clean
buffers_alloc
stats_reset
(4 rows)

The view for the bgwriter does not do that. I'd suggest to use
functions that are named as pg_stat_get_checkpoint_$att with shorter
$atts. It is true that "timed" is a bit confusing, because it refers
to a number of checkpoints, and that can be read as a time value (?).
So how about num_timed? And for the others num_requested and
buffers_written?

+ * Unlike the checkpoint fields, reqquests related fields are protected by

s/reqquests/requests/.

SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
{
+ SlruShared shared = ctl->shared;
int fd;
int save_errno;
int result;

+	/* update the stats counter of flushes */
+	pgstat_count_slru_flush(shared->slru_stats_idx);

Why is that in 0002? Isn't that something we should treat as a bug
fix of its own, even backpatching it to make sure that the flush
requests for individual commit_ts, multixact and clog files are
counted in the stats?

Saying that, I am OK with moving ahead with 0001 and 0002 to remove
buffers_backend_fsync and buffers_backend from pg_stat_bgwriter, but
it is better to merge them into a single commit. It helps with 0003
and this would encourage the use of pg_stat_io that does a better job
overall with more field granularity.
--
Michael

#32Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Michael Paquier (#31)
3 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Thu, Oct 26, 2023 at 7:30 AM Michael Paquier <michael@paquier.xyz> wrote:

I was looking at this patch, and got a few comments.

Thanks.

The view for the bgwriter does not do that. I'd suggest to use
functions that are named as pg_stat_get_checkpoint_$att with shorter
$atts. It is true that "timed" is a bit confusing, because it refers
to a number of checkpoints, and that can be read as a time value (?).
So how about num_timed? And for the others num_requested and
buffers_written?

+1. PSA v9-0003.

+ * Unlike the checkpoint fields, reqquests related fields are protected by

s/reqquests/requests/.

Fixed.

SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
{
+ SlruShared shared = ctl->shared;
int fd;
int save_errno;
int result;

+       /* update the stats counter of flushes */
+       pgstat_count_slru_flush(shared->slru_stats_idx);

Why is that in 0002? Isn't that something we should treat as a bug
fix of its own, even backpatching it to make sure that the flush
requests for individual commit_ts, multixact and clog files are
counted in the stats?

+1. I included the fix in a separate patch 0002 here.

Saying that, I am OK with moving ahead with 0001 and 0002 to remove
buffers_backend_fsync and buffers_backend from pg_stat_bgwriter, but
it is better to merge them into a single commit. It helps with 0003
and this would encourage the use of pg_stat_io that does a better job
overall with more field granularity.

I merged v8 0001 and 0002 into one single patch, PSA v9-0001.

PSA v9 patch set.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v9-0001-Do-not-count-backend-writes-and-fsycns-in-checkpo.patchapplication/octet-stream; name=v9-0001-Do-not-count-backend-writes-and-fsycns-in-checkpo.patchDownload
From 28982a27f2c2480a68e3345dc0bbcb4a05f15410 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Thu, 26 Oct 2023 10:28:46 +0000
Subject: [PATCH v9] Do not count backend writes and fsycns in checkpointer
 stats

Two of the backend stats 1) number of buffers written directly by
a backend, 2) number of times a backend had to execute its own
fsync are being tracked in checkpointer stats and exposed to the
user via pg_stat_bgwriter view (columns buffers_backend and
buffers_backend_fsync). They are not actually checkpointer
properties but backend properties. Now that we have pg_stat_io to
track all the backend related stats including writes and fsyncs,
it is redundant/inaccurate to keep them in checkpointer stats.
This commit removes both of these columns from checkpointer stats.

Author: Bharath Rupireddy
Reviewed-by: Bertrand Drouvot, Andres Freund
Discussion: https://www.postgresql.org/message-id/20230210004604.mcszbscsqs3bc5nx%40awork3.anarazel.de
---
 doc/src/sgml/monitoring.sgml                  | 20 ------------
 src/backend/catalog/system_views.sql          |  2 --
 src/backend/postmaster/checkpointer.c         | 32 ++-----------------
 .../utils/activity/pgstat_checkpointer.c      |  4 ---
 src/backend/utils/adt/pgstatfuncs.c           | 12 -------
 src/include/catalog/pg_proc.dat               |  9 ------
 src/include/pgstat.h                          |  2 --
 src/test/regress/expected/rules.out           |  2 --
 8 files changed, 2 insertions(+), 81 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 3f49ff79f3..9fea60b5b2 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -2953,26 +2953,6 @@ description | Waiting for a newly initialized WAL file to reach durable storage
       </para></entry>
      </row>
 
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend</structfield> <type>bigint</type>
-      </para>
-      <para>
-       Number of buffers written directly by a backend
-      </para></entry>
-     </row>
-
-     <row>
-      <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_backend_fsync</structfield> <type>bigint</type>
-      </para>
-      <para>
-       Number of times a backend had to execute its own
-       <function>fsync</function> call (normally the background writer handles those
-       even when the backend does its own write)
-      </para></entry>
-     </row>
-
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
        <structfield>buffers_alloc</structfield> <type>bigint</type>
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index fcb14976c0..886f175fc2 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1118,8 +1118,6 @@ CREATE VIEW pg_stat_bgwriter AS
         pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-        pg_stat_get_buf_written_backend() AS buffers_backend,
-        pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index ace9893d95..4fe403c9a8 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -91,17 +91,11 @@
  * requesting backends since the last checkpoint start.  The flags are
  * chosen so that OR'ing is the correct way to combine multiple requests.
  *
- * num_backend_writes is used to count the number of buffer writes performed
- * by user backend processes.  This counter should be wide enough that it
- * can't overflow during a single processing cycle.  num_backend_fsync
- * counts the subset of those writes that also had to do their own fsync,
- * because the checkpointer failed to absorb their request.
- *
  * The requests array holds fsync requests sent by backends and not yet
  * absorbed by the checkpointer.
  *
- * Unlike the checkpoint fields, num_backend_writes, num_backend_fsync, and
- * the requests fields are protected by CheckpointerCommLock.
+ * Unlike the checkpoint fields, requests related fields are protected by
+ * CheckpointerCommLock.
  *----------
  */
 typedef struct
@@ -125,9 +119,6 @@ typedef struct
 	ConditionVariable start_cv; /* signaled when ckpt_started advances */
 	ConditionVariable done_cv;	/* signaled when ckpt_done advances */
 
-	uint32		num_backend_writes; /* counts user backend buffer writes */
-	uint32		num_backend_fsync;	/* counts user backend fsync calls */
-
 	int			num_requests;	/* current # of requests */
 	int			max_requests;	/* allocated array size */
 	CheckpointerRequest requests[FLEXIBLE_ARRAY_MEMBER];
@@ -1095,10 +1086,6 @@ ForwardSyncRequest(const FileTag *ftag, SyncRequestType type)
 
 	LWLockAcquire(CheckpointerCommLock, LW_EXCLUSIVE);
 
-	/* Count all backend writes regardless of if they fit in the queue */
-	if (!AmBackgroundWriterProcess())
-		CheckpointerShmem->num_backend_writes++;
-
 	/*
 	 * If the checkpointer isn't running or the request queue is full, the
 	 * backend will have to perform its own fsync request.  But before forcing
@@ -1108,12 +1095,6 @@ ForwardSyncRequest(const FileTag *ftag, SyncRequestType type)
 		(CheckpointerShmem->num_requests >= CheckpointerShmem->max_requests &&
 		 !CompactCheckpointerRequestQueue()))
 	{
-		/*
-		 * Count the subset of writes where backends have to do their own
-		 * fsync
-		 */
-		if (!AmBackgroundWriterProcess())
-			CheckpointerShmem->num_backend_fsync++;
 		LWLockRelease(CheckpointerCommLock);
 		return false;
 	}
@@ -1270,15 +1251,6 @@ AbsorbSyncRequests(void)
 
 	LWLockAcquire(CheckpointerCommLock, LW_EXCLUSIVE);
 
-	/* Transfer stats counts into pending pgstats message */
-	PendingCheckpointerStats.buf_written_backend
-		+= CheckpointerShmem->num_backend_writes;
-	PendingCheckpointerStats.buf_fsync_backend
-		+= CheckpointerShmem->num_backend_fsync;
-
-	CheckpointerShmem->num_backend_writes = 0;
-	CheckpointerShmem->num_backend_fsync = 0;
-
 	/*
 	 * We try to avoid holding the lock for a long time by copying the request
 	 * array, and processing the requests after releasing the lock.
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index 26dec112f6..03ed5dddda 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -52,8 +52,6 @@ pgstat_report_checkpointer(void)
 	CHECKPOINTER_ACC(checkpoint_write_time);
 	CHECKPOINTER_ACC(checkpoint_sync_time);
 	CHECKPOINTER_ACC(buf_written_checkpoints);
-	CHECKPOINTER_ACC(buf_written_backend);
-	CHECKPOINTER_ACC(buf_fsync_backend);
 #undef CHECKPOINTER_ACC
 
 	pgstat_end_changecount_write(&stats_shmem->changecount);
@@ -120,7 +118,5 @@ pgstat_checkpointer_snapshot_cb(void)
 	CHECKPOINTER_COMP(checkpoint_write_time);
 	CHECKPOINTER_COMP(checkpoint_sync_time);
 	CHECKPOINTER_COMP(buf_written_checkpoints);
-	CHECKPOINTER_COMP(buf_written_backend);
-	CHECKPOINTER_COMP(buf_fsync_backend);
 #undef CHECKPOINTER_COMP
 }
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 3b44af8006..6468b6a805 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1233,18 +1233,6 @@ pg_stat_get_bgwriter_stat_reset_time(PG_FUNCTION_ARGS)
 	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_bgwriter()->stat_reset_timestamp);
 }
 
-Datum
-pg_stat_get_buf_written_backend(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_backend);
-}
-
-Datum
-pg_stat_get_buf_fsync_backend(PG_FUNCTION_ARGS)
-{
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_fsync_backend);
-}
-
 Datum
 pg_stat_get_buf_alloc(PG_FUNCTION_ARGS)
 {
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 06435e8b92..bc41e92677 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5738,15 +5738,6 @@
   proname => 'pg_stat_get_checkpoint_sync_time', provolatile => 's',
   proparallel => 'r', prorettype => 'float8', proargtypes => '',
   prosrc => 'pg_stat_get_checkpoint_sync_time' },
-{ oid => '2775', descr => 'statistics: number of buffers written by backends',
-  proname => 'pg_stat_get_buf_written_backend', provolatile => 's',
-  proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_buf_written_backend' },
-{ oid => '3063',
-  descr => 'statistics: number of backend buffer writes that did their own fsync',
-  proname => 'pg_stat_get_buf_fsync_backend', provolatile => 's',
-  proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_buf_fsync_backend' },
 { oid => '2859', descr => 'statistics: number of buffer allocations',
   proname => 'pg_stat_get_buf_alloc', provolatile => 's', proparallel => 'r',
   prorettype => 'int8', proargtypes => '', prosrc => 'pg_stat_get_buf_alloc' },
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index fe2642f71a..e6fd20f1ce 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -265,8 +265,6 @@ typedef struct PgStat_CheckpointerStats
 	PgStat_Counter checkpoint_write_time;	/* times in milliseconds */
 	PgStat_Counter checkpoint_sync_time;
 	PgStat_Counter buf_written_checkpoints;
-	PgStat_Counter buf_written_backend;
-	PgStat_Counter buf_fsync_backend;
 } PgStat_CheckpointerStats;
 
 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 2c60400ade..798d1610f2 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1823,8 +1823,6 @@ pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints
     pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
     pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
-    pg_stat_get_buf_written_backend() AS buffers_backend,
-    pg_stat_get_buf_fsync_backend() AS buffers_backend_fsync,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT oid AS datid,
-- 
2.34.1

v9-0002-Count-SLRU-page-flushes-during-checkpoint-or-data.patchapplication/octet-stream; name=v9-0002-Count-SLRU-page-flushes-during-checkpoint-or-data.patchDownload
From 8a7680657fb0b97cf8ff47bdb77144eaa6978339 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Thu, 26 Oct 2023 12:52:34 +0000
Subject: [PATCH v9] Count SLRU page flushes during checkpoint or database
 shutdown

SLRU page flushes aren't counted during checkpoint or database
shutdown in SlruSyncFileTag unlike flushes following page writes
in SlruPhysicalWritePage. This commit fixes it by counting the
SLRU flushes even in SlruSyncFileTag.

Author: Bharath Rupireddy
Reviewed-by: Michael Paquier
Discussion: https://www.postgresql.org/message-id/ZTnIHhZiIPpEFLbL%40paquier.xyz
---
 src/backend/access/transam/slru.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 9ed24e1185..9802b9e1fb 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -1593,6 +1593,7 @@ SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
 int
 SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
 {
+	SlruShared	shared = ctl->shared;
 	int			fd;
 	int			save_errno;
 	int			result;
@@ -1611,5 +1612,9 @@ SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
 	CloseTransientFile(fd);
 
 	errno = save_errno;
+
+	/* update the stats counter of flushes */
+	pgstat_count_slru_flush(shared->slru_stats_idx);
+
 	return result;
 }
-- 
2.34.1

v9-0003-Introduce-a-new-view-for-checkpointer-related-sta.patchapplication/octet-stream; name=v9-0003-Introduce-a-new-view-for-checkpointer-related-sta.patchDownload
From 8843d6e49b7511d8e433058337698355f51c568c Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Thu, 26 Oct 2023 14:45:13 +0000
Subject: [PATCH v9] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as
well. It has been that way so far because historically
checkpointer was part of bgwriter until the commits 806a2ae and
bf405ba separated them out way back in PG 9.2.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

Bump catalog version.

Author: Bharath Rupireddy
Reviewed-by: Bertrand Drouvot, Andres Freund
Discussion: https://www.postgresql.org/message-id/CALj2ACVxX2ii%3D66RypXRweZe2EsBRiPMj0aHfRfHUeXJcC7kHg%40mail.gmail.com
---
 doc/src/sgml/monitoring.sgml                  | 98 ++++++++++++++-----
 src/backend/access/transam/xlog.c             |  4 +-
 src/backend/catalog/system_views.sql          | 14 ++-
 src/backend/postmaster/checkpointer.c         |  6 +-
 src/backend/storage/buffer/bufmgr.c           |  2 +-
 .../utils/activity/pgstat_checkpointer.c      | 21 ++--
 src/backend/utils/adt/pgstatfuncs.c           | 33 ++++---
 src/include/catalog/pg_proc.dat               | 30 +++---
 src/include/pgstat.h                          | 11 ++-
 src/test/recovery/t/029_stats_restart.pl      |  6 +-
 src/test/regress/expected/rules.out           | 13 +--
 src/test/regress/expected/stats.out           | 21 +++-
 src/test/regress/sql/stats.sql                | 12 ++-
 13 files changed, 178 insertions(+), 93 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 9fea60b5b2..0792dadc9b 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -451,6 +451,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_database</structname><indexterm><primary>pg_stat_database</primary></indexterm></entry>
       <entry>One row per database, showing database-wide statistics. See
@@ -2868,7 +2877,7 @@ description | Waiting for a newly initialized WAL file to reach durable storage
 
   <para>
    The <structname>pg_stat_bgwriter</structname> view will always have a
-   single row, containing global data for the cluster.
+   single row, containing data about the bgwriter of the cluster.
   </para>
 
   <table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
@@ -2888,77 +2897,118 @@ description | Waiting for a newly initialized WAL file to reach durable storage
     <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+       <structfield>buffers_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of buffers written by the background writer
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_req</structfield> <type>bigint</type>
+       <structfield>maxwritten_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of times the background writer stopped a cleaning
+       scan because it had written too many buffers
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+       <structfield>buffers_alloc</structfield> <type>bigint</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       Number of buffers allocated
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       Time at which these statistics were last reset
       </para></entry>
      </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
+
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
 
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
+
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing data about the checkpointer process of the cluster.
+  </para>
+
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+       Column Type
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Description
       </para></entry>
      </row>
+    </thead>
 
+    <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_clean</structfield> <type>bigint</type>
+       <structfield>num_timed</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written by the background writer
+       Number of scheduled checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>maxwritten_clean</structfield> <type>bigint</type>
+       <structfield>num_requested</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times the background writer stopped a cleaning
-       scan because it had written too many buffers
+       Number of requested checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_alloc</structfield> <type>bigint</type>
+       <structfield>write_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of buffers allocated
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>sync_time</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_written</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written during checkpoints
       </para></entry>
      </row>
 
@@ -4669,8 +4719,10 @@ description | Waiting for a newly initialized WAL file to reach durable storage
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>io</literal> to reset all the counters shown in the
         <structname>pg_stat_io</structname> view,
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 40461923ea..b541be8eec 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6349,8 +6349,8 @@ LogCheckpointEnd(bool restartpoint)
 												 CheckpointStats.ckpt_sync_end_t);
 
 	/* Accumulate checkpoint timing summary data, in milliseconds. */
-	PendingCheckpointerStats.checkpoint_write_time += write_msecs;
-	PendingCheckpointerStats.checkpoint_sync_time += sync_msecs;
+	PendingCheckpointerStats.write_time += write_msecs;
+	PendingCheckpointerStats.sync_time += sync_msecs;
 
 	/*
 	 * All of the published timing statistics are accounted for.  Only
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 886f175fc2..b65f6b5249 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1111,16 +1111,20 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_checkpointer_num_timed() AS num_timed,
+        pg_stat_get_checkpointer_num_requested() AS num_requested,
+        pg_stat_get_checkpointer_write_time() AS write_time,
+        pg_stat_get_checkpointer_sync_time() AS sync_time,
+        pg_stat_get_checkpointer_buffers_written() AS buffers_written,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_io AS
 SELECT
        b.backend_type,
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 4fe403c9a8..a3c1aba24e 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -358,7 +358,7 @@ CheckpointerMain(void)
 		if (((volatile CheckpointerShmemStruct *) CheckpointerShmem)->ckpt_flags)
 		{
 			do_checkpoint = true;
-			PendingCheckpointerStats.requested_checkpoints++;
+			PendingCheckpointerStats.num_requested++;
 		}
 
 		/*
@@ -372,7 +372,7 @@ CheckpointerMain(void)
 		if (elapsed_secs >= CheckPointTimeout)
 		{
 			if (!do_checkpoint)
-				PendingCheckpointerStats.timed_checkpoints++;
+				PendingCheckpointerStats.num_timed++;
 			do_checkpoint = true;
 			flags |= CHECKPOINT_CAUSE_TIME;
 		}
@@ -569,7 +569,7 @@ HandleCheckpointerInterrupts(void)
 		 * updates the statistics, increment the checkpoint request and flush
 		 * out pending statistic.
 		 */
-		PendingCheckpointerStats.requested_checkpoints++;
+		PendingCheckpointerStats.num_requested++;
 		ShutdownXLOG(0, 0);
 		pgstat_report_checkpointer();
 		pgstat_report_wal(true);
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 21a29f9081..dc504a1ae0 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -2751,7 +2751,7 @@ BufferSync(int flags)
 			if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN)
 			{
 				TRACE_POSTGRESQL_BUFFER_SYNC_WRITTEN(buf_id);
-				PendingCheckpointerStats.buf_written_checkpoints++;
+				PendingCheckpointerStats.buffers_written++;
 				num_written++;
 			}
 		}
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index 03ed5dddda..301a0bc7bd 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -47,11 +47,11 @@ pgstat_report_checkpointer(void)
 	pgstat_begin_changecount_write(&stats_shmem->changecount);
 
 #define CHECKPOINTER_ACC(fld) stats_shmem->stats.fld += PendingCheckpointerStats.fld
-	CHECKPOINTER_ACC(timed_checkpoints);
-	CHECKPOINTER_ACC(requested_checkpoints);
-	CHECKPOINTER_ACC(checkpoint_write_time);
-	CHECKPOINTER_ACC(checkpoint_sync_time);
-	CHECKPOINTER_ACC(buf_written_checkpoints);
+	CHECKPOINTER_ACC(num_timed);
+	CHECKPOINTER_ACC(num_requested);
+	CHECKPOINTER_ACC(write_time);
+	CHECKPOINTER_ACC(sync_time);
+	CHECKPOINTER_ACC(buffers_written);
 #undef CHECKPOINTER_ACC
 
 	pgstat_end_changecount_write(&stats_shmem->changecount);
@@ -92,6 +92,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
@@ -113,10 +114,10 @@ pgstat_checkpointer_snapshot_cb(void)
 
 	/* compensate by reset offsets */
 #define CHECKPOINTER_COMP(fld) pgStatLocal.snapshot.checkpointer.fld -= reset.fld;
-	CHECKPOINTER_COMP(timed_checkpoints);
-	CHECKPOINTER_COMP(requested_checkpoints);
-	CHECKPOINTER_COMP(checkpoint_write_time);
-	CHECKPOINTER_COMP(checkpoint_sync_time);
-	CHECKPOINTER_COMP(buf_written_checkpoints);
+	CHECKPOINTER_COMP(num_timed);
+	CHECKPOINTER_COMP(num_requested);
+	CHECKPOINTER_COMP(write_time);
+	CHECKPOINTER_COMP(sync_time);
+	CHECKPOINTER_COMP(buffers_written);
 #undef CHECKPOINTER_COMP
 }
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6468b6a805..2d35dbf31b 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1182,21 +1182,21 @@ PG_STAT_GET_DBENTRY_FLOAT8_MS(idle_in_transaction_time)
 PG_STAT_GET_DBENTRY_FLOAT8_MS(session_time)
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_checkpointer_num_timed(PG_FUNCTION_ARGS)
 {
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
+	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_timed);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_checkpointer_num_requested(PG_FUNCTION_ARGS)
 {
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
+	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_requested);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_checkpointer_buffers_written(PG_FUNCTION_ARGS)
 {
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
+	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buffers_written);
 }
 
 Datum
@@ -1212,19 +1212,25 @@ pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
 }
 
 Datum
-pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS)
+pg_stat_get_checkpointer_write_time(PG_FUNCTION_ARGS)
 {
 	/* time is already in msec, just convert to double for presentation */
 	PG_RETURN_FLOAT8((double)
-					 pgstat_fetch_stat_checkpointer()->checkpoint_write_time);
+					 pgstat_fetch_stat_checkpointer()->write_time);
 }
 
 Datum
-pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
+pg_stat_get_checkpointer_sync_time(PG_FUNCTION_ARGS)
 {
 	/* time is already in msec, just convert to double for presentation */
 	PG_RETURN_FLOAT8((double)
-					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
+					 pgstat_fetch_stat_checkpointer()->sync_time);
+}
+
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
 }
 
 Datum
@@ -1738,14 +1744,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "io") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_IO);
 	else if (strcmp(target, "recovery_prefetch") == 0)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index bc41e92677..568aa80d92 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5700,20 +5700,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_checkpointer_num_timed', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_checkpointer_num_timed' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_checkpointer_num_requested', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_checkpointer_num_requested' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_checkpointer_buffers_written', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_checkpointer_buffers_written' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
@@ -5730,14 +5734,14 @@
   prosrc => 'pg_stat_get_bgwriter_stat_reset_time' },
 { oid => '3160',
   descr => 'statistics: checkpoint time spent writing buffers to disk, in milliseconds',
-  proname => 'pg_stat_get_checkpoint_write_time', provolatile => 's',
+  proname => 'pg_stat_get_checkpointer_write_time', provolatile => 's',
   proparallel => 'r', prorettype => 'float8', proargtypes => '',
-  prosrc => 'pg_stat_get_checkpoint_write_time' },
+  prosrc => 'pg_stat_get_checkpointer_write_time' },
 { oid => '3161',
   descr => 'statistics: checkpoint time spent synchronizing buffers to disk, in milliseconds',
-  proname => 'pg_stat_get_checkpoint_sync_time', provolatile => 's',
+  proname => 'pg_stat_get_checkpointer_sync_time', provolatile => 's',
   proparallel => 'r', prorettype => 'float8', proargtypes => '',
-  prosrc => 'pg_stat_get_checkpoint_sync_time' },
+  prosrc => 'pg_stat_get_checkpointer_sync_time' },
 { oid => '2859', descr => 'statistics: number of buffer allocations',
   proname => 'pg_stat_get_buf_alloc', provolatile => 's', proparallel => 'r',
   prorettype => 'int8', proargtypes => '', prosrc => 'pg_stat_get_buf_alloc' },
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index e6fd20f1ce..f95d8db0c4 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -260,11 +260,12 @@ typedef struct PgStat_BgWriterStats
 
 typedef struct PgStat_CheckpointerStats
 {
-	PgStat_Counter timed_checkpoints;
-	PgStat_Counter requested_checkpoints;
-	PgStat_Counter checkpoint_write_time;	/* times in milliseconds */
-	PgStat_Counter checkpoint_sync_time;
-	PgStat_Counter buf_written_checkpoints;
+	PgStat_Counter num_timed;
+	PgStat_Counter num_requested;
+	PgStat_Counter write_time;	/* times in milliseconds */
+	PgStat_Counter sync_time;
+	PgStat_Counter buffers_written;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 742bd57e28..f6368ab1d3 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT num_timed + num_requested FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 798d1610f2..1442c43d9c 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1816,15 +1816,16 @@ pg_stat_archiver| SELECT archived_count,
     last_failed_time,
     stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
-    pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_checkpointer_num_timed() AS num_timed,
+    pg_stat_get_checkpointer_num_requested() AS num_requested,
+    pg_stat_get_checkpointer_write_time() AS write_time,
+    pg_stat_get_checkpointer_sync_time() AS sync_time,
+    pg_stat_get_checkpointer_buffers_written() AS buffers_written,
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT oid AS datid,
     datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 94187e59cf..d79a5de009 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -828,8 +828,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT num_requested AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -839,7 +839,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -930,6 +930,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 1e21e55c6d..055b52a90c 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -417,8 +417,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT num_requested AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -432,7 +432,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -470,6 +470,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#33Michael Paquier
michael@paquier.xyz
In reply to: Bharath Rupireddy (#32)
Re: Introduce a new view for checkpointer related stats

On Thu, Oct 26, 2023 at 10:55:00PM +0530, Bharath Rupireddy wrote:

On Thu, Oct 26, 2023 at 7:30 AM Michael Paquier <michael@paquier.xyz> wrote:

Why is that in 0002? Isn't that something we should treat as a bug
fix of its own, even backpatching it to make sure that the flush
requests for individual commit_ts, multixact and clog files are
counted in the stats?

+1. I included the fix in a separate patch 0002 here.

Hmm. As per the existing call of pgstat_count_slru_flush() in
SimpleLruWriteAll(), routine called SimpleLruFlush() until ~13 and
dee663f78439, an incrementation of 1 for slru_stats_idx refers to all
the flushes for all the dirty data of this SLRU in a single pass.
This addition actually means that we would now increment the counter
for each sync request, changing its meaning. Perhaps there is an
argument for changing the meaning of this parameter to be based on the
number of flush requests completed, but if that were to happen it
would be better to remove pgstat_count_slru_flush() in
SimpleLruWriteAll(), I guess, or just aggregate this counter once,
which would be cheaper.

Saying that, I am OK with moving ahead with 0001 and 0002 to remove
buffers_backend_fsync and buffers_backend from pg_stat_bgwriter, but
it is better to merge them into a single commit. It helps with 0003
and this would encourage the use of pg_stat_io that does a better job
overall with more field granularity.

I merged v8 0001 and 0002 into one single patch, PSA v9-0001.

v9-0001 is OK, so I have applied it.

v9-0003 is mostly a mechanical change, and it passes the eye test. I
have spotted two nits.

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_checkpointer_num_timed() AS num_timed,
+        pg_stat_get_checkpointer_num_requested() AS num_requested,
+        pg_stat_get_checkpointer_write_time() AS write_time,
+        pg_stat_get_checkpointer_sync_time() AS sync_time,
+        pg_stat_get_checkpointer_buffers_written() AS buffers_written,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;

Okay with this layer. I am wondering if others have opinions to
share about these names for the attributes of pg_stat_checkpointer,
though.

-   single row, containing global data for the cluster.
+   single row, containing data about the bgwriter of the cluster.

"bgwriter" is used in one place of the docs, so perhaps "background
writer" is better here?

The error message generated for an incorrect target needs to be
updated in pg_stat_reset_shared():
=# select pg_stat_reset_shared('checkpointe');
ERROR: 22023: unrecognized reset target: "checkpointe"
HINT: Target must be "archiver", "bgwriter", "io", "recovery_prefetch", or "wal".
--
Michael

#34Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Michael Paquier (#33)
1 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Fri, Oct 27, 2023 at 8:03 AM Michael Paquier <michael@paquier.xyz> wrote:

Hmm. As per the existing call of pgstat_count_slru_flush() in
SimpleLruWriteAll(), routine called SimpleLruFlush() until ~13 and
dee663f78439, an incrementation of 1 for slru_stats_idx refers to all
the flushes for all the dirty data of this SLRU in a single pass.

This addition actually means that we would now increment the counter
for each sync request, changing its meaning. Perhaps there is an
argument for changing the meaning of this parameter to be based on the
number of flush requests completed, but if that were to happen it
would be better to remove pgstat_count_slru_flush() in
SimpleLruWriteAll(), I guess, or just aggregate this counter once,
which would be cheaper.

Right. Interestingly, there are 2 SLRU flush related wait events
WAIT_EVENT_SLRU_SYNC ("Waiting for SLRU data to reach durable storage
following a page write") and WAIT_EVENT_SLRU_FLUSH_SYNC ("Waiting for
SLRU data to reach durable storage during a checkpoint or database
shutdown"). And, we're counting the SLRU flushes in two of these
places into one single stat variable. These two events look confusing
and may be useful if shown in an aggregated way.

A possible way is to move existing pgstat_count_slru_flush in
SimpleLruWriteAll closer to pg_fsync and WAIT_EVENT_SLRU_SYNC in
SlruPhysicalWritePage, remove WAIT_EVENT_SLRU_FLUSH_SYNC completely,
use WAIT_EVENT_SLRU_SYNC in SlruSyncFileTag and count the flushes in
SlruSyncFileTag. This aggregated way is much simpler IMV.

Another possible way is to have separate stat variables for each of
the SLRU flushes WAIT_EVENT_SLRU_SYNC and WAIT_EVENT_SLRU_FLUSH_SYNC
and expose them separately in pg_stat_slru. I don't like this
approach.

v9-0003 is mostly a mechanical change, and it passes the eye test.

Thanks. Indeed it contains mechanical changes.

I have spotted two nits.

+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_checkpointer_num_timed() AS num_timed,
+        pg_stat_get_checkpointer_num_requested() AS num_requested,
+        pg_stat_get_checkpointer_write_time() AS write_time,
+        pg_stat_get_checkpointer_sync_time() AS sync_time,
+        pg_stat_get_checkpointer_buffers_written() AS buffers_written,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;

Okay with this layer. I am wondering if others have opinions to
share about these names for the attributes of pg_stat_checkpointer,
though.

I think these column names are a good fit in this context as we can't
just call timed/requested/write/sync and having "checkpoint" makes the
column names long unnecessarily. FWIW, I see some of the user-exposed
field names starting with num_* (num_nonnulls, num_nulls, num_lwlocks,
num_transactions).

-   single row, containing global data for the cluster.
+   single row, containing data about the bgwriter of the cluster.

"bgwriter" is used in one place of the docs, so perhaps "background
writer" is better here?

+1. Changed in the attached v10-0001.

The error message generated for an incorrect target needs to be
updated in pg_stat_reset_shared():
=# select pg_stat_reset_shared('checkpointe');
ERROR: 22023: unrecognized reset target: "checkpointe"
HINT: Target must be "archiver", "bgwriter", "io", "recovery_prefetch", or "wal".

+1. Changed in the attached v10-001. FWIW, having a test case in
stats.sql emitting this error message and hint would have helped here.
If okay, I can add one.

PS: I'll park the SLRU flush related patch aside until the approach is
finalized. I'm posting the pg_stat_checkpointer patch as v10-0001.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v10-0001-Introduce-a-new-view-for-checkpointer-related-st.patchapplication/x-patch; name=v10-0001-Introduce-a-new-view-for-checkpointer-related-st.patchDownload
From d64200c575bf8c9f54bdefad95f84dff5a8381eb Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Fri, 27 Oct 2023 04:42:55 +0000
Subject: [PATCH v10] Introduce a new view for checkpointer related stats

pg_stat_bgwriter view currently reports checkpointer stats as
well. It has been that way so far because historically
checkpointer was part of bgwriter until the commits 806a2ae and
bf405ba separated them out way back in PG 9.2.

It is time for us to separate checkpointer stats to its own view
called pg_stat_checkpointer.

Bump catalog version.

Author: Bharath Rupireddy
Reviewed-by: Bertrand Drouvot, Andres Freund
Discussion: https://www.postgresql.org/message-id/CALj2ACVxX2ii%3D66RypXRweZe2EsBRiPMj0aHfRfHUeXJcC7kHg%40mail.gmail.com
---
 doc/src/sgml/monitoring.sgml                  | 98 ++++++++++++++-----
 src/backend/access/transam/xlog.c             |  4 +-
 src/backend/catalog/system_views.sql          | 14 ++-
 src/backend/postmaster/checkpointer.c         |  6 +-
 src/backend/storage/buffer/bufmgr.c           |  2 +-
 .../utils/activity/pgstat_checkpointer.c      | 21 ++--
 src/backend/utils/adt/pgstatfuncs.c           | 35 +++----
 src/include/catalog/pg_proc.dat               | 30 +++---
 src/include/pgstat.h                          | 11 ++-
 src/test/recovery/t/029_stats_restart.pl      |  6 +-
 src/test/regress/expected/rules.out           | 13 +--
 src/test/regress/expected/stats.out           | 21 +++-
 src/test/regress/sql/stats.sql                | 12 ++-
 13 files changed, 179 insertions(+), 94 deletions(-)

diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 9fea60b5b2..082267e15f 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -451,6 +451,15 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      </entry>
      </row>
 
+     <row>
+      <entry><structname>pg_stat_checkpointer</structname><indexterm><primary>pg_stat_checkpointer</primary></indexterm></entry>
+      <entry>One row only, showing statistics about the
+       checkpointer process's activity. See
+       <link linkend="monitoring-pg-stat-checkpointer-view">
+       <structname>pg_stat_checkpointer</structname></link> for details.
+     </entry>
+     </row>
+
      <row>
       <entry><structname>pg_stat_database</structname><indexterm><primary>pg_stat_database</primary></indexterm></entry>
       <entry>One row per database, showing database-wide statistics. See
@@ -2868,7 +2877,7 @@ description | Waiting for a newly initialized WAL file to reach durable storage
 
   <para>
    The <structname>pg_stat_bgwriter</structname> view will always have a
-   single row, containing global data for the cluster.
+   single row, containing data about the background writer of the cluster.
   </para>
 
   <table id="pg-stat-bgwriter-view" xreflabel="pg_stat_bgwriter">
@@ -2888,77 +2897,118 @@ description | Waiting for a newly initialized WAL file to reach durable storage
     <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_timed</structfield> <type>bigint</type>
+       <structfield>buffers_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of scheduled checkpoints that have been performed
+       Number of buffers written by the background writer
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoints_req</structfield> <type>bigint</type>
+       <structfield>maxwritten_clean</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of requested checkpoints that have been performed
+       Number of times the background writer stopped a cleaning
+       scan because it had written too many buffers
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_write_time</structfield> <type>double precision</type>
+       <structfield>buffers_alloc</structfield> <type>bigint</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are written to disk, in milliseconds
+       Number of buffers allocated
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>checkpoint_sync_time</structfield> <type>double precision</type>
+       <structfield>stats_reset</structfield> <type>timestamp with time zone</type>
       </para>
       <para>
-       Total amount of time that has been spent in the portion of
-       checkpoint processing where files are synchronized to disk, in
-       milliseconds
+       Time at which these statistics were last reset
       </para></entry>
      </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect2>
+
+ <sect2 id="monitoring-pg-stat-checkpointer-view">
+  <title><structname>pg_stat_checkpointer</structname></title>
 
+  <indexterm>
+   <primary>pg_stat_checkpointer</primary>
+  </indexterm>
+
+  <para>
+   The <structname>pg_stat_checkpointer</structname> view will always have a
+   single row, containing data about the checkpointer process of the cluster.
+  </para>
+
+  <table id="pg-stat-checkpointer-view" xreflabel="pg_stat_checkpointer">
+   <title><structname>pg_stat_checkpointer</structname> View</title>
+   <tgroup cols="1">
+    <thead>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_checkpoint</structfield> <type>bigint</type>
+       Column Type
       </para>
       <para>
-       Number of buffers written during checkpoints
+       Description
       </para></entry>
      </row>
+    </thead>
 
+    <tbody>
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_clean</structfield> <type>bigint</type>
+       <structfield>num_timed</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of buffers written by the background writer
+       Number of scheduled checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>maxwritten_clean</structfield> <type>bigint</type>
+       <structfield>num_requested</structfield> <type>bigint</type>
       </para>
       <para>
-       Number of times the background writer stopped a cleaning
-       scan because it had written too many buffers
+       Number of requested checkpoints that have been performed
       </para></entry>
      </row>
 
      <row>
       <entry role="catalog_table_entry"><para role="column_definition">
-       <structfield>buffers_alloc</structfield> <type>bigint</type>
+       <structfield>write_time</structfield> <type>double precision</type>
       </para>
       <para>
-       Number of buffers allocated
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are written to disk, in milliseconds
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>sync_time</structfield> <type>double precision</type>
+      </para>
+      <para>
+       Total amount of time that has been spent in the portion of
+       checkpoint processing where files are synchronized to disk, in
+       milliseconds
+      </para></entry>
+     </row>
+
+     <row>
+      <entry role="catalog_table_entry"><para role="column_definition">
+       <structfield>buffers_written</structfield> <type>bigint</type>
+      </para>
+      <para>
+       Number of buffers written during checkpoints
       </para></entry>
      </row>
 
@@ -4669,8 +4719,10 @@ description | Waiting for a newly initialized WAL file to reach durable storage
         Resets some cluster-wide statistics counters to zero, depending on the
         argument.  The argument can be <literal>bgwriter</literal> to reset
         all the counters shown in
-        the <structname>pg_stat_bgwriter</structname>
-        view, <literal>archiver</literal> to reset all the counters shown in
+        the <structname>pg_stat_bgwriter</structname> view,
+        <literal>checkpointer</literal> to reset all the counters shown in
+        the <structname>pg_stat_checkpointer</structname> view,
+        <literal>archiver</literal> to reset all the counters shown in
         the <structname>pg_stat_archiver</structname> view,
         <literal>io</literal> to reset all the counters shown in the
         <structname>pg_stat_io</structname> view,
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 40461923ea..b541be8eec 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -6349,8 +6349,8 @@ LogCheckpointEnd(bool restartpoint)
 												 CheckpointStats.ckpt_sync_end_t);
 
 	/* Accumulate checkpoint timing summary data, in milliseconds. */
-	PendingCheckpointerStats.checkpoint_write_time += write_msecs;
-	PendingCheckpointerStats.checkpoint_sync_time += sync_msecs;
+	PendingCheckpointerStats.write_time += write_msecs;
+	PendingCheckpointerStats.sync_time += sync_msecs;
 
 	/*
 	 * All of the published timing statistics are accounted for.  Only
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 886f175fc2..b65f6b5249 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1111,16 +1111,20 @@ CREATE VIEW pg_stat_archiver AS
 
 CREATE VIEW pg_stat_bgwriter AS
     SELECT
-        pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-        pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-        pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-        pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-        pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
         pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
         pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
         pg_stat_get_buf_alloc() AS buffers_alloc,
         pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
 
+CREATE VIEW pg_stat_checkpointer AS
+    SELECT
+        pg_stat_get_checkpointer_num_timed() AS num_timed,
+        pg_stat_get_checkpointer_num_requested() AS num_requested,
+        pg_stat_get_checkpointer_write_time() AS write_time,
+        pg_stat_get_checkpointer_sync_time() AS sync_time,
+        pg_stat_get_checkpointer_buffers_written() AS buffers_written,
+        pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
+
 CREATE VIEW pg_stat_io AS
 SELECT
        b.backend_type,
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 4fe403c9a8..a3c1aba24e 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -358,7 +358,7 @@ CheckpointerMain(void)
 		if (((volatile CheckpointerShmemStruct *) CheckpointerShmem)->ckpt_flags)
 		{
 			do_checkpoint = true;
-			PendingCheckpointerStats.requested_checkpoints++;
+			PendingCheckpointerStats.num_requested++;
 		}
 
 		/*
@@ -372,7 +372,7 @@ CheckpointerMain(void)
 		if (elapsed_secs >= CheckPointTimeout)
 		{
 			if (!do_checkpoint)
-				PendingCheckpointerStats.timed_checkpoints++;
+				PendingCheckpointerStats.num_timed++;
 			do_checkpoint = true;
 			flags |= CHECKPOINT_CAUSE_TIME;
 		}
@@ -569,7 +569,7 @@ HandleCheckpointerInterrupts(void)
 		 * updates the statistics, increment the checkpoint request and flush
 		 * out pending statistic.
 		 */
-		PendingCheckpointerStats.requested_checkpoints++;
+		PendingCheckpointerStats.num_requested++;
 		ShutdownXLOG(0, 0);
 		pgstat_report_checkpointer();
 		pgstat_report_wal(true);
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 21a29f9081..dc504a1ae0 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -2751,7 +2751,7 @@ BufferSync(int flags)
 			if (SyncOneBuffer(buf_id, false, &wb_context) & BUF_WRITTEN)
 			{
 				TRACE_POSTGRESQL_BUFFER_SYNC_WRITTEN(buf_id);
-				PendingCheckpointerStats.buf_written_checkpoints++;
+				PendingCheckpointerStats.buffers_written++;
 				num_written++;
 			}
 		}
diff --git a/src/backend/utils/activity/pgstat_checkpointer.c b/src/backend/utils/activity/pgstat_checkpointer.c
index 03ed5dddda..301a0bc7bd 100644
--- a/src/backend/utils/activity/pgstat_checkpointer.c
+++ b/src/backend/utils/activity/pgstat_checkpointer.c
@@ -47,11 +47,11 @@ pgstat_report_checkpointer(void)
 	pgstat_begin_changecount_write(&stats_shmem->changecount);
 
 #define CHECKPOINTER_ACC(fld) stats_shmem->stats.fld += PendingCheckpointerStats.fld
-	CHECKPOINTER_ACC(timed_checkpoints);
-	CHECKPOINTER_ACC(requested_checkpoints);
-	CHECKPOINTER_ACC(checkpoint_write_time);
-	CHECKPOINTER_ACC(checkpoint_sync_time);
-	CHECKPOINTER_ACC(buf_written_checkpoints);
+	CHECKPOINTER_ACC(num_timed);
+	CHECKPOINTER_ACC(num_requested);
+	CHECKPOINTER_ACC(write_time);
+	CHECKPOINTER_ACC(sync_time);
+	CHECKPOINTER_ACC(buffers_written);
 #undef CHECKPOINTER_ACC
 
 	pgstat_end_changecount_write(&stats_shmem->changecount);
@@ -92,6 +92,7 @@ pgstat_checkpointer_reset_all_cb(TimestampTz ts)
 									&stats_shmem->stats,
 									sizeof(stats_shmem->stats),
 									&stats_shmem->changecount);
+	stats_shmem->stats.stat_reset_timestamp = ts;
 	LWLockRelease(&stats_shmem->lock);
 }
 
@@ -113,10 +114,10 @@ pgstat_checkpointer_snapshot_cb(void)
 
 	/* compensate by reset offsets */
 #define CHECKPOINTER_COMP(fld) pgStatLocal.snapshot.checkpointer.fld -= reset.fld;
-	CHECKPOINTER_COMP(timed_checkpoints);
-	CHECKPOINTER_COMP(requested_checkpoints);
-	CHECKPOINTER_COMP(checkpoint_write_time);
-	CHECKPOINTER_COMP(checkpoint_sync_time);
-	CHECKPOINTER_COMP(buf_written_checkpoints);
+	CHECKPOINTER_COMP(num_timed);
+	CHECKPOINTER_COMP(num_requested);
+	CHECKPOINTER_COMP(write_time);
+	CHECKPOINTER_COMP(sync_time);
+	CHECKPOINTER_COMP(buffers_written);
 #undef CHECKPOINTER_COMP
 }
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index 6468b6a805..f3ad1e38f7 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -1182,21 +1182,21 @@ PG_STAT_GET_DBENTRY_FLOAT8_MS(idle_in_transaction_time)
 PG_STAT_GET_DBENTRY_FLOAT8_MS(session_time)
 
 Datum
-pg_stat_get_bgwriter_timed_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_checkpointer_num_timed(PG_FUNCTION_ARGS)
 {
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->timed_checkpoints);
+	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_timed);
 }
 
 Datum
-pg_stat_get_bgwriter_requested_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_checkpointer_num_requested(PG_FUNCTION_ARGS)
 {
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->requested_checkpoints);
+	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->num_requested);
 }
 
 Datum
-pg_stat_get_bgwriter_buf_written_checkpoints(PG_FUNCTION_ARGS)
+pg_stat_get_checkpointer_buffers_written(PG_FUNCTION_ARGS)
 {
-	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buf_written_checkpoints);
+	PG_RETURN_INT64(pgstat_fetch_stat_checkpointer()->buffers_written);
 }
 
 Datum
@@ -1212,19 +1212,25 @@ pg_stat_get_bgwriter_maxwritten_clean(PG_FUNCTION_ARGS)
 }
 
 Datum
-pg_stat_get_checkpoint_write_time(PG_FUNCTION_ARGS)
+pg_stat_get_checkpointer_write_time(PG_FUNCTION_ARGS)
 {
 	/* time is already in msec, just convert to double for presentation */
 	PG_RETURN_FLOAT8((double)
-					 pgstat_fetch_stat_checkpointer()->checkpoint_write_time);
+					 pgstat_fetch_stat_checkpointer()->write_time);
 }
 
 Datum
-pg_stat_get_checkpoint_sync_time(PG_FUNCTION_ARGS)
+pg_stat_get_checkpointer_sync_time(PG_FUNCTION_ARGS)
 {
 	/* time is already in msec, just convert to double for presentation */
 	PG_RETURN_FLOAT8((double)
-					 pgstat_fetch_stat_checkpointer()->checkpoint_sync_time);
+					 pgstat_fetch_stat_checkpointer()->sync_time);
+}
+
+Datum
+pg_stat_get_checkpointer_stat_reset_time(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_TIMESTAMPTZ(pgstat_fetch_stat_checkpointer()->stat_reset_timestamp);
 }
 
 Datum
@@ -1738,14 +1744,9 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 	if (strcmp(target, "archiver") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_ARCHIVER);
 	else if (strcmp(target, "bgwriter") == 0)
-	{
-		/*
-		 * Historically checkpointer was part of bgwriter, continue to reset
-		 * both for now.
-		 */
 		pgstat_reset_of_kind(PGSTAT_KIND_BGWRITER);
+	else if (strcmp(target, "checkpointer") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_CHECKPOINTER);
-	}
 	else if (strcmp(target, "io") == 0)
 		pgstat_reset_of_kind(PGSTAT_KIND_IO);
 	else if (strcmp(target, "recovery_prefetch") == 0)
@@ -1756,7 +1757,7 @@ pg_stat_reset_shared(PG_FUNCTION_ARGS)
 		ereport(ERROR,
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("unrecognized reset target: \"%s\"", target),
-				 errhint("Target must be \"archiver\", \"bgwriter\", \"io\", \"recovery_prefetch\", or \"wal\".")));
+				 errhint("Target must be \"archiver\", \"bgwriter\", \"checkpointer\", \"io\", \"recovery_prefetch\", or \"wal\".")));
 
 	PG_RETURN_VOID();
 }
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index bc41e92677..568aa80d92 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5700,20 +5700,24 @@
   proargnames => '{archived_count,last_archived_wal,last_archived_time,failed_count,last_failed_wal,last_failed_time,stats_reset}',
   prosrc => 'pg_stat_get_archiver' },
 { oid => '2769',
-  descr => 'statistics: number of timed checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_timed_checkpoints', provolatile => 's',
+  descr => 'statistics: number of timed checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_checkpointer_num_timed', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_timed_checkpoints' },
+  prosrc => 'pg_stat_get_checkpointer_num_timed' },
 { oid => '2770',
-  descr => 'statistics: number of backend requested checkpoints started by the bgwriter',
-  proname => 'pg_stat_get_bgwriter_requested_checkpoints', provolatile => 's',
+  descr => 'statistics: number of backend requested checkpoints started by the checkpointer',
+  proname => 'pg_stat_get_checkpointer_num_requested', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_requested_checkpoints' },
+  prosrc => 'pg_stat_get_checkpointer_num_requested' },
 { oid => '2771',
-  descr => 'statistics: number of buffers written by the bgwriter during checkpoints',
-  proname => 'pg_stat_get_bgwriter_buf_written_checkpoints', provolatile => 's',
+  descr => 'statistics: number of buffers written by the checkpointer',
+  proname => 'pg_stat_get_checkpointer_buffers_written', provolatile => 's',
   proparallel => 'r', prorettype => 'int8', proargtypes => '',
-  prosrc => 'pg_stat_get_bgwriter_buf_written_checkpoints' },
+  prosrc => 'pg_stat_get_checkpointer_buffers_written' },
+{ oid => '8206', descr => 'statistics: last reset for the checkpointer',
+  proname => 'pg_stat_get_checkpointer_stat_reset_time', provolatile => 's',
+  proparallel => 'r', prorettype => 'timestamptz', proargtypes => '',
+  prosrc => 'pg_stat_get_checkpointer_stat_reset_time' },
 { oid => '2772',
   descr => 'statistics: number of buffers written by the bgwriter for cleaning dirty buffers',
   proname => 'pg_stat_get_bgwriter_buf_written_clean', provolatile => 's',
@@ -5730,14 +5734,14 @@
   prosrc => 'pg_stat_get_bgwriter_stat_reset_time' },
 { oid => '3160',
   descr => 'statistics: checkpoint time spent writing buffers to disk, in milliseconds',
-  proname => 'pg_stat_get_checkpoint_write_time', provolatile => 's',
+  proname => 'pg_stat_get_checkpointer_write_time', provolatile => 's',
   proparallel => 'r', prorettype => 'float8', proargtypes => '',
-  prosrc => 'pg_stat_get_checkpoint_write_time' },
+  prosrc => 'pg_stat_get_checkpointer_write_time' },
 { oid => '3161',
   descr => 'statistics: checkpoint time spent synchronizing buffers to disk, in milliseconds',
-  proname => 'pg_stat_get_checkpoint_sync_time', provolatile => 's',
+  proname => 'pg_stat_get_checkpointer_sync_time', provolatile => 's',
   proparallel => 'r', prorettype => 'float8', proargtypes => '',
-  prosrc => 'pg_stat_get_checkpoint_sync_time' },
+  prosrc => 'pg_stat_get_checkpointer_sync_time' },
 { oid => '2859', descr => 'statistics: number of buffer allocations',
   proname => 'pg_stat_get_buf_alloc', provolatile => 's', proparallel => 'r',
   prorettype => 'int8', proargtypes => '', prosrc => 'pg_stat_get_buf_alloc' },
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index e6fd20f1ce..f95d8db0c4 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -260,11 +260,12 @@ typedef struct PgStat_BgWriterStats
 
 typedef struct PgStat_CheckpointerStats
 {
-	PgStat_Counter timed_checkpoints;
-	PgStat_Counter requested_checkpoints;
-	PgStat_Counter checkpoint_write_time;	/* times in milliseconds */
-	PgStat_Counter checkpoint_sync_time;
-	PgStat_Counter buf_written_checkpoints;
+	PgStat_Counter num_timed;
+	PgStat_Counter num_requested;
+	PgStat_Counter write_time;	/* times in milliseconds */
+	PgStat_Counter sync_time;
+	PgStat_Counter buffers_written;
+	TimestampTz stat_reset_timestamp;
 } PgStat_CheckpointerStats;
 
 
diff --git a/src/test/recovery/t/029_stats_restart.pl b/src/test/recovery/t/029_stats_restart.pl
index 742bd57e28..f6368ab1d3 100644
--- a/src/test/recovery/t/029_stats_restart.pl
+++ b/src/test/recovery/t/029_stats_restart.pl
@@ -173,7 +173,7 @@ is($wal_start->{reset}, $wal_restart->{reset},
 
 ## Check that checkpoint stats are reset, WAL stats aren't affected
 
-$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('bgwriter')");
+$node->safe_psql($connect_db, "SELECT pg_stat_reset_shared('checkpointer')");
 
 $sect = "post ckpt reset";
 my $ckpt_reset = checkpoint_stats();
@@ -323,9 +323,9 @@ sub checkpoint_stats
 	my %results;
 
 	$results{count} = $node->safe_psql($connect_db,
-		"SELECT checkpoints_timed + checkpoints_req FROM pg_stat_bgwriter");
+		"SELECT num_timed + num_requested FROM pg_stat_checkpointer");
 	$results{reset} = $node->safe_psql($connect_db,
-		"SELECT stats_reset FROM pg_stat_bgwriter");
+		"SELECT stats_reset FROM pg_stat_checkpointer");
 
 	return \%results;
 }
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 798d1610f2..1442c43d9c 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1816,15 +1816,16 @@ pg_stat_archiver| SELECT archived_count,
     last_failed_time,
     stats_reset
    FROM pg_stat_get_archiver() s(archived_count, last_archived_wal, last_archived_time, failed_count, last_failed_wal, last_failed_time, stats_reset);
-pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_timed_checkpoints() AS checkpoints_timed,
-    pg_stat_get_bgwriter_requested_checkpoints() AS checkpoints_req,
-    pg_stat_get_checkpoint_write_time() AS checkpoint_write_time,
-    pg_stat_get_checkpoint_sync_time() AS checkpoint_sync_time,
-    pg_stat_get_bgwriter_buf_written_checkpoints() AS buffers_checkpoint,
-    pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
+pg_stat_bgwriter| SELECT pg_stat_get_bgwriter_buf_written_clean() AS buffers_clean,
     pg_stat_get_bgwriter_maxwritten_clean() AS maxwritten_clean,
     pg_stat_get_buf_alloc() AS buffers_alloc,
     pg_stat_get_bgwriter_stat_reset_time() AS stats_reset;
+pg_stat_checkpointer| SELECT pg_stat_get_checkpointer_num_timed() AS num_timed,
+    pg_stat_get_checkpointer_num_requested() AS num_requested,
+    pg_stat_get_checkpointer_write_time() AS write_time,
+    pg_stat_get_checkpointer_sync_time() AS sync_time,
+    pg_stat_get_checkpointer_buffers_written() AS buffers_written,
+    pg_stat_get_checkpointer_stat_reset_time() AS stats_reset;
 pg_stat_database| SELECT oid AS datid,
     datname,
         CASE
diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 94187e59cf..d79a5de009 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -828,8 +828,8 @@ SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
  t
 (1 row)
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT num_requested AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
@@ -839,7 +839,7 @@ DROP TABLE test_stats_temp;
 -- results of the first.
 CHECKPOINT;
 CHECKPOINT;
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
  ?column? 
 ----------
  t
@@ -930,6 +930,21 @@ SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 (1 row)
 
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 1e21e55c6d..055b52a90c 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -417,8 +417,8 @@ SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELEC
 SELECT pg_stat_force_next_flush();
 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
 
--- Test pg_stat_bgwriter checkpointer-related stats, together with pg_stat_wal
-SELECT checkpoints_req AS rqst_ckpts_before FROM pg_stat_bgwriter \gset
+-- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
+SELECT num_requested AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
 
 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
@@ -432,7 +432,7 @@ DROP TABLE test_stats_temp;
 CHECKPOINT;
 CHECKPOINT;
 
-SELECT checkpoints_req > :rqst_ckpts_before FROM pg_stat_bgwriter;
+SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
 
 -- Test pg_stat_get_backend_idset() and some allied functions.
@@ -470,6 +470,12 @@ SELECT pg_stat_reset_shared('bgwriter');
 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
 
+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+
 -- Test that reset_shared with wal specified as the stats type works
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 SELECT pg_stat_reset_shared('wal');
-- 
2.34.1

#35Michael Paquier
michael@paquier.xyz
In reply to: Bharath Rupireddy (#34)
Re: Introduce a new view for checkpointer related stats

On Fri, Oct 27, 2023 at 10:23:34AM +0530, Bharath Rupireddy wrote:

A possible way is to move existing pgstat_count_slru_flush in
SimpleLruWriteAll closer to pg_fsync and WAIT_EVENT_SLRU_SYNC in
SlruPhysicalWritePage, remove WAIT_EVENT_SLRU_FLUSH_SYNC completely,
use WAIT_EVENT_SLRU_SYNC in SlruSyncFileTag and count the flushes in
SlruSyncFileTag. This aggregated way is much simpler IMV.

Another possible way is to have separate stat variables for each of
the SLRU flushes WAIT_EVENT_SLRU_SYNC and WAIT_EVENT_SLRU_FLUSH_SYNC
and expose them separately in pg_stat_slru. I don't like this
approach.

This touches an area covered by a different patch, registered in this
commit fest as well:
/messages/by-id/CAMm1aWb18EpT0whJrjG+-nyhNouXET6ZUw0pNYYAe+NezpvsAA@mail.gmail.com

So perhaps we'd better move the discussion there. The patch posted
there is going to need a rebase anyway once the split with
pg_stat_checkpointer is introduced.

The error message generated for an incorrect target needs to be
updated in pg_stat_reset_shared():
=# select pg_stat_reset_shared('checkpointe');
ERROR: 22023: unrecognized reset target: "checkpointe"
HINT: Target must be "archiver", "bgwriter", "io", "recovery_prefetch", or "wal".

+1. Changed in the attached v10-001. FWIW, having a test case in
stats.sql emitting this error message and hint would have helped here.
If okay, I can add one.

PS: I'll park the SLRU flush related patch aside until the approach is
finalized. I'm posting the pg_stat_checkpointer patch as v10-0001.

Thanks. That seems OK. I don't have the wits to risk my weekend on
buildfarm failures if any, so that will have to wait a bit.
--
Michael

#36Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Michael Paquier (#35)
Re: Introduce a new view for checkpointer related stats

On Fri, Oct 27, 2023 at 10:32 AM Michael Paquier <michael@paquier.xyz> wrote:

On Fri, Oct 27, 2023 at 10:23:34AM +0530, Bharath Rupireddy wrote:

A possible way is to move existing pgstat_count_slru_flush in
SimpleLruWriteAll closer to pg_fsync and WAIT_EVENT_SLRU_SYNC in
SlruPhysicalWritePage, remove WAIT_EVENT_SLRU_FLUSH_SYNC completely,
use WAIT_EVENT_SLRU_SYNC in SlruSyncFileTag and count the flushes in
SlruSyncFileTag. This aggregated way is much simpler IMV.

Another possible way is to have separate stat variables for each of
the SLRU flushes WAIT_EVENT_SLRU_SYNC and WAIT_EVENT_SLRU_FLUSH_SYNC
and expose them separately in pg_stat_slru. I don't like this
approach.

This touches an area covered by a different patch, registered in this
commit fest as well:
/messages/by-id/CAMm1aWb18EpT0whJrjG+-nyhNouXET6ZUw0pNYYAe+NezpvsAA@mail.gmail.com

So perhaps we'd better move the discussion there. The patch posted
there is going to need a rebase anyway once the split with
pg_stat_checkpointer is introduced.

Yeah, I'll re-look at the SLRU stuff and the other thread next week.

finalized. I'm posting the pg_stat_checkpointer patch as v10-0001.

Thanks. That seems OK. I don't have the wits to risk my weekend on
buildfarm failures if any, so that will have to wait a bit.

Hm, okay :)

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

#37Michael Paquier
michael@paquier.xyz
In reply to: Bharath Rupireddy (#34)
Re: Introduce a new view for checkpointer related stats

On Fri, Oct 27, 2023 at 10:23:34AM +0530, Bharath Rupireddy wrote:

+1. Changed in the attached v10-001. FWIW, having a test case in
stats.sql emitting this error message and hint would have helped here.
If okay, I can add one.

That may be something to do. At least it was missed on this thread,
even if we don't add a new pgstat shared type every day.

PS: I'll park the SLRU flush related patch aside until the approach is
finalized. I'm posting the pg_stat_checkpointer patch as v10-0001.

+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset

Note that you have forgotten to update the test of
pg_stat_reset_shared(NULL) to check for the value of
checkpointer_reset_ts. I've added an extra SELECT to check that for
pg_stat_checkpointer, and applied v8.
--
Michael

#38Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Michael Paquier (#37)
2 attachment(s)
Re: Introduce a new view for checkpointer related stats

On Mon, Oct 30, 2023 at 6:19 AM Michael Paquier <michael@paquier.xyz> wrote:

On Fri, Oct 27, 2023 at 10:23:34AM +0530, Bharath Rupireddy wrote:

+1. Changed in the attached v10-001. FWIW, having a test case in
stats.sql emitting this error message and hint would have helped here.
If okay, I can add one.

That may be something to do. At least it was missed on this thread,
even if we don't add a new pgstat shared type every day.

Right. Adding test coverage for the error-case is no bad IMV
(https://coverage.postgresql.org/src/backend/utils/adt/pgstatfuncs.c.gcov.html).
Here's the attached 0001 patch for that.

PS: I'll park the SLRU flush related patch aside until the approach is
finalized. I'm posting the pg_stat_checkpointer patch as v10-0001.

+-- Test that reset_shared with checkpointer specified as the stats type works
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
+SELECT pg_stat_reset_shared('checkpointer');
+SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
+SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset

Note that you have forgotten to update the test of
pg_stat_reset_shared(NULL) to check for the value of
checkpointer_reset_ts. I've added an extra SELECT to check that for
pg_stat_checkpointer, and applied v8.

Oh, thanks for taking care of this. While at it, I noticed that
there's no coverage for pg_stat_reset_shared('recovery_prefetch') and
XLogPrefetchResetStats()
https://coverage.postgresql.org/src/backend/access/transam/xlogprefetcher.c.gcov.html.
Most of the recovery_prefetch code is covered with recovery/streaming
related tests, but the reset stats part is missing. So, I've added
coverage for it in the attached 0002.

--
Bharath Rupireddy
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachments:

v1-0001-Add-error-case-test-for-pg_stat_reset_shared-with.patchapplication/octet-stream; name=v1-0001-Add-error-case-test-for-pg_stat_reset_shared-with.patchDownload
From d679aa38b5d7e828ac7eef4a239e9da3fbdc0704 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Mon, 30 Oct 2023 05:31:03 +0000
Subject: [PATCH v1] Add error case test for pg_stat_reset_shared with unknown
 stats type

This commit adds an error case test for pg_stat_reset_shared with an
unknown stats type to help with the code coverage a bit.
---
 src/test/regress/expected/stats.out | 4 ++++
 src/test/regress/sql/stats.sql      | 3 +++
 2 files changed, 7 insertions(+)

diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 32ad7f3dcc..53b632dcd3 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -991,6 +991,10 @@ SELECT stats_reset = :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
  t
 (1 row)
 
+-- Test error case for reset_shared with unknown stats type
+SELECT pg_stat_reset_shared('unknown');
+ERROR:  unrecognized reset target: "unknown"
+HINT:  Target must be "archiver", "bgwriter", "checkpointer", "io", "recovery_prefetch", or "wal".
 -- Test that reset works for pg_stat_database
 -- Since pg_stat_database stats_reset starts out as NULL, reset it once first so we have something to compare it to
 SELECT pg_stat_reset();
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index 8bfeed607f..febb83add0 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -489,6 +489,9 @@ SELECT stats_reset = :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset = :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
 SELECT stats_reset = :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
 
+-- Test error case for reset_shared with unknown stats type
+SELECT pg_stat_reset_shared('unknown');
+
 -- Test that reset works for pg_stat_database
 
 -- Since pg_stat_database stats_reset starts out as NULL, reset it once first so we have something to compare it to
-- 
2.34.1

v1-0002-Add-test-for-resetting-recovery_prefetch-shared-s.patchapplication/octet-stream; name=v1-0002-Add-test-for-resetting-recovery_prefetch-shared-s.patchDownload
From 71bcf31a76e56502086e5b60cfbfba5e9c64cb23 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Mon, 30 Oct 2023 06:27:11 +0000
Subject: [PATCH v1] Add test for resetting recovery_prefetch shared stats

This commit adds test for resetting recovery_prefetch shared stats
to help with the code coverage of XLogPrefetchResetStats().
---
 src/test/regress/expected/stats.out | 21 +++++++++++++++++++++
 src/test/regress/sql/stats.sql      |  7 +++++++
 2 files changed, 28 insertions(+)

diff --git a/src/test/regress/expected/stats.out b/src/test/regress/expected/stats.out
index 53b632dcd3..65997334be 100644
--- a/src/test/regress/expected/stats.out
+++ b/src/test/regress/expected/stats.out
@@ -960,6 +960,21 @@ SELECT stats_reset > :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
 (1 row)
 
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
+-- Test that reset_shared with recovery_prefetch specified as the stats type works
+SELECT stats_reset AS recovery_prefetch_reset_ts FROM pg_stat_recovery_prefetch \gset
+SELECT pg_stat_reset_shared('recovery_prefetch');
+ pg_stat_reset_shared 
+----------------------
+ 
+(1 row)
+
+SELECT stats_reset > :'recovery_prefetch_reset_ts'::timestamptz FROM pg_stat_recovery_prefetch;
+ ?column? 
+----------
+ t
+(1 row)
+
+SELECT stats_reset AS recovery_prefetch_reset_ts FROM pg_stat_recovery_prefetch \gset
 -- Test that reset_shared with no specified stats type doesn't reset anything
 SELECT pg_stat_reset_shared(NULL);
  pg_stat_reset_shared 
@@ -991,6 +1006,12 @@ SELECT stats_reset = :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
  t
 (1 row)
 
+SELECT stats_reset = :'recovery_prefetch_reset_ts'::timestamptz FROM pg_stat_recovery_prefetch;
+ ?column? 
+----------
+ t
+(1 row)
+
 -- Test error case for reset_shared with unknown stats type
 SELECT pg_stat_reset_shared('unknown');
 ERROR:  unrecognized reset target: "unknown"
diff --git a/src/test/regress/sql/stats.sql b/src/test/regress/sql/stats.sql
index febb83add0..498e32de7a 100644
--- a/src/test/regress/sql/stats.sql
+++ b/src/test/regress/sql/stats.sql
@@ -482,12 +482,19 @@ SELECT pg_stat_reset_shared('wal');
 SELECT stats_reset > :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
 
+-- Test that reset_shared with recovery_prefetch specified as the stats type works
+SELECT stats_reset AS recovery_prefetch_reset_ts FROM pg_stat_recovery_prefetch \gset
+SELECT pg_stat_reset_shared('recovery_prefetch');
+SELECT stats_reset > :'recovery_prefetch_reset_ts'::timestamptz FROM pg_stat_recovery_prefetch;
+SELECT stats_reset AS recovery_prefetch_reset_ts FROM pg_stat_recovery_prefetch \gset
+
 -- Test that reset_shared with no specified stats type doesn't reset anything
 SELECT pg_stat_reset_shared(NULL);
 SELECT stats_reset = :'archiver_reset_ts'::timestamptz FROM pg_stat_archiver;
 SELECT stats_reset = :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
 SELECT stats_reset = :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
 SELECT stats_reset = :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
+SELECT stats_reset = :'recovery_prefetch_reset_ts'::timestamptz FROM pg_stat_recovery_prefetch;
 
 -- Test error case for reset_shared with unknown stats type
 SELECT pg_stat_reset_shared('unknown');
-- 
2.34.1

#39Michael Paquier
michael@paquier.xyz
In reply to: Bharath Rupireddy (#38)
Re: Introduce a new view for checkpointer related stats

On Mon, Oct 30, 2023 at 11:59:10AM +0530, Bharath Rupireddy wrote:

Oh, thanks for taking care of this. While at it, I noticed that
there's no coverage for pg_stat_reset_shared('recovery_prefetch') and
XLogPrefetchResetStats()
https://coverage.postgresql.org/src/backend/access/transam/xlogprefetcher.c.gcov.html.
Most of the recovery_prefetch code is covered with recovery/streaming
related tests, but the reset stats part is missing. So, I've added
coverage for it in the attached 0002.

Indeed, good catch. I didn't notice the hole in the coverage reports.
I have merged 0001 and 0002 together, and applied them as of
5b2147d9fcc1.
--
Michael