diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 01fad38..7d953f1 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -716,6 +716,12 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
           point.
          </para>
         </listitem>
+        <listitem>
+         <para>
+          <literal>IO</>: The server process is waiting for a IO to complete.
+          <literal>wait_event</> will identify the specific wait point.
+         </para>
+        </listitem>
        </itemizedlist>
       </entry>
      </row>
@@ -1260,6 +1266,272 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
          <entry><literal>RecoveryApplyDelay</></entry>
          <entry>Waiting to apply WAL at recovery because it is delayed.</entry>
         </row>
+        <row>
+         <entry morerows="65"><literal>IO</></entry>
+         <entry><literal>ReadDataBlock</></entry>
+         <entry>Waiting during relation data block read.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteDataBlock</></entry>
+         <entry>Waiting during relation data block write.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncDataBlock</></entry>
+         <entry>Waiting during relation data block sync.</entry>
+        </row>
+        <row>
+         <entry><literal>ExtendDataBlock</></entry>
+         <entry>Waiting during add a block to the relation.</entry>
+        </row>
+        <row>
+         <entry><literal>FlushDataBlock</></entry>
+         <entry>Waiting during write pages back to storage.</entry>
+        </row>
+        <row>
+         <entry><literal>PrefetchDataBlock</></entry>
+         <entry>Waiting during asynchronous read of the specified block of a relation.</entry>
+        </row>
+        <row>
+         <entry><literal>TruncateDataBlock</></entry>
+         <entry>Waiting during truncate relation to specified number of blocks.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncRelation</></entry>
+         <entry>Waiting during sync writes to stable storage.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncImmedRelation</></entry>
+         <entry>Waiting during immediate sync a relation to stable storage.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteRewriteDataBlock</></entry>
+         <entry>Waiting to write data block during rewrite heap.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncRewriteDataBlock</></entry>
+         <entry>Waiting to sync data block during rewrite heap.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteBuffile</></entry>
+         <entry>Waiting during buffile read operation.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteBuffile</></entry>
+         <entry>Waiting during buffile write operation.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadXLog</></entry>
+         <entry>Waiting during read the XLOG page.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadCopyXLog</></entry>
+         <entry>Wait to read the XLOG page during create a new XLOG file segment by copying a pre-existing one.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteXLog</></entry>
+         <entry>Waiting during write the XLOG page.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteInitXLogFile</></entry>
+         <entry>Waiting to write the XLOG page during XLOG file initialization.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteCopyXLogFile</></entry>
+         <entry>Waiting to write the XLOG page during create a new XLOG file segment by copying a pre-existing one.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteBootstrapXLog</></entry>
+         <entry>Waiting to write the XLOG page during bootstrap.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncInitXLogFile</></entry>
+         <entry>Waiting to sync the XLOG page during XLOG file initialization.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncCopyXLogFile</></entry>
+         <entry>Waiting to sync the XLOG page during create a new XLOG file segment by copying a pre-existing one.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncBootstrapXLog</></entry>
+         <entry>Waiting to sync the XLOG page during bootstrap.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncAssignXLogMethod</></entry>
+         <entry>Waiting to assign xlog sync method.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteControlFile</></entry>
+         <entry>Waiting to write the control file.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteUpdateControlFile</></entry>
+         <entry>Waiting to write the control file during update control file.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadControlFile</></entry>
+         <entry>Waiting to read the control file.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncWriteControlFile</></entry>
+         <entry>Waiting to sync the control file.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncUpdateControlFile</></entry>
+         <entry>Waiting to sync the control file during update control file.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadApplyLogicalMapping</></entry>
+         <entry>Waiting to read logical mapping during apply a single mapping file.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteLogicalMappingRewrite</></entry>
+         <entry>Waiting to write logical mapping during xlog logical rewrite.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncLogicalMappingRewrite</></entry>
+         <entry>Waiting to sync logical mapping during xlog logical rewrite.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncLogicalMappingRewriteHeap</></entry>
+         <entry>Waiting to sync logical mapping during a checkpoint for logical rewrite mappings.</entry>
+        </row>
+        <row>
+         <entry><literal>TruncateLogicalMappingRewrite</></entry>
+         <entry>Waiting to truncate logical mapping during xlog logical rewrite.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteSnapbuildSerialize</></entry>
+         <entry>Waiting to write snapshot during serialize the snapshot.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadSnapbuildSerialize</></entry>
+         <entry>Waiting to read snapshot during serialize the snapshot.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncSnapbuildSerialize</></entry>
+         <entry>Waiting to sync snapshot during serialize the snapshot.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadSLRUPage</></entry>
+         <entry>Waiting to read page during physical read of a page into a buffer slot.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteSLRUPage</></entry>
+         <entry>Waiting to write page during physical write of a page from a buffer slot.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncSLRUWritePage</></entry>
+         <entry>Waiting to sync page during physical write of a page from a buffer slot.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncSLRUFlush</></entry>
+         <entry>Waiting to sync page during flush dirty pages to disk during checkpoint or database shutdown.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadTimelineHistoryWrite</></entry>
+         <entry>Waiting to read timeline history during write timeline history.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadTimelineHistoryWalsender</></entry>
+         <entry>Waiting to read timeline history during walsander timeline command.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteTimelineHistory</></entry>
+         <entry>Waiting to write timeline history.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteTimelineHistoryFile</></entry>
+         <entry>Waiting to write timeline history during a history file write for given timeline and contents.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncTimelineHistoryWrite</></entry>
+         <entry>Waiting to sync timeline history during write timeline history</entry>
+        </row>
+        <row>
+         <entry><literal>SyncTimelineHistoryFile</></entry>
+         <entry>Waiting to sync timeline history during a history file write for given timeline and contents.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadTwophaseFile</></entry>
+         <entry>Waiting to read two phase file.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteRecreateTwophaseFile</></entry>
+         <entry>Waiting to write two phase file during recreate two phase file.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncRecreateTwophaseFile</></entry>
+         <entry>Waiting to sync two phase file during recreate two phase file.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadSysloggerFile</></entry>
+         <entry>Wait during read syslogger file.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteSysloggerFile</></entry>
+         <entry>Wait during write syslogger file.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadRestorREPLSlot</></entry>
+         <entry>Wait to read REPL slot during load a single slot from disk into memory.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteREPLSlot</></entry>
+         <entry>Wait to write REPL slot.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncRestoreREPLSlot</></entry>
+         <entry>Wait to sync REPL slot during load a single slot from disk into memory.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadCopyFile</></entry>
+         <entry>Waiting to read during copy file.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteCopyFile</></entry>
+         <entry>Waiting to write during copy file.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadLoadRELMAPFile</></entry>
+         <entry>Waiting to read RELMAP file.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteLoadRELMAPFile</></entry>
+         <entry>Waiting to write RELMAP file.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncLoadRELMAPFile</></entry>
+         <entry>Waiting to sync RELMAP file.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadCreateLockFile</></entry>
+         <entry>Wait to read lock file during create lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadAddToDataDirLockFile</></entry>
+         <entry>Wait to read lock file during add a line in the data directory lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>ReadRecheckDataDirLockFile</></entry>
+         <entry>Wait to read lock file during recheck that the data directory lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteCreateLockFile</></entry>
+         <entry>Wait to write lock file during create lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>WriteAddToDataDirLockFile</></entry>
+         <entry>Wait to write lock file during add a line in the data directory lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncCreateLockFile</></entry>
+         <entry>Wait to sync lock file during create lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>SyncAddToDataDirLockFile</></entry>
+         <entry>Wait to sync lock file during add a line in the data directory lock file.</entry>
+        </row>
+
       </tbody>
      </tgroup>
     </table>
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index 90ab6f2..709acbf 100644
--- a/src/backend/access/heap/rewriteheap.c
+++ b/src/backend/access/heap/rewriteheap.c
@@ -119,6 +119,8 @@
 
 #include "lib/ilist.h"
 
+#include "pgstat.h"
+
 #include "replication/logical.h"
 #include "replication/slot.h"
 
@@ -916,7 +918,8 @@ logical_heap_rewrite_flush_mappings(RewriteState state)
 		 * Note that we deviate from the usual WAL coding practices here,
 		 * check the above "Logical rewrite support" comment for reasoning.
 		 */
-		written = FileWrite(src->vfd, waldata_start, len);
+		written = FileWrite(src->vfd, waldata_start, len,
+							WAIT_EVENT_WRITE_REWRITE_DATA_BLOCK);
 		if (written != len)
 			ereport(ERROR,
 					(errcode_for_file_access(),
@@ -957,7 +960,7 @@ logical_end_heap_rewrite(RewriteState state)
 	hash_seq_init(&seq_status, state->rs_logical_mappings);
 	while ((src = (RewriteMappingFile *) hash_seq_search(&seq_status)) != NULL)
 	{
-		if (FileSync(src->vfd) != 0)
+		if (FileSync(src->vfd, WAIT_EVENT_SYNC_REWRITE_DATA_BLOCK) != 0)
 			ereport(ERROR,
 					(errcode_for_file_access(),
 					 errmsg("could not fsync file \"%s\": %m", src->path)));
@@ -1141,11 +1144,13 @@ heap_xlog_logical_rewrite(XLogReaderState *r)
 	 * Truncate all data that's not guaranteed to have been safely fsynced (by
 	 * previous record or by the last checkpoint).
 	 */
+	pgstat_report_wait_start(WAIT_EVENT_TRUNCATE_LOGICAL_MAPPING_REWRITE);
 	if (ftruncate(fd, xlrec->offset) != 0)
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not truncate file \"%s\" to %u: %m",
 						path, (uint32) xlrec->offset)));
+	pgstat_report_wait_end();
 
 	/* now seek to the position we want to write our data to */
 	if (lseek(fd, xlrec->offset, SEEK_SET) != xlrec->offset)
@@ -1159,20 +1164,24 @@ heap_xlog_logical_rewrite(XLogReaderState *r)
 	len = xlrec->num_mappings * sizeof(LogicalRewriteMappingData);
 
 	/* write out tail end of mapping file (again) */
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_LOGICAL_MAPPING_REWRITE);
 	if (write(fd, data, len) != len)
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not write to file \"%s\": %m", path)));
+	pgstat_report_wait_end();
 
 	/*
 	 * Now fsync all previously written data. We could improve things and only
 	 * do this for the last write to a file, but the required bookkeeping
 	 * doesn't seem worth the trouble.
 	 */
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_LOGICAL_MAPPING_REWRITE);
 	if (pg_fsync(fd) != 0)
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not fsync file \"%s\": %m", path)));
+	pgstat_report_wait_end();
 
 	CloseTransientFile(fd);
 }
@@ -1266,10 +1275,12 @@ CheckPointLogicalRewriteHeap(void)
 			 * changed or have only been created since the checkpoint's start,
 			 * but it's currently not deemed worth the effort.
 			 */
-			else if (pg_fsync(fd) != 0)
+			pgstat_report_wait_start(WAIT_EVENT_SYNC_LOGICAL_MAPPING_REWRITE_HEAP);
+			if (pg_fsync(fd) != 0)
 				ereport(ERROR,
 						(errcode_for_file_access(),
 						 errmsg("could not fsync file \"%s\": %m", path)));
+			pgstat_report_wait_end();
 			CloseTransientFile(fd);
 		}
 	}
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index a66ef5c..237e8eb 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -54,6 +54,7 @@
 #include "access/slru.h"
 #include "access/transam.h"
 #include "access/xlog.h"
+#include "pgstat.h"
 #include "storage/fd.h"
 #include "storage/shmem.h"
 #include "miscadmin.h"
@@ -675,13 +676,16 @@ SlruPhysicalReadPage(SlruCtl ctl, int pageno, int slotno)
 	}
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_READ_SLRU_PAGE);
 	if (read(fd, shared->page_buffer[slotno], BLCKSZ) != BLCKSZ)
 	{
+		pgstat_report_wait_end();
 		slru_errcause = SLRU_READ_FAILED;
 		slru_errno = errno;
 		CloseTransientFile(fd);
 		return false;
 	}
+	pgstat_report_wait_end();
 
 	if (CloseTransientFile(fd))
 	{
@@ -834,8 +838,10 @@ SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
 	}
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_SLRU_PAGE);
 	if (write(fd, shared->page_buffer[slotno], BLCKSZ) != BLCKSZ)
 	{
+		pgstat_report_wait_end();
 		/* if write didn't set errno, assume problem is no disk space */
 		if (errno == 0)
 			errno = ENOSPC;
@@ -845,6 +851,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
 			CloseTransientFile(fd);
 		return false;
 	}
+	pgstat_report_wait_end();
 
 	/*
 	 * If not part of Flush, need to fsync now.  We assume this happens
@@ -852,6 +859,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
 	 */
 	if (!fdata)
 	{
+		pgstat_report_wait_start(WAIT_EVENT_SYNC_SLRU_WRITE_PAGE);
 		if (ctl->do_fsync && pg_fsync(fd))
 		{
 			slru_errcause = SLRU_FSYNC_FAILED;
@@ -859,6 +867,7 @@ SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno, SlruFlush fdata)
 			CloseTransientFile(fd);
 			return false;
 		}
+		pgstat_report_wait_end();
 
 		if (CloseTransientFile(fd))
 		{
@@ -1126,6 +1135,7 @@ SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
 	ok = true;
 	for (i = 0; i < fdata.num_files; i++)
 	{
+		pgstat_report_wait_start(WAIT_EVENT_SYNC_SLRU_FLUSH);
 		if (ctl->do_fsync && pg_fsync(fdata.fd[i]))
 		{
 			slru_errcause = SLRU_FSYNC_FAILED;
@@ -1133,6 +1143,7 @@ SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
 			pageno = fdata.segno[i] * SLRU_PAGES_PER_SEGMENT;
 			ok = false;
 		}
+		pgstat_report_wait_end();
 
 		if (CloseTransientFile(fdata.fd[i]))
 		{
diff --git a/src/backend/access/transam/timeline.c b/src/backend/access/transam/timeline.c
index c8240b1..052f77f 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -39,6 +39,7 @@
 #include "access/xlog.h"
 #include "access/xlog_internal.h"
 #include "access/xlogdefs.h"
+#include "pgstat.h"
 #include "storage/fd.h"
 
 /*
@@ -339,7 +340,9 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
 		for (;;)
 		{
 			errno = 0;
+			pgstat_report_wait_start(WAIT_EVENT_READ_TIMELINE_HISTORY_WRITE);
 			nbytes = (int) read(srcfd, buffer, sizeof(buffer));
+			pgstat_report_wait_end();
 			if (nbytes < 0 || errno != 0)
 				ereport(ERROR,
 						(errcode_for_file_access(),
@@ -347,6 +350,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
 			if (nbytes == 0)
 				break;
 			errno = 0;
+			pgstat_report_wait_start(WAIT_EVENT_WRITE_TIMELINE_HISTORY);
 			if ((int) write(fd, buffer, nbytes) != nbytes)
 			{
 				int			save_errno = errno;
@@ -366,6 +370,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
 						(errcode_for_file_access(),
 					 errmsg("could not write to file \"%s\": %m", tmppath)));
 			}
+			pgstat_report_wait_end();
 		}
 		CloseTransientFile(srcfd);
 	}
@@ -401,10 +406,12 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
 				 errmsg("could not write to file \"%s\": %m", tmppath)));
 	}
 
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_TIMELINE_HISTORY_WRITE);
 	if (pg_fsync(fd) != 0)
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not fsync file \"%s\": %m", tmppath)));
+	pgstat_report_wait_end();
 
 	if (CloseTransientFile(fd))
 		ereport(ERROR,
@@ -461,6 +468,7 @@ writeTimeLineHistoryFile(TimeLineID tli, char *content, int size)
 				 errmsg("could not create file \"%s\": %m", tmppath)));
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_TIMELINE_HISTORY_FILE);
 	if ((int) write(fd, content, size) != size)
 	{
 		int			save_errno = errno;
@@ -476,11 +484,14 @@ writeTimeLineHistoryFile(TimeLineID tli, char *content, int size)
 				(errcode_for_file_access(),
 				 errmsg("could not write to file \"%s\": %m", tmppath)));
 	}
+	pgstat_report_wait_end();
 
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_TIMELINE_HISTORY_FILE);
 	if (pg_fsync(fd) != 0)
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not fsync file \"%s\": %m", tmppath)));
+	pgstat_report_wait_end();
 
 	if (CloseTransientFile(fd))
 		ereport(ERROR,
diff --git a/src/backend/access/transam/twophase.c b/src/backend/access/transam/twophase.c
index 5b72c1d..3ab361e 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1200,8 +1200,10 @@ ReadTwoPhaseFile(TransactionId xid, bool give_warnings)
 	 */
 	buf = (char *) palloc(stat.st_size);
 
+	pgstat_report_wait_start(WAIT_EVENT_READ_TWOPHASE_FILE);
 	if (read(fd, buf, stat.st_size) != stat.st_size)
 	{
+		pgstat_report_wait_end();
 		CloseTransientFile(fd);
 		if (give_warnings)
 			ereport(WARNING,
@@ -1212,6 +1214,7 @@ ReadTwoPhaseFile(TransactionId xid, bool give_warnings)
 		return NULL;
 	}
 
+	pgstat_report_wait_end();
 	CloseTransientFile(fd);
 
 	hdr = (TwoPhaseFileHeader *) buf;
@@ -1542,8 +1545,10 @@ RecreateTwoPhaseFile(TransactionId xid, void *content, int len)
 						path)));
 
 	/* Write content and CRC */
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_RECREATE_TWOPHASE_FILE);
 	if (write(fd, content, len) != len)
 	{
+		pgstat_report_wait_end();
 		CloseTransientFile(fd);
 		ereport(ERROR,
 				(errcode_for_file_access(),
@@ -1551,16 +1556,19 @@ RecreateTwoPhaseFile(TransactionId xid, void *content, int len)
 	}
 	if (write(fd, &statefile_crc, sizeof(pg_crc32c)) != sizeof(pg_crc32c))
 	{
+		pgstat_report_wait_end();
 		CloseTransientFile(fd);
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not write two-phase state file: %m")));
 	}
+	pgstat_report_wait_end();
 
 	/*
 	 * We must fsync the file because the end-of-replay checkpoint will not do
 	 * so, there being no GXACT in shared memory yet to tell it to.
 	 */
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_RECREATE_TWOPHASE_FILE);
 	if (pg_fsync(fd) != 0)
 	{
 		CloseTransientFile(fd);
@@ -1568,6 +1576,7 @@ RecreateTwoPhaseFile(TransactionId xid, void *content, int len)
 				(errcode_for_file_access(),
 				 errmsg("could not fsync two-phase state file: %m")));
 	}
+	pgstat_report_wait_end();
 
 	if (CloseTransientFile(fd) != 0)
 		ereport(ERROR,
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index 2f5d603..8725d9b 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2340,7 +2340,9 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
 			do
 			{
 				errno = 0;
+				pgstat_report_wait_start(WAIT_EVENT_WRITE_XLOG);
 				written = write(openLogFile, from, nleft);
+				pgstat_report_wait_end();
 				if (written <= 0)
 				{
 					if (errno == EINTR)
@@ -3091,6 +3093,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
 	for (nbytes = 0; nbytes < XLogSegSize; nbytes += XLOG_BLCKSZ)
 	{
 		errno = 0;
+		pgstat_report_wait_start(WAIT_EVENT_WRITE_INIT_XLOG_FILE);
 		if ((int) write(fd, zbuffer, XLOG_BLCKSZ) != (int) XLOG_BLCKSZ)
 		{
 			int			save_errno = errno;
@@ -3109,8 +3112,10 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
 					(errcode_for_file_access(),
 					 errmsg("could not write to file \"%s\": %m", tmppath)));
 		}
+		pgstat_report_wait_end();
 	}
 
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_INIT_XLOG_FILE);
 	if (pg_fsync(fd) != 0)
 	{
 		close(fd);
@@ -3118,6 +3123,7 @@ XLogFileInit(XLogSegNo logsegno, bool *use_existent, bool use_lock)
 				(errcode_for_file_access(),
 				 errmsg("could not fsync file \"%s\": %m", tmppath)));
 	}
+	pgstat_report_wait_end();
 
 	if (close(fd))
 		ereport(ERROR,
@@ -3244,6 +3250,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
 			if (nread > sizeof(buffer))
 				nread = sizeof(buffer);
 			errno = 0;
+			pgstat_report_wait_start(WAIT_EVENT_READ_COPY_XLOG);
 			if (read(srcfd, buffer, nread) != nread)
 			{
 				if (errno != 0)
@@ -3256,8 +3263,10 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
 							(errmsg("not enough data in file \"%s\"",
 									path)));
 			}
+			pgstat_report_wait_end();
 		}
 		errno = 0;
+		pgstat_report_wait_start(WAIT_EVENT_WRITE_COPY_XLOG_FILE);
 		if ((int) write(fd, buffer, sizeof(buffer)) != (int) sizeof(buffer))
 		{
 			int			save_errno = errno;
@@ -3273,12 +3282,15 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
 					(errcode_for_file_access(),
 					 errmsg("could not write to file \"%s\": %m", tmppath)));
 		}
+		pgstat_report_wait_end();
 	}
 
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_COPY_XLOG_FILE);
 	if (pg_fsync(fd) != 0)
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not fsync file \"%s\": %m", tmppath)));
+	pgstat_report_wait_end();
 
 	if (CloseTransientFile(fd))
 		ereport(ERROR,
@@ -4303,6 +4315,7 @@ WriteControlFile(void)
 						XLOG_CONTROL_FILE)));
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_CONTROL_FILE);
 	if (write(fd, buffer, PG_CONTROL_SIZE) != PG_CONTROL_SIZE)
 	{
 		/* if write didn't set errno, assume problem is no disk space */
@@ -4312,11 +4325,14 @@ WriteControlFile(void)
 				(errcode_for_file_access(),
 				 errmsg("could not write to control file: %m")));
 	}
+	pgstat_report_wait_end();
 
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_WRITE_CONTROL_FILE);
 	if (pg_fsync(fd) != 0)
 		ereport(PANIC,
 				(errcode_for_file_access(),
 				 errmsg("could not fsync control file: %m")));
+	pgstat_report_wait_end();
 
 	if (close(fd))
 		ereport(PANIC,
@@ -4342,10 +4358,12 @@ ReadControlFile(void)
 				 errmsg("could not open control file \"%s\": %m",
 						XLOG_CONTROL_FILE)));
 
+	pgstat_report_wait_start(WAIT_EVENT_READ_CONTROL_FILE);
 	if (read(fd, ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
 		ereport(PANIC,
 				(errcode_for_file_access(),
 				 errmsg("could not read from control file: %m")));
+	pgstat_report_wait_end();
 
 	close(fd);
 
@@ -4539,6 +4557,7 @@ UpdateControlFile(void)
 						XLOG_CONTROL_FILE)));
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_UPDATE_CONTROL_FILE);
 	if (write(fd, ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
 	{
 		/* if write didn't set errno, assume problem is no disk space */
@@ -4548,11 +4567,14 @@ UpdateControlFile(void)
 				(errcode_for_file_access(),
 				 errmsg("could not write to control file: %m")));
 	}
+	pgstat_report_wait_end();
 
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_UPDATE_CONTROL_FILE);
 	if (pg_fsync(fd) != 0)
 		ereport(PANIC,
 				(errcode_for_file_access(),
 				 errmsg("could not fsync control file: %m")));
+	pgstat_report_wait_end();
 
 	if (close(fd))
 		ereport(PANIC,
@@ -4919,6 +4941,7 @@ BootStrapXLOG(void)
 
 	/* Write the first page with the initial record */
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_BOOTSTRAP_XLOG);
 	if (write(openLogFile, page, XLOG_BLCKSZ) != XLOG_BLCKSZ)
 	{
 		/* if write didn't set errno, assume problem is no disk space */
@@ -4928,11 +4951,14 @@ BootStrapXLOG(void)
 				(errcode_for_file_access(),
 			  errmsg("could not write bootstrap transaction log file: %m")));
 	}
+	pgstat_report_wait_end();
 
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_BOOTSTRAP_XLOG);
 	if (pg_fsync(openLogFile) != 0)
 		ereport(PANIC,
 				(errcode_for_file_access(),
 			  errmsg("could not fsync bootstrap transaction log file: %m")));
+	pgstat_report_wait_end();
 
 	if (close(openLogFile))
 		ereport(PANIC,
@@ -9865,11 +9891,13 @@ assign_xlog_sync_method(int new_sync_method, void *extra)
 		 */
 		if (openLogFile >= 0)
 		{
+			pgstat_report_wait_start(WAIT_EVENT_SYNC_ASSIGN_XLOG_SYNC_METHOD);
 			if (pg_fsync(openLogFile) != 0)
 				ereport(PANIC,
 						(errcode_for_file_access(),
 						 errmsg("could not fsync log segment %s: %m",
 							  XLogFileNameP(ThisTimeLineID, openLogSegNo))));
+			pgstat_report_wait_end();
 			if (get_sync_bit(sync_method) != get_sync_bit(new_sync_method))
 				XLogFileClose();
 		}
@@ -11322,6 +11350,7 @@ retry:
 		goto next_record_is_invalid;
 	}
 
+	pgstat_report_wait_start(WAIT_EVENT_READ_XLOG);
 	if (read(readFile, readBuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
 	{
 		char		fname[MAXFNAMELEN];
@@ -11333,6 +11362,7 @@ retry:
 						fname, readOff)));
 		goto next_record_is_invalid;
 	}
+	pgstat_report_wait_end();
 
 	Assert(targetSegNo == readSegNo);
 	Assert(targetPageOff == readOff);
diff --git a/src/backend/access/transam/xlogutils.c b/src/backend/access/transam/xlogutils.c
index 0de2419..24538bc 100644
--- a/src/backend/access/transam/xlogutils.c
+++ b/src/backend/access/transam/xlogutils.c
@@ -24,6 +24,7 @@
 #include "access/xlogutils.h"
 #include "catalog/catalog.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "storage/smgr.h"
 #include "utils/guc.h"
 #include "utils/hsearch.h"
@@ -727,7 +728,9 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
 		else
 			segbytes = nbytes;
 
+		pgstat_report_wait_start(WAIT_EVENT_READ_XLOG);
 		readbytes = read(sendFile, p, segbytes);
+		pgstat_report_wait_end();
 		if (readbytes <= 0)
 		{
 			char		path[MAXPGPATH];
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 7176cf1..5a8a945 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -280,6 +280,7 @@ 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);
@@ -3176,6 +3177,9 @@ pgstat_get_wait_event_type(uint32 wait_event_info)
 		case PG_WAIT_TIMEOUT:
 			event_type = "Timeout";
 			break;
+		case PG_WAIT_IO:
+			event_type = "IO";
+			break;
 		default:
 			event_type = "???";
 			break;
@@ -3246,6 +3250,13 @@ pgstat_get_wait_event(uint32 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;
@@ -3433,6 +3444,247 @@ pgstat_get_wait_timeout(WaitEventTimeout w)
 }
 
 /* ----------
+ * 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_READ_DATA_BLOCK:
+			event_name = "ReadDataBlock";
+			break;
+		case WAIT_EVENT_WRITE_DATA_BLOCK:
+			event_name = "WriteDataBlock";
+			break;
+		case WAIT_EVENT_SYNC_DATA_BLOCK:
+			event_name = "SyncDataBlock";
+			break;
+		case WAIT_EVENT_EXTEND_DATA_BLOCK:
+			event_name = "ExtendDataBlock";
+			break;
+		case WAIT_EVENT_FLUSH_DATA_BLOCK:
+			event_name = "FlushDataBlock";
+			break;
+		case WAIT_EVENT_PREFETCH_DATA_BLOCK:
+			event_name = "PrefetchDataBlock";
+			break;
+		case WAIT_EVENT_TRUNCATE_RELATION_DATA_BLOCKS:
+			event_name = "TruncateDataBlock";
+			break;
+		case WAIT_EVENT_SYNC_RELATION:
+			event_name = "SyncRelation";
+			break;
+		case WAIT_EVENT_SYNC_IMMED_RELATION:
+			event_name = "SyncImmedRelation";
+			break;
+		case WAIT_EVENT_WRITE_REWRITE_DATA_BLOCK:
+			event_name = "WriteRewriteDataBlock";
+			break;
+		case WAIT_EVENT_SYNC_REWRITE_DATA_BLOCK:
+			event_name = "SyncRewriteDataBlock";
+			break;
+		case WAIT_EVENT_READ_BUFFILE:
+			event_name = "ReadBuffile";
+			break;
+		case WAIT_EVENT_WRITE_BUFFILE:
+			event_name = "WriteBuffile";
+			break;
+		/* XLOG wait event */
+		case WAIT_EVENT_READ_XLOG:
+			event_name = "ReadXLog";
+			break;
+		case WAIT_EVENT_READ_COPY_XLOG:
+			event_name = "ReadCopyXLog";
+			break;
+		case WAIT_EVENT_WRITE_XLOG:
+			event_name = "WriteXLog";
+			break;
+		case WAIT_EVENT_WRITE_INIT_XLOG_FILE:
+			event_name = "WriteInitXLogFile";
+			break;
+		case WAIT_EVENT_WRITE_COPY_XLOG_FILE:
+			event_name = "WriteCopyXLogFile";
+			break;
+		case WAIT_EVENT_WRITE_BOOTSTRAP_XLOG:
+			event_name = "WriteBootstrapXLog";
+			break;
+		case WAIT_EVENT_SYNC_INIT_XLOG_FILE:
+			event_name = "SyncInitXLogFile";
+			break;
+		case WAIT_EVENT_SYNC_COPY_XLOG_FILE:
+			event_name = "SyncCopyXLogFile";
+			break;
+		case WAIT_EVENT_SYNC_BOOTSTRAP_XLOG:
+			event_name = "SyncBootStrapXLog";
+			break;
+		case WAIT_EVENT_SYNC_ASSIGN_XLOG_SYNC_METHOD:
+			event_name = "SyncAssignXLogMethod";
+			break;
+		/* Control file wait events */
+		case WAIT_EVENT_WRITE_CONTROL_FILE:
+			event_name = "WriteControlFile";
+			break;
+		case WAIT_EVENT_WRITE_UPDATE_CONTROL_FILE:
+			event_name = "WriteUpdateControlFile";
+			break;
+		case WAIT_EVENT_READ_CONTROL_FILE:
+			event_name = "ReadControlFile";
+			break;
+		case WAIT_EVENT_SYNC_WRITE_CONTROL_FILE:
+			event_name = "SyncWriteControlFile";
+			break;
+		case WAIT_EVENT_SYNC_UPDATE_CONTROL_FILE:
+			event_name = "SyncUpdateControlFile";
+			break;
+		/* reorder buffer wait event */
+		case WAIT_EVENT_READ_REORDER_BUFFER:
+			event_name = "ReadReorderBuffer";
+			break;
+		case WAIT_EVENT_WRITE_REORDER_BUFFER:
+			event_name = "WriteReorderBuffer";
+			break;
+		/* logical mapping wait event */
+		case WAIT_EVENT_READ_APPLY_LOGICAL_MAPPING:
+			event_name = "ReadApplyLogicalMapping";
+			break;
+		case WAIT_EVENT_WRITE_LOGICAL_MAPPING_REWRITE:
+			event_name = "WriteLogicalMappingRewrite";
+			break;
+		case WAIT_EVENT_SYNC_LOGICAL_MAPPING_REWRITE:
+			event_name = "SyncLogicalMappingRewrite";
+			break;
+		case WAIT_EVENT_SYNC_LOGICAL_MAPPING_REWRITE_HEAP:
+			event_name = "SyncLogicalMappingRewriteHeap";
+			break;
+		case WAIT_EVENT_TRUNCATE_LOGICAL_MAPPING_REWRITE:
+			event_name = "TruncateLogicalMappingRewrite";
+			break;
+		/* Snapbuild wait event */
+		case WAIT_EVENT_WRITE_SNAPBUILD_SERIALIZE:
+			event_name = "WriteSnapbuildSerialize";
+			break;
+		case WAIT_EVENT_READ_SNAPBUILD_RESTORE:
+			event_name = "ReadSnapbuildRestore";
+			break;
+		case WAIT_EVENT_SYNC_SNAPBUILD_SERIALIZE:
+			event_name = "SyncSnapbuildSerialize";
+			break;
+		/* SLRU wait event */
+		case WAIT_EVENT_READ_SLRU_PAGE:
+			event_name = "ReadSLRUPage";
+			break;
+		case WAIT_EVENT_WRITE_SLRU_PAGE:
+			event_name = "WriteSLRUPage";
+			break;
+		case WAIT_EVENT_SYNC_SLRU_FLUSH:
+			event_name = "SyncSLRUFlush";
+			break;
+		case WAIT_EVENT_SYNC_SLRU_WRITE_PAGE:
+			event_name = "SyncSLRUWritePage";
+			break;
+		/* TIMELINE HISTORY wait event */
+		case WAIT_EVENT_READ_TIMELINE_HISTORY_WALSENDER:
+			event_name = "ReadTimelineHistoryWalsender";
+			break;
+		case WAIT_EVENT_WRITE_TIMELINE_HISTORY:
+			event_name = "WriteTimelineHistory";
+			break;
+		case WAIT_EVENT_WRITE_TIMELINE_HISTORY_FILE:
+			event_name = "WriteTimelineHistoryFile";
+			break;
+		case WAIT_EVENT_READ_TIMELINE_HISTORY_WRITE:
+			event_name = "ReadTimelineHistoryWrite";
+			break;
+		case WAIT_EVENT_SYNC_TIMELINE_HISTORY_WRITE:
+			event_name = "SyncTimelineHistoryWrite";
+			break;
+		case WAIT_EVENT_SYNC_TIMELINE_HISTORY_FILE:
+			event_name = "SyncTimelineHistoryFile";
+			break;
+		/* TWOPHASE FILE wait event */
+		case WAIT_EVENT_READ_TWOPHASE_FILE:
+			event_name = "ReadTwophaseFile";
+			break;
+		case WAIT_EVENT_WRITE_RECREATE_TWOPHASE_FILE:
+			event_name = "WriteRecreateTwophaseFile";
+			break;
+		case WAIT_EVENT_SYNC_RECREATE_TWOPHASE_FILE:
+			event_name = "SyncRecreateTwophaseFile";
+			break;
+		/* SYSLOGGER wait event */
+		case WAIT_EVENT_READ_SYSLOGGER_FILE:
+			event_name = "ReadSysloggerFile";
+			break;
+		case WAIT_EVENT_WRITE_SYSLOGGER_FILE:
+			event_name = "WriteSysloggerFile";
+			break;
+		/* REPLSLOT wait event */
+		case WAIT_EVENT_READ_RESTORE_REPLSLOT:
+			event_name = "ReadRestorREPLSlot";
+			break;
+		case WAIT_EVENT_WRITE_REPLSLOT:
+			event_name = "WriteREPLSlot";
+			break;
+		case WAIT_EVENT_SYNC_RESTORE_REPLSLOT:
+			event_name = "SyncRestoreREPLSlot";
+			break;
+		case WAIT_EVENT_SYNC_SAVE_REPLSLOT:
+			event_name = "SyncSaveREPLSlot";
+			break;
+		/* COPYDIR IO wait event */
+		case WAIT_EVENT_READ_COPY_FILE:
+			event_name = "ReadCopyFile";
+			break;
+		case WAIT_EVENT_WRITE_COPY_FILE:
+			event_name = "WriteCopyFile";
+			break;
+		/* RELMAP IO wait event */
+		case WAIT_EVENT_READ_LOAD_RELMAP_FILE:
+			event_name = "ReadLoadRELMAPFile";
+			break;
+		case WAIT_EVENT_WRITE_RELMAP_FILE:
+			event_name = "WriteRELMAPFile";
+			break;
+		case WAIT_EVENT_SYNC_WRITE_RELMAP_FILE:
+			event_name = "SyncWriteRELMAFile";
+			break;
+		/* LOCK FILE IO wait event */
+		case WAIT_EVENT_READ_CREATE_LOCK_FILE:
+			event_name = "ReadCreateLockFile";
+			break;
+		case WAIT_EVENT_READ_ADDTODATEDIR_LOCK_FILE:
+			event_name = "ReadAddToDataDirLockFile";
+			break;
+		case WAIT_EVENT_READ_RECHECKDATADIR_LOCK_FILE:
+			event_name = "ReadRecheckDataDirLockFile";
+			break;
+		case WAIT_EVENT_WRITE_CREATE_LOCK_FILE:
+			event_name = "WriteCreateLockFile";
+			break;
+		case WAIT_EVENT_WRITE_ADDTODATEDIR_LOCK_FILE:
+			event_name = "WriteAddToDataDirLockFile";
+			break;
+		case WAIT_EVENT_SYNC_ADDTODATEDIR_LOCK_FILE:
+			event_name = "SyncAddToDataDirLockFile";
+			break;
+		case WAIT_EVENT_SYNC_CREATE_LOCK_FILE:
+			event_name = "SyncCreateLockFile";
+			break;
+
+		/* no default case, so that compiler will warn */
+	}
+
+	return event_name;
+}
+
+
+/* ----------
  * pgstat_get_backend_current_activity() -
  *
  *	Return a string representing the current activity of the backend with
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index 13a0301..1ba9a5c 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -432,9 +432,11 @@ SysLoggerMain(int argc, char *argv[])
 		{
 			int			bytesRead;
 
+			pgstat_report_wait_start(WAIT_EVENT_READ_SYSLOGGER_FILE);
 			bytesRead = read(syslogPipe[0],
 							 logbuffer + bytes_in_logbuffer,
 							 sizeof(logbuffer) - bytes_in_logbuffer);
+			pgstat_report_wait_end();
 			if (bytesRead < 0)
 			{
 				if (errno != EINTR)
@@ -992,7 +994,9 @@ write_syslogger_file(const char *buffer, int count, int destination)
 		open_csvlogfile();
 
 	logfile = destination == LOG_DESTINATION_CSVLOG ? csvlogFile : syslogFile;
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_SYSLOGGER_FILE);
 	rc = fwrite(buffer, 1, count, logfile);
+	pgstat_report_wait_end();
 
 	/* can't use ereport here because of possible recursion */
 	if (rc != count)
diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index d805ef4..a32bd3e 100644
--- a/src/backend/replication/logical/reorderbuffer.c
+++ b/src/backend/replication/logical/reorderbuffer.c
@@ -58,6 +58,7 @@
 #include "catalog/catalog.h"
 #include "lib/binaryheap.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "replication/logical.h"
 #include "replication/reorderbuffer.h"
 #include "replication/slot.h"
@@ -2317,6 +2318,7 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 
 	ondisk->size = sz;
 
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_REORDER_BUFFER);
 	if (write(fd, rb->outbuf, ondisk->size) != ondisk->size)
 	{
 		int			save_errno = errno;
@@ -2328,6 +2330,7 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 				 errmsg("could not write to data file for XID %u: %m",
 						txn->xid)));
 	}
+	pgstat_report_wait_end();
 
 	Assert(ondisk->change.action == change->action);
 }
@@ -2408,7 +2411,9 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		 * end of this file.
 		 */
 		ReorderBufferSerializeReserve(rb, sizeof(ReorderBufferDiskChange));
+		pgstat_report_wait_start(WAIT_EVENT_READ_REORDER_BUFFER);
 		readBytes = read(*fd, rb->outbuf, sizeof(ReorderBufferDiskChange));
+		pgstat_report_wait_end();
 
 		/* eof */
 		if (readBytes == 0)
@@ -2435,8 +2440,10 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
 							 sizeof(ReorderBufferDiskChange) + ondisk->size);
 		ondisk = (ReorderBufferDiskChange *) rb->outbuf;
 
+		pgstat_report_wait_start(WAIT_EVENT_READ_REORDER_BUFFER);
 		readBytes = read(*fd, rb->outbuf + sizeof(ReorderBufferDiskChange),
 						 ondisk->size - sizeof(ReorderBufferDiskChange));
+		pgstat_report_wait_end();
 
 		if (readBytes < 0)
 			ereport(ERROR,
@@ -3089,7 +3096,9 @@ ApplyLogicalMappingFile(HTAB *tuplecid_data, Oid relid, const char *fname)
 		memset(&key, 0, sizeof(ReorderBufferTupleCidKey));
 
 		/* read all mappings till the end of the file */
+		pgstat_report_wait_start(WAIT_EVENT_READ_APPLY_LOGICAL_MAPPING);
 		readBytes = read(fd, &map, sizeof(LogicalRewriteMappingData));
+		pgstat_report_wait_end();
 
 		if (readBytes < 0)
 			ereport(ERROR,
diff --git a/src/backend/replication/logical/snapbuild.c b/src/backend/replication/logical/snapbuild.c
index 1e02aa9..3fc1343 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -116,6 +116,8 @@
 #include "access/transam.h"
 #include "access/xact.h"
 
+#include "pgstat.h"
+
 #include "replication/logical.h"
 #include "replication/reorderbuffer.h"
 #include "replication/snapbuild.h"
@@ -1581,6 +1583,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 		ereport(ERROR,
 				(errmsg("could not open file \"%s\": %m", path)));
 
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_SNAPBUILD_SERIALIZE);
 	if ((write(fd, ondisk, needed_length)) != needed_length)
 	{
 		CloseTransientFile(fd);
@@ -1588,6 +1591,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 				(errcode_for_file_access(),
 				 errmsg("could not write to file \"%s\": %m", tmppath)));
 	}
+	pgstat_report_wait_end();
 
 	/*
 	 * fsync the file before renaming so that even if we crash after this we
@@ -1597,6 +1601,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 	 * some noticeable overhead since it's performed synchronously during
 	 * decoding?
 	 */
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_SNAPBUILD_SERIALIZE);
 	if (pg_fsync(fd) != 0)
 	{
 		CloseTransientFile(fd);
@@ -1604,6 +1609,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 				(errcode_for_file_access(),
 				 errmsg("could not fsync file \"%s\": %m", tmppath)));
 	}
+	pgstat_report_wait_end();
 	CloseTransientFile(fd);
 
 	fsync_fname("pg_logical/snapshots", true);
@@ -1678,7 +1684,9 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
 
 
 	/* read statically sized portion of snapshot */
+	pgstat_report_wait_start(WAIT_EVENT_READ_SNAPBUILD_RESTORE);
 	readBytes = read(fd, &ondisk, SnapBuildOnDiskConstantSize);
+	pgstat_report_wait_end();
 	if (readBytes != SnapBuildOnDiskConstantSize)
 	{
 		CloseTransientFile(fd);
@@ -1704,7 +1712,9 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
 			SnapBuildOnDiskConstantSize - SnapBuildOnDiskNotChecksummedSize);
 
 	/* read SnapBuild */
+	pgstat_report_wait_start(WAIT_EVENT_READ_SNAPBUILD_RESTORE);
 	readBytes = read(fd, &ondisk.builder, sizeof(SnapBuild));
+	pgstat_report_wait_end();
 	if (readBytes != sizeof(SnapBuild))
 	{
 		CloseTransientFile(fd);
@@ -1718,7 +1728,9 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
 	/* restore running xacts information */
 	sz = sizeof(TransactionId) * ondisk.builder.running.xcnt_space;
 	ondisk.builder.running.xip = MemoryContextAllocZero(builder->context, sz);
+	pgstat_report_wait_start(WAIT_EVENT_READ_SNAPBUILD_RESTORE);
 	readBytes = read(fd, ondisk.builder.running.xip, sz);
+	pgstat_report_wait_end();
 	if (readBytes != sz)
 	{
 		CloseTransientFile(fd);
@@ -1732,7 +1744,9 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
 	/* restore committed xacts information */
 	sz = sizeof(TransactionId) * ondisk.builder.committed.xcnt;
 	ondisk.builder.committed.xip = MemoryContextAllocZero(builder->context, sz);
+	pgstat_report_wait_start(WAIT_EVENT_READ_SNAPBUILD_RESTORE);
 	readBytes = read(fd, ondisk.builder.committed.xip, sz);
+	pgstat_report_wait_end();
 	if (readBytes != sz)
 	{
 		CloseTransientFile(fd);
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index 10d69d0..d4ebcd9 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -43,6 +43,7 @@
 #include "access/xlog_internal.h"
 #include "common/string.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "replication/slot.h"
 #include "storage/fd.h"
 #include "storage/proc.h"
@@ -1100,10 +1101,12 @@ SaveSlotToPath(ReplicationSlot *slot, const char *dir, int elevel)
 				SnapBuildOnDiskChecksummedSize);
 	FIN_CRC32C(cp.checksum);
 
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_REPLSLOT);
 	if ((write(fd, &cp, sizeof(cp))) != sizeof(cp))
 	{
 		int			save_errno = errno;
 
+		pgstat_report_wait_end();
 		CloseTransientFile(fd);
 		errno = save_errno;
 		ereport(elevel,
@@ -1112,8 +1115,10 @@ SaveSlotToPath(ReplicationSlot *slot, const char *dir, int elevel)
 						tmppath)));
 		return;
 	}
+	pgstat_report_wait_end();
 
 	/* fsync the temporary file */
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_SAVE_REPLSLOT);
 	if (pg_fsync(fd) != 0)
 	{
 		int			save_errno = errno;
@@ -1126,6 +1131,7 @@ SaveSlotToPath(ReplicationSlot *slot, const char *dir, int elevel)
 						tmppath)));
 		return;
 	}
+	pgstat_report_wait_end();
 
 	CloseTransientFile(fd);
 
@@ -1202,6 +1208,7 @@ RestoreSlotFromDisk(const char *name)
 	 * Sync state file before we're reading from it. We might have crashed
 	 * while it wasn't synced yet and we shouldn't continue on that basis.
 	 */
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_RESTORE_REPLSLOT);
 	if (pg_fsync(fd) != 0)
 	{
 		CloseTransientFile(fd);
@@ -1210,6 +1217,7 @@ RestoreSlotFromDisk(const char *name)
 				 errmsg("could not fsync file \"%s\": %m",
 						path)));
 	}
+	pgstat_report_wait_end();
 
 	/* Also sync the parent directory */
 	START_CRIT_SECTION();
@@ -1217,7 +1225,9 @@ RestoreSlotFromDisk(const char *name)
 	END_CRIT_SECTION();
 
 	/* read part of statefile that's guaranteed to be version independent */
+	pgstat_report_wait_start(WAIT_EVENT_READ_RESTORE_REPLSLOT);
 	readBytes = read(fd, &cp, ReplicationSlotOnDiskConstantSize);
+	pgstat_report_wait_end();
 	if (readBytes != ReplicationSlotOnDiskConstantSize)
 	{
 		int			saved_errno = errno;
@@ -1253,9 +1263,11 @@ RestoreSlotFromDisk(const char *name)
 					  path, cp.length)));
 
 	/* Now that we know the size, read the entire file */
+	pgstat_report_wait_start(WAIT_EVENT_READ_RESTORE_REPLSLOT);
 	readBytes = read(fd,
 					 (char *) &cp + ReplicationSlotOnDiskConstantSize,
 					 cp.length);
+	pgstat_report_wait_end();
 	if (readBytes != cp.length)
 	{
 		int			saved_errno = errno;
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index f3082c3..db0d458 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -496,7 +496,9 @@ SendTimeLineHistory(TimeLineHistoryCmd *cmd)
 		char		rbuf[BLCKSZ];
 		int			nread;
 
+		pgstat_report_wait_start(WAIT_EVENT_READ_TIMELINE_HISTORY_WALSENDER);
 		nread = read(fd, rbuf, sizeof(rbuf));
+		pgstat_report_wait_end();
 		if (nread <= 0)
 			ereport(ERROR,
 					(errcode_for_file_access(),
@@ -2137,7 +2139,9 @@ retry:
 		else
 			segbytes = nbytes;
 
+		pgstat_report_wait_start(WAIT_EVENT_READ_XLOG);
 		readbytes = read(sendFile, p, segbytes);
+		pgstat_report_wait_end();
 		if (readbytes <= 0)
 		{
 			ereport(ERROR,
diff --git a/src/backend/storage/file/buffile.c b/src/backend/storage/file/buffile.c
index 7ebd636..971cfd1 100644
--- a/src/backend/storage/file/buffile.c
+++ b/src/backend/storage/file/buffile.c
@@ -37,6 +37,7 @@
 #include "postgres.h"
 
 #include "executor/instrument.h"
+#include "pgstat.h"
 #include "storage/fd.h"
 #include "storage/buffile.h"
 #include "storage/buf_internals.h"
@@ -254,7 +255,10 @@ BufFileLoadBuffer(BufFile *file)
 	/*
 	 * Read whatever we can get, up to a full bufferload.
 	 */
-	file->nbytes = FileRead(thisfile, file->buffer, sizeof(file->buffer));
+	file->nbytes = FileRead(thisfile,
+							file->buffer,
+							sizeof(file->buffer),
+							WAIT_EVENT_READ_BUFFILE);
 	if (file->nbytes < 0)
 		file->nbytes = 0;
 	file->offsets[file->curFile] += file->nbytes;
@@ -317,7 +321,10 @@ BufFileDumpBuffer(BufFile *file)
 				return;			/* seek failed, give up */
 			file->offsets[file->curFile] = file->curOffset;
 		}
-		bytestowrite = FileWrite(thisfile, file->buffer + wpos, bytestowrite);
+		bytestowrite = FileWrite(thisfile,
+								 file->buffer + wpos,
+								 bytestowrite,
+								 WAIT_EVENT_WRITE_BUFFILE);
 		if (bytestowrite <= 0)
 			return;				/* failed to write */
 		file->offsets[file->curFile] += bytestowrite;
diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c
index 101da47..2eda42d 100644
--- a/src/backend/storage/file/copydir.c
+++ b/src/backend/storage/file/copydir.c
@@ -25,7 +25,7 @@
 #include "storage/copydir.h"
 #include "storage/fd.h"
 #include "miscadmin.h"
-
+#include "pgstat.h"
 
 /*
  * copydir: copy a directory
@@ -169,7 +169,9 @@ copy_file(char *fromfile, char *tofile)
 		/* If we got a cancel signal during the copy of the file, quit */
 		CHECK_FOR_INTERRUPTS();
 
+		pgstat_report_wait_start(WAIT_EVENT_READ_COPY_FILE);
 		nbytes = read(srcfd, buffer, COPY_BUF_SIZE);
+		pgstat_report_wait_end();
 		if (nbytes < 0)
 			ereport(ERROR,
 					(errcode_for_file_access(),
@@ -177,8 +179,10 @@ copy_file(char *fromfile, char *tofile)
 		if (nbytes == 0)
 			break;
 		errno = 0;
+		pgstat_report_wait_start(WAIT_EVENT_WRITE_COPY_FILE);
 		if ((int) write(dstfd, buffer, nbytes) != nbytes)
 		{
+			pgstat_report_wait_end();
 			/* if write didn't set errno, assume problem is no disk space */
 			if (errno == 0)
 				errno = ENOSPC;
@@ -186,6 +190,7 @@ copy_file(char *fromfile, char *tofile)
 					(errcode_for_file_access(),
 					 errmsg("could not write to file \"%s\": %m", tofile)));
 		}
+		pgstat_report_wait_end();
 
 		/*
 		 * We fsync the files later but first flush them to avoid spamming the
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index ce4bd0f..431fc48 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -1512,7 +1512,7 @@ FileClose(File file)
  * to read into.
  */
 int
-FilePrefetch(File file, off_t offset, int amount)
+FilePrefetch(File file, off_t offset, int amount, uint32 wait_event_info)
 {
 #if defined(USE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED)
 	int			returnCode;
@@ -1527,8 +1527,10 @@ FilePrefetch(File file, off_t offset, int amount)
 	if (returnCode < 0)
 		return returnCode;
 
+	pgstat_report_wait_start(wait_event_info);
 	returnCode = posix_fadvise(VfdCache[file].fd, offset, amount,
 							   POSIX_FADV_WILLNEED);
+	pgstat_report_wait_end();
 
 	return returnCode;
 #else
@@ -1538,7 +1540,7 @@ FilePrefetch(File file, off_t offset, int amount)
 }
 
 void
-FileWriteback(File file, off_t offset, off_t nbytes)
+FileWriteback(File file, off_t offset, off_t nbytes, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1559,11 +1561,13 @@ FileWriteback(File file, off_t offset, off_t nbytes)
 	if (returnCode < 0)
 		return;
 
+	pgstat_report_wait_start(wait_event_info);
 	pg_flush_data(VfdCache[file].fd, offset, nbytes);
+	pgstat_report_wait_end();
 }
 
 int
-FileRead(File file, char *buffer, int amount)
+FileRead(File file, char *buffer, int amount, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1578,6 +1582,7 @@ FileRead(File file, char *buffer, int amount)
 	if (returnCode < 0)
 		return returnCode;
 
+	pgstat_report_wait_start(wait_event_info);
 retry:
 	returnCode = read(VfdCache[file].fd, buffer, amount);
 
@@ -1613,12 +1618,13 @@ retry:
 		/* Trouble, so assume we don't know the file position anymore */
 		VfdCache[file].seekPos = FileUnknownPos;
 	}
+	pgstat_report_wait_end();
 
 	return returnCode;
 }
 
 int
-FileWrite(File file, char *buffer, int amount)
+FileWrite(File file, char *buffer, int amount, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1658,6 +1664,7 @@ FileWrite(File file, char *buffer, int amount)
 		}
 	}
 
+	pgstat_report_wait_start(wait_event_info);
 retry:
 	errno = 0;
 	returnCode = write(VfdCache[file].fd, buffer, amount);
@@ -1708,12 +1715,13 @@ retry:
 		/* Trouble, so assume we don't know the file position anymore */
 		VfdCache[file].seekPos = FileUnknownPos;
 	}
+	pgstat_report_wait_end();
 
 	return returnCode;
 }
 
 int
-FileSync(File file)
+FileSync(File file, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1726,7 +1734,11 @@ FileSync(File file)
 	if (returnCode < 0)
 		return returnCode;
 
-	return pg_fsync(VfdCache[file].fd);
+	pgstat_report_wait_start(wait_event_info);
+	returnCode = pg_fsync(VfdCache[file].fd);
+	pgstat_report_wait_end();
+
+	return returnCode;
 }
 
 off_t
@@ -1810,7 +1822,7 @@ FileTell(File file)
 #endif
 
 int
-FileTruncate(File file, off_t offset)
+FileTruncate(File file, off_t offset, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1823,7 +1835,9 @@ FileTruncate(File file, off_t offset)
 	if (returnCode < 0)
 		return returnCode;
 
+	pgstat_report_wait_start(wait_event_info);
 	returnCode = ftruncate(VfdCache[file].fd, offset);
+	pgstat_report_wait_end();
 
 	if (returnCode == 0 && VfdCache[file].fileSize > offset)
 	{
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 1d9384e..9f57d7f 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -28,6 +28,7 @@
 #include "miscadmin.h"
 #include "access/xlog.h"
 #include "catalog/catalog.h"
+#include "pgstat.h"
 #include "portability/instr_time.h"
 #include "postmaster/bgwriter.h"
 #include "storage/fd.h"
@@ -536,7 +537,7 @@ mdextend(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 				 errmsg("could not seek to block %u in file \"%s\": %m",
 						blocknum, FilePathName(v->mdfd_vfd))));
 
-	if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ)) != BLCKSZ)
+	if ((nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ, WAIT_EVENT_EXTEND_DATA_BLOCK)) != BLCKSZ)
 	{
 		if (nbytes < 0)
 			ereport(ERROR,
@@ -667,7 +668,7 @@ mdprefetch(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum)
 
 	Assert(seekpos < (off_t) BLCKSZ * RELSEG_SIZE);
 
-	(void) FilePrefetch(v->mdfd_vfd, seekpos, BLCKSZ);
+	(void) FilePrefetch(v->mdfd_vfd, seekpos, BLCKSZ, WAIT_EVENT_PREFETCH_DATA_BLOCK);
 #endif   /* USE_PREFETCH */
 }
 
@@ -716,7 +717,7 @@ mdwriteback(SMgrRelation reln, ForkNumber forknum,
 
 		seekpos = (off_t) BLCKSZ *(blocknum % ((BlockNumber) RELSEG_SIZE));
 
-		FileWriteback(v->mdfd_vfd, seekpos, (off_t) BLCKSZ * nflush);
+		FileWriteback(v->mdfd_vfd, seekpos, (off_t) BLCKSZ * nflush, WAIT_EVENT_FLUSH_DATA_BLOCK);
 
 		nblocks -= nflush;
 		blocknum += nflush;
@@ -753,7 +754,7 @@ mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 				 errmsg("could not seek to block %u in file \"%s\": %m",
 						blocknum, FilePathName(v->mdfd_vfd))));
 
-	nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ);
+	nbytes = FileRead(v->mdfd_vfd, buffer, BLCKSZ, WAIT_EVENT_READ_DATA_BLOCK);
 
 	TRACE_POSTGRESQL_SMGR_MD_READ_DONE(forknum, blocknum,
 									   reln->smgr_rnode.node.spcNode,
@@ -829,7 +830,7 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 				 errmsg("could not seek to block %u in file \"%s\": %m",
 						blocknum, FilePathName(v->mdfd_vfd))));
 
-	nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ);
+	nbytes = FileWrite(v->mdfd_vfd, buffer, BLCKSZ, WAIT_EVENT_WRITE_DATA_BLOCK);
 
 	TRACE_POSTGRESQL_SMGR_MD_WRITE_DONE(forknum, blocknum,
 										reln->smgr_rnode.node.spcNode,
@@ -967,7 +968,7 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks)
 			 * This segment is no longer active. We truncate the file, but do
 			 * not delete it, for reasons explained in the header comments.
 			 */
-			if (FileTruncate(v->mdfd_vfd, 0) < 0)
+			if (FileTruncate(v->mdfd_vfd, 0, WAIT_EVENT_TRUNCATE_RELATION_DATA_BLOCKS) < 0)
 				ereport(ERROR,
 						(errcode_for_file_access(),
 						 errmsg("could not truncate file \"%s\": %m",
@@ -993,7 +994,7 @@ mdtruncate(SMgrRelation reln, ForkNumber forknum, BlockNumber nblocks)
 			 */
 			BlockNumber lastsegblocks = nblocks - priorblocks;
 
-			if (FileTruncate(v->mdfd_vfd, (off_t) lastsegblocks * BLCKSZ) < 0)
+			if (FileTruncate(v->mdfd_vfd, (off_t) lastsegblocks * BLCKSZ, WAIT_EVENT_TRUNCATE_RELATION_DATA_BLOCKS) < 0)
 				ereport(ERROR,
 						(errcode_for_file_access(),
 					errmsg("could not truncate file \"%s\" to %u blocks: %m",
@@ -1037,7 +1038,7 @@ mdimmedsync(SMgrRelation reln, ForkNumber forknum)
 	{
 		MdfdVec    *v = &reln->md_seg_fds[forknum][segno - 1];
 
-		if (FileSync(v->mdfd_vfd) < 0)
+		if (FileSync(v->mdfd_vfd, WAIT_EVENT_SYNC_IMMED_RELATION) < 0)
 			ereport(ERROR,
 					(errcode_for_file_access(),
 					 errmsg("could not fsync file \"%s\": %m",
@@ -1232,7 +1233,7 @@ mdsync(void)
 					INSTR_TIME_SET_CURRENT(sync_start);
 
 					if (seg != NULL &&
-						FileSync(seg->mdfd_vfd) >= 0)
+						FileSync(seg->mdfd_vfd, WAIT_EVENT_SYNC_RELATION) >= 0)
 					{
 						/* Success; update statistics about sync timing */
 						INSTR_TIME_SET_CURRENT(sync_end);
@@ -1443,7 +1444,7 @@ register_dirty_segment(SMgrRelation reln, ForkNumber forknum, MdfdVec *seg)
 		ereport(DEBUG1,
 				(errmsg("could not forward fsync request because request queue is full")));
 
-		if (FileSync(seg->mdfd_vfd) < 0)
+		if (FileSync(seg->mdfd_vfd, WAIT_EVENT_SYNC_DATA_BLOCK) < 0)
 			ereport(ERROR,
 					(errcode_for_file_access(),
 					 errmsg("could not fsync file \"%s\": %m",
diff --git a/src/backend/utils/cache/relmapper.c b/src/backend/utils/cache/relmapper.c
index c9d6e44..ee5ded9 100644
--- a/src/backend/utils/cache/relmapper.c
+++ b/src/backend/utils/cache/relmapper.c
@@ -50,6 +50,7 @@
 #include "catalog/pg_tablespace.h"
 #include "catalog/storage.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "storage/fd.h"
 #include "storage/lwlock.h"
 #include "utils/inval.h"
@@ -658,11 +659,15 @@ load_relmap_file(bool shared)
 	 * look, the sinval signaling mechanism will make us re-read it before we
 	 * are able to access any relation that's affected by the change.
 	 */
+	pgstat_report_wait_start(WAIT_EVENT_READ_LOAD_RELMAP_FILE);
 	if (read(fd, map, sizeof(RelMapFile)) != sizeof(RelMapFile))
+	{
 		ereport(FATAL,
 				(errcode_for_file_access(),
 				 errmsg("could not read relation mapping file \"%s\": %m",
 						mapfilename)));
+	}
+	pgstat_report_wait_end();
 
 	CloseTransientFile(fd);
 
@@ -774,6 +779,7 @@ write_relmap_file(bool shared, RelMapFile *newmap,
 	}
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_RELMAP_FILE);
 	if (write(fd, newmap, sizeof(RelMapFile)) != sizeof(RelMapFile))
 	{
 		/* if write didn't set errno, assume problem is no disk space */
@@ -784,6 +790,7 @@ write_relmap_file(bool shared, RelMapFile *newmap,
 				 errmsg("could not write to relation mapping file \"%s\": %m",
 						mapfilename)));
 	}
+	pgstat_report_wait_end();
 
 	/*
 	 * We choose to fsync the data to disk before considering the task done.
@@ -791,11 +798,13 @@ write_relmap_file(bool shared, RelMapFile *newmap,
 	 * issue, but it would complicate checkpointing --- see notes for
 	 * CheckPointRelationMap.
 	 */
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_WRITE_RELMAP_FILE);
 	if (pg_fsync(fd) != 0)
 		ereport(ERROR,
 				(errcode_for_file_access(),
 				 errmsg("could not fsync relation mapping file \"%s\": %m",
 						mapfilename)));
+	pgstat_report_wait_end();
 
 	if (CloseTransientFile(fd))
 		ereport(ERROR,
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index e984e79..e58cfa5 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -36,6 +36,7 @@
 #include "libpq/libpq.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "postmaster/autovacuum.h"
 #include "postmaster/postmaster.h"
 #include "storage/fd.h"
@@ -857,11 +858,13 @@ CreateLockFile(const char *filename, bool amPostmaster,
 					 errmsg("could not open lock file \"%s\": %m",
 							filename)));
 		}
+		pgstat_report_wait_start(WAIT_EVENT_READ_CREATE_LOCK_FILE);
 		if ((len = read(fd, buffer, sizeof(buffer) - 1)) < 0)
 			ereport(FATAL,
 					(errcode_for_file_access(),
 					 errmsg("could not read lock file \"%s\": %m",
 							filename)));
+		pgstat_report_wait_end();
 		close(fd);
 
 		if (len == 0)
@@ -1010,6 +1013,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
 		strlcat(buffer, "\n", sizeof(buffer));
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_CREATE_LOCK_FILE);
 	if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
 	{
 		int			save_errno = errno;
@@ -1022,6 +1026,9 @@ CreateLockFile(const char *filename, bool amPostmaster,
 				(errcode_for_file_access(),
 				 errmsg("could not write lock file \"%s\": %m", filename)));
 	}
+	pgstat_report_wait_end();
+
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_CREATE_LOCK_FILE);
 	if (pg_fsync(fd) != 0)
 	{
 		int			save_errno = errno;
@@ -1033,6 +1040,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
 				(errcode_for_file_access(),
 				 errmsg("could not write lock file \"%s\": %m", filename)));
 	}
+	pgstat_report_wait_end();
 	if (close(fd) != 0)
 	{
 		int			save_errno = errno;
@@ -1165,7 +1173,9 @@ AddToDataDirLockFile(int target_line, const char *str)
 						DIRECTORY_LOCK_FILE)));
 		return;
 	}
+	pgstat_report_wait_start(WAIT_EVENT_READ_ADDTODATEDIR_LOCK_FILE);
 	len = read(fd, srcbuffer, sizeof(srcbuffer) - 1);
+	pgstat_report_wait_end();
 	if (len < 0)
 	{
 		ereport(LOG,
@@ -1218,6 +1228,7 @@ AddToDataDirLockFile(int target_line, const char *str)
 	 */
 	len = strlen(destbuffer);
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_WRITE_ADDTODATEDIR_LOCK_FILE);
 	if (lseek(fd, (off_t) 0, SEEK_SET) != 0 ||
 		(int) write(fd, destbuffer, len) != len)
 	{
@@ -1231,6 +1242,8 @@ AddToDataDirLockFile(int target_line, const char *str)
 		close(fd);
 		return;
 	}
+	pgstat_report_wait_end();
+	pgstat_report_wait_start(WAIT_EVENT_SYNC_ADDTODATEDIR_LOCK_FILE);
 	if (pg_fsync(fd) != 0)
 	{
 		ereport(LOG,
@@ -1238,6 +1251,7 @@ AddToDataDirLockFile(int target_line, const char *str)
 				 errmsg("could not write to file \"%s\": %m",
 						DIRECTORY_LOCK_FILE)));
 	}
+	pgstat_report_wait_end();
 	if (close(fd) != 0)
 	{
 		ereport(LOG,
@@ -1294,7 +1308,9 @@ RecheckDataDirLockFile(void)
 				return true;
 		}
 	}
+	pgstat_report_wait_start(WAIT_EVENT_READ_RECHECKDATADIR_LOCK_FILE);
 	len = read(fd, buffer, sizeof(buffer) - 1);
+	pgstat_report_wait_end();
 	if (len < 0)
 	{
 		ereport(LOG,
diff --git a/src/common/controldata_utils.c b/src/common/controldata_utils.c
index f1a097a..0d48469 100644
--- a/src/common/controldata_utils.c
+++ b/src/common/controldata_utils.c
@@ -16,6 +16,7 @@
 
 #ifndef FRONTEND
 #include "postgres.h"
+#include "pgstat.h"
 #else
 #include "postgres_fe.h"
 #endif
@@ -64,6 +65,9 @@ get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
 	}
 #endif
 
+#ifndef FRONTEND
+	pgstat_report_wait_start(WAIT_EVENT_READ_CONTROL_FILE);
+#endif
 	if (read(fd, ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
 #ifndef FRONTEND
 		ereport(ERROR,
@@ -76,7 +80,9 @@ get_controlfile(const char *DataDir, const char *progname, bool *crc_ok_p)
 		exit(EXIT_FAILURE);
 	}
 #endif
-
+#ifndef FRONTEND
+	pgstat_report_wait_end();
+#endif
 	close(fd);
 
 	/* Check the CRC. */
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index de8225b..5e599ed 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -723,6 +723,7 @@ typedef enum BackendState
 #define PG_WAIT_EXTENSION			0x07000000U
 #define PG_WAIT_IPC					0x08000000U
 #define PG_WAIT_TIMEOUT				0x09000000U
+#define PG_WAIT_IO					0x0A000000U
 
 /* ----------
  * Wait Events - Activity
@@ -804,6 +805,98 @@ typedef enum
 } WaitEventTimeout;
 
 /* ----------
+ * Wait Events - IO
+ *
+ * Use this category when a process is waiting for a IO.
+ * ----------
+ */
+typedef enum
+{
+	WAIT_EVENT_READ_DATA_BLOCK,
+	WAIT_EVENT_WRITE_DATA_BLOCK,
+	WAIT_EVENT_SYNC_DATA_BLOCK,
+	WAIT_EVENT_EXTEND_DATA_BLOCK,
+	WAIT_EVENT_FLUSH_DATA_BLOCK,
+	WAIT_EVENT_PREFETCH_DATA_BLOCK,
+	WAIT_EVENT_WRITE_REWRITE_DATA_BLOCK,
+	WAIT_EVENT_SYNC_REWRITE_DATA_BLOCK,
+	WAIT_EVENT_TRUNCATE_RELATION_DATA_BLOCKS,
+	WAIT_EVENT_SYNC_RELATION,
+	WAIT_EVENT_SYNC_IMMED_RELATION,
+	WAIT_EVENT_READ_BUFFILE,
+	WAIT_EVENT_WRITE_BUFFILE,
+	/* Wait event for XLOG */
+	WAIT_EVENT_READ_XLOG,
+	WAIT_EVENT_READ_COPY_XLOG,
+	WAIT_EVENT_WRITE_XLOG,
+	WAIT_EVENT_WRITE_INIT_XLOG_FILE,
+	WAIT_EVENT_WRITE_COPY_XLOG_FILE,
+	WAIT_EVENT_WRITE_BOOTSTRAP_XLOG,
+	WAIT_EVENT_SYNC_INIT_XLOG_FILE,
+	WAIT_EVENT_SYNC_COPY_XLOG_FILE,
+	WAIT_EVENT_SYNC_BOOTSTRAP_XLOG,
+	WAIT_EVENT_SYNC_ASSIGN_XLOG_SYNC_METHOD,
+	/* Wait event for CONTROL_FILE */
+	WAIT_EVENT_WRITE_CONTROL_FILE,
+	WAIT_EVENT_WRITE_UPDATE_CONTROL_FILE,
+	WAIT_EVENT_SYNC_WRITE_CONTROL_FILE,
+	WAIT_EVENT_SYNC_UPDATE_CONTROL_FILE,
+	WAIT_EVENT_READ_CONTROL_FILE,
+	/* Wait event for REORDER BUFFER */
+	WAIT_EVENT_READ_REORDER_BUFFER,
+	WAIT_EVENT_WRITE_REORDER_BUFFER,
+	/* Wait event for LOGICAL MAPPING */
+	WAIT_EVENT_READ_APPLY_LOGICAL_MAPPING,
+	WAIT_EVENT_WRITE_LOGICAL_MAPPING_REWRITE,
+	WAIT_EVENT_SYNC_LOGICAL_MAPPING_REWRITE,
+	WAIT_EVENT_SYNC_LOGICAL_MAPPING_REWRITE_HEAP,
+	WAIT_EVENT_TRUNCATE_LOGICAL_MAPPING_REWRITE,
+	/* Wait event for SNAPBUILD */
+	WAIT_EVENT_WRITE_SNAPBUILD_SERIALIZE,
+	WAIT_EVENT_READ_SNAPBUILD_RESTORE,
+	WAIT_EVENT_SYNC_SNAPBUILD_SERIALIZE,
+	/* Wait event for SNRU */
+	WAIT_EVENT_READ_SLRU_PAGE,
+	WAIT_EVENT_WRITE_SLRU_PAGE,
+	WAIT_EVENT_SYNC_SLRU_FLUSH,
+	WAIT_EVENT_SYNC_SLRU_WRITE_PAGE,
+	/* Wait event for TIMELINE HISTORY */
+	WAIT_EVENT_READ_TIMELINE_HISTORY_WALSENDER,
+	WAIT_EVENT_READ_TIMELINE_HISTORY_WRITE,
+	WAIT_EVENT_WRITE_TIMELINE_HISTORY,
+	WAIT_EVENT_WRITE_TIMELINE_HISTORY_FILE,
+	WAIT_EVENT_SYNC_TIMELINE_HISTORY_WRITE,
+	WAIT_EVENT_SYNC_TIMELINE_HISTORY_FILE,
+	/* Wait event for TWOPHASE FILE */
+	WAIT_EVENT_READ_TWOPHASE_FILE,
+	WAIT_EVENT_WRITE_RECREATE_TWOPHASE_FILE,
+	WAIT_EVENT_SYNC_RECREATE_TWOPHASE_FILE,
+	/* Wait event for SYSLOGGER */
+	WAIT_EVENT_READ_SYSLOGGER_FILE,
+	WAIT_EVENT_WRITE_SYSLOGGER_FILE,
+	/* Wait event for REPLSLOT */
+	WAIT_EVENT_READ_RESTORE_REPLSLOT,
+	WAIT_EVENT_WRITE_REPLSLOT,
+	WAIT_EVENT_SYNC_RESTORE_REPLSLOT,
+	WAIT_EVENT_SYNC_SAVE_REPLSLOT,
+	/* Wait event for copydir */
+	WAIT_EVENT_READ_COPY_FILE,
+	WAIT_EVENT_WRITE_COPY_FILE,
+	/* Wait event RELMAP FILE */
+	WAIT_EVENT_READ_LOAD_RELMAP_FILE,
+	WAIT_EVENT_WRITE_RELMAP_FILE,
+	WAIT_EVENT_SYNC_WRITE_RELMAP_FILE,
+	/* Wait event for LOCK FILE */
+	WAIT_EVENT_READ_CREATE_LOCK_FILE,
+	WAIT_EVENT_READ_ADDTODATEDIR_LOCK_FILE,
+	WAIT_EVENT_READ_RECHECKDATADIR_LOCK_FILE,
+	WAIT_EVENT_WRITE_CREATE_LOCK_FILE,
+	WAIT_EVENT_WRITE_ADDTODATEDIR_LOCK_FILE,
+	WAIT_EVENT_SYNC_ADDTODATEDIR_LOCK_FILE,
+	WAIT_EVENT_SYNC_CREATE_LOCK_FILE
+} WaitEventIO;
+
+/* ----------
  * Command type for progress reporting purposes
  * ----------
  */
diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h
index 1a43a2c..ac37502 100644
--- a/src/include/storage/fd.h
+++ b/src/include/storage/fd.h
@@ -68,13 +68,13 @@ extern int	max_safe_fds;
 extern File PathNameOpenFile(FileName fileName, int fileFlags, int fileMode);
 extern File OpenTemporaryFile(bool interXact);
 extern void FileClose(File file);
-extern int	FilePrefetch(File file, off_t offset, int amount);
-extern int	FileRead(File file, char *buffer, int amount);
-extern int	FileWrite(File file, char *buffer, int amount);
-extern int	FileSync(File file);
+extern int	FilePrefetch(File file, off_t offset, int amount, uint32 wait_event_info);
+extern int	FileRead(File file, char *buffer, int amount, uint32 wait_event_info);
+extern int	FileWrite(File file, char *buffer, int amount, uint32 wait_event_info);
+extern int	FileSync(File file, uint32 wait_event_info);
 extern off_t FileSeek(File file, off_t offset, int whence);
-extern int	FileTruncate(File file, off_t offset);
-extern void FileWriteback(File file, off_t offset, off_t nbytes);
+extern int	FileTruncate(File file, off_t offset, uint32 wait_event_info);
+extern void FileWriteback(File file, off_t offset, off_t nbytes, uint32 wait_event_info);
 extern char *FilePathName(File file);
 extern int	FileGetRawDesc(File file);
 extern int	FileGetRawFlags(File file);
