Hi,

This grew out of my patch to split the waits event code out of
pgstat.[ch], which in turn grew out of the shared memory stats patch
series.


pgstat_report_wait_start() and pgstat_report_wait_end() currently check
pgstat_track_activities before assigning to MyProc->wait_event_info.
Given the small cost of the assignment, and that pgstat_track_activities
is almost always used, I'm doubtful that that's the right tradeoff.

Normally I would say that branch prediction will take care of this cost
- but because pgstat_report_wait_{start,end} are inlined, that has to
happen in each of the calling locations.

The code works out to be something like the following (this is from
basebackup_read_file, the simplest caller I could quickly find, I
removed interspersed code from it):

267             if (!pgstat_track_activities || !proc)
   0x0000000000430e4d <+13>:    cmpb   $0x1,0x4882e1(%rip)        # 0x8b9135 
<pgstat_track_activities>

265             volatile PGPROC *proc = MyProc;
   0x0000000000430e54 <+20>:    mov    0x48c52d(%rip),%rax        # 0x8bd388 
<MyProc>

266
267             if (!pgstat_track_activities || !proc)
   0x0000000000430e5b <+27>:    jne    0x430e6c <basebackup_read_file+44>
   0x0000000000430e5d <+29>:    test   %rax,%rax
   0x0000000000430e60 <+32>:    je     0x430e6c <basebackup_read_file+44>

268                     return;
269
270             /*
271              * Since this is a four-byte field which is always read and 
written as
272              * four-bytes, updates are atomic.
273              */
274             proc->wait_event_info = wait_event_info;
   0x0000000000430e62 <+34>:    movl   $0xa000000,0x2c8(%rax)

/home/andres/src/postgresql/src/backend/replication/basebackup.c:
2014            rc = pg_pread(fd, buf, nbytes, offset);
   0x0000000000430e6c <+44>:    call   0xc4790 <pread@plt>

stripping the source:
   0x0000000000430e4d <+13>:    cmpb   $0x1,0x4882e1(%rip)        # 0x8b9135 
<pgstat_track_activities>
   0x0000000000430e54 <+20>:    mov    0x48c52d(%rip),%rax        # 0x8bd388 
<MyProc>
   0x0000000000430e5b <+27>:    jne    0x430e6c <basebackup_read_file+44>
   0x0000000000430e5d <+29>:    test   %rax,%rax
   0x0000000000430e60 <+32>:    je     0x430e6c <basebackup_read_file+44>
   0x0000000000430e62 <+34>:    movl   $0xa000000,0x2c8(%rax)
   0x0000000000430e6c <+44>:    call   0xc4790 <pread@plt>


just removing the pgstat_track_activities check turns that into

   0x0000000000430d8d <+13>:    mov    0x48c5f4(%rip),%rax        # 0x8bd388 
<MyProc>
   0x0000000000430d94 <+20>:    test   %rax,%rax
   0x0000000000430d97 <+23>:    je     0x430da3 <basebackup_read_file+35>
   0x0000000000430d99 <+25>:    movl   $0xa000000,0x2c8(%rax)
   0x0000000000430da3 <+35>:    call   0xc4790 <pread@plt>

which does seem (a bit) nicer.

However, we can improve this further, entirely eliminating branches, by
introducing something like "my_wait_event_info" that initially just
points to a local variable and is switched to shared once MyProc is
assigned.

Obviously incorrect, for comparison: Just removing the MyProc != NULL
check yields:
   0x0000000000430bcd <+13>:    mov    0x48c7b4(%rip),%rax        # 0x8bd388 
<MyProc>
   0x0000000000430bd4 <+20>:    movl   $0xa000000,0x2c8(%rax)
   0x0000000000430bde <+30>:    call   0xc47d0 <pread@plt>

using a uint32 *my_wait_event_info yields:
   0x0000000000430b4d <+13>:    mov    0x47615c(%rip),%rax        # 0x8a6cb0 
<my_wait_event_info>
   0x0000000000430b54 <+20>:    movl   $0xa000000,(%rax)
   0x0000000000430b5a <+26>:    call   0xc47d0 <pread@plt>

Note how the lack of offset addressing in the my_wait_event_info version
makes the instruction smaller (call is at 26 instead of 30).


Now, perhaps all of this isn't worth optimizing, most of the things done
within pgstat_report_wait_start()/end() are expensive-ish. And forward
branches are statically predicted to be not taken on several
platforms. I have seen this these instructions show up in profiles in
workloads with contended lwlocks at least...

There's also a small win in code size:
   text    data     bss     dec     hex filename
8932095  192160  204656 9328911  8e590f src/backend/postgres
8928544  192160  204656 9325360  8e4b30 src/backend/postgres_my_wait_event_info


If we went for the my_wait_event_info approach there is one further
advantage, after my change to move the wait event code into a separate
file: wait_event.h does not need to include proc.h anymore, which seems
architecturally nice for things like fd.c.


Attached is patch series doing this.


I'm inclined to separately change the comment format for
wait_event.[ch], there's no no reason to stick with the current style:

/* ----------
 * pgstat_report_wait_start() -
 *
 *      Called from places where server process needs to wait.  This is called
 *      to report wait event information.  The wait information is stored
 *      as 4-bytes where first byte represents the wait event class (type of
 *      wait, for different types of wait, refer WaitClass) and the next
 *      3-bytes represent the actual wait event.  Currently 2-bytes are used
 *      for wait event which is sufficient for current usage, 1-byte is
 *      reserved for future usage.
 *
 * NB: this *must* be able to survive being called before MyProc has been
 * initialized.
 * ----------
 */

I.e. I'd like to remove the ----- framing, the repetition of the
function name, and the varying indentation in the comment.

Greetings,

Andres Freund
>From 017fd5b2ba6e6cdf5c9dd544a73095a3173dc6b8 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Fri, 2 Apr 2021 11:50:11 -0700
Subject: [PATCH v2 1/3] Split wait events out of pgstat.[ch].

---
 src/include/pgstat.h                    | 274 +---------
 src/include/utils/wait_event.h          | 302 +++++++++++
 src/backend/postmaster/pgstat.c         | 673 -----------------------
 src/backend/utils/Makefile              |  15 +-
 src/backend/utils/activity/Makefile     |  19 +
 src/backend/utils/activity/wait_event.c | 690 ++++++++++++++++++++++++
 6 files changed, 1026 insertions(+), 947 deletions(-)
 create mode 100644 src/include/utils/wait_event.h
 create mode 100644 src/backend/utils/activity/Makefile
 create mode 100644 src/backend/utils/activity/wait_event.c

diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index fe6683cf5c8..3247c7b8ad0 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -17,9 +17,9 @@
 #include "port/atomics.h"
 #include "portability/instr_time.h"
 #include "postmaster/pgarch.h"
-#include "storage/proc.h"
 #include "utils/hsearch.h"
 #include "utils/relcache.h"
+#include "utils/wait_event.h" /* for backward compatibility */
 
 
 /* ----------
@@ -897,222 +897,6 @@ typedef enum BackendState
 	STATE_DISABLED
 } BackendState;
 
-
-/* ----------
- * Wait Classes
- * ----------
- */
-#define PG_WAIT_LWLOCK				0x01000000U
-#define PG_WAIT_LOCK				0x03000000U
-#define PG_WAIT_BUFFER_PIN			0x04000000U
-#define PG_WAIT_ACTIVITY			0x05000000U
-#define PG_WAIT_CLIENT				0x06000000U
-#define PG_WAIT_EXTENSION			0x07000000U
-#define PG_WAIT_IPC					0x08000000U
-#define PG_WAIT_TIMEOUT				0x09000000U
-#define PG_WAIT_IO					0x0A000000U
-
-/* ----------
- * Wait Events - Activity
- *
- * Use this category when a process is waiting because it has no work to do,
- * unless the "Client" or "Timeout" category describes the situation better.
- * Typically, this should only be used for background processes.
- * ----------
- */
-typedef enum
-{
-	WAIT_EVENT_ARCHIVER_MAIN = PG_WAIT_ACTIVITY,
-	WAIT_EVENT_AUTOVACUUM_MAIN,
-	WAIT_EVENT_BGWRITER_HIBERNATE,
-	WAIT_EVENT_BGWRITER_MAIN,
-	WAIT_EVENT_CHECKPOINTER_MAIN,
-	WAIT_EVENT_LOGICAL_APPLY_MAIN,
-	WAIT_EVENT_LOGICAL_LAUNCHER_MAIN,
-	WAIT_EVENT_PGSTAT_MAIN,
-	WAIT_EVENT_RECOVERY_WAL_STREAM,
-	WAIT_EVENT_SYSLOGGER_MAIN,
-	WAIT_EVENT_WAL_RECEIVER_MAIN,
-	WAIT_EVENT_WAL_SENDER_MAIN,
-	WAIT_EVENT_WAL_WRITER_MAIN
-} WaitEventActivity;
-
-/* ----------
- * Wait Events - Client
- *
- * Use this category when a process is waiting to send data to or receive data
- * from the frontend process to which it is connected.  This is never used for
- * a background process, which has no client connection.
- * ----------
- */
-typedef enum
-{
-	WAIT_EVENT_CLIENT_READ = PG_WAIT_CLIENT,
-	WAIT_EVENT_CLIENT_WRITE,
-	WAIT_EVENT_GSS_OPEN_SERVER,
-	WAIT_EVENT_LIBPQWALRECEIVER_CONNECT,
-	WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE,
-	WAIT_EVENT_SSL_OPEN_SERVER,
-	WAIT_EVENT_WAL_SENDER_WAIT_WAL,
-	WAIT_EVENT_WAL_SENDER_WRITE_DATA,
-} WaitEventClient;
-
-/* ----------
- * Wait Events - IPC
- *
- * Use this category when a process cannot complete the work it is doing because
- * it is waiting for a notification from another process.
- * ----------
- */
-typedef enum
-{
-	WAIT_EVENT_APPEND_READY = PG_WAIT_IPC,
-	WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE,
-	WAIT_EVENT_BGWORKER_SHUTDOWN,
-	WAIT_EVENT_BGWORKER_STARTUP,
-	WAIT_EVENT_BTREE_PAGE,
-	WAIT_EVENT_BUFFER_IO,
-	WAIT_EVENT_CHECKPOINT_DONE,
-	WAIT_EVENT_CHECKPOINT_START,
-	WAIT_EVENT_EXECUTE_GATHER,
-	WAIT_EVENT_HASH_BATCH_ALLOCATE,
-	WAIT_EVENT_HASH_BATCH_ELECT,
-	WAIT_EVENT_HASH_BATCH_LOAD,
-	WAIT_EVENT_HASH_BUILD_ALLOCATE,
-	WAIT_EVENT_HASH_BUILD_ELECT,
-	WAIT_EVENT_HASH_BUILD_HASH_INNER,
-	WAIT_EVENT_HASH_BUILD_HASH_OUTER,
-	WAIT_EVENT_HASH_GROW_BATCHES_ALLOCATE,
-	WAIT_EVENT_HASH_GROW_BATCHES_DECIDE,
-	WAIT_EVENT_HASH_GROW_BATCHES_ELECT,
-	WAIT_EVENT_HASH_GROW_BATCHES_FINISH,
-	WAIT_EVENT_HASH_GROW_BATCHES_REPARTITION,
-	WAIT_EVENT_HASH_GROW_BUCKETS_ALLOCATE,
-	WAIT_EVENT_HASH_GROW_BUCKETS_ELECT,
-	WAIT_EVENT_HASH_GROW_BUCKETS_REINSERT,
-	WAIT_EVENT_LOGICAL_SYNC_DATA,
-	WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE,
-	WAIT_EVENT_MQ_INTERNAL,
-	WAIT_EVENT_MQ_PUT_MESSAGE,
-	WAIT_EVENT_MQ_RECEIVE,
-	WAIT_EVENT_MQ_SEND,
-	WAIT_EVENT_PARALLEL_BITMAP_SCAN,
-	WAIT_EVENT_PARALLEL_CREATE_INDEX_SCAN,
-	WAIT_EVENT_PARALLEL_FINISH,
-	WAIT_EVENT_PROCARRAY_GROUP_UPDATE,
-	WAIT_EVENT_PROC_SIGNAL_BARRIER,
-	WAIT_EVENT_PROMOTE,
-	WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT,
-	WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE,
-	WAIT_EVENT_RECOVERY_PAUSE,
-	WAIT_EVENT_REPLICATION_ORIGIN_DROP,
-	WAIT_EVENT_REPLICATION_SLOT_DROP,
-	WAIT_EVENT_SAFE_SNAPSHOT,
-	WAIT_EVENT_SYNC_REP,
-	WAIT_EVENT_WAL_RECEIVER_EXIT,
-	WAIT_EVENT_WAL_RECEIVER_WAIT_START,
-	WAIT_EVENT_XACT_GROUP_UPDATE
-} WaitEventIPC;
-
-/* ----------
- * Wait Events - Timeout
- *
- * Use this category when a process is waiting for a timeout to expire.
- * ----------
- */
-typedef enum
-{
-	WAIT_EVENT_BASE_BACKUP_THROTTLE = PG_WAIT_TIMEOUT,
-	WAIT_EVENT_PG_SLEEP,
-	WAIT_EVENT_RECOVERY_APPLY_DELAY,
-	WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL,
-	WAIT_EVENT_VACUUM_DELAY
-} WaitEventTimeout;
-
-/* ----------
- * Wait Events - IO
- *
- * Use this category when a process is waiting for a IO.
- * ----------
- */
-typedef enum
-{
-	WAIT_EVENT_BASEBACKUP_READ = PG_WAIT_IO,
-	WAIT_EVENT_BUFFILE_READ,
-	WAIT_EVENT_BUFFILE_WRITE,
-	WAIT_EVENT_BUFFILE_TRUNCATE,
-	WAIT_EVENT_CONTROL_FILE_READ,
-	WAIT_EVENT_CONTROL_FILE_SYNC,
-	WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE,
-	WAIT_EVENT_CONTROL_FILE_WRITE,
-	WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE,
-	WAIT_EVENT_COPY_FILE_READ,
-	WAIT_EVENT_COPY_FILE_WRITE,
-	WAIT_EVENT_DATA_FILE_EXTEND,
-	WAIT_EVENT_DATA_FILE_FLUSH,
-	WAIT_EVENT_DATA_FILE_IMMEDIATE_SYNC,
-	WAIT_EVENT_DATA_FILE_PREFETCH,
-	WAIT_EVENT_DATA_FILE_READ,
-	WAIT_EVENT_DATA_FILE_SYNC,
-	WAIT_EVENT_DATA_FILE_TRUNCATE,
-	WAIT_EVENT_DATA_FILE_WRITE,
-	WAIT_EVENT_DSM_FILL_ZERO_WRITE,
-	WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ,
-	WAIT_EVENT_LOCK_FILE_ADDTODATADIR_SYNC,
-	WAIT_EVENT_LOCK_FILE_ADDTODATADIR_WRITE,
-	WAIT_EVENT_LOCK_FILE_CREATE_READ,
-	WAIT_EVENT_LOCK_FILE_CREATE_SYNC,
-	WAIT_EVENT_LOCK_FILE_CREATE_WRITE,
-	WAIT_EVENT_LOCK_FILE_RECHECKDATADIR_READ,
-	WAIT_EVENT_LOGICAL_REWRITE_CHECKPOINT_SYNC,
-	WAIT_EVENT_LOGICAL_REWRITE_MAPPING_SYNC,
-	WAIT_EVENT_LOGICAL_REWRITE_MAPPING_WRITE,
-	WAIT_EVENT_LOGICAL_REWRITE_SYNC,
-	WAIT_EVENT_LOGICAL_REWRITE_TRUNCATE,
-	WAIT_EVENT_LOGICAL_REWRITE_WRITE,
-	WAIT_EVENT_RELATION_MAP_READ,
-	WAIT_EVENT_RELATION_MAP_SYNC,
-	WAIT_EVENT_RELATION_MAP_WRITE,
-	WAIT_EVENT_REORDER_BUFFER_READ,
-	WAIT_EVENT_REORDER_BUFFER_WRITE,
-	WAIT_EVENT_REORDER_LOGICAL_MAPPING_READ,
-	WAIT_EVENT_REPLICATION_SLOT_READ,
-	WAIT_EVENT_REPLICATION_SLOT_RESTORE_SYNC,
-	WAIT_EVENT_REPLICATION_SLOT_SYNC,
-	WAIT_EVENT_REPLICATION_SLOT_WRITE,
-	WAIT_EVENT_SLRU_FLUSH_SYNC,
-	WAIT_EVENT_SLRU_READ,
-	WAIT_EVENT_SLRU_SYNC,
-	WAIT_EVENT_SLRU_WRITE,
-	WAIT_EVENT_SNAPBUILD_READ,
-	WAIT_EVENT_SNAPBUILD_SYNC,
-	WAIT_EVENT_SNAPBUILD_WRITE,
-	WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC,
-	WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE,
-	WAIT_EVENT_TIMELINE_HISTORY_READ,
-	WAIT_EVENT_TIMELINE_HISTORY_SYNC,
-	WAIT_EVENT_TIMELINE_HISTORY_WRITE,
-	WAIT_EVENT_TWOPHASE_FILE_READ,
-	WAIT_EVENT_TWOPHASE_FILE_SYNC,
-	WAIT_EVENT_TWOPHASE_FILE_WRITE,
-	WAIT_EVENT_WALSENDER_TIMELINE_HISTORY_READ,
-	WAIT_EVENT_WAL_BOOTSTRAP_SYNC,
-	WAIT_EVENT_WAL_BOOTSTRAP_WRITE,
-	WAIT_EVENT_WAL_COPY_READ,
-	WAIT_EVENT_WAL_COPY_SYNC,
-	WAIT_EVENT_WAL_COPY_WRITE,
-	WAIT_EVENT_WAL_INIT_SYNC,
-	WAIT_EVENT_WAL_INIT_WRITE,
-	WAIT_EVENT_WAL_READ,
-	WAIT_EVENT_WAL_SYNC,
-	WAIT_EVENT_WAL_SYNC_METHOD_ASSIGN,
-	WAIT_EVENT_WAL_WRITE,
-	WAIT_EVENT_LOGICAL_CHANGES_READ,
-	WAIT_EVENT_LOGICAL_CHANGES_WRITE,
-	WAIT_EVENT_LOGICAL_SUBXACT_READ,
-	WAIT_EVENT_LOGICAL_SUBXACT_WRITE
-} WaitEventIO;
-
 /* ----------
  * Command type for progress reporting purposes
  * ----------
@@ -1463,8 +1247,6 @@ extern void pgstat_report_activity(BackendState state, const char *cmd_str);
 extern void pgstat_report_tempfile(size_t filesize);
 extern void pgstat_report_appname(const char *appname);
 extern void pgstat_report_xact_timestamp(TimestampTz tstamp);
-extern const char *pgstat_get_wait_event(uint32 wait_event_info);
-extern const char *pgstat_get_wait_event_type(uint32 wait_event_info);
 extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
 extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
 													   int buflen);
@@ -1483,60 +1265,6 @@ extern void pgstat_initstats(Relation rel);
 
 extern char *pgstat_clip_activity(const char *raw_activity);
 
-/* ----------
- * pgstat_report_wait_start() -
- *
- *	Called from places where server process needs to wait.  This is called
- *	to report wait event information.  The wait information is stored
- *	as 4-bytes where first byte represents the wait event class (type of
- *	wait, for different types of wait, refer WaitClass) and the next
- *	3-bytes represent the actual wait event.  Currently 2-bytes are used
- *	for wait event which is sufficient for current usage, 1-byte is
- *	reserved for future usage.
- *
- * NB: this *must* be able to survive being called before MyProc has been
- * initialized.
- * ----------
- */
-static inline void
-pgstat_report_wait_start(uint32 wait_event_info)
-{
-	volatile PGPROC *proc = MyProc;
-
-	if (!pgstat_track_activities || !proc)
-		return;
-
-	/*
-	 * Since this is a four-byte field which is always read and written as
-	 * four-bytes, updates are atomic.
-	 */
-	proc->wait_event_info = wait_event_info;
-}
-
-/* ----------
- * pgstat_report_wait_end() -
- *
- *	Called to report end of a wait.
- *
- * NB: this *must* be able to survive being called before MyProc has been
- * initialized.
- * ----------
- */
-static inline void
-pgstat_report_wait_end(void)
-{
-	volatile PGPROC *proc = MyProc;
-
-	if (!pgstat_track_activities || !proc)
-		return;
-
-	/*
-	 * Since this is a four-byte field which is always read and written as
-	 * four-bytes, updates are atomic.
-	 */
-	proc->wait_event_info = 0;
-}
-
 /* nontransactional event counts are simple enough to inline */
 
 #define pgstat_count_heap_scan(rel)									\
diff --git a/src/include/utils/wait_event.h b/src/include/utils/wait_event.h
new file mode 100644
index 00000000000..2d6abfcb3f8
--- /dev/null
+++ b/src/include/utils/wait_event.h
@@ -0,0 +1,302 @@
+/* ----------
+ *	wait_event.h
+ *
+ *	Definitions related to postgres wait event reporting
+ *
+ *	Copyright (c) 2001-2021, PostgreSQL Global Development Group
+ *
+ *	src/include/utils/wait_event.h
+ * ----------
+ */
+#ifndef WAIT_EVENT_H
+#define WAIT_EVENT_H
+
+
+#include "storage/proc.h" /* for MyProc */
+
+
+/* ----------
+ * Wait Classes
+ * ----------
+ */
+#define PG_WAIT_LWLOCK				0x01000000U
+#define PG_WAIT_LOCK				0x03000000U
+#define PG_WAIT_BUFFER_PIN			0x04000000U
+#define PG_WAIT_ACTIVITY			0x05000000U
+#define PG_WAIT_CLIENT				0x06000000U
+#define PG_WAIT_EXTENSION			0x07000000U
+#define PG_WAIT_IPC					0x08000000U
+#define PG_WAIT_TIMEOUT				0x09000000U
+#define PG_WAIT_IO					0x0A000000U
+
+/* ----------
+ * Wait Events - Activity
+ *
+ * Use this category when a process is waiting because it has no work to do,
+ * unless the "Client" or "Timeout" category describes the situation better.
+ * Typically, this should only be used for background processes.
+ * ----------
+ */
+typedef enum
+{
+	WAIT_EVENT_ARCHIVER_MAIN = PG_WAIT_ACTIVITY,
+	WAIT_EVENT_AUTOVACUUM_MAIN,
+	WAIT_EVENT_BGWRITER_HIBERNATE,
+	WAIT_EVENT_BGWRITER_MAIN,
+	WAIT_EVENT_CHECKPOINTER_MAIN,
+	WAIT_EVENT_LOGICAL_APPLY_MAIN,
+	WAIT_EVENT_LOGICAL_LAUNCHER_MAIN,
+	WAIT_EVENT_PGSTAT_MAIN,
+	WAIT_EVENT_RECOVERY_WAL_STREAM,
+	WAIT_EVENT_SYSLOGGER_MAIN,
+	WAIT_EVENT_WAL_RECEIVER_MAIN,
+	WAIT_EVENT_WAL_SENDER_MAIN,
+	WAIT_EVENT_WAL_WRITER_MAIN
+} WaitEventActivity;
+
+/* ----------
+ * Wait Events - Client
+ *
+ * Use this category when a process is waiting to send data to or receive data
+ * from the frontend process to which it is connected.  This is never used for
+ * a background process, which has no client connection.
+ * ----------
+ */
+typedef enum
+{
+	WAIT_EVENT_CLIENT_READ = PG_WAIT_CLIENT,
+	WAIT_EVENT_CLIENT_WRITE,
+	WAIT_EVENT_GSS_OPEN_SERVER,
+	WAIT_EVENT_LIBPQWALRECEIVER_CONNECT,
+	WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE,
+	WAIT_EVENT_SSL_OPEN_SERVER,
+	WAIT_EVENT_WAL_SENDER_WAIT_WAL,
+	WAIT_EVENT_WAL_SENDER_WRITE_DATA,
+} WaitEventClient;
+
+/* ----------
+ * Wait Events - IPC
+ *
+ * Use this category when a process cannot complete the work it is doing because
+ * it is waiting for a notification from another process.
+ * ----------
+ */
+typedef enum
+{
+	WAIT_EVENT_APPEND_READY = PG_WAIT_IPC,
+	WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE,
+	WAIT_EVENT_BGWORKER_SHUTDOWN,
+	WAIT_EVENT_BGWORKER_STARTUP,
+	WAIT_EVENT_BTREE_PAGE,
+	WAIT_EVENT_BUFFER_IO,
+	WAIT_EVENT_CHECKPOINT_DONE,
+	WAIT_EVENT_CHECKPOINT_START,
+	WAIT_EVENT_EXECUTE_GATHER,
+	WAIT_EVENT_HASH_BATCH_ALLOCATE,
+	WAIT_EVENT_HASH_BATCH_ELECT,
+	WAIT_EVENT_HASH_BATCH_LOAD,
+	WAIT_EVENT_HASH_BUILD_ALLOCATE,
+	WAIT_EVENT_HASH_BUILD_ELECT,
+	WAIT_EVENT_HASH_BUILD_HASH_INNER,
+	WAIT_EVENT_HASH_BUILD_HASH_OUTER,
+	WAIT_EVENT_HASH_GROW_BATCHES_ALLOCATE,
+	WAIT_EVENT_HASH_GROW_BATCHES_DECIDE,
+	WAIT_EVENT_HASH_GROW_BATCHES_ELECT,
+	WAIT_EVENT_HASH_GROW_BATCHES_FINISH,
+	WAIT_EVENT_HASH_GROW_BATCHES_REPARTITION,
+	WAIT_EVENT_HASH_GROW_BUCKETS_ALLOCATE,
+	WAIT_EVENT_HASH_GROW_BUCKETS_ELECT,
+	WAIT_EVENT_HASH_GROW_BUCKETS_REINSERT,
+	WAIT_EVENT_LOGICAL_SYNC_DATA,
+	WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE,
+	WAIT_EVENT_MQ_INTERNAL,
+	WAIT_EVENT_MQ_PUT_MESSAGE,
+	WAIT_EVENT_MQ_RECEIVE,
+	WAIT_EVENT_MQ_SEND,
+	WAIT_EVENT_PARALLEL_BITMAP_SCAN,
+	WAIT_EVENT_PARALLEL_CREATE_INDEX_SCAN,
+	WAIT_EVENT_PARALLEL_FINISH,
+	WAIT_EVENT_PROCARRAY_GROUP_UPDATE,
+	WAIT_EVENT_PROC_SIGNAL_BARRIER,
+	WAIT_EVENT_PROMOTE,
+	WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT,
+	WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE,
+	WAIT_EVENT_RECOVERY_PAUSE,
+	WAIT_EVENT_REPLICATION_ORIGIN_DROP,
+	WAIT_EVENT_REPLICATION_SLOT_DROP,
+	WAIT_EVENT_SAFE_SNAPSHOT,
+	WAIT_EVENT_SYNC_REP,
+	WAIT_EVENT_WAL_RECEIVER_EXIT,
+	WAIT_EVENT_WAL_RECEIVER_WAIT_START,
+	WAIT_EVENT_XACT_GROUP_UPDATE
+} WaitEventIPC;
+
+/* ----------
+ * Wait Events - Timeout
+ *
+ * Use this category when a process is waiting for a timeout to expire.
+ * ----------
+ */
+typedef enum
+{
+	WAIT_EVENT_BASE_BACKUP_THROTTLE = PG_WAIT_TIMEOUT,
+	WAIT_EVENT_PG_SLEEP,
+	WAIT_EVENT_RECOVERY_APPLY_DELAY,
+	WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL,
+	WAIT_EVENT_VACUUM_DELAY
+} WaitEventTimeout;
+
+/* ----------
+ * Wait Events - IO
+ *
+ * Use this category when a process is waiting for a IO.
+ * ----------
+ */
+typedef enum
+{
+	WAIT_EVENT_BASEBACKUP_READ = PG_WAIT_IO,
+	WAIT_EVENT_BUFFILE_READ,
+	WAIT_EVENT_BUFFILE_WRITE,
+	WAIT_EVENT_BUFFILE_TRUNCATE,
+	WAIT_EVENT_CONTROL_FILE_READ,
+	WAIT_EVENT_CONTROL_FILE_SYNC,
+	WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE,
+	WAIT_EVENT_CONTROL_FILE_WRITE,
+	WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE,
+	WAIT_EVENT_COPY_FILE_READ,
+	WAIT_EVENT_COPY_FILE_WRITE,
+	WAIT_EVENT_DATA_FILE_EXTEND,
+	WAIT_EVENT_DATA_FILE_FLUSH,
+	WAIT_EVENT_DATA_FILE_IMMEDIATE_SYNC,
+	WAIT_EVENT_DATA_FILE_PREFETCH,
+	WAIT_EVENT_DATA_FILE_READ,
+	WAIT_EVENT_DATA_FILE_SYNC,
+	WAIT_EVENT_DATA_FILE_TRUNCATE,
+	WAIT_EVENT_DATA_FILE_WRITE,
+	WAIT_EVENT_DSM_FILL_ZERO_WRITE,
+	WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ,
+	WAIT_EVENT_LOCK_FILE_ADDTODATADIR_SYNC,
+	WAIT_EVENT_LOCK_FILE_ADDTODATADIR_WRITE,
+	WAIT_EVENT_LOCK_FILE_CREATE_READ,
+	WAIT_EVENT_LOCK_FILE_CREATE_SYNC,
+	WAIT_EVENT_LOCK_FILE_CREATE_WRITE,
+	WAIT_EVENT_LOCK_FILE_RECHECKDATADIR_READ,
+	WAIT_EVENT_LOGICAL_REWRITE_CHECKPOINT_SYNC,
+	WAIT_EVENT_LOGICAL_REWRITE_MAPPING_SYNC,
+	WAIT_EVENT_LOGICAL_REWRITE_MAPPING_WRITE,
+	WAIT_EVENT_LOGICAL_REWRITE_SYNC,
+	WAIT_EVENT_LOGICAL_REWRITE_TRUNCATE,
+	WAIT_EVENT_LOGICAL_REWRITE_WRITE,
+	WAIT_EVENT_RELATION_MAP_READ,
+	WAIT_EVENT_RELATION_MAP_SYNC,
+	WAIT_EVENT_RELATION_MAP_WRITE,
+	WAIT_EVENT_REORDER_BUFFER_READ,
+	WAIT_EVENT_REORDER_BUFFER_WRITE,
+	WAIT_EVENT_REORDER_LOGICAL_MAPPING_READ,
+	WAIT_EVENT_REPLICATION_SLOT_READ,
+	WAIT_EVENT_REPLICATION_SLOT_RESTORE_SYNC,
+	WAIT_EVENT_REPLICATION_SLOT_SYNC,
+	WAIT_EVENT_REPLICATION_SLOT_WRITE,
+	WAIT_EVENT_SLRU_FLUSH_SYNC,
+	WAIT_EVENT_SLRU_READ,
+	WAIT_EVENT_SLRU_SYNC,
+	WAIT_EVENT_SLRU_WRITE,
+	WAIT_EVENT_SNAPBUILD_READ,
+	WAIT_EVENT_SNAPBUILD_SYNC,
+	WAIT_EVENT_SNAPBUILD_WRITE,
+	WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC,
+	WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE,
+	WAIT_EVENT_TIMELINE_HISTORY_READ,
+	WAIT_EVENT_TIMELINE_HISTORY_SYNC,
+	WAIT_EVENT_TIMELINE_HISTORY_WRITE,
+	WAIT_EVENT_TWOPHASE_FILE_READ,
+	WAIT_EVENT_TWOPHASE_FILE_SYNC,
+	WAIT_EVENT_TWOPHASE_FILE_WRITE,
+	WAIT_EVENT_WALSENDER_TIMELINE_HISTORY_READ,
+	WAIT_EVENT_WAL_BOOTSTRAP_SYNC,
+	WAIT_EVENT_WAL_BOOTSTRAP_WRITE,
+	WAIT_EVENT_WAL_COPY_READ,
+	WAIT_EVENT_WAL_COPY_SYNC,
+	WAIT_EVENT_WAL_COPY_WRITE,
+	WAIT_EVENT_WAL_INIT_SYNC,
+	WAIT_EVENT_WAL_INIT_WRITE,
+	WAIT_EVENT_WAL_READ,
+	WAIT_EVENT_WAL_SYNC,
+	WAIT_EVENT_WAL_SYNC_METHOD_ASSIGN,
+	WAIT_EVENT_WAL_WRITE,
+	WAIT_EVENT_LOGICAL_CHANGES_READ,
+	WAIT_EVENT_LOGICAL_CHANGES_WRITE,
+	WAIT_EVENT_LOGICAL_SUBXACT_READ,
+	WAIT_EVENT_LOGICAL_SUBXACT_WRITE
+} WaitEventIO;
+
+
+extern const char *pgstat_get_wait_event(uint32 wait_event_info);
+extern const char *pgstat_get_wait_event_type(uint32 wait_event_info);
+static inline void pgstat_report_wait_start(uint32 wait_event_info);
+static inline void pgstat_report_wait_end(void);
+
+
+/*
+ * Repeated here for the inline functions because it is declared in pgstat.h,
+ * which includes this header.
+ */
+extern PGDLLIMPORT bool pgstat_track_activities;
+
+
+/* ----------
+ * pgstat_report_wait_start() -
+ *
+ *	Called from places where server process needs to wait.  This is called
+ *	to report wait event information.  The wait information is stored
+ *	as 4-bytes where first byte represents the wait event class (type of
+ *	wait, for different types of wait, refer WaitClass) and the next
+ *	3-bytes represent the actual wait event.  Currently 2-bytes are used
+ *	for wait event which is sufficient for current usage, 1-byte is
+ *	reserved for future usage.
+ *
+ * NB: this *must* be able to survive being called before MyProc has been
+ * initialized.
+ * ----------
+ */
+static inline void
+pgstat_report_wait_start(uint32 wait_event_info)
+{
+	volatile PGPROC *proc = MyProc;
+
+	if (!pgstat_track_activities || !proc)
+		return;
+
+	/*
+	 * Since this is a four-byte field which is always read and written as
+	 * four-bytes, updates are atomic.
+	 */
+	proc->wait_event_info = wait_event_info;
+}
+
+/* ----------
+ * pgstat_report_wait_end() -
+ *
+ *	Called to report end of a wait.
+ *
+ * NB: this *must* be able to survive being called before MyProc has been
+ * initialized.
+ * ----------
+ */
+static inline void
+pgstat_report_wait_end(void)
+{
+	volatile PGPROC *proc = MyProc;
+
+	if (!pgstat_track_activities || !proc)
+		return;
+
+	/*
+	 * Since this is a four-byte field which is always read and written as
+	 * four-bytes, updates are atomic.
+	 */
+	proc->wait_event_info = 0;
+}
+
+
+#endif /* WAIT_EVENT_H */
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 2f3f378e633..de239136f48 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -352,12 +352,6 @@ static PgStat_TableStatus *get_tabstat_entry(Oid rel_id, bool isshared);
 
 static void pgstat_setup_memcxt(void);
 
-static const char *pgstat_get_wait_activity(WaitEventActivity w);
-static const char *pgstat_get_wait_client(WaitEventClient w);
-static const char *pgstat_get_wait_ipc(WaitEventIPC w);
-static const char *pgstat_get_wait_timeout(WaitEventTimeout w);
-static const char *pgstat_get_wait_io(WaitEventIO w);
-
 static void pgstat_setheader(PgStat_MsgHdr *hdr, StatMsgType mtype);
 static void pgstat_send(void *msg, int len);
 
@@ -3751,673 +3745,6 @@ pgstat_read_current_status(void)
 	localBackendStatusTable = localtable;
 }
 
-/* ----------
- * pgstat_get_wait_event_type() -
- *
- *	Return a string representing the current wait event type, backend is
- *	waiting on.
- */
-const char *
-pgstat_get_wait_event_type(uint32 wait_event_info)
-{
-	uint32		classId;
-	const char *event_type;
-
-	/* report process as not waiting. */
-	if (wait_event_info == 0)
-		return NULL;
-
-	classId = wait_event_info & 0xFF000000;
-
-	switch (classId)
-	{
-		case PG_WAIT_LWLOCK:
-			event_type = "LWLock";
-			break;
-		case PG_WAIT_LOCK:
-			event_type = "Lock";
-			break;
-		case PG_WAIT_BUFFER_PIN:
-			event_type = "BufferPin";
-			break;
-		case PG_WAIT_ACTIVITY:
-			event_type = "Activity";
-			break;
-		case PG_WAIT_CLIENT:
-			event_type = "Client";
-			break;
-		case PG_WAIT_EXTENSION:
-			event_type = "Extension";
-			break;
-		case PG_WAIT_IPC:
-			event_type = "IPC";
-			break;
-		case PG_WAIT_TIMEOUT:
-			event_type = "Timeout";
-			break;
-		case PG_WAIT_IO:
-			event_type = "IO";
-			break;
-		default:
-			event_type = "???";
-			break;
-	}
-
-	return event_type;
-}
-
-/* ----------
- * pgstat_get_wait_event() -
- *
- *	Return a string representing the current wait event, backend is
- *	waiting on.
- */
-const char *
-pgstat_get_wait_event(uint32 wait_event_info)
-{
-	uint32		classId;
-	uint16		eventId;
-	const char *event_name;
-
-	/* report process as not waiting. */
-	if (wait_event_info == 0)
-		return NULL;
-
-	classId = wait_event_info & 0xFF000000;
-	eventId = wait_event_info & 0x0000FFFF;
-
-	switch (classId)
-	{
-		case PG_WAIT_LWLOCK:
-			event_name = GetLWLockIdentifier(classId, eventId);
-			break;
-		case PG_WAIT_LOCK:
-			event_name = GetLockNameFromTagType(eventId);
-			break;
-		case PG_WAIT_BUFFER_PIN:
-			event_name = "BufferPin";
-			break;
-		case PG_WAIT_ACTIVITY:
-			{
-				WaitEventActivity w = (WaitEventActivity) wait_event_info;
-
-				event_name = pgstat_get_wait_activity(w);
-				break;
-			}
-		case PG_WAIT_CLIENT:
-			{
-				WaitEventClient w = (WaitEventClient) wait_event_info;
-
-				event_name = pgstat_get_wait_client(w);
-				break;
-			}
-		case PG_WAIT_EXTENSION:
-			event_name = "Extension";
-			break;
-		case PG_WAIT_IPC:
-			{
-				WaitEventIPC w = (WaitEventIPC) wait_event_info;
-
-				event_name = pgstat_get_wait_ipc(w);
-				break;
-			}
-		case PG_WAIT_TIMEOUT:
-			{
-				WaitEventTimeout w = (WaitEventTimeout) wait_event_info;
-
-				event_name = pgstat_get_wait_timeout(w);
-				break;
-			}
-		case PG_WAIT_IO:
-			{
-				WaitEventIO w = (WaitEventIO) wait_event_info;
-
-				event_name = pgstat_get_wait_io(w);
-				break;
-			}
-		default:
-			event_name = "unknown wait event";
-			break;
-	}
-
-	return event_name;
-}
-
-/* ----------
- * pgstat_get_wait_activity() -
- *
- * Convert WaitEventActivity to string.
- * ----------
- */
-static const char *
-pgstat_get_wait_activity(WaitEventActivity w)
-{
-	const char *event_name = "unknown wait event";
-
-	switch (w)
-	{
-		case WAIT_EVENT_ARCHIVER_MAIN:
-			event_name = "ArchiverMain";
-			break;
-		case WAIT_EVENT_AUTOVACUUM_MAIN:
-			event_name = "AutoVacuumMain";
-			break;
-		case WAIT_EVENT_BGWRITER_HIBERNATE:
-			event_name = "BgWriterHibernate";
-			break;
-		case WAIT_EVENT_BGWRITER_MAIN:
-			event_name = "BgWriterMain";
-			break;
-		case WAIT_EVENT_CHECKPOINTER_MAIN:
-			event_name = "CheckpointerMain";
-			break;
-		case WAIT_EVENT_LOGICAL_APPLY_MAIN:
-			event_name = "LogicalApplyMain";
-			break;
-		case WAIT_EVENT_LOGICAL_LAUNCHER_MAIN:
-			event_name = "LogicalLauncherMain";
-			break;
-		case WAIT_EVENT_PGSTAT_MAIN:
-			event_name = "PgStatMain";
-			break;
-		case WAIT_EVENT_RECOVERY_WAL_STREAM:
-			event_name = "RecoveryWalStream";
-			break;
-		case WAIT_EVENT_SYSLOGGER_MAIN:
-			event_name = "SysLoggerMain";
-			break;
-		case WAIT_EVENT_WAL_RECEIVER_MAIN:
-			event_name = "WalReceiverMain";
-			break;
-		case WAIT_EVENT_WAL_SENDER_MAIN:
-			event_name = "WalSenderMain";
-			break;
-		case WAIT_EVENT_WAL_WRITER_MAIN:
-			event_name = "WalWriterMain";
-			break;
-			/* no default case, so that compiler will warn */
-	}
-
-	return event_name;
-}
-
-/* ----------
- * pgstat_get_wait_client() -
- *
- * Convert WaitEventClient to string.
- * ----------
- */
-static const char *
-pgstat_get_wait_client(WaitEventClient w)
-{
-	const char *event_name = "unknown wait event";
-
-	switch (w)
-	{
-		case WAIT_EVENT_CLIENT_READ:
-			event_name = "ClientRead";
-			break;
-		case WAIT_EVENT_CLIENT_WRITE:
-			event_name = "ClientWrite";
-			break;
-		case WAIT_EVENT_GSS_OPEN_SERVER:
-			event_name = "GSSOpenServer";
-			break;
-		case WAIT_EVENT_LIBPQWALRECEIVER_CONNECT:
-			event_name = "LibPQWalReceiverConnect";
-			break;
-		case WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE:
-			event_name = "LibPQWalReceiverReceive";
-			break;
-		case WAIT_EVENT_SSL_OPEN_SERVER:
-			event_name = "SSLOpenServer";
-			break;
-		case WAIT_EVENT_WAL_SENDER_WAIT_WAL:
-			event_name = "WalSenderWaitForWAL";
-			break;
-		case WAIT_EVENT_WAL_SENDER_WRITE_DATA:
-			event_name = "WalSenderWriteData";
-			break;
-			/* no default case, so that compiler will warn */
-	}
-
-	return event_name;
-}
-
-/* ----------
- * pgstat_get_wait_ipc() -
- *
- * Convert WaitEventIPC to string.
- * ----------
- */
-static const char *
-pgstat_get_wait_ipc(WaitEventIPC w)
-{
-	const char *event_name = "unknown wait event";
-
-	switch (w)
-	{
-		case WAIT_EVENT_APPEND_READY:
-			event_name = "AppendReady";
-			break;
-		case WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE:
-			event_name = "BackupWaitWalArchive";
-			break;
-		case WAIT_EVENT_BGWORKER_SHUTDOWN:
-			event_name = "BgWorkerShutdown";
-			break;
-		case WAIT_EVENT_BGWORKER_STARTUP:
-			event_name = "BgWorkerStartup";
-			break;
-		case WAIT_EVENT_BTREE_PAGE:
-			event_name = "BtreePage";
-			break;
-		case WAIT_EVENT_BUFFER_IO:
-			event_name = "BufferIO";
-			break;
-		case WAIT_EVENT_CHECKPOINT_DONE:
-			event_name = "CheckpointDone";
-			break;
-		case WAIT_EVENT_CHECKPOINT_START:
-			event_name = "CheckpointStart";
-			break;
-		case WAIT_EVENT_EXECUTE_GATHER:
-			event_name = "ExecuteGather";
-			break;
-		case WAIT_EVENT_HASH_BATCH_ALLOCATE:
-			event_name = "HashBatchAllocate";
-			break;
-		case WAIT_EVENT_HASH_BATCH_ELECT:
-			event_name = "HashBatchElect";
-			break;
-		case WAIT_EVENT_HASH_BATCH_LOAD:
-			event_name = "HashBatchLoad";
-			break;
-		case WAIT_EVENT_HASH_BUILD_ALLOCATE:
-			event_name = "HashBuildAllocate";
-			break;
-		case WAIT_EVENT_HASH_BUILD_ELECT:
-			event_name = "HashBuildElect";
-			break;
-		case WAIT_EVENT_HASH_BUILD_HASH_INNER:
-			event_name = "HashBuildHashInner";
-			break;
-		case WAIT_EVENT_HASH_BUILD_HASH_OUTER:
-			event_name = "HashBuildHashOuter";
-			break;
-		case WAIT_EVENT_HASH_GROW_BATCHES_ALLOCATE:
-			event_name = "HashGrowBatchesAllocate";
-			break;
-		case WAIT_EVENT_HASH_GROW_BATCHES_DECIDE:
-			event_name = "HashGrowBatchesDecide";
-			break;
-		case WAIT_EVENT_HASH_GROW_BATCHES_ELECT:
-			event_name = "HashGrowBatchesElect";
-			break;
-		case WAIT_EVENT_HASH_GROW_BATCHES_FINISH:
-			event_name = "HashGrowBatchesFinish";
-			break;
-		case WAIT_EVENT_HASH_GROW_BATCHES_REPARTITION:
-			event_name = "HashGrowBatchesRepartition";
-			break;
-		case WAIT_EVENT_HASH_GROW_BUCKETS_ALLOCATE:
-			event_name = "HashGrowBucketsAllocate";
-			break;
-		case WAIT_EVENT_HASH_GROW_BUCKETS_ELECT:
-			event_name = "HashGrowBucketsElect";
-			break;
-		case WAIT_EVENT_HASH_GROW_BUCKETS_REINSERT:
-			event_name = "HashGrowBucketsReinsert";
-			break;
-		case WAIT_EVENT_LOGICAL_SYNC_DATA:
-			event_name = "LogicalSyncData";
-			break;
-		case WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE:
-			event_name = "LogicalSyncStateChange";
-			break;
-		case WAIT_EVENT_MQ_INTERNAL:
-			event_name = "MessageQueueInternal";
-			break;
-		case WAIT_EVENT_MQ_PUT_MESSAGE:
-			event_name = "MessageQueuePutMessage";
-			break;
-		case WAIT_EVENT_MQ_RECEIVE:
-			event_name = "MessageQueueReceive";
-			break;
-		case WAIT_EVENT_MQ_SEND:
-			event_name = "MessageQueueSend";
-			break;
-		case WAIT_EVENT_PARALLEL_BITMAP_SCAN:
-			event_name = "ParallelBitmapScan";
-			break;
-		case WAIT_EVENT_PARALLEL_CREATE_INDEX_SCAN:
-			event_name = "ParallelCreateIndexScan";
-			break;
-		case WAIT_EVENT_PARALLEL_FINISH:
-			event_name = "ParallelFinish";
-			break;
-		case WAIT_EVENT_PROCARRAY_GROUP_UPDATE:
-			event_name = "ProcArrayGroupUpdate";
-			break;
-		case WAIT_EVENT_PROC_SIGNAL_BARRIER:
-			event_name = "ProcSignalBarrier";
-			break;
-		case WAIT_EVENT_PROMOTE:
-			event_name = "Promote";
-			break;
-		case WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT:
-			event_name = "RecoveryConflictSnapshot";
-			break;
-		case WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE:
-			event_name = "RecoveryConflictTablespace";
-			break;
-		case WAIT_EVENT_RECOVERY_PAUSE:
-			event_name = "RecoveryPause";
-			break;
-		case WAIT_EVENT_REPLICATION_ORIGIN_DROP:
-			event_name = "ReplicationOriginDrop";
-			break;
-		case WAIT_EVENT_REPLICATION_SLOT_DROP:
-			event_name = "ReplicationSlotDrop";
-			break;
-		case WAIT_EVENT_SAFE_SNAPSHOT:
-			event_name = "SafeSnapshot";
-			break;
-		case WAIT_EVENT_SYNC_REP:
-			event_name = "SyncRep";
-			break;
-		case WAIT_EVENT_WAL_RECEIVER_EXIT:
-			event_name = "WalReceiverExit";
-			break;
-		case WAIT_EVENT_WAL_RECEIVER_WAIT_START:
-			event_name = "WalReceiverWaitStart";
-			break;
-		case WAIT_EVENT_XACT_GROUP_UPDATE:
-			event_name = "XactGroupUpdate";
-			break;
-			/* no default case, so that compiler will warn */
-	}
-
-	return event_name;
-}
-
-/* ----------
- * pgstat_get_wait_timeout() -
- *
- * Convert WaitEventTimeout to string.
- * ----------
- */
-static const char *
-pgstat_get_wait_timeout(WaitEventTimeout w)
-{
-	const char *event_name = "unknown wait event";
-
-	switch (w)
-	{
-		case WAIT_EVENT_BASE_BACKUP_THROTTLE:
-			event_name = "BaseBackupThrottle";
-			break;
-		case WAIT_EVENT_PG_SLEEP:
-			event_name = "PgSleep";
-			break;
-		case WAIT_EVENT_RECOVERY_APPLY_DELAY:
-			event_name = "RecoveryApplyDelay";
-			break;
-		case WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL:
-			event_name = "RecoveryRetrieveRetryInterval";
-			break;
-		case WAIT_EVENT_VACUUM_DELAY:
-			event_name = "VacuumDelay";
-			break;
-			/* no default case, so that compiler will warn */
-	}
-
-	return event_name;
-}
-
-/* ----------
- * pgstat_get_wait_io() -
- *
- * Convert WaitEventIO to string.
- * ----------
- */
-static const char *
-pgstat_get_wait_io(WaitEventIO w)
-{
-	const char *event_name = "unknown wait event";
-
-	switch (w)
-	{
-		case WAIT_EVENT_BASEBACKUP_READ:
-			event_name = "BaseBackupRead";
-			break;
-		case WAIT_EVENT_BUFFILE_READ:
-			event_name = "BufFileRead";
-			break;
-		case WAIT_EVENT_BUFFILE_WRITE:
-			event_name = "BufFileWrite";
-			break;
-		case WAIT_EVENT_BUFFILE_TRUNCATE:
-			event_name = "BufFileTruncate";
-			break;
-		case WAIT_EVENT_CONTROL_FILE_READ:
-			event_name = "ControlFileRead";
-			break;
-		case WAIT_EVENT_CONTROL_FILE_SYNC:
-			event_name = "ControlFileSync";
-			break;
-		case WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE:
-			event_name = "ControlFileSyncUpdate";
-			break;
-		case WAIT_EVENT_CONTROL_FILE_WRITE:
-			event_name = "ControlFileWrite";
-			break;
-		case WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE:
-			event_name = "ControlFileWriteUpdate";
-			break;
-		case WAIT_EVENT_COPY_FILE_READ:
-			event_name = "CopyFileRead";
-			break;
-		case WAIT_EVENT_COPY_FILE_WRITE:
-			event_name = "CopyFileWrite";
-			break;
-		case WAIT_EVENT_DATA_FILE_EXTEND:
-			event_name = "DataFileExtend";
-			break;
-		case WAIT_EVENT_DATA_FILE_FLUSH:
-			event_name = "DataFileFlush";
-			break;
-		case WAIT_EVENT_DATA_FILE_IMMEDIATE_SYNC:
-			event_name = "DataFileImmediateSync";
-			break;
-		case WAIT_EVENT_DATA_FILE_PREFETCH:
-			event_name = "DataFilePrefetch";
-			break;
-		case WAIT_EVENT_DATA_FILE_READ:
-			event_name = "DataFileRead";
-			break;
-		case WAIT_EVENT_DATA_FILE_SYNC:
-			event_name = "DataFileSync";
-			break;
-		case WAIT_EVENT_DATA_FILE_TRUNCATE:
-			event_name = "DataFileTruncate";
-			break;
-		case WAIT_EVENT_DATA_FILE_WRITE:
-			event_name = "DataFileWrite";
-			break;
-		case WAIT_EVENT_DSM_FILL_ZERO_WRITE:
-			event_name = "DSMFillZeroWrite";
-			break;
-		case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ:
-			event_name = "LockFileAddToDataDirRead";
-			break;
-		case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_SYNC:
-			event_name = "LockFileAddToDataDirSync";
-			break;
-		case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_WRITE:
-			event_name = "LockFileAddToDataDirWrite";
-			break;
-		case WAIT_EVENT_LOCK_FILE_CREATE_READ:
-			event_name = "LockFileCreateRead";
-			break;
-		case WAIT_EVENT_LOCK_FILE_CREATE_SYNC:
-			event_name = "LockFileCreateSync";
-			break;
-		case WAIT_EVENT_LOCK_FILE_CREATE_WRITE:
-			event_name = "LockFileCreateWrite";
-			break;
-		case WAIT_EVENT_LOCK_FILE_RECHECKDATADIR_READ:
-			event_name = "LockFileReCheckDataDirRead";
-			break;
-		case WAIT_EVENT_LOGICAL_REWRITE_CHECKPOINT_SYNC:
-			event_name = "LogicalRewriteCheckpointSync";
-			break;
-		case WAIT_EVENT_LOGICAL_REWRITE_MAPPING_SYNC:
-			event_name = "LogicalRewriteMappingSync";
-			break;
-		case WAIT_EVENT_LOGICAL_REWRITE_MAPPING_WRITE:
-			event_name = "LogicalRewriteMappingWrite";
-			break;
-		case WAIT_EVENT_LOGICAL_REWRITE_SYNC:
-			event_name = "LogicalRewriteSync";
-			break;
-		case WAIT_EVENT_LOGICAL_REWRITE_TRUNCATE:
-			event_name = "LogicalRewriteTruncate";
-			break;
-		case WAIT_EVENT_LOGICAL_REWRITE_WRITE:
-			event_name = "LogicalRewriteWrite";
-			break;
-		case WAIT_EVENT_RELATION_MAP_READ:
-			event_name = "RelationMapRead";
-			break;
-		case WAIT_EVENT_RELATION_MAP_SYNC:
-			event_name = "RelationMapSync";
-			break;
-		case WAIT_EVENT_RELATION_MAP_WRITE:
-			event_name = "RelationMapWrite";
-			break;
-		case WAIT_EVENT_REORDER_BUFFER_READ:
-			event_name = "ReorderBufferRead";
-			break;
-		case WAIT_EVENT_REORDER_BUFFER_WRITE:
-			event_name = "ReorderBufferWrite";
-			break;
-		case WAIT_EVENT_REORDER_LOGICAL_MAPPING_READ:
-			event_name = "ReorderLogicalMappingRead";
-			break;
-		case WAIT_EVENT_REPLICATION_SLOT_READ:
-			event_name = "ReplicationSlotRead";
-			break;
-		case WAIT_EVENT_REPLICATION_SLOT_RESTORE_SYNC:
-			event_name = "ReplicationSlotRestoreSync";
-			break;
-		case WAIT_EVENT_REPLICATION_SLOT_SYNC:
-			event_name = "ReplicationSlotSync";
-			break;
-		case WAIT_EVENT_REPLICATION_SLOT_WRITE:
-			event_name = "ReplicationSlotWrite";
-			break;
-		case WAIT_EVENT_SLRU_FLUSH_SYNC:
-			event_name = "SLRUFlushSync";
-			break;
-		case WAIT_EVENT_SLRU_READ:
-			event_name = "SLRURead";
-			break;
-		case WAIT_EVENT_SLRU_SYNC:
-			event_name = "SLRUSync";
-			break;
-		case WAIT_EVENT_SLRU_WRITE:
-			event_name = "SLRUWrite";
-			break;
-		case WAIT_EVENT_SNAPBUILD_READ:
-			event_name = "SnapbuildRead";
-			break;
-		case WAIT_EVENT_SNAPBUILD_SYNC:
-			event_name = "SnapbuildSync";
-			break;
-		case WAIT_EVENT_SNAPBUILD_WRITE:
-			event_name = "SnapbuildWrite";
-			break;
-		case WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC:
-			event_name = "TimelineHistoryFileSync";
-			break;
-		case WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE:
-			event_name = "TimelineHistoryFileWrite";
-			break;
-		case WAIT_EVENT_TIMELINE_HISTORY_READ:
-			event_name = "TimelineHistoryRead";
-			break;
-		case WAIT_EVENT_TIMELINE_HISTORY_SYNC:
-			event_name = "TimelineHistorySync";
-			break;
-		case WAIT_EVENT_TIMELINE_HISTORY_WRITE:
-			event_name = "TimelineHistoryWrite";
-			break;
-		case WAIT_EVENT_TWOPHASE_FILE_READ:
-			event_name = "TwophaseFileRead";
-			break;
-		case WAIT_EVENT_TWOPHASE_FILE_SYNC:
-			event_name = "TwophaseFileSync";
-			break;
-		case WAIT_EVENT_TWOPHASE_FILE_WRITE:
-			event_name = "TwophaseFileWrite";
-			break;
-		case WAIT_EVENT_WALSENDER_TIMELINE_HISTORY_READ:
-			event_name = "WALSenderTimelineHistoryRead";
-			break;
-		case WAIT_EVENT_WAL_BOOTSTRAP_SYNC:
-			event_name = "WALBootstrapSync";
-			break;
-		case WAIT_EVENT_WAL_BOOTSTRAP_WRITE:
-			event_name = "WALBootstrapWrite";
-			break;
-		case WAIT_EVENT_WAL_COPY_READ:
-			event_name = "WALCopyRead";
-			break;
-		case WAIT_EVENT_WAL_COPY_SYNC:
-			event_name = "WALCopySync";
-			break;
-		case WAIT_EVENT_WAL_COPY_WRITE:
-			event_name = "WALCopyWrite";
-			break;
-		case WAIT_EVENT_WAL_INIT_SYNC:
-			event_name = "WALInitSync";
-			break;
-		case WAIT_EVENT_WAL_INIT_WRITE:
-			event_name = "WALInitWrite";
-			break;
-		case WAIT_EVENT_WAL_READ:
-			event_name = "WALRead";
-			break;
-		case WAIT_EVENT_WAL_SYNC:
-			event_name = "WALSync";
-			break;
-		case WAIT_EVENT_WAL_SYNC_METHOD_ASSIGN:
-			event_name = "WALSyncMethodAssign";
-			break;
-		case WAIT_EVENT_WAL_WRITE:
-			event_name = "WALWrite";
-			break;
-		case WAIT_EVENT_LOGICAL_CHANGES_READ:
-			event_name = "LogicalChangesRead";
-			break;
-		case WAIT_EVENT_LOGICAL_CHANGES_WRITE:
-			event_name = "LogicalChangesWrite";
-			break;
-		case WAIT_EVENT_LOGICAL_SUBXACT_READ:
-			event_name = "LogicalSubxactRead";
-			break;
-		case WAIT_EVENT_LOGICAL_SUBXACT_WRITE:
-			event_name = "LogicalSubxactWrite";
-			break;
-
-			/* no default case, so that compiler will warn */
-	}
-
-	return event_name;
-}
-
-
 /* ----------
  * pgstat_get_backend_current_activity() -
  *
diff --git a/src/backend/utils/Makefile b/src/backend/utils/Makefile
index 26e07100a5d..59b22552606 100644
--- a/src/backend/utils/Makefile
+++ b/src/backend/utils/Makefile
@@ -14,7 +14,20 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS        = fmgrtab.o
-SUBDIRS     = adt cache error fmgr hash init mb misc mmgr resowner sort time
+SUBDIRS     = \
+	activity \
+	adt \
+	cache \
+	error \
+	fmgr \
+	hash \
+	init \
+	mb \
+	misc \
+	mmgr \
+	resowner \
+	sort \
+	time
 
 # location of Catalog.pm
 catalogdir  = $(top_srcdir)/src/backend/catalog
diff --git a/src/backend/utils/activity/Makefile b/src/backend/utils/activity/Makefile
new file mode 100644
index 00000000000..7cbe0cdbe81
--- /dev/null
+++ b/src/backend/utils/activity/Makefile
@@ -0,0 +1,19 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for backend/utils/activity
+#
+# Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
+#
+# src/backend/utils/activity/Makefile
+#
+#-------------------------------------------------------------------------
+
+subdir = src/backend/utils/activity
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+OBJS = \
+	wait_event.o
+
+include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/utils/activity/wait_event.c b/src/backend/utils/activity/wait_event.c
new file mode 100644
index 00000000000..840ebef92ab
--- /dev/null
+++ b/src/backend/utils/activity/wait_event.c
@@ -0,0 +1,690 @@
+/* ----------
+ * wait_event.c
+ *	  Wait event reporting infrastructure.
+ *
+ * Copyright (c) 2001-2021, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ *	  src/backend/postmaster/wait_event.c
+ * ----------
+ */
+#include "postgres.h"
+
+#include "storage/lmgr.h" /* for GetLockNameFromTagType */
+#include "storage/lwlock.h" /* for GetLWLockIdentifier */
+#include "utils/wait_event.h"
+
+
+static const char *pgstat_get_wait_activity(WaitEventActivity w);
+static const char *pgstat_get_wait_client(WaitEventClient w);
+static const char *pgstat_get_wait_ipc(WaitEventIPC w);
+static const char *pgstat_get_wait_timeout(WaitEventTimeout w);
+static const char *pgstat_get_wait_io(WaitEventIO w);
+
+
+/* ----------
+ * pgstat_get_wait_event_type() -
+ *
+ *	Return a string representing the current wait event type, backend is
+ *	waiting on.
+ */
+const char *
+pgstat_get_wait_event_type(uint32 wait_event_info)
+{
+	uint32		classId;
+	const char *event_type;
+
+	/* report process as not waiting. */
+	if (wait_event_info == 0)
+		return NULL;
+
+	classId = wait_event_info & 0xFF000000;
+
+	switch (classId)
+	{
+		case PG_WAIT_LWLOCK:
+			event_type = "LWLock";
+			break;
+		case PG_WAIT_LOCK:
+			event_type = "Lock";
+			break;
+		case PG_WAIT_BUFFER_PIN:
+			event_type = "BufferPin";
+			break;
+		case PG_WAIT_ACTIVITY:
+			event_type = "Activity";
+			break;
+		case PG_WAIT_CLIENT:
+			event_type = "Client";
+			break;
+		case PG_WAIT_EXTENSION:
+			event_type = "Extension";
+			break;
+		case PG_WAIT_IPC:
+			event_type = "IPC";
+			break;
+		case PG_WAIT_TIMEOUT:
+			event_type = "Timeout";
+			break;
+		case PG_WAIT_IO:
+			event_type = "IO";
+			break;
+		default:
+			event_type = "???";
+			break;
+	}
+
+	return event_type;
+}
+
+/* ----------
+ * pgstat_get_wait_event() -
+ *
+ *	Return a string representing the current wait event, backend is
+ *	waiting on.
+ */
+const char *
+pgstat_get_wait_event(uint32 wait_event_info)
+{
+	uint32		classId;
+	uint16		eventId;
+	const char *event_name;
+
+	/* report process as not waiting. */
+	if (wait_event_info == 0)
+		return NULL;
+
+	classId = wait_event_info & 0xFF000000;
+	eventId = wait_event_info & 0x0000FFFF;
+
+	switch (classId)
+	{
+		case PG_WAIT_LWLOCK:
+			event_name = GetLWLockIdentifier(classId, eventId);
+			break;
+		case PG_WAIT_LOCK:
+			event_name = GetLockNameFromTagType(eventId);
+			break;
+		case PG_WAIT_BUFFER_PIN:
+			event_name = "BufferPin";
+			break;
+		case PG_WAIT_ACTIVITY:
+			{
+				WaitEventActivity w = (WaitEventActivity) wait_event_info;
+
+				event_name = pgstat_get_wait_activity(w);
+				break;
+			}
+		case PG_WAIT_CLIENT:
+			{
+				WaitEventClient w = (WaitEventClient) wait_event_info;
+
+				event_name = pgstat_get_wait_client(w);
+				break;
+			}
+		case PG_WAIT_EXTENSION:
+			event_name = "Extension";
+			break;
+		case PG_WAIT_IPC:
+			{
+				WaitEventIPC w = (WaitEventIPC) wait_event_info;
+
+				event_name = pgstat_get_wait_ipc(w);
+				break;
+			}
+		case PG_WAIT_TIMEOUT:
+			{
+				WaitEventTimeout w = (WaitEventTimeout) wait_event_info;
+
+				event_name = pgstat_get_wait_timeout(w);
+				break;
+			}
+		case PG_WAIT_IO:
+			{
+				WaitEventIO w = (WaitEventIO) wait_event_info;
+
+				event_name = pgstat_get_wait_io(w);
+				break;
+			}
+		default:
+			event_name = "unknown wait event";
+			break;
+	}
+
+	return event_name;
+}
+
+/* ----------
+ * pgstat_get_wait_activity() -
+ *
+ * Convert WaitEventActivity to string.
+ * ----------
+ */
+static const char *
+pgstat_get_wait_activity(WaitEventActivity w)
+{
+	const char *event_name = "unknown wait event";
+
+	switch (w)
+	{
+		case WAIT_EVENT_ARCHIVER_MAIN:
+			event_name = "ArchiverMain";
+			break;
+		case WAIT_EVENT_AUTOVACUUM_MAIN:
+			event_name = "AutoVacuumMain";
+			break;
+		case WAIT_EVENT_BGWRITER_HIBERNATE:
+			event_name = "BgWriterHibernate";
+			break;
+		case WAIT_EVENT_BGWRITER_MAIN:
+			event_name = "BgWriterMain";
+			break;
+		case WAIT_EVENT_CHECKPOINTER_MAIN:
+			event_name = "CheckpointerMain";
+			break;
+		case WAIT_EVENT_LOGICAL_APPLY_MAIN:
+			event_name = "LogicalApplyMain";
+			break;
+		case WAIT_EVENT_LOGICAL_LAUNCHER_MAIN:
+			event_name = "LogicalLauncherMain";
+			break;
+		case WAIT_EVENT_PGSTAT_MAIN:
+			event_name = "PgStatMain";
+			break;
+		case WAIT_EVENT_RECOVERY_WAL_STREAM:
+			event_name = "RecoveryWalStream";
+			break;
+		case WAIT_EVENT_SYSLOGGER_MAIN:
+			event_name = "SysLoggerMain";
+			break;
+		case WAIT_EVENT_WAL_RECEIVER_MAIN:
+			event_name = "WalReceiverMain";
+			break;
+		case WAIT_EVENT_WAL_SENDER_MAIN:
+			event_name = "WalSenderMain";
+			break;
+		case WAIT_EVENT_WAL_WRITER_MAIN:
+			event_name = "WalWriterMain";
+			break;
+			/* no default case, so that compiler will warn */
+	}
+
+	return event_name;
+}
+
+/* ----------
+ * pgstat_get_wait_client() -
+ *
+ * Convert WaitEventClient to string.
+ * ----------
+ */
+static const char *
+pgstat_get_wait_client(WaitEventClient w)
+{
+	const char *event_name = "unknown wait event";
+
+	switch (w)
+	{
+		case WAIT_EVENT_CLIENT_READ:
+			event_name = "ClientRead";
+			break;
+		case WAIT_EVENT_CLIENT_WRITE:
+			event_name = "ClientWrite";
+			break;
+		case WAIT_EVENT_GSS_OPEN_SERVER:
+			event_name = "GSSOpenServer";
+			break;
+		case WAIT_EVENT_LIBPQWALRECEIVER_CONNECT:
+			event_name = "LibPQWalReceiverConnect";
+			break;
+		case WAIT_EVENT_LIBPQWALRECEIVER_RECEIVE:
+			event_name = "LibPQWalReceiverReceive";
+			break;
+		case WAIT_EVENT_SSL_OPEN_SERVER:
+			event_name = "SSLOpenServer";
+			break;
+		case WAIT_EVENT_WAL_SENDER_WAIT_WAL:
+			event_name = "WalSenderWaitForWAL";
+			break;
+		case WAIT_EVENT_WAL_SENDER_WRITE_DATA:
+			event_name = "WalSenderWriteData";
+			break;
+			/* no default case, so that compiler will warn */
+	}
+
+	return event_name;
+}
+
+/* ----------
+ * pgstat_get_wait_ipc() -
+ *
+ * Convert WaitEventIPC to string.
+ * ----------
+ */
+static const char *
+pgstat_get_wait_ipc(WaitEventIPC w)
+{
+	const char *event_name = "unknown wait event";
+
+	switch (w)
+	{
+		case WAIT_EVENT_APPEND_READY:
+			event_name = "AppendReady";
+			break;
+		case WAIT_EVENT_BACKUP_WAIT_WAL_ARCHIVE:
+			event_name = "BackupWaitWalArchive";
+			break;
+		case WAIT_EVENT_BGWORKER_SHUTDOWN:
+			event_name = "BgWorkerShutdown";
+			break;
+		case WAIT_EVENT_BGWORKER_STARTUP:
+			event_name = "BgWorkerStartup";
+			break;
+		case WAIT_EVENT_BTREE_PAGE:
+			event_name = "BtreePage";
+			break;
+		case WAIT_EVENT_BUFFER_IO:
+			event_name = "BufferIO";
+			break;
+		case WAIT_EVENT_CHECKPOINT_DONE:
+			event_name = "CheckpointDone";
+			break;
+		case WAIT_EVENT_CHECKPOINT_START:
+			event_name = "CheckpointStart";
+			break;
+		case WAIT_EVENT_EXECUTE_GATHER:
+			event_name = "ExecuteGather";
+			break;
+		case WAIT_EVENT_HASH_BATCH_ALLOCATE:
+			event_name = "HashBatchAllocate";
+			break;
+		case WAIT_EVENT_HASH_BATCH_ELECT:
+			event_name = "HashBatchElect";
+			break;
+		case WAIT_EVENT_HASH_BATCH_LOAD:
+			event_name = "HashBatchLoad";
+			break;
+		case WAIT_EVENT_HASH_BUILD_ALLOCATE:
+			event_name = "HashBuildAllocate";
+			break;
+		case WAIT_EVENT_HASH_BUILD_ELECT:
+			event_name = "HashBuildElect";
+			break;
+		case WAIT_EVENT_HASH_BUILD_HASH_INNER:
+			event_name = "HashBuildHashInner";
+			break;
+		case WAIT_EVENT_HASH_BUILD_HASH_OUTER:
+			event_name = "HashBuildHashOuter";
+			break;
+		case WAIT_EVENT_HASH_GROW_BATCHES_ALLOCATE:
+			event_name = "HashGrowBatchesAllocate";
+			break;
+		case WAIT_EVENT_HASH_GROW_BATCHES_DECIDE:
+			event_name = "HashGrowBatchesDecide";
+			break;
+		case WAIT_EVENT_HASH_GROW_BATCHES_ELECT:
+			event_name = "HashGrowBatchesElect";
+			break;
+		case WAIT_EVENT_HASH_GROW_BATCHES_FINISH:
+			event_name = "HashGrowBatchesFinish";
+			break;
+		case WAIT_EVENT_HASH_GROW_BATCHES_REPARTITION:
+			event_name = "HashGrowBatchesRepartition";
+			break;
+		case WAIT_EVENT_HASH_GROW_BUCKETS_ALLOCATE:
+			event_name = "HashGrowBucketsAllocate";
+			break;
+		case WAIT_EVENT_HASH_GROW_BUCKETS_ELECT:
+			event_name = "HashGrowBucketsElect";
+			break;
+		case WAIT_EVENT_HASH_GROW_BUCKETS_REINSERT:
+			event_name = "HashGrowBucketsReinsert";
+			break;
+		case WAIT_EVENT_LOGICAL_SYNC_DATA:
+			event_name = "LogicalSyncData";
+			break;
+		case WAIT_EVENT_LOGICAL_SYNC_STATE_CHANGE:
+			event_name = "LogicalSyncStateChange";
+			break;
+		case WAIT_EVENT_MQ_INTERNAL:
+			event_name = "MessageQueueInternal";
+			break;
+		case WAIT_EVENT_MQ_PUT_MESSAGE:
+			event_name = "MessageQueuePutMessage";
+			break;
+		case WAIT_EVENT_MQ_RECEIVE:
+			event_name = "MessageQueueReceive";
+			break;
+		case WAIT_EVENT_MQ_SEND:
+			event_name = "MessageQueueSend";
+			break;
+		case WAIT_EVENT_PARALLEL_BITMAP_SCAN:
+			event_name = "ParallelBitmapScan";
+			break;
+		case WAIT_EVENT_PARALLEL_CREATE_INDEX_SCAN:
+			event_name = "ParallelCreateIndexScan";
+			break;
+		case WAIT_EVENT_PARALLEL_FINISH:
+			event_name = "ParallelFinish";
+			break;
+		case WAIT_EVENT_PROCARRAY_GROUP_UPDATE:
+			event_name = "ProcArrayGroupUpdate";
+			break;
+		case WAIT_EVENT_PROC_SIGNAL_BARRIER:
+			event_name = "ProcSignalBarrier";
+			break;
+		case WAIT_EVENT_PROMOTE:
+			event_name = "Promote";
+			break;
+		case WAIT_EVENT_RECOVERY_CONFLICT_SNAPSHOT:
+			event_name = "RecoveryConflictSnapshot";
+			break;
+		case WAIT_EVENT_RECOVERY_CONFLICT_TABLESPACE:
+			event_name = "RecoveryConflictTablespace";
+			break;
+		case WAIT_EVENT_RECOVERY_PAUSE:
+			event_name = "RecoveryPause";
+			break;
+		case WAIT_EVENT_REPLICATION_ORIGIN_DROP:
+			event_name = "ReplicationOriginDrop";
+			break;
+		case WAIT_EVENT_REPLICATION_SLOT_DROP:
+			event_name = "ReplicationSlotDrop";
+			break;
+		case WAIT_EVENT_SAFE_SNAPSHOT:
+			event_name = "SafeSnapshot";
+			break;
+		case WAIT_EVENT_SYNC_REP:
+			event_name = "SyncRep";
+			break;
+		case WAIT_EVENT_WAL_RECEIVER_EXIT:
+			event_name = "WalReceiverExit";
+			break;
+		case WAIT_EVENT_WAL_RECEIVER_WAIT_START:
+			event_name = "WalReceiverWaitStart";
+			break;
+		case WAIT_EVENT_XACT_GROUP_UPDATE:
+			event_name = "XactGroupUpdate";
+			break;
+			/* no default case, so that compiler will warn */
+	}
+
+	return event_name;
+}
+
+/* ----------
+ * pgstat_get_wait_timeout() -
+ *
+ * Convert WaitEventTimeout to string.
+ * ----------
+ */
+static const char *
+pgstat_get_wait_timeout(WaitEventTimeout w)
+{
+	const char *event_name = "unknown wait event";
+
+	switch (w)
+	{
+		case WAIT_EVENT_BASE_BACKUP_THROTTLE:
+			event_name = "BaseBackupThrottle";
+			break;
+		case WAIT_EVENT_PG_SLEEP:
+			event_name = "PgSleep";
+			break;
+		case WAIT_EVENT_RECOVERY_APPLY_DELAY:
+			event_name = "RecoveryApplyDelay";
+			break;
+		case WAIT_EVENT_RECOVERY_RETRIEVE_RETRY_INTERVAL:
+			event_name = "RecoveryRetrieveRetryInterval";
+			break;
+		case WAIT_EVENT_VACUUM_DELAY:
+			event_name = "VacuumDelay";
+			break;
+			/* no default case, so that compiler will warn */
+	}
+
+	return event_name;
+}
+
+/* ----------
+ * pgstat_get_wait_io() -
+ *
+ * Convert WaitEventIO to string.
+ * ----------
+ */
+static const char *
+pgstat_get_wait_io(WaitEventIO w)
+{
+	const char *event_name = "unknown wait event";
+
+	switch (w)
+	{
+		case WAIT_EVENT_BASEBACKUP_READ:
+			event_name = "BaseBackupRead";
+			break;
+		case WAIT_EVENT_BUFFILE_READ:
+			event_name = "BufFileRead";
+			break;
+		case WAIT_EVENT_BUFFILE_WRITE:
+			event_name = "BufFileWrite";
+			break;
+		case WAIT_EVENT_BUFFILE_TRUNCATE:
+			event_name = "BufFileTruncate";
+			break;
+		case WAIT_EVENT_CONTROL_FILE_READ:
+			event_name = "ControlFileRead";
+			break;
+		case WAIT_EVENT_CONTROL_FILE_SYNC:
+			event_name = "ControlFileSync";
+			break;
+		case WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE:
+			event_name = "ControlFileSyncUpdate";
+			break;
+		case WAIT_EVENT_CONTROL_FILE_WRITE:
+			event_name = "ControlFileWrite";
+			break;
+		case WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE:
+			event_name = "ControlFileWriteUpdate";
+			break;
+		case WAIT_EVENT_COPY_FILE_READ:
+			event_name = "CopyFileRead";
+			break;
+		case WAIT_EVENT_COPY_FILE_WRITE:
+			event_name = "CopyFileWrite";
+			break;
+		case WAIT_EVENT_DATA_FILE_EXTEND:
+			event_name = "DataFileExtend";
+			break;
+		case WAIT_EVENT_DATA_FILE_FLUSH:
+			event_name = "DataFileFlush";
+			break;
+		case WAIT_EVENT_DATA_FILE_IMMEDIATE_SYNC:
+			event_name = "DataFileImmediateSync";
+			break;
+		case WAIT_EVENT_DATA_FILE_PREFETCH:
+			event_name = "DataFilePrefetch";
+			break;
+		case WAIT_EVENT_DATA_FILE_READ:
+			event_name = "DataFileRead";
+			break;
+		case WAIT_EVENT_DATA_FILE_SYNC:
+			event_name = "DataFileSync";
+			break;
+		case WAIT_EVENT_DATA_FILE_TRUNCATE:
+			event_name = "DataFileTruncate";
+			break;
+		case WAIT_EVENT_DATA_FILE_WRITE:
+			event_name = "DataFileWrite";
+			break;
+		case WAIT_EVENT_DSM_FILL_ZERO_WRITE:
+			event_name = "DSMFillZeroWrite";
+			break;
+		case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ:
+			event_name = "LockFileAddToDataDirRead";
+			break;
+		case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_SYNC:
+			event_name = "LockFileAddToDataDirSync";
+			break;
+		case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_WRITE:
+			event_name = "LockFileAddToDataDirWrite";
+			break;
+		case WAIT_EVENT_LOCK_FILE_CREATE_READ:
+			event_name = "LockFileCreateRead";
+			break;
+		case WAIT_EVENT_LOCK_FILE_CREATE_SYNC:
+			event_name = "LockFileCreateSync";
+			break;
+		case WAIT_EVENT_LOCK_FILE_CREATE_WRITE:
+			event_name = "LockFileCreateWrite";
+			break;
+		case WAIT_EVENT_LOCK_FILE_RECHECKDATADIR_READ:
+			event_name = "LockFileReCheckDataDirRead";
+			break;
+		case WAIT_EVENT_LOGICAL_REWRITE_CHECKPOINT_SYNC:
+			event_name = "LogicalRewriteCheckpointSync";
+			break;
+		case WAIT_EVENT_LOGICAL_REWRITE_MAPPING_SYNC:
+			event_name = "LogicalRewriteMappingSync";
+			break;
+		case WAIT_EVENT_LOGICAL_REWRITE_MAPPING_WRITE:
+			event_name = "LogicalRewriteMappingWrite";
+			break;
+		case WAIT_EVENT_LOGICAL_REWRITE_SYNC:
+			event_name = "LogicalRewriteSync";
+			break;
+		case WAIT_EVENT_LOGICAL_REWRITE_TRUNCATE:
+			event_name = "LogicalRewriteTruncate";
+			break;
+		case WAIT_EVENT_LOGICAL_REWRITE_WRITE:
+			event_name = "LogicalRewriteWrite";
+			break;
+		case WAIT_EVENT_RELATION_MAP_READ:
+			event_name = "RelationMapRead";
+			break;
+		case WAIT_EVENT_RELATION_MAP_SYNC:
+			event_name = "RelationMapSync";
+			break;
+		case WAIT_EVENT_RELATION_MAP_WRITE:
+			event_name = "RelationMapWrite";
+			break;
+		case WAIT_EVENT_REORDER_BUFFER_READ:
+			event_name = "ReorderBufferRead";
+			break;
+		case WAIT_EVENT_REORDER_BUFFER_WRITE:
+			event_name = "ReorderBufferWrite";
+			break;
+		case WAIT_EVENT_REORDER_LOGICAL_MAPPING_READ:
+			event_name = "ReorderLogicalMappingRead";
+			break;
+		case WAIT_EVENT_REPLICATION_SLOT_READ:
+			event_name = "ReplicationSlotRead";
+			break;
+		case WAIT_EVENT_REPLICATION_SLOT_RESTORE_SYNC:
+			event_name = "ReplicationSlotRestoreSync";
+			break;
+		case WAIT_EVENT_REPLICATION_SLOT_SYNC:
+			event_name = "ReplicationSlotSync";
+			break;
+		case WAIT_EVENT_REPLICATION_SLOT_WRITE:
+			event_name = "ReplicationSlotWrite";
+			break;
+		case WAIT_EVENT_SLRU_FLUSH_SYNC:
+			event_name = "SLRUFlushSync";
+			break;
+		case WAIT_EVENT_SLRU_READ:
+			event_name = "SLRURead";
+			break;
+		case WAIT_EVENT_SLRU_SYNC:
+			event_name = "SLRUSync";
+			break;
+		case WAIT_EVENT_SLRU_WRITE:
+			event_name = "SLRUWrite";
+			break;
+		case WAIT_EVENT_SNAPBUILD_READ:
+			event_name = "SnapbuildRead";
+			break;
+		case WAIT_EVENT_SNAPBUILD_SYNC:
+			event_name = "SnapbuildSync";
+			break;
+		case WAIT_EVENT_SNAPBUILD_WRITE:
+			event_name = "SnapbuildWrite";
+			break;
+		case WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC:
+			event_name = "TimelineHistoryFileSync";
+			break;
+		case WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE:
+			event_name = "TimelineHistoryFileWrite";
+			break;
+		case WAIT_EVENT_TIMELINE_HISTORY_READ:
+			event_name = "TimelineHistoryRead";
+			break;
+		case WAIT_EVENT_TIMELINE_HISTORY_SYNC:
+			event_name = "TimelineHistorySync";
+			break;
+		case WAIT_EVENT_TIMELINE_HISTORY_WRITE:
+			event_name = "TimelineHistoryWrite";
+			break;
+		case WAIT_EVENT_TWOPHASE_FILE_READ:
+			event_name = "TwophaseFileRead";
+			break;
+		case WAIT_EVENT_TWOPHASE_FILE_SYNC:
+			event_name = "TwophaseFileSync";
+			break;
+		case WAIT_EVENT_TWOPHASE_FILE_WRITE:
+			event_name = "TwophaseFileWrite";
+			break;
+		case WAIT_EVENT_WALSENDER_TIMELINE_HISTORY_READ:
+			event_name = "WALSenderTimelineHistoryRead";
+			break;
+		case WAIT_EVENT_WAL_BOOTSTRAP_SYNC:
+			event_name = "WALBootstrapSync";
+			break;
+		case WAIT_EVENT_WAL_BOOTSTRAP_WRITE:
+			event_name = "WALBootstrapWrite";
+			break;
+		case WAIT_EVENT_WAL_COPY_READ:
+			event_name = "WALCopyRead";
+			break;
+		case WAIT_EVENT_WAL_COPY_SYNC:
+			event_name = "WALCopySync";
+			break;
+		case WAIT_EVENT_WAL_COPY_WRITE:
+			event_name = "WALCopyWrite";
+			break;
+		case WAIT_EVENT_WAL_INIT_SYNC:
+			event_name = "WALInitSync";
+			break;
+		case WAIT_EVENT_WAL_INIT_WRITE:
+			event_name = "WALInitWrite";
+			break;
+		case WAIT_EVENT_WAL_READ:
+			event_name = "WALRead";
+			break;
+		case WAIT_EVENT_WAL_SYNC:
+			event_name = "WALSync";
+			break;
+		case WAIT_EVENT_WAL_SYNC_METHOD_ASSIGN:
+			event_name = "WALSyncMethodAssign";
+			break;
+		case WAIT_EVENT_WAL_WRITE:
+			event_name = "WALWrite";
+			break;
+		case WAIT_EVENT_LOGICAL_CHANGES_READ:
+			event_name = "LogicalChangesRead";
+			break;
+		case WAIT_EVENT_LOGICAL_CHANGES_WRITE:
+			event_name = "LogicalChangesWrite";
+			break;
+		case WAIT_EVENT_LOGICAL_SUBXACT_READ:
+			event_name = "LogicalSubxactRead";
+			break;
+		case WAIT_EVENT_LOGICAL_SUBXACT_WRITE:
+			event_name = "LogicalSubxactWrite";
+			break;
+
+			/* no default case, so that compiler will warn */
+	}
+
+	return event_name;
+}
-- 
2.31.0.121.g9198c13e34

>From 666af45df37fcba4493dc1119df3dcb8c410ee38 Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Fri, 2 Apr 2021 11:58:37 -0700
Subject: [PATCH v2 2/3] Do not rely on pgstat.h including storage/proc.h.

---
 src/backend/postmaster/pgarch.c                 | 2 ++
 src/backend/postmaster/pgstat.c                 | 1 +
 src/backend/replication/walreceiver.c           | 1 +
 src/backend/storage/lmgr/lmgr.c                 | 1 +
 src/backend/utils/adt/misc.c                    | 1 +
 contrib/pg_stat_statements/pg_stat_statements.c | 2 ++
 6 files changed, 8 insertions(+)

diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 746c836d420..dfc7abbc975 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -44,7 +44,9 @@
 #include "storage/ipc.h"
 #include "storage/latch.h"
 #include "storage/pmsignal.h"
+#include "storage/proc.h"
 #include "storage/procsignal.h"
+#include "storage/shmem.h"
 #include "utils/guc.h"
 #include "utils/ps_status.h"
 
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index de239136f48..498d6ee1236 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -61,6 +61,7 @@
 #include "storage/latch.h"
 #include "storage/lmgr.h"
 #include "storage/pg_shmem.h"
+#include "storage/proc.h"
 #include "storage/procsignal.h"
 #include "storage/sinvaladt.h"
 #include "utils/ascii.h"
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 2b6fa4019b8..9a0e3806fcf 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -69,6 +69,7 @@
 #include "replication/walsender.h"
 #include "storage/ipc.h"
 #include "storage/pmsignal.h"
+#include "storage/proc.h"
 #include "storage/procarray.h"
 #include "storage/procsignal.h"
 #include "utils/acl.h"
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c
index 5736d03083f..cdf2266d6d5 100644
--- a/src/backend/storage/lmgr/lmgr.c
+++ b/src/backend/storage/lmgr/lmgr.c
@@ -23,6 +23,7 @@
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "storage/lmgr.h"
+#include "storage/proc.h"
 #include "storage/procarray.h"
 #include "storage/sinvaladt.h"
 #include "utils/inval.h"
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 634f574d7eb..88faf4dfd72 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -36,6 +36,7 @@
 #include "postmaster/syslogger.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
+#include "storage/latch.h"
 #include "tcop/tcopprot.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 6feea2ab4f4..1141d2b0673 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -76,6 +76,8 @@
 #include "pgstat.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
+#include "storage/lwlock.h"
+#include "storage/shmem.h"
 #include "storage/spin.h"
 #include "tcop/utility.h"
 #include "utils/acl.h"
-- 
2.31.0.121.g9198c13e34

>From 73d1ec2e41f221f8864bc7f9bfa0ffa81cee505b Mon Sep 17 00:00:00 2001
From: Andres Freund <and...@anarazel.de>
Date: Fri, 2 Apr 2021 12:25:21 -0700
Subject: [PATCH v2 3/3] Improve efficiency of wait event reporting.

---
 src/include/utils/wait_event.h          | 42 +++++++------------------
 src/backend/storage/lmgr/proc.c         | 24 +++++++++-----
 src/backend/utils/activity/wait_event.c | 41 ++++++++++++++++++++++++
 3 files changed, 69 insertions(+), 38 deletions(-)

diff --git a/src/include/utils/wait_event.h b/src/include/utils/wait_event.h
index 2d6abfcb3f8..cff683a24eb 100644
--- a/src/include/utils/wait_event.h
+++ b/src/include/utils/wait_event.h
@@ -12,9 +12,6 @@
 #define WAIT_EVENT_H
 
 
-#include "storage/proc.h" /* for MyProc */
-
-
 /* ----------
  * Wait Classes
  * ----------
@@ -235,13 +232,10 @@ extern const char *pgstat_get_wait_event(uint32 wait_event_info);
 extern const char *pgstat_get_wait_event_type(uint32 wait_event_info);
 static inline void pgstat_report_wait_start(uint32 wait_event_info);
 static inline void pgstat_report_wait_end(void);
+extern void pgstat_set_wait_event_storage(uint32 *wait_event_info);
+extern void pgstat_reset_wait_event_storage(void);
 
-
-/*
- * Repeated here for the inline functions because it is declared in pgstat.h,
- * which includes this header.
- */
-extern PGDLLIMPORT bool pgstat_track_activities;
+extern PGDLLIMPORT uint32 *my_wait_event_info;
 
 
 /* ----------
@@ -255,47 +249,35 @@ extern PGDLLIMPORT bool pgstat_track_activities;
  *	for wait event which is sufficient for current usage, 1-byte is
  *	reserved for future usage.
  *
- * NB: this *must* be able to survive being called before MyProc has been
- * initialized.
+ *	Historically we used to make this reporting conditional on
+ *	pgstat_track_activities, but the check for that seems to add more cost
+ *	than it saves.
+ *
+ *	my_wait_event_info initially points to local memory, making it save to
+ *	call this before MyProc has been initialized.
  * ----------
  */
 static inline void
 pgstat_report_wait_start(uint32 wait_event_info)
 {
-	volatile PGPROC *proc = MyProc;
-
-	if (!pgstat_track_activities || !proc)
-		return;
-
 	/*
 	 * Since this is a four-byte field which is always read and written as
 	 * four-bytes, updates are atomic.
 	 */
-	proc->wait_event_info = wait_event_info;
+	*(volatile uint32 *) my_wait_event_info = wait_event_info;
 }
 
 /* ----------
  * pgstat_report_wait_end() -
  *
  *	Called to report end of a wait.
- *
- * NB: this *must* be able to survive being called before MyProc has been
- * initialized.
  * ----------
  */
 static inline void
 pgstat_report_wait_end(void)
 {
-	volatile PGPROC *proc = MyProc;
-
-	if (!pgstat_track_activities || !proc)
-		return;
-
-	/*
-	 * Since this is a four-byte field which is always read and written as
-	 * four-bytes, updates are atomic.
-	 */
-	proc->wait_event_info = 0;
+	/* see pgstat_report_wait_start() */
+	*(volatile uint32 *) my_wait_event_info = 0;
 }
 
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 897045ee272..692f21ef6a8 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -448,6 +448,9 @@ InitProcess(void)
 	OwnLatch(&MyProc->procLatch);
 	SwitchToSharedLatch();
 
+	/* now that we have a proc, report wait events to shared memory */
+	pgstat_set_wait_event_storage(&MyProc->wait_event_info);
+
 	/*
 	 * We might be reusing a semaphore that belonged to a failed process. So
 	 * be careful and reinitialize its value here.  (This is not strictly
@@ -601,6 +604,9 @@ InitAuxiliaryProcess(void)
 	OwnLatch(&MyProc->procLatch);
 	SwitchToSharedLatch();
 
+	/* now that we have a proc, report wait events to shared memory */
+	pgstat_set_wait_event_storage(&MyProc->wait_event_info);
+
 	/* Check that group locking fields are in a proper initial state. */
 	Assert(MyProc->lockGroupLeader == NULL);
 	Assert(dlist_is_empty(&MyProc->lockGroupMembers));
@@ -884,10 +890,15 @@ ProcKill(int code, Datum arg)
 	/*
 	 * Reset MyLatch to the process local one.  This is so that signal
 	 * handlers et al can continue using the latch after the shared latch
-	 * isn't ours anymore. After that clear MyProc and disown the shared
-	 * latch.
+	 * isn't ours anymore.
+	 *
+	 * Similarly, stop reporting wait events to MyProc->wait_event_info.
+	 *
+	 * After that clear MyProc and disown the shared latch.
 	 */
 	SwitchBackToLocalLatch();
+	pgstat_reset_wait_event_storage();
+
 	proc = MyProc;
 	MyProc = NULL;
 	DisownLatch(&proc->procLatch);
@@ -952,13 +963,10 @@ AuxiliaryProcKill(int code, Datum arg)
 	/* Cancel any pending condition variable sleep, too */
 	ConditionVariableCancelSleep();
 
-	/*
-	 * Reset MyLatch to the process local one.  This is so that signal
-	 * handlers et al can continue using the latch after the shared latch
-	 * isn't ours anymore. After that clear MyProc and disown the shared
-	 * latch.
-	 */
+	/* look at the equivalent ProcKill() code for comments */
 	SwitchBackToLocalLatch();
+	pgstat_reset_wait_event_storage();
+
 	proc = MyProc;
 	MyProc = NULL;
 	DisownLatch(&proc->procLatch);
diff --git a/src/backend/utils/activity/wait_event.c b/src/backend/utils/activity/wait_event.c
index 840ebef92ab..accc1eb5776 100644
--- a/src/backend/utils/activity/wait_event.c
+++ b/src/backend/utils/activity/wait_event.c
@@ -7,6 +7,17 @@
  *
  * IDENTIFICATION
  *	  src/backend/postmaster/wait_event.c
+ *
+ * NOTES
+ *
+ * To make pgstat_report_wait_start() and pgstat_report_wait_end() as
+ * lightweight as possible, they do not check if shared memory (MyProc
+ * specifically, where the wait event is stored) is already available. Instead
+ * we initially set my_wait_event_info to a process local variable, which then
+ * is redirected to shared memory using pgstat_set_wait_event_storage(). For
+ * the same reason pgstat_track_activities is not checked - the check adds
+ * more work than it saves.
+ *
  * ----------
  */
 #include "postgres.h"
@@ -23,6 +34,36 @@ static const char *pgstat_get_wait_timeout(WaitEventTimeout w);
 static const char *pgstat_get_wait_io(WaitEventIO w);
 
 
+static uint32 local_my_wait_event_info;
+uint32	   *my_wait_event_info = &local_my_wait_event_info;
+
+
+/*
+ * Configure wait event reporting to report wait events to *wait_event_info.
+ * *wait_event_info needs to be valid until pgstat_reset_wait_event_storage()
+ * is called.
+ *
+ * Expected to be called during backend startup, to point my_wait_event_info
+ * into shared memory.
+ */
+void
+pgstat_set_wait_event_storage(uint32 *wait_event_info)
+{
+	my_wait_event_info = wait_event_info;
+}
+
+/*
+ * Reset wait event storage location.
+ *
+ * Expected to be called during backend shutdown, before the location set up
+ * pgstat_set_wait_event_storage() becomes invalid.
+ */
+void
+pgstat_reset_wait_event_storage(void)
+{
+	my_wait_event_info = &local_my_wait_event_info;
+}
+
 /* ----------
  * pgstat_get_wait_event_type() -
  *
-- 
2.31.0.121.g9198c13e34

Reply via email to