wait events for disk I/O

Started by Rushabh Lathiaalmost 9 years ago24 messages
#1Rushabh Lathia
rushabh.lathia@gmail.com
1 attachment(s)

Hi All,

Attached is the patch, which extend the existing wait event infrastructure
to
implement the wait events for the disk I/O. Basically pg_stat_activity's
wait
event information to show data about disk I/O as well as IPC primitives.

Implementation details:

- Added PG_WAIT_IO to pgstat.h and a new enum WaitEventIO
- Added a wait_event_info argument to FileRead, FileWrite, FilePrefetch,
FileWriteback, FileSync, and FileTruncate. Set this wait event just before
performing the file system operation and clear it just after.
- Pass down an appropriate wait event from caller of any of those
functions.
- Also set and clear a wait event around standalone calls to read(),
write(), fsync() in other parts of the system.
- Added documentation for all newly added wait event.

Open issue:
- Might missed few standalone calls to read(), write(), etc which need
to pass the wait_event_info.

Thanks to my colleague Robert Haas for his help in design.

Please let me know your thought, and thanks for reading.

Thanks,
Rushabh Lathia
www.EnterpriseDB.com

Attachments:

wait_event_disk_IO.patchbinary/octet-stream; name=wait_event_disk_IO.patchDownload
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);
#2Michael Paquier
michael.paquier@gmail.com
In reply to: Rushabh Lathia (#1)
Re: wait events for disk I/O

On Mon, Jan 30, 2017 at 10:01 PM, Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

Attached is the patch, which extend the existing wait event infrastructure
to implement the wait events for the disk I/O. Basically pg_stat_activity's
wait event information to show data about disk I/O as well as IPC primitives.

Implementation details:

- Added PG_WAIT_IO to pgstat.h and a new enum WaitEventIO
- Added a wait_event_info argument to FileRead, FileWrite, FilePrefetch,
FileWriteback, FileSync, and FileTruncate. Set this wait event just before
performing the file system operation and clear it just after.
- Pass down an appropriate wait event from caller of any of those
functions.
- Also set and clear a wait event around standalone calls to read(),
write(), fsync() in other parts of the system.
- Added documentation for all newly added wait event.

Looks neat, those are unlikely to overlap with other wait events.

Open issue:
- Might missed few standalone calls to read(), write(), etc which need
to pass the wait_event_info.

It may be an idea to use LD_PRELOAD with custom versions of read(),
write() and fsync(), and look at the paths where no flags are set in
MyProc->wait_event_info, and log information when that happens.

Thanks to my colleague Robert Haas for his help in design.
Please let me know your thought, and thanks for reading.

Did you consider a wrapper of the type pg_read_event() or
pg_write_event(), etc.?
--
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#3Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Michael Paquier (#2)
Re: wait events for disk I/O

On Tue, Jan 31, 2017 at 8:54 AM, Michael Paquier <michael.paquier@gmail.com>
wrote:

On Mon, Jan 30, 2017 at 10:01 PM, Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

Attached is the patch, which extend the existing wait event

infrastructure

to implement the wait events for the disk I/O. Basically

pg_stat_activity's

wait event information to show data about disk I/O as well as IPC

primitives.

Implementation details:

- Added PG_WAIT_IO to pgstat.h and a new enum WaitEventIO
- Added a wait_event_info argument to FileRead, FileWrite, FilePrefetch,
FileWriteback, FileSync, and FileTruncate. Set this wait event just

before

performing the file system operation and clear it just after.
- Pass down an appropriate wait event from caller of any of those
functions.
- Also set and clear a wait event around standalone calls to read(),
write(), fsync() in other parts of the system.
- Added documentation for all newly added wait event.

Looks neat, those are unlikely to overlap with other wait events.

Thanks.

Open issue:
- Might missed few standalone calls to read(), write(), etc which need
to pass the wait_event_info.

It may be an idea to use LD_PRELOAD with custom versions of read(),
write() and fsync(), and look at the paths where no flags are set in
MyProc->wait_event_info, and log information when that happens.

Yes, may be I will try this.

Thanks to my colleague Robert Haas for his help in design.
Please let me know your thought, and thanks for reading.

Did you consider a wrapper of the type pg_read_event() or
pg_write_event(), etc.?

I thought on that, but eventually stick to this approach as it looks
more neat and uniform with other wait event implementation.

--
Michael

Thanks,
Rushabh Lathia
www.EnterpriseDB.com

#4Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Rushabh Lathia (#3)
1 attachment(s)
Re: wait events for disk I/O

My colleague Rahila reported compilation issue with
the patch. Issue was only coming with we do the clean
build on the branch.

Fixed the same into latest version of patch.

Thanks,

On Tue, Jan 31, 2017 at 11:09 AM, Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:

On Tue, Jan 31, 2017 at 8:54 AM, Michael Paquier <
michael.paquier@gmail.com> wrote:

On Mon, Jan 30, 2017 at 10:01 PM, Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

Attached is the patch, which extend the existing wait event

infrastructure

to implement the wait events for the disk I/O. Basically

pg_stat_activity's

wait event information to show data about disk I/O as well as IPC

primitives.

Implementation details:

- Added PG_WAIT_IO to pgstat.h and a new enum WaitEventIO
- Added a wait_event_info argument to FileRead, FileWrite, FilePrefetch,
FileWriteback, FileSync, and FileTruncate. Set this wait event just

before

performing the file system operation and clear it just after.
- Pass down an appropriate wait event from caller of any of those
functions.
- Also set and clear a wait event around standalone calls to read(),
write(), fsync() in other parts of the system.
- Added documentation for all newly added wait event.

Looks neat, those are unlikely to overlap with other wait events.

Thanks.

Open issue:
- Might missed few standalone calls to read(), write(), etc which need
to pass the wait_event_info.

It may be an idea to use LD_PRELOAD with custom versions of read(),
write() and fsync(), and look at the paths where no flags are set in
MyProc->wait_event_info, and log information when that happens.

Yes, may be I will try this.

Thanks to my colleague Robert Haas for his help in design.
Please let me know your thought, and thanks for reading.

Did you consider a wrapper of the type pg_read_event() or
pg_write_event(), etc.?

I thought on that, but eventually stick to this approach as it looks
more neat and uniform with other wait event implementation.

--
Michael

Thanks,
Rushabh Lathia
www.EnterpriseDB.com

--
Rushabh Lathia

Attachments:

wait_event_for_disk_IO_v1.patchapplication/x-download; name=wait_event_for_disk_IO_v1.patchDownload
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index fad5cb0..3b7b0fd 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>
@@ -1264,6 +1270,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 c7b283c..2456500 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 50c70b2..4aabfba 100644
--- a/src/backend/access/transam/twophase.c
+++ b/src/backend/access/transam/twophase.c
@@ -1201,8 +1201,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,
@@ -1213,6 +1215,7 @@ ReadTwoPhaseFile(TransactionId xid, bool give_warnings)
 		return NULL;
 	}
 
+	pgstat_report_wait_end();
 	CloseTransientFile(fd);
 
 	hdr = (TwoPhaseFileHeader *) buf;
@@ -1543,8 +1546,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(),
@@ -1552,16 +1557,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);
@@ -1569,6 +1577,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 f23e108..1132b95 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2454,7 +2454,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)
@@ -3205,6 +3207,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;
@@ -3223,8 +3226,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);
@@ -3232,6 +3237,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,
@@ -3358,6 +3364,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)
@@ -3370,8 +3377,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;
@@ -3387,12 +3396,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,
@@ -4417,6 +4429,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 */
@@ -4426,11 +4439,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,
@@ -4456,10 +4472,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);
 
@@ -4653,6 +4671,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 */
@@ -4662,11 +4681,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,
@@ -5033,6 +5055,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 */
@@ -5042,11 +5065,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,
@@ -9995,11 +10021,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();
 		}
@@ -11452,6 +11480,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];
@@ -11463,6 +11492,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 8b99b78..d17d541 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"
@@ -728,7 +729,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 ada374c..5bd4964 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;
@@ -3436,6 +3447,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 7dc97fa..8bd4dda 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 c0f28dd..f47eefd 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 ba506e2..f723941 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -462,7 +462,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(),
@@ -2072,7 +2074,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 6c17b54..d0f0f37 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/include/pgstat.h b/src/include/pgstat.h
index 8b710ec..6d1cebc 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
@@ -805,6 +806,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);
#5Amit Kapila
amit.kapila16@gmail.com
In reply to: Rushabh Lathia (#4)
Re: wait events for disk I/O

On Mon, Feb 20, 2017 at 4:04 PM, Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

My colleague Rahila reported compilation issue with
the patch. Issue was only coming with we do the clean
build on the branch.

Fixed the same into latest version of patch.

Few assorted comments:

1.
+        <row>
+         <entry><literal>WriteBuffile</></entry>
+         <entry>Waiting during
buffile read operation.</entry>
+        </row>

Operation name and definition are not matching.

2.
+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();

AFAIK, this call is non-blocking and will just initiate a read, so do
you think we should record wait event for such a call.

3.
- 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)

Do we want to consider recording wait event for both write and sync?
It seems to me OS level writes are relatively cheap and sync calls are
expensive, so shouldn't we just log for sync calls? I could see the
similar usage at multiple places in the patch.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#6Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Amit Kapila (#5)
Re: wait events for disk I/O

On Sat, Mar 4, 2017 at 7:53 PM, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Mon, Feb 20, 2017 at 4:04 PM, Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

My colleague Rahila reported compilation issue with
the patch. Issue was only coming with we do the clean
build on the branch.

Fixed the same into latest version of patch.

Few assorted comments:

1.
+        <row>
+         <entry><literal>WriteBuffile</></entry>
+         <entry>Waiting during
buffile read operation.</entry>
+        </row>

Operation name and definition are not matching.

Will fix this.

2.
+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();

AFAIK, this call is non-blocking and will just initiate a read, so do
you think we should record wait event for such a call.

Yes, prefecth call is a non-blocking and will just initiate a read. But
this info
about the prefetch into wait events will give more info about the system.

3.

- 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)

Do we want to consider recording wait event for both write and sync?
It seems to me OS level writes are relatively cheap and sync calls are
expensive, so shouldn't we just log for sync calls? I could see the
similar usage at multiple places in the patch.

Yes, I thought of adding wait event only for the sync but then recording the
wait event for both write and sync. I understand that OS level writes are
cheap but it still have some cost attached to that. Also I thought for the
monitoring tool being develop using this wait events, will have more useful
capture data if we try to collect as much info as we can. Or may be not.

I am open for other opinion/suggestions.

--

With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
Rushabh Lathia

#7Robert Haas
robertmhaas@gmail.com
In reply to: Rushabh Lathia (#6)
Re: wait events for disk I/O

On Mon, Mar 6, 2017 at 3:27 AM, Rushabh Lathia <rushabh.lathia@gmail.com> wrote:

Yes, I thought of adding wait event only for the sync but then recording the
wait event for both write and sync. I understand that OS level writes are
cheap but it still have some cost attached to that. Also I thought for the
monitoring tool being develop using this wait events, will have more useful
capture data if we try to collect as much info as we can. Or may be not.

I am open for other opinion/suggestions.

Writes are NOT always fast. I've seen cases of write() blocking for
LONG periods of time on systems that are in the process of failing, or
just busy. So I think we certainly want to advertise a wait event for
those.

Likewise, I agree that the prefetch call probably SHOULDN'T block, but
just because it shouldn't doesn't mean it never will.

I think somebody should try a pgbench run with this patch applied,
using a scale factor greater than shared_buffers, and generate a wait
event profile, just to see if these are showing up and how often.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#8Michael Paquier
michael.paquier@gmail.com
In reply to: Robert Haas (#7)
Re: wait events for disk I/O

On Tue, Mar 7, 2017 at 8:57 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Mar 6, 2017 at 3:27 AM, Rushabh Lathia <rushabh.lathia@gmail.com> wrote:

Yes, I thought of adding wait event only for the sync but then recording the
wait event for both write and sync. I understand that OS level writes are
cheap but it still have some cost attached to that. Also I thought for the
monitoring tool being develop using this wait events, will have more useful
capture data if we try to collect as much info as we can. Or may be not.

I am open for other opinion/suggestions.

Writes are NOT always fast. I've seen cases of write() blocking for
LONG periods of time on systems that are in the process of failing, or
just busy. So I think we certainly want to advertise a wait event for
those.

+1. I see that quite often really happens, and a lot particularly on
overloaded VMs. Having to debug such systems until you notice that
what is slow is just the underlying system is no fun. So being able to
show up an event state in memory where we can say that things are
stuck on I/O just with PG interface can really help in diagnostics
without having to look at storage-level logs for a first impression.
-- 
Michael

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#7)
Re: wait events for disk I/O

On Tue, Mar 7, 2017 at 5:27 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Mar 6, 2017 at 3:27 AM, Rushabh Lathia <rushabh.lathia@gmail.com> wrote:

Yes, I thought of adding wait event only for the sync but then recording the
wait event for both write and sync. I understand that OS level writes are
cheap but it still have some cost attached to that. Also I thought for the
monitoring tool being develop using this wait events, will have more useful
capture data if we try to collect as much info as we can. Or may be not.

I am open for other opinion/suggestions.

Writes are NOT always fast. I've seen cases of write() blocking for
LONG periods of time on systems that are in the process of failing, or
just busy. So I think we certainly want to advertise a wait event for
those.

Sure, if you think both Writes and Reads at OS level can have some
chance of blocking in obscure cases, then we should add a wait event
for them.

Likewise, I agree that the prefetch call probably SHOULDN'T block, but
just because it shouldn't doesn't mean it never will.

I think somebody should try a pgbench run with this patch applied,
using a scale factor greater than shared_buffers, and generate a wait
event profile, just to see if these are showing up and how often.

Yeah, that makes sense to me and we should try for both read-write and
read-only tests.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#9)
Re: wait events for disk I/O

On Mon, Mar 6, 2017 at 9:09 PM, Amit Kapila <amit.kapila16@gmail.com> wrote:

Sure, if you think both Writes and Reads at OS level can have some
chance of blocking in obscure cases, then we should add a wait event
for them.

I think writes have a chance of blocking in cases even in cases that
are not very obscure at all.

I think somebody should try a pgbench run with this patch applied,
using a scale factor greater than shared_buffers, and generate a wait
event profile, just to see if these are showing up and how often.

Yeah, that makes sense to me and we should try for both read-write and
read-only tests.

wfm.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#10)
Re: wait events for disk I/O

On Tue, Mar 7, 2017 at 9:16 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Mar 6, 2017 at 9:09 PM, Amit Kapila <amit.kapila16@gmail.com> wrote:

Sure, if you think both Writes and Reads at OS level can have some
chance of blocking in obscure cases, then we should add a wait event
for them.

I think writes have a chance of blocking in cases even in cases that
are not very obscure at all.

Point taken for writes, but I think in general we should have some
criteria based on which we can decide whether to have a wait event for
a particular call. It should not happen that we have tons of wait
events and out of which, only a few are helpful in most of the cases
in real-world scenarios.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#11)
Re: wait events for disk I/O

On Tue, Mar 7, 2017 at 9:32 PM, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Mar 7, 2017 at 9:16 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Mon, Mar 6, 2017 at 9:09 PM, Amit Kapila <amit.kapila16@gmail.com> wrote:

Sure, if you think both Writes and Reads at OS level can have some
chance of blocking in obscure cases, then we should add a wait event
for them.

I think writes have a chance of blocking in cases even in cases that
are not very obscure at all.

Point taken for writes, but I think in general we should have some
criteria based on which we can decide whether to have a wait event for
a particular call. It should not happen that we have tons of wait
events and out of which, only a few are helpful in most of the cases
in real-world scenarios.

Well, the problem is that if you pick and choose which wait events to
add based on what you think will be common, you're actually kind of
hosing yourself. Because now when something uncommon happens, suddenly
you don't get any wait event data and you can't tell what's happening.
I think the number of new wait events added by Rushabh's patch is
wholly reasonable. Yeah, some of those are going to be a lot more
common than others, but so what? We add wait events so that we can
find out what's going on. I don't want to sometimes know when a
backend is blocked on an I/O. I want to ALWAYS know.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#13Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Robert Haas (#12)
1 attachment(s)
Re: wait events for disk I/O

On Wed, Mar 8, 2017 at 8:23 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Mar 7, 2017 at 9:32 PM, Amit Kapila <amit.kapila16@gmail.com>
wrote:

On Tue, Mar 7, 2017 at 9:16 PM, Robert Haas <robertmhaas@gmail.com>

wrote:

On Mon, Mar 6, 2017 at 9:09 PM, Amit Kapila <amit.kapila16@gmail.com>

wrote:

Sure, if you think both Writes and Reads at OS level can have some
chance of blocking in obscure cases, then we should add a wait event
for them.

I think writes have a chance of blocking in cases even in cases that
are not very obscure at all.

Point taken for writes, but I think in general we should have some
criteria based on which we can decide whether to have a wait event for
a particular call. It should not happen that we have tons of wait
events and out of which, only a few are helpful in most of the cases
in real-world scenarios.

Well, the problem is that if you pick and choose which wait events to
add based on what you think will be common, you're actually kind of
hosing yourself. Because now when something uncommon happens, suddenly
you don't get any wait event data and you can't tell what's happening.
I think the number of new wait events added by Rushabh's patch is
wholly reasonable. Yeah, some of those are going to be a lot more
common than others, but so what? We add wait events so that we can
find out what's going on. I don't want to sometimes know when a
backend is blocked on an I/O. I want to ALWAYS know.

Yes, I agree with Robert. Knowing what we want and what we don't
want is difficult to judge. Something which we might think its not useful
information, and later of end up into situation where we re-think about
adding those missing stuff is not good. Having more information about
the system, specially for monitoring purpose is always good.

I am attaching another version of the patch, as I found stupid mistake
in the earlier version of patch, where I missed to initialize initial value
to
WaitEventIO enum. Also earlier version was not getting cleanly apply on
the current version of sources.

--
Rushabh Lathia
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Attachments:

wait_event_for_disk_IO_v2.patchapplication/x-download; name=wait_event_for_disk_IO_v2.patchDownload
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index fad5cb0..3704f5d 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>
@@ -1264,6 +1270,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>ReadBuffile</></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 c7b283c..2456500 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 1fdc591..5ca811f 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -38,6 +38,7 @@
 #include "access/xlog.h"
 #include "access/xlog_internal.h"
 #include "access/xlogdefs.h"
+#include "pgstat.h"
 #include "storage/fd.h"
 
 /*
@@ -338,7 +339,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(),
@@ -346,6 +349,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;
@@ -365,6 +369,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);
 	}
@@ -400,10 +405,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,
@@ -460,6 +467,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;
@@ -475,11 +483,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 0a8edb9..1f8bfd6 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 744360c..fa18b7e 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2456,7 +2456,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)
@@ -3207,6 +3209,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;
@@ -3225,8 +3228,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);
@@ -3234,6 +3239,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,
@@ -3360,6 +3366,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)
@@ -3372,8 +3379,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;
@@ -3389,12 +3398,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,
@@ -4414,6 +4426,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 */
@@ -4423,11 +4436,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,
@@ -4453,10 +4469,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);
 
@@ -4634,6 +4652,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 */
@@ -4643,11 +4662,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,
@@ -5036,6 +5058,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 */
@@ -5045,11 +5068,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,
@@ -9999,11 +10025,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();
 		}
@@ -11456,6 +11484,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];
@@ -11467,6 +11496,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 8b99b78..d17d541 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"
@@ -728,7 +729,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 2fb9a8b..4ec704e 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;
@@ -3436,6 +3447,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 aaefdae..9328814 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -441,9 +441,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)
@@ -1001,7 +1003,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 8aac670..767ea5e 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"
@@ -2275,6 +2276,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;
@@ -2286,6 +2288,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);
 }
@@ -2366,7 +2369,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)
@@ -2393,8 +2398,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,
@@ -3047,7 +3054,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 6f19cdc..c33bf48 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -115,6 +115,8 @@
 #include "access/transam.h"
 #include "access/xact.h"
 
+#include "pgstat.h"
+
 #include "replication/logical.h"
 #include "replication/reorderbuffer.h"
 #include "replication/snapbuild.h"
@@ -1580,6 +1582,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);
@@ -1587,6 +1590,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
@@ -1596,6 +1600,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);
@@ -1603,6 +1608,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);
@@ -1677,7 +1683,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);
@@ -1703,7 +1711,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);
@@ -1717,7 +1727,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);
@@ -1731,7 +1743,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 dd3a936..9be0185 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -462,7 +462,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(),
@@ -2076,7 +2078,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 fd02fc0..16f0c92 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -1550,7 +1550,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;
@@ -1565,8 +1565,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
@@ -1576,7 +1578,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;
 
@@ -1597,11 +1599,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;
 	Vfd		   *vfdP;
@@ -1619,6 +1623,7 @@ FileRead(File file, char *buffer, int amount)
 
 	vfdP = &VfdCache[file];
 
+	pgstat_report_wait_start(wait_event_info);
 retry:
 	returnCode = read(vfdP->fd, buffer, amount);
 
@@ -1658,12 +1663,13 @@ retry:
 		/* Trouble, so assume we don't know the file position anymore */
 		vfdP->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;
 	Vfd		   *vfdP;
@@ -1719,6 +1725,7 @@ FileWrite(File file, char *buffer, int amount)
 		}
 	}
 
+	pgstat_report_wait_start(wait_event_info);
 retry:
 	errno = 0;
 	returnCode = write(vfdP->fd, buffer, amount);
@@ -1777,12 +1784,13 @@ retry:
 		/* Trouble, so assume we don't know the file position anymore */
 		vfdP->seekPos = FileUnknownPos;
 	}
+	pgstat_report_wait_end();
 
 	return returnCode;
 }
 
 int
-FileSync(File file)
+FileSync(File file, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1795,7 +1803,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
@@ -1887,7 +1899,7 @@ FileTell(File file)
 #endif
 
 int
-FileTruncate(File file, off_t offset)
+FileTruncate(File file, off_t offset, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1900,7 +1912,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 6c17b54..d0f0f37 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 e0298ee..90cc9bf 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -35,6 +35,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"
@@ -856,11 +857,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)
@@ -1009,6 +1012,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;
@@ -1021,6 +1025,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;
@@ -1032,6 +1039,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;
@@ -1164,7 +1172,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,
@@ -1217,6 +1227,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)
 	{
@@ -1230,6 +1241,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,
@@ -1237,6 +1250,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,
@@ -1293,7 +1307,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/include/pgstat.h b/src/include/pgstat.h
index 0062fb8..dfb0aba 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
@@ -805,6 +806,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 = PG_WAIT_IO,
+	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);
#14Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Rushabh Lathia (#13)
1 attachment(s)
Re: wait events for disk I/O

On Wed, Mar 8, 2017 at 4:50 PM, Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:

I am attaching another version of the patch, as I found stupid mistake
in the earlier version of patch, where I missed to initialize initial
value to
WaitEventIO enum. Also earlier version was not getting cleanly apply on
the current version of sources.

I have applied attached patch, set shared_buffers to 128kB and ran pgbench,
I am able to see below distinct IO events.

--with ./pgbench -i -s 500 postgres
application_name wait_event_type wait_event query
pgbench IO ExtendDataBlock
copy pgbench_account
pgbench IO WriteXLog
copy pgbench_account
pgbench IO WriteDataBlock
copy pgbench_account
pgbench IO ReadDataBlock
vacuum analyze pgben
pgbench IO ReadBuffile
alter table pgbench_

--with ./pgbench -T 600 postgres (readwrite)
application_name wait_event_type wait_event query
pgbench IO ReadDataBlock
UPDATE pgbench_accou
pgbench IO WriteDataBlock
UPDATE pgbench_telle
IO SyncDataBlock

pgbench IO SyncDataBlock
UPDATE pgbench_telle
IO SyncDataBlock
autovacuum: VACUUM A
pgbench IO WriteXLog
END;
pgbench IO ExtendDataBlock
copy pgbench_account

--with ./pgbench -T 600 -S postgres (select only)
application_name wait_event_type wait_event query
pgbench IO ReadDataBlock
SELECT abalance FROM

Attached excel with all IO event values.

Thanks & Regards,
Rajkumar Raghuwanshi
QMG, EnterpriseDB Corporation

Attachments:

wait_event_for_disk_io.odsapplication/vnd.oasis.opendocument.spreadsheet; name=wait_event_for_disk_io.odsDownload
PK��gJ�l9�..mimetypeapplication/vnd.oasis.opendocument.spreadsheetPK��gJG�=�>�>�Thumbnails/thumbnail.png�PNG


IHDR��(�N(�IDATx���w�U��]����N����qt��`A���Q�HVr�9� D�,Y@��3(Q1��8���>�����zw�9������O���v���o����x<�y^ZZZ�9���')�/����X����������~�;��Yk�~����%�l��Ka�:n	m��EI
u\=u[������o�R-�_!�%�'�"##��h#�v�
2������X#*T������"x���Z��5����^y��G����[����K�CM�.��"n���������/�?�����o2�K��r��r{������h�)��H�zA9?�R�K������Q"j����T�Q��jA��%z�n�Y����j���������q��
~��'_��m������R^`��,&�RS������0�pI
�LXx������v�����\�p�����/c�[���_.Q�����^�hQd�_B�`:g���Z���)�l��i�!/��K�F�(W�������q�i-�Ma9�H�"��|��~������{�������e�t%�h��'O?~���o�7o�c�=���~�>�D[������?���^D]2�.�����s������z��I�&��O�Y={�|�����_���?��ok��������_��h��������;���b�p�
�s��[�n�-�������~��_�~|�A�F������:Mk}���?z�G}4~�x|�6l�[o������������#�4<��#�V����|��Y�f<x��(_���m2�B�
~��+��2|��������k��=���g����k��^�re�|���?���	& ������u4�[N�8��L�6���o��'O���K��S�NO<��W_}�+���z:��_��U�v�����eK�������p��G�X�"�;v��`�7�@�Os^`�}���Q��a-�X���+��h����m��!}���B\�Z�*\��
 ���=zq�m�v��}��c���?B9<�^���\z�)�A(���Y���I��_���V�Z�)Sf���s���R�
�+����7�Z�j�������o�B��N�J�`.|G�P���g�0���Ey��k��Y�xq��������cC�,Y�[&N�Hp���k��Rt��x��M�4A����B����F�(}�<y�h���}��7�b��eQz��f��y�M7��u�]=�#Z.��M�[��;�:|�����7��`=���3v���|�r8@Gx�w�A}lIq��K.�
,X��`u<�y�f�w���� 6�|���^����)�B�|	�E_K�,��K/��?����2��v����c������PPz��t���
�k�FR��o���?!��_�������
4�D{`2V�(=�B�Ez+T��X�����^�z��y�:ux��T�R9s�D��g��,2��r��iT�R�J���3(5�����w7k��~"K�)"�]w����_J�� P_�r�m��ap8$�G��#!���p�GA���KS4N���w(%����Fqq$�
���5h!�E�h
�G���*�c�
�2��u+�0�)S�� f�r��7l�+�z��?��\(A��
���@i����6�l����m�}Y�O�+8p ����o�C�[^}�U:��%���7��	W�yp�����$~�a  .�v`/d�%D@S��5�#x5��P�S_���>��=}FuPL�0P�v���C�������1b$�-�} : L�.�_��	��g�}��O?��h:l=t���s�=8��/��p���X@9�CAQ�A9$��8$�!p Z4�{��0�K�B-�>�������W��D@$m��	��dh6��������yB����w��-����B'�"1e�o��
��a��M-�&j���fP;�;g�B0�-G�^{�5��������Ca�s@�J��)��[�H8I��fa�E'�>�K�RB' �6��K��/\2&���7t
$�I�OwB���l��,���Ql��c�qp����k��ww��w���s�=���L���X�/������.�F���y�K�A�4�k���t�AX6�r�
��s���q���Pa
d�/�
��^A��)d m�W�����pL���P!��N�)6��p�@C����W�4E#X0�S�O?�4�j�)RY��rPt�m�6��0�S��C�a��?B���\�I(�0'���g	��*��t�R�N<"�!t�*����uP)~B$^E��&��+]W���\C�\����~�����
�0 a�I�I�G�8g��"��������
�O��~b���������T@���25�D�����M�n�//��	���o^�
�C$l�cl�
����G<j��a*W�:F��+�G�($���8�A��_��<'7��2UC�	��w��_�K\�F��t
��W����������Kf`s���Hs�.�N��4�`�6�p��A��s�Q
�W�)7�8��dX,���*��y
e�%�\5�b���W6��������{#��'��r�:e'vQ����+l��)�u'd$�����	���Q�}5k�w�%�N7A�f�5%���R^,6��v�x+n r#A�#�^�q���r��l�0��}^0�g����_�����J����Hn��v���K����g�o6^"GTn$Y�I�pGn�n���QI#]kq��e�VS�nkn��C��`(��S���2�P���J�m���9~6@e����[��@��1�i������AP'~�:�e�P��D�l���M�z������3���d*�C�'VNh'w0��=���������q��Pdq�j�e�n����Z~��w�� w���� �d��N������A]�9�3����LM`%��pFX��pZz���,9(����d�J��rE^@h��g����:8����m�U��$Gt���o*}���������O"���}�g��V��$J�
!���������!#s�z�f�����'l'!��<h��g���HE�+f����<�O�8�k�IIMx����)����$]��� {�% ��iv������-Z�'�5���,���	#�������}�����j�I��x��l��_�5�j��o$�6m	4!�*.:A�U�V�Xt�@��/�0���DR�z���-[��4�2dH<�~�K�@?1/��A�	8�=I\�?��\^��a�����d�
��U�V��)��;i�$�2	<���b��)������2q�D���aJ@����
0�D�������
u�8�[�Y��Cj���T�Y���G�!�.2h����4j�S 	G��� ����������J�"H�yw�����?o�W��~��o���
�!�;���e%����3�//U�Yh3v�,��n��!,Un��`������#'RJpH���k�b�����#���Nb��$��o_4�v���"����&����d��+eaH
!�:�an�c.��b��A������E��#D���<x�uS�P73�0�����)
�4������ ����|��bzB�LB����Rg�/�t	0��DR�N��>�f��1/<(��&�F��!,$��$��*P2�s�LF�U@T8���qc�%0z� �!R c'��-(�>���`���4����*���� �%K���h��W^A"h	��E�/F��(�M9���n@�%D�#������}�u3=��������CD$�}t�Jd��| ����p�:ur��
��
� �{��AL%l�����!m�>D!Q���������D��>r�<�J@?��8��<���3gN�����<Nk`f��u�6������?~|���D�"�`��=�N��W_}V ��89�%�.��P�[�n������/��3k�,�B�E�"qx�J�&&��/�����{0�3�<���h�@��KA����{��9�����?Q#��A�SO=�)CH<	��LTV���X0b�uxMl������h>��&SzR<�0!������@�Bg���1�.]���e��Wy�J��&���oD�S������J����`t�fRx���j�p�O>��5+��Z��D;��0�d����4���xF�IR�}w�:�v)��:���z���6�Ob��3�'-2{�}�;��0������q��V�3�-\8
{�|�lCS9���^dJ�h�i��e%Y��a�X02���	0�:s��dq����q�:���%��jOhL<I���-O�l<2�k�m�,�m�h6����(�	i6D�(��)�q�,��x�)f�l�������x0�w&O�K�O.!��v�"Y�����]��� ��7��,��q� �����]7��O�3Z�"���-#
�f��d~+�������i�	=�q���������^�I��m�N��r�\r�%�w8�3\���:�7o���T�" ��m�,���N��h�#r��}�'@HOb���T�!��.��W��>������K/�D���_6b�L��E:l�02R�>����U+
���%�t��/��Hv�%��g��2e
��D����#�����?�@GP�����K)�4i(��b�pL��������5j��2%z^�|��w����o��u��,X$�����%Dr���g�.]���W����}����:tF&�#W�����,�Z�����$~�~np3������U$�	���bC@w�A =T2D3(�l�@r����#�z���:Y�v������4
9��7k��l�{XG����O�?~���7���3'�5f�:r��������#����^�vda�1M��;M=r���L�01�0$rd�8�S�Q� Q�@y	<��V�T	D� t�&QI�c +��0�����%K�JT
���#�<�r����z���������]�v-^�8���'��G��q2@(@��(p�t���:��@��G
�0M�	��P�@�zR<�0!�P u���8L�7j���DqdF�1
4����+�	2F��W/�
*"����e��%KG�pNx�������Z�8��k�.\x��-T�Avy�C�6m��={k���%Dh#�����+���S�2;{>�5�7Jg�{>��oDGnx2�gq���@D4�H`�/[/�D������E�bo��������K�{	%(�
!X����bC�"E`��',�1|#��$|���'��_��G��� Z�a�Z�%�iP��'�./H���gc�4���zK�S00�l�W	��'��7���z���P�p�BZ�P���>�J�*��?(2�>tNx�O*���?��p��Ac� �Y.}��*Q���B�@f��@.�`�<
:��� �x���q�#F� d#����:�8p�-��s�=�����zS'P���d�?[�l�}�v�
B��}�Y���|�����`��#j�bRd�!���o��W^y%!"�G�s��B��P������u��i�V�����I�����E�d?��)F<�[�DnL���D���� )��S�,��V�p�=��P�Bh	�K�����*�
R�/��r4	���q��CBp3��$�	�>�(zC5q��yy�y.��%(�&/=u���9r/�Hk�7N+B�����4�>�\�r���C9}@����4f�%Qi��	Jl�W����r�h��hQ�;2f4%�`}6:KM�#���`��	��$��jO�*��}0!������B�<
�>���<��q�����T�����L1l����`��Z�A��n��+^'���4���:u�qP3gU����`��	��B|�O7���@���^4���s/�F}���h��V=�T�13p�����zg��:�����
4����)�-&
GG�s�LS1=��������6;8G��^��J[����$��lh4�r��������t�hS$��1�IQ�������g�&��F��n`����`�]h>�JB�����j�	�2}�L���O��f{�rw�m����Zn��U���+X���:{S�We�+^~�eP'�s���F",�\��"��=#�2}<5��6t����D�XcSZ�>D���E�n{���#�<Bf���1�y�\@<�T�Ur���U�Vq��u@���p����O�>d�w1J�����kZ��2e
!��J���o��&�i	}�j�6n����_~����#G���.\`�����[������O�3Z�"���3f�/_�����5 �B}����_CR����YR��
6$�p�K/�T�F�e��]w�uO=�T�n�����O �	`h��Q#L�����"�>}��4�j�����i+��g�}F������[���5o��c���^{�����?��@1R�]�v�����^��j��9�$�H��@��mp��������s�+VEy������>��
��&����O6��j�u�����[t����<x0�!�}���F!�
�	\�w��WC'\�-�W��#�+��g	y���3�R�
�/^6"���~��i��%(
�C� ��o�Yc�s��k�!������9r$���{��z_J?1-Z@9)������n��;w�Deqc���4�
E��,aNa�A$��
���;H#�@��{�n^S�bE��B������;qE�|�	zM��7o�T��`H����[�/������k�O��R*/I��Od��F)LH�)B"s��qt���h�$1(���R�J�Oh)�7�|��g���;##�U��Y3�j�3I�-��B���z>�����I�!�FMb�4K����GA���z�jb��+���fx��>|-A�qe)�n���i]���\"D�&b6�DPC��p��
�{�/��#+�7�)xGm��J���E��1�J`@Xp�v�D���� <�@��BHB���(���p��������w/��*2{�l7*���o�7(��Y��I!BA/�9+���m��@��N�����>H���	�&�������h_�U�ZG���U=�n����{�R�
Mc���8��������v��y�N�im�����@�����6m�6l���>��R	�y�8�&^��-�'�b�xtl�o��	f�`����Gp���S�N�.H���[������2m�n������|�W�� 	�`�DLt�6x%X����7o�L�G�P����-���f��w���iM��={x"��.���C�n������uS�R%��q����IA5�3����"�+E�gDR����YF�	��k�u�
z���P�#�m���_�4���|����������d.��)
�����#�h`
��Ib�da���D=,���f���f��a[L�B�����@�}#����&�L�x0��9��^0�P%�Q7wT��Q������_��;�h�����OM�;��	����,��"�����-`������l$���
����K������\����u6�fckbz��,��������`06�q[��dV����[����a�ns��6��4!�8�$�2��IP�Dt�
<����tO��=���FhTTQd��{E�
U3vs52���c*�=zW
%�����-tLH�J��N�Vc��X
����h<c����6�"wQS<�������^GM75K�)J�����?�ErN����R�X�����n��L^���t��k����������"(P��M�r8�j���8n�8 ��!C������{o�f�����#���'���'�yI����u�/��B���q�p��������;�@���_�5j�.�7oNrDMP�Rt����k77�A���$��y�%�R���v�J���������_x���skg�?�����$��}�z���T �5����W�-��t��;v�����D3������x�4���~BW�,9i�M�H��5'L�~
I�>��fY@6j�I\���~��L���>��S�.E
$\��
hR��8o�<�-�EQ�c�5�v�%��g�=-Z�������=��^V��%E7���:����}��I$�t�G��j��Mf��5J�7DB��A^F���W/����B��1�@_Brd�����<���?�]h���� m�������<?�����+a&�Eu�'H�_�>�6>�X�bh�j����U�V����/^<j�(���������9�/���7��Pg����+�L�������E���*]�4����B�@ #�)�#?��v�����z��[�I+�l��<n�$������o����<��L������)h6�L���S'�I����[�pam1��P�OM��r��G'x
?4h��.]�`���������G�(��9��
y����fzS)���;P��1c���
���O����������� �1T��K���2�w�3Ey�gMG�{��	V���z���� Y	4Y�'��Q
S�\�+��P(�H������P�&5n�x��%�������E�l���7����
�����yH���F����C�^���)*Xa:������=
4F!�%5k���Z�A��(��7/~7[�h�����k�K���?�d���t��y`��!48�q(<E�gDR��g�fe�J��/_���E������������g����F?��C�4jh����b8` �m@��2�l�@^�r��E�-�h���
^(��_ZE��/���C����K+��?4z�L��%��wc�L�7����rA��n!v�ub)=�.�Z��pf�I3�m��8����A���	Z���~���}�y������%��P�s8��cWBp'�LJ�����F��������3")��S�l�w.F�`��f���J�Bhp�su5����c�Y$/��L�uzK����!;,
�$�w�S�36j���K*�I|l1Q���'�;�b���������Sf�����={�\�����Fm�>2�>,z�>$(D�f��S��+DsB����Xz*�.�9��q�9�=~����{���E1*�
!����'����s�DF�=:w����?*Q�z��%K^h���1P��+�u��e���s�>���o��&%�W6A�T�RZ5����5k��_�n�z���-Z�P����KP�`��e_w��9.���4*T�6mX;/��	+�$�]�U������'�|r����&W�V���>1b0�����J2u�)��=k!���Q�"E@����N�V�n��f�J������x0JaB�e�7�p�-�}���;v�R�u�|���5j�2d���Z����/_�R�J�g�����u4��H��C�:u&O����	��2.u�SD��0} �����?;v,f��i����#~�q����4i�����o�����A%��k���O��2���G�#�h�����/�2��)��=k����L���*�l�I�B���d�&�'��Q
�����
2YJ��c�����+�P�D����5�^X�p���+'L������o�c�]�V�� #!q���^``)z�"�LQ�
���z�Y�r�^0��?�A��p�Z��@�����n�=�d�"��'��P�B(��cj!���sp�4:a���cy�����
U�TI����e��`����w��0�	��F[x��v�m$�$��^X�j�<���J�^::���
�<i������t]d/����(J�S�!����R�,Ye�!(��-\���g�_�5zC5��q�������`-[g$��(�w�^�X1��������;#�����7��`����E�j�T-���W���L�@�f���
���	t
>�9�������=��i��a�������{p�Mq�4��0�>bExF��|C�o����z���H���h	�`������C��V���?�=D
�)��U��=i�M�6Z<����J��/���n�mM4�{�
�z��W����#��������\�H��_�+W�r����!�����X[�[�����^�bE?����`�X�^�!L���������_����[�&PY��5�r��Y�� ��!�"y�u�y��ik�����>�Y��99pBx��x#8LN��l��E���+���s�=z�5���!��)��=����W��/E9%����L�x�b����������mJ�����3��s��BDx!}
���<Y"s��*�Ms�J���5I�>���1-8T��CvC����E7V��9�d6-�R��k@B�I��d��'H�������	]u�������w����F)|~����dQ,Li�2���%�[�f���L�J��E�����6���V���*��T�5	"�Jz��ws��`�X�T0��h�S��D�Hsv%�6m�������qgoX���Y���^����#��p�X������C8p0�msz�;�!,�C�-[�1��(H ��/k����p���=�9r����DMQ4�F�=TBNB]�����dI����"f���$R���(��CX<���	��	B2@�������z�
"#��X��V�^��m���d�PS^~�e���QQ��d�K�H������2�Q_�)��v�����Z�L	Bu*P2�s�LF���q���d��������������y������{����/GX/�/"�"���ilG!���3��m{���F����#�,]�4��EM��
*���+��n���
"�C�~�/�;�V�|y�2�f"n�\�z5$��y�~��/G"�k^��E�_�%=q��Y�=����w�n�
��O�������t���t���>�&M�DZ����{F�
I=�+W��2e
P��G���2�5��{ U����='w�cpF
i��N:t�xD�}���K��5Cu<HF��h�8����t|}��8#����)P��!�;������x����GW�Av�=%��{�!V�\Y�k�2eB�5��8�����G��9}�a��U�-[�,McX��C������6n�'���P8��&���d��y���r
�/���|��}�v����,+�_8���������qW����I5�Lw����-���/���i���|p�����~��hF��S����xQ��]%D���E���N��Rb�t�I�~�!J���[������������9sR���n�e4�n�^O}|�)���$�����9��������^�z5m�S�$��9�sv�B�����S�N�'RT��_�	{�g�d�
�����������'������2�����g��e�������y��2nBpx�M0�������FM���:w������������U�8��s��)�������
Np��?�J��2���6���Dq�M_1s��e=��@={��t"��Q���vh@�Ba�?�`�����{�e�v�P#<7����kp��5	��"<hW��"P���n��F@���c�QBp$t�s��6��~���@e ��{C�x
��=�oA��t��a�5}�
�=A�h��)��y��������.��G���?���;.�!��L�H���UV�a�)��^�l���mh�U��d�&�'��Q
�lx"�j]G�qc{si>�����L.Z��=�B�-`?�6�G/�w���M%��=���2?�����e ���x��������Q��w��+�x��������"N�����^��R���4�F>���L�lBzR<��E���g����I��{r8[jjh�w��Id�`|(���^�$R�5�A�����`�},����9���T��������- ����eT�x��f����9���.�O�	���'sB�`�hsO�1"S7{F$e�xVghd���`��6%#�����^p��=���������\fz��2�����
�0L\�sf��
���u]���@�s�:�����m&k6!=)<S���WA!:a.�qO^��p{��m�FtH�t4�	"z��]����{ZI�e"�f,X����r��\A=m($Oh>��)��O5=����[������f��I�����![=�.�[�~���C�SA=:�#a�gDR����Yla�@�a�_��M7�$�����3�B�
�Q�+o��O?��?CG?��T�X�r���%��6 C-t�7�?�)AW�K�,�b����/]��P�B��g%q^�=�kkoL(�\v��Y��@d������y�Yh+V�8p�����\��V���y������A�{��}��wyw�z��*�}�Y��A��.�����\�02Xnz��
��P��3o���(-�i8����1N��>�v�;��i��	h�������mLj��iS8���_4O� ��[�h���PJ��P T��/EFL�|�����4�Ee�4j�[���a�M�6}������i'O�$)���OB`W�����w����=����16��?��p�������~��
4���O0�M<���qwC���?���:v���}{t�t�������``�`������@��~������d��a����u�z����Cy���5�%#T���o�18�����	T������0j���%�2s�{��58$TS�=
�/_N~��k�! ,}�N,+W���
����7��{�G}��m��T!���6�Bh+#��[$B*�!l��ah1:���p��'}`UZ��g�*[C�<J���c�������� �C`�V<�|�����D_��%����B�$�
�KC�j����}���|�,_��������l���Q�%T�[���{?~<>F11����kQ����������>e�:��t�P�I�&����@o�wz
�0oz��W��C��7����	�.��2�e�R���2d ����+Q�y������b�xJ���Y�h~��B+V��W_�iZA��D�l��Bt�H�z����� nI�<r��)J�=��Kx�;fFDCE`=z4�	l�VU�^������#�):���xP=�������@
��j���h��Q�\�r�x���(H�9E$_<�F	��L)�0~�k����9c�������4g2�h���^2-$G�P��Z�
�t������=�/��q�3�B?������\�r:��A��D����t��)�#��Q�J����S D�
��d��$_Q�H�kjQ
	��D����x=o�PMm����x0>�
}�P����\>^x���l
a����7���/���*������B����;����v���P:�]�4��R}����c���-��_���QIR�lZ�f/U����7��j����c��aq�Hs�\�a
���+�Li����UZ�}�\"�vi�|�pv�����m���:%��a�2w:���-Q��,:�}���8H{ij�>�����.��B�Ky)�;0h����U����&�"	&{6!^������i<�@��')��S�,���{��f�{�c�� ������M&��E�������#����7�C�S��2rd<���7}�t�Y��+�q����#F�x��g�<r'���I��:)Z��h��l��$�ln�?�������[/�uai��\�V��C���Vs��M$_��J\���n��/^�X[��|��c.��73��a�����C�*w�������I�������a���b���9s0_�+��,�{�#��s'���t�R*������D�#e��u+z�LJ��g�yF�!3�
���	�
)k���{������6��5K�k��T�BO��&���y��]�N*���<��{���]�v}�����) �7f��x���[��;���>c*�z�B{������PDL���'��,��J�Tx�e��H��B� ��q<��S���,���4��m��u+�N�ga�8�����F����da�����WI�Go���n�Ct�V�N�>M�����
*��� t���l���l�!�Qx���|���U��o��������.)����m��]���*^���0�b�^�(�@����d�4����m������c��]�����3JCdh���$d�#���i�$��h��-[x�-����l��m�
����)��>��	��/[�����(2��
�!��~b�Yp�B*P^�V��'O�p�
J���������Z!����*g�F����E�Ct09��l�����>��f�5�m���������?�8����Gm�i ��HD�������zJ�\�R��M����'O&�����u7�	�M���W���;�Rx
w���WzdEU��+V���R��D, ���C_~�%ZL>�c������(��	D��k:��������7G��'���gC�,%�0.�G*���#G��`�����3��qI�%�Z�*��}0!��.X�n����z���O�2�������o��6���	x)*� �&�'� �;v*���/�r��
(�V��C�	�P�LV�^����R�fs���j��>�������C��2*))�v3f#��A7r���=v�~@��5j�2
OC����*���;�VCU�E���y�v�4i�mSm$�D�I.��
�9Z��1n�V�
=�
�w�w�P�P��
�L��6��l����������y�rp�����z��AM<
�T���J��X�"����.����
:��J���G�|����J�#bfXW���q�x��D�v��� Q��5��F��KfE(����7�|,F �]�_��S7��x0���� u������&�<������Dk/�+Gp<��{��k�����B%X�n�U-����.���w��.�3�H"�L@^ P�uM��h���)~YK�;�K�M�2H��������s�\k��/L�!�����\������+/�K$�il�@��9�%����u/�ph;�����];(���4�tv/04�i��^�C0��&X�����#�/�Y�b�g<���8�����?��o�E0���i2^{)1P�Y���:ySb7�8��������i���9�����,���$t��k]&#]���I1P��J�����x6��H4LYR9Pn���� ��9!�4J�G*������SH*��}�\�>��,WQ�H���o;f�������|�A���k��Xd���H�� ]����^�����*z�X�|���I�_��@�o���k��-����������N
�F6$�$�����l����k���K.���l��.@��]a��U�f��	H\�f��E�r?�%����/lT6'a2r�p�z�z��'�'iV�y�:������{.�Z�v��;w��1c�����s$2k�,P,`��H
���P�r����u���;Z��k��r����{�np��M��������EO�v���PC�D��E����9���t��h��W^!Gkc7P��t��������
��[$$���g�| ���A���~��=:>=��dJO��&��
e� b��t�������L^	�.]
4�� ��[�"�����`"��[������8q"b�����>y�%��J���z22$��c��$���!������yE�j�` i8/������J���)������^��S'����';{��GQ������{����7k�����������+��C���BW2wA@�jV�
���SP,@�1��Cm�n6+T%�0!�&������PnB���a��M��D������b�tI�
6�������N�G�������t�M���7:�S�0i�oa��J
! �����Q_p
��J���u*} "@?��#
���Wp6�D���x��u�~���k��}H�2����~��rU�Gh���@8��_��AF�2^s��	O<����Gq��[������u�
~��2^�b���W_��#����Z�*FP,���J{q���&���e��
�
���qc�t���[pl�'��UA�\���G�x
*�(�e�	�Z�<c���
*�=���Me����O�2e��y��D�o��
�� �Es8*�G��	����WB"e�3S/�BTY�@z�����o���8�
��M��q���m	(�
FAQ�������O���#p�6�@{�F�������� !�>t�P`���F�?Jy�]w���hX
-/�_��br<�;��(��F�C��K�.�]����2�l�z����Gcx,��s���eM�����y�bxU �y�H������cP��������t�=��#���
q?J(!����^p�|��CL�>�	(\�T[]��*�a:�f5��Q#kV��Js�����O�1o"r��A �<�#Q�P�VS{O�6<�ok`��v�u\�D��?���pt�Y�j���g
�|$e�x
������p<��.��e��xp4�����R����U�D����
&����j�f.��%�Q��J���Et��6���l��Eu,I���cFnH��y�Z��O�S6����/d%V����*Jga�����Bk���y�$�q��;`��i��T(�=o^��[�l&k���2:�m>	�����P��������{RV�)���D���l���W��������n�h@��I����<n�jK����e4��&8��1��W�k�-7��kB�W�����?��A��&����"'��ic��d�)�?7~���'N�4h������c�)����'�i���7��W^y��gI��o����/����� �*U�`�����h�c��u��!W ����
={��Z�c3����%}�=��[��|�������z�� ZB-�$��2�
�4�`�������=�y  �F�I������iu��;�i�+��2}�|�Z�X�hQ�X�zue�� ��&SzR<�0!��>)|�� x��Q����c��}�����K�N4�����A�����
�X��P;��J�*�>�^�y���������)�na����������L���S��?��Cd��<�}���5k���n���C�P2@l�]v�em��%�;|�0������xX�A{�"����G���Kk�OS�7y��#�D!]���������a�fe��E(��5r����h��Y�x�i��(O���k:�;�=���=�V����&0�(QB��!TCG�D���=<B�����`�&t�-7� �])����{��?�04���3")��S�l%�%�Y�F�G}����t�%������Dq�9�
���>��g������d<��������a$$#S��x$���=�NF���LL�:���������|������<�7"��,�S�L���I
4���-}�L��e�R���%
#�mxxd�3g�
��L��{�AKn���
<�|����"3`Y�?��y�w�)�$���O�7��s��|-���3fP�q����x/�=�~����5k���'OB(!���NP��7��`i��&i{,�O�f}S���k��=���������+$�h5km��QZ�?{�l��$%t?	�e���4�T�8�o�������7k?I��9?u�����h�17(���?~������/�I\+V����Cw�������{��U���R�d���6���o&�������>�r�D�@ah���q}��"���Z^�Y���B5�
�SS3�Y|������^0�d���ML�>�_}���}P�����^tz�zJ��$"�iu}2����x��E@��
�"�������/)Dk_Y���S�h\L�������)�^���Q#;_��M&��`����t��Ck!����F��&�k���9�q��n!"*�,y �*�lp�^�_��H��x0�VM���M���Y����
)T't�������k�/|����������<�.j�2wZb��Nv�!����D��=R�X0Zr���o���6���yA�#��x?���o��������o�`m����9I�w���LTV��Y��y�~�a����I����+����L�l�+��Q
�,V�8q����`�&�U�z����v��\�2����[��d�L�2��@{ �,Y�sd���7���O����z���W_}5��mX������_�~x��z��Pa���>�`�����=�t���&M���������'��?�P
�^�n�W_}��'��h����C���_k|�����V2��N�^�y ���s���=���o���y�Y�f��/(��~�H��
{�_����[���:"@�5j��kW���W��z��V�Z�-F���@h�<o�����Cy���{o����e�Ry��	����-����q�/�u����������3K(���O�>�������*T 1�9sf�B���J�(RM�!�
v��1^����C��^X�i�&������\�(X�����Kd��~F��9!u�@<8g����4Ry������5$e�xj�����p����	��x���|���p�O�>&��AW���w�N�I��{Y�&Mn���+WR�^�<��������%�\2v�X�&���� )�x��=��<��V��Q��y���D.#�9�@[�4�F��
����(
FC�0e:~����?����kY�[o����3�_G-�3�J�3Zj*ZM�:�������~
I�>���xp���0A��UK~~0�^~��@,mC(K�.U8C�H��q����7��S�N�7��pD\�����M'�
3C������M�r���6l��d���f<4�H��c�����w��t$�O���'��_���;m��+W.���sb��i��K�"�����Xp��a�X�.�Z��������)S�M����.�����!����B��npA��s����g�&t�������<����_��)�5X�USa�C���S���7�?���P��������0�(��>|�p���y��4�b�������/�(��w�
��@j�m��]�j������Ia���@���'��`��Y��C���v�M(�a -<=�����~�������&4�%�"B�$�`/O,Y�@H;w���M�V����-�g�-Q�������pB!�Faf����vi����qK��_t�7�|=��q�]'��_���*
*���=g3G�]�_)���s���+�7��/��
D��hE4W�V�M�WB�s��`v�����(*�>������E����t���w����<g�?z��s�]w���3:�)I�������5�,����}���n��|��.9~m�)�5dsXUM6���`���������w���}
r���=�s�;q����q��W��o���7kk�������M����is����Q�
��d���q9����Dw��m&k6�2�MR��*�a|��9d������d��y�2M7��_+q�G�qs'!]t? ���E��� �����������V;��(N}mJb������C�N=0�8q�I��Z���w|����$�$��?c�&|�MZ]�p!q��K�R��26���C��$�$n�����X��������SvJ�����oa�RZ����x�8��;H�����60�j�l�
����@=��>^y�" -(wH(�����o?q�����@	x��$��T�<^����;�X��`�HP����b0s����#r�l���Q+�O������4�6m"A�0a������~��d^t(��K/Q���'��_�	z��u@+����o��=�E�qi�z���A����m�D��d8��c���*U:~�8��}�v��2�
Rt�&�G���<������	�t�B����� ����k�v��^�M!,|��;u������R�J�FG��L�l�'}0�!���y�M7��]�a>���3��q�F��/'�:y�$�;vl�B��������]�����;H
����Z�n=y�������
H��w��4i�VI��S��{�n�	9<*K���2����d�2h��	-_�U}
�0/�@��`�������7�;�u�FD@��W�N�.�=�&]�]������t�A�I����-Z|���("I���-�.�O�y��f�<I�	?�7o�
GP]�r�6W�}v���d��/��"��
H������?���y��e�n����t���R�c��!A����;����/����m[��y���_�T���U9���)S��p�,4 D���U�p
���d��u�������i��f���6��C�Qst3����Ul��Yz��"f:���0+���oa0o+��G}��^IV��9e�Fk�BO��&�9�,���l�@��3gN4I#Bx��ZE��t�?mm �y����=�/}�$h�����bB�ah%�r�����9s&
j9��`����W�`��5k��-�n��T�#6
2���^x��E������C��N�6����U#j
[T�X�<��3t�t�5���da��N������_8��Y3��@�=��+_z���z��C�B0�-[�,Z��O�>h�`��]0A �Z�j��6�'�d�l�t�
�>���#Z!~�Di
��y�fJ�X�� \�p h���;��XW�^�=x�b������h3n,�������
���J�t�%D�_%�xW:�&@ps���k���
���)�� �O!�������B��2���>S`��r�'`D��9:X�N�q8�����f��X��!�:�y &n����	X��8t���9��_����B��`%;x�}tf*`����eKH?%��+}J+I>C���B��J:��{��Zn�/�|��N�9YXwv��M6��iuo�j��?Un��`B��+�@;�IWZ������P&
n�K�$�����`��&�j�H�]�D7�;�,Tw_�w�W;T��nn�'�N����?��m0k��`��)Wz�u�p�*P�DR -���U���F�]�l*7Ra�0${<l�j!4�g&g������UK�@V��Aq���Cm�Oy�&��i��8���C�4����)�I!�L��9�������]�s��&a�	�I�`���4����pZ��Q`�Tw�Ik��sI
����6�>�97�N������T)<p��ld�x�I����}&��J��!�5��N���.^�B���l���{�4o����~����S����y*��c��;u�& x��d/W�\D�w�:L���*4l��L�D�$�@"0��w�HD1%��$A�F�>}��7������m��CX@i���?��s�:��-}�Q��}��s��G�"�3f���6w��h���{"��iX�|���f��z�/_�w���y���v��e�y����F��/:K}�0t�\��w�%S��%	���~��h`
*S�	�{��GB@Z��FQJx�)=)<#��_t�����s��1�*U=z�vM ���pu���8~>����*���"`8L���=��S��v����	p}��wk��n���a�h��]�v��s�I��n��#�7��a	�"%���)S���%�a3x �"0�n��u��*Qm%�I�{��$uU�V�������}��=�B����u�0p^�m�v����J���u��_�j!�.�=p@��u�]w��:�������$Y���M�6��"E���O<��&w��;��!�h3W���x��6�vD%2)b�+�������N�jB��%Khs���2�	�A�����{n��m�@�B�@�� ��{�z�| n4������Q._j��I�p}��#F`%���|!��~jc�}s��z��4�	�5�����(S����K��l���
a&�U��!\�pL7���C%.S�C"&����Ym����FSq�����V�x&����j�Z�v-!C�4&��4^�O���MP>X�@�+} QGw��>��������(��l�2�[��)A�1�%Jh;4�&�
44hD�	����9�EeL����wW�pa4�Bs?^�����#1Tn���>�|>|8��
(���y��_~��rq����s�Nd��)b��o�	^? �=�����a�(
����w1'���h>F'��F���-[�@T��jG�'O���dr��+��(��:T�*)A��=rn�������s�#X�y���3��j����>�@*�#�����YU�T�����X�H�19$��?��:����C�jZ*��t���Gy���*��=����3!��c�i�:��G!\P�����#!�Fy��E�Y�i>���d���CMiX2�!(�US�5��S���V�Z��]s�5���$s
�i��n�x^���������!�PK���O(;��X������40+�J:������K��
�Q�a���*qK��[e��m����<{�����F�!L�v.�Rm4b/s�.�R��9_7U��`��������Ui��p�#�9{x�s��y��`{Wc�;4�3o�H�\S��|�37c�������!�\.���X/8�>��,Y.��>[�m/�8��b�,�ClM�n�&Z-��d����b�_CR�����[�����`T�CG6�g��x������b�A^^�Y�^�p�]��qwU�����j��4�P�/����:4EK���������9!�b��MBc����L%+�w�-���N�8���d U��x'���
2�l����
v��<a]�
�"o�#��z��u��)����He����W�\��G5i�$��}�+}m��������nC<���D�bdA=�D/Z��@������
6h�!�{����b����)��d2��Y���G����G�&�������{	o2�'��Q
�l"�Ao1/���{����i����u��>|&�&B`��o�M�_|�C��7o�|���yY��������%���/��hPM����������G�i����E�-?5�C��k�IIH�t|00�rnH�������������/	I2=��#(��c���f��7���9���)S!���v�����H�m�V�d�j�M��}j�����Y`Xx����/�G	H�����~P9g����������[�F����B�(���}��P~����s<x���_�~<��u���_��,Z�t)bB��}�Y�k��!V��0���x�h��t���_|��1Z'��,H�����N�|��`x��F�T��a���G�D������Hb�z��	W���9�m��/�H�7�D!<�M���x05V��21�-[�����1���/�<%����q���
 rk��#��(rr����Y	��$
�����$! `����P�H�;���]�v���C�#���"��y�0}	z������Y�bF��W_����^�'���l*������lRJ�(�:��N0`�%	%	F�SD1H�t��o��k���4�����O������Y�1��S���aC<%����74`��	�+���E	����a~������kQ T��%���
�7���Fx���9��"��6o��*hU8O�l�G��d�9����f��e@-�(��fhw����01m�4M�����=-�7o�<�u��7��h1�h��9HTS�ID��[7B�h���k�nr��[�DB��9s �V�ZO<�`���&(�(��5k��1���g#l|5�i���a5lW�]��K@�H���;��������(����Yd������&b��0��G%X�m������������Y�{����O�8���B��[�R%/2��M Zj��A�4j���VtJ�y���Ju��jx�w������?����|]��w�{" �y����fx���/��v=pV�@����G4N��do�^�W���=M=�q��&�
���{��D����N��^�6l������������b�g�x0q��^���6���#�kL��L�u���{��#� e�k��|c�&F�`�\�_��av�h/�dSz�I�^�)�E�	�L�l����h�iw�w
hh^,8��s�]���m�_���vg�{�^�X����?)�6Z=�����%�lJk�9�s>9Q��w�Q_��X`D{���`7|� ��f�r2'�kH���4�Ih;���3���[�����e�i��k`d�������3�TB�~�^q�$_m�ug���������2*�B�L�@�`6t��H#��������W������O?���^G9A%b�W:�,LL��^���D1�_?x����O8P�%��U�v�M���$�Q��
#u�2e��v���p���}�jp�}�
7 ��8��qc�5:�DX�����1c��y���Ikh~�-������4Q^�U+��1��?@M������3��(|�"��z�����3Z��+W����]wI��C�4�X�����1z~`�0���#G'v�fSS�����<U�(��*��[���;/��'O2/�����?��#� 8����}�m��`/Y6p�}��X`d�2b��Q�F�U������\�r�S(���G��������?�{�EeQRl�%��Y��T�>}��4���C�<j�k���i�@=i�Y�dI4��G���
�+tG��}��=z��
4�������H
�`�eO��<�)h���������P{�f���LOM3� H<�����[���o���/_N������KS,���cq!��#z��AuP����+V��^}�U��fQ2�	-��C#IT�����I����Z���pW��=�f:�`D���i���m�3�X�"E�����@�P�"9A�X������X����l��{d����5k��0�0��Z2�r���*U"����;I����H	8�(ZS���=X����X��M�6h�:x���%K��X����*�����B����iS�O� (��V��9��\d���q����t��g��1D��x��w�	J����6���W��5�g���ftY�BC;����GF�SD1e����#��`�w������A�,H���4���h��8���+q�b<$T�s�t�RMa��5Qp����%Xw���DT�����
0�]�v�%���n���;������oM�8��K/�h
��q<�����]F)O��SZ���|@����CbV����*m�I������hn��!�l@*�����G��^��Mi�c�F\4�"�u����'t��d�J�=.Un��`B��'��t(�ea��{���^�@��E��=<j��M��:��B�����������B@xm�����B�
�&L� �bK,+#�b1:�S���AP���O+���r�������e�_Z��g�j�s9�U�h��&���l}�Y\�������
z�I��/;�	�t�y�X��i��he-k1�f�\��=��r�F^}��j
�Rb���3�M�Iy�)���-Z����e���3�
Q��`*��q #@s)�!�5{F$e�xj����s������S%�n�����2=�����U\t��
w��{.�;z����4�>�,���Mt��a
�j�����x���;f7����M8�5�f���LOMs,�O77��>y��S�N�4i#��,y�J�c��F�����9_������Bj�V�`�n��E��9�]gC;�)������[y�-���G�1i�$wl4-��i��K��a��5G��k���~����v�wi���T@��)���eKBU�����Y��xJ��~d�Z,���x��ap4I���=7n|��P���+B�������^H������t��e����!����*��M�6MzZ�BeaDYM���c�;����X_�h��M2�w���;w�@�`7dI>M�5i)b�Y�/s�d��O^�$�9~�8��9s��g%�d��F)LH�I��7��B��1~�xmM���ZH���|�<y2j���m�����?�����_
�I}H6��`���3f����k�;��m�����R�5,m��-�l�~
���oPBy������Y�����s������x�=P���Gc���Q�F��7�d���rrN��7B%������_���~����M��s��=��?_D?<"����O$)E�+U�$���4��E�E��ac�����L�R�@��9sb���T����nb�dL �5j�Z�
'����5���`\�W.j��m89D���K/���o������8���;�d��k�"�5kv2������/��A-�g�\)1y#�D���s�ig�/���Tw��c�a7<N?�Z��b�d &Y��5����xl��V�q�x!��d��F)LH�BU��Eq!G�!�E�����33�:�xP&�\���,�>t�P��%�3�O	��v�z�-jD�{��G��5k�L`�7�|���>��{F������x��z?�����G/^L��2�����:.Dun��&�F4�������(L�?z�(�G�i]MB�>i]eE�hy<�����������v��U�X���cp3�b �B7.I��(IQ��B���4[o�/B���?�2�
@Z�?�	��b��Lz���:,�J1�b��i�z�F�,�@Bh	ne������u�0oDd ����o������S�9�}�����={j���T�G�N��v�2<
�C�:�	�Py
Lw�~����������M�6A���_���K�C������������pq�Dt����9�Y�J��/�
Z ��_������#i|L�~�4r�AB8m��U�Lt������s�/(
�Y�7�\��!>Di�1e��Y�z5��w�}��������w�D>�,L
E����J�_HG����w���v��6������	���xch���c&�-O���mM�E2k�a��/E�gDR��g�k�S1H/�aZ������{K��c�����X�:w�*�1\��F��p*Aw�j>���8�+u7c6��j:LQ�V�Rmw���w�%Zg��L2�L&����9SZ5]F��
�L�av_�`m�~����Kt��_�2���*v������?���� 3��j���h������x�>��t_�r�F��lx�
��.c����������n��9��+
[IZ��*bc��+G�X��Z7%8[(�9�sh��3�P���6��s�B���/���������`Y����u��9sBza���I�P���~Cx�J��^"��h�h�������8q"9�P6`�x����rf��C�5���D�2�={v��9�I��L57n�V�^���YZ������1�!^}�U�2�i����&�H�[�paP��~����e�A��6l�@\�n�jc������A�2S��^x���_F���+�}��%K�:����x]�,�6I;	l�
@�0�����>��g�Pq��A��I��I�&Q
�@!�N&���$����R
,����Ys��A�3*�-���tx2%�7o&��qr1���3��-Lw�Xp��myt�rH����
�A'����[�%X6y#����{���	$�;j�(�zB�9a���������)�LV�e
��nH	�;��1c���N�:d�0%4���f��F)LH�i3cc�Mv;x�`�/_�l�����j�O�����~�tU���M���|����8iy�>}h���#!���m��!Y8�i!V�H�s��6�>��h�2�>��hz���8X^If�|���I���T�\�_��om��	�o��U����W�RS�ej��x����A,Ik��f�GGb\A&$)4���*�0aCoW	�%o�>}��?���s��ar�+������'�#�/�/�w�����?+���;���$;�|,9w����G�D:�2��'�I�W����=����t����k)�]�v��-�6�U�X��@�1^��p��GI5����.{��7x%"A[�(B�L������_��QD;� ����10�!�9rd�F�N�8��o�>�g��xY>��U+z�Qw<
|���o���;k�,?�DG�=�3�A*��W�\y��q\,��&}oP���e��Q�7o^4q�[���u�B��eR�q���*U�L��>�U��i�r�z��'_z�%����	>	
����1%�[�.�����=~�{J���D~����������l�@��C���1b�fE0�.D���w��0���L�u�����*U�9sf���u����{�W(�h����_�������^=��P5�E�n����S'*�h;~�x�#��2d����3���A�WY�@�v	���3%��?���q��=�������������@Q�+��#
�w)lm�wy��<�I�h�C�r��T��T��D������|�I�����s��/��,��'�.�Kk��O�Eu�K)����A
K�4�H�V���Cb�)��wyrG��m\��\fGW��B������h�E6���i��z����b ��%��7N��F&ln[<���1�f�x��[����u/�oL(-�&�}X�\�M���!)��S�lYL�q���S�D���Qw(��e�zcO���?�NHg�$�������4$m��g�
�Omm�k�����	�'O����vo�e���}'3����jqg/��i����oE�=#�2}<���r�x]u�����ru�~! ����X�A�y)5�,�u(!�C��V�dA;dH���v�<���eaF�����-T���@Q�>D�����|`p�m��b�Y\�{���;t��@ii����5k-Z�B[/����^���u��y����W�Z�q�-\�H�ck=?�e�<��m��A�h�6E@F�T��JH�.��R������X���c~�D�4h�
}������x�6�������=�P���)S47:�/_�k���^{��:���`��F���SO���E�n�T��)��~�)%k�td��W��d��B���@��S�����M���m&k6�2u�)h�x����mC��_��H��#�[��Ir��V�XA������/a)B!�D�d�8{�s�l��������>��7nL����������/2�����*���u�������������_��
�x�&MF�$�2�A	�&}C6G�!����O�O�>�������f��_<���hUI�Ta�����l��
6D�o���C����+����_��njs���� E���_~���2�`��s�
$7�Ul'��h��E��}s���Y�r��U�X1�yrS�N-T�5q-0�}4-t������9�U�b�gx�o��Wmq���#�.����sC�W\��(�BA<����
�*�C����R�*����o_}����f����O�A:�������V�m2d�0���'��Q
�l\�t���'�4�~�G	`)l�OE�8$���m�3F:�����_{�5z� r�G������M�RB�+������PA��P�s�-Z�������4�C���mm�)�C��v	����%L������6���[ ��W7���W_�{���|�
�#�5j�H��b4��?�<���{Q�f��u���'�h�z�"<�H�������P�={�.\Y�����u���7�%��b�A��1�M���_�D��+Wr�
��D��{q-��e��7��'���?��[�IsO9Nh��v���z�x0��wA1K�*�3~�w��W� ��'^����[A{p��H|��'(�����n�Z�lC'"$����@�����x���'���@�^�":g��E�V��*����"�;v`P`~�fx�!_��#�<Bz�!T��G���M%�k�r����v�<����'D��@qc��)���X����R����C��$[k������QG;V�������
����@��~F�S�h@x������q
�|$e�x�8Tl1�*�
'hI���_:����������sNv��Q�W�B��R���A�Jk����IZp�S����f���4x�i���������E��\,����`h+�K���US��$�������)��wy�u$Z��cx<��Oh�1\�oD�X��i��I��m=�9�*T�GT�>n/�e\f!,�_/B�E]5�qj�)���Wlp]��$���l��}F{{�\&W�E����mP���5)VZp��$�*q7�B(<R�������V4���Y��D�>�{���	������>���?�Ie��={v�*U@c��O���`��pp��h����1C�-A*�FG���K�Ta��Q$�7nK+V�����F ��	e���,�[�l	�F�@r���*�^�����O?�t�Y�@�?`�����G����K:�y��5 �=�p�B��v����Rk���o�A�����
���O��A�|��H�Q�F����B�
��O=�Z%,�i�gDR��gJ3%�)�=@�#G�l����%K4��L�\�Y�zu�b�A�YAC�E�}���w�+i2�����}�]�2�r���!8�G3��_����;��3w�\�	�v��]��L���&D���_����G�n�c �������!����t+��1���}�R5B]�
����Q�g�yF����V�/_�w���4 �9H��Z�	���\�rm��e���sa���D���o���n���W�*t
@~����?N���m�W_}U���/�-M����z�<y�����BK�(�	��I�����K���O>��~�5"�C���h��G
���b�X���a���������4�F�v�m�St+��GQ�!D��V�z��U�@���Xs��P*�D��'a5�c(:��k�P�k���h3u�Y�*�	i6������O>Ax�
�tQ�J�*]~���6m��DM�&��'A�"������w
�
pT��2�AQ������FMy#�U���{�6m$2��7="=�na��D"����q�h+`�����n�]�x�2=4!��9��t�?u����+�m������o��������d�Yy�`�H}���Z�nM����f��>&�f�f����(�	i6&�����_}�-!~�����������~_{�5t��E��!!�'N�(H��/�h-�	������H���q�����@��M�4!��X��@��C`��#48���u+L������Q�x�	��6���\�2�AS�~����^�G>�a1�0o��b��6n���j��E��������o��,�*������.��."�3#x�}��D��'�%r�b��y����Y�����B]�������1��K����/�o�>�#VM����+�k k!Z;vl��
�i����l����U����A����/���=�~�F��4r���t�^0;��>?��hy�(&5-��6�u(��+v�����`�}U�mD7tI:v�;���;��������G]q����#�o�og��D��Cp0�`�~���w�
�U���??z�s04x���$t���]N}t�<�=7�B�@"�B�M�c���M3�@
��rzM�
Gdk�c�B�X�����AE��f�:������3�D�I����Fn�bV��� �6����{��E��3z�,9?���ab����; �K��W��:�8����
g��t6���y���f���as�������b�Z�
k�T���j������W����e��7[C����O��H��7�L�g��&A��,q*$P�j���x�����FZ+HX�0a��S}5�������K�pI�lI�
$����6��)s�SZ��d���:DI���=�
<D�>����2��L#9A(��0�=����m�I;'k�����~z���[�l;v,��,�t��):���{ ]]�t�t!X�Dz���!�"{���.�'�$�%��8qb����:�[���s������$S(%�	�!�*W�� ��>���4�
q#Y���-[��
�f�~���mf`1�����o`��O����6m��!��]�����H.F�4�F��,YB�C��o��v��a����J�^g�~����~���������Ct�*UPk����F��L�I�`���4�O������n#Bup��k��yh��D������?�s��I��a����G����l������8`��i������r
,�E��A�K/�T����7�����I�Q�Y�f���s�N�l/�Pa��V4��E������]�vEU���V�J>�����9��j4����C�Zu�
Q�.�g� o�F�������<M��)�#����s�/����n\����T����	i��3![�2�!-G���������8	���*U�Q�F8$��L�R�Y���#\�I[4k��L4����6y�dDS�ti���;j�V"����Y�������	@�� �F1�"��w@e��})TH��r�{�nm������_s��J$J���/"��������2� 9$��U+�����G���O�>Hyc�~":�*�^��$�a�x\%H�J���k�z�j�!*5n��P0g�b��,���Bd����������3]ow8Rh<x02�4i����(�fj��}�W�1����.�B5����r�D!��s�B�-�S8�����w�^|u�6m0�mY�($��@��5k�����������b�l�
�6��v��=�g����?�Sy���/�$�|:KT"��p(�����'C4�B���_��C�[�nA���&�o�let�+�qO�|�5t�zn�!��V�Z�C���5�C�	��/����
��s~���r�c����/��������=�E^1�X�b�&������_���5T��!�
�A�+-h���j�����62�)���
c\������{��2_�
�����(��xp��;wN(Db��}�Q��1T'teY�"�KS8��l�p�1P��pLC��@����-���h='?�Q���Ggu����m�*����o��)fq�U��'p��(Z�J;������������=`�1�t�u���H��jF6ea�r���0�$��J!�
!������C�A��f�
���c�)�_Y�?=����#W9�<Z��w�s�c��3^��K�����1.������EN��@.Q��4���jc�6*����d�}�����>#�����M���={��Oc� ���Lq�Hj��B���z�����'��/��+��f�#��<M���_|���g���?~�*����O40��+Ey�g��O?�4�2@�h���G/�
�d�Z���x�5k���T}�)K��0Ta��E��3fh��������<�J�����X>Y���F���z�-�y�|�!/�j�t���s�w�T���d������F��������,����+W�X��C��}�0R�y��hu�*�� 6d=��s'N� w�	�)$��\�9�
n��(��?:�Z��.(-���RA&7w�\D{��Q���7�"�`�L������|�>�RhJC�9l�0Y�yd^$�8�g�}���/���8R���;g/�/|����[�A��/�����S���f�Ja�N��w���k�V�Z�%�r�CE�%��\�2��{
����X�^�H��r��A���m��Y�t�LG6��(O���:!{E{�ll��{�!��������7������c C�#F�P���Q�c���<���.|<x0�~>���#�AE*U��6�^��j�*r+�>�7���-+Q����[��f�w�^|3i?�
Opx��V��g��	����;�8�^��'
.=@a��X�zU�M��D(^�`>,c(��x��x���Bi4p�OFu���:Hn/4������5����G����.T�9rd�N��:&��g��Vn���;v�(W������T�����O�<I@@QP��5k��_���_;v,�khWyAF�\3������x?��d8�	}��Z�h%�P#�8n?�+W�D6e���Ki�!K���**����l��YR�iB�P*�Hr������x>4����i*w��V�qIJ�x�cj��������1�@x�����R�t�+� �Ep6���i0c���,��-Zh�%�B9^}�U�	%�]��y� ZX�^=$��0~$�+��������&�����������+B�J_��s�K�,Y�N�����F�xx���Ba1���E�<�_(��i:<��	��x��ck�\)�q�&Z�Z5j���9s�����F�S���x���P��
K2�����f�A��!B�p�;�S'�`@:\J��r@�0o�Br�]8Q *��85Q<
�A�hO�b!;�����5L���������X>��6MQ��{��T�E6�p�5�<����h�/|d�����h��m���$y�#����\�(eik�y 
�d{H��N�������������mg���E�����X�c���v�S��'��)h���%��x����{g���[NE�A���z��l��qyj�	�J��7��hy�L>�|J�����Y����Y��59X%���a-.�<"]�O�3�e�,�o�Rk��e\Qo0#�� S��{ k������3�2��t)P�3jx0G���iU��%��hy�D,����Oe�
��d��I�>�)��`.�K�
���Vy���'���i�Zz��RO����R��_�p��;���@X9�u�!������m~s8k�-��"�����id�c��7e�}�u}�9�@���
@
W�Z5}�K������`5n�/d�0���o�A�;d�o
��+T��et9�0"�MT=v���q��8)����)����lzf��� ����Qu���@l��
4�,\�!U�Re��-T�=�� ������9s`u�M.\
�e�)��G�
U3�A�����]�6�6m:u�T7������K��+JR�*��}0!���Y�f��Q��]�VP�x�b@��l���0�|����/'�:}�4b^�ti�n��~���-[���[�==����iT�8q"R ��)�C	��������/"V�$�*����	`�M�6�	����X������4h���#a�a@Q��S�p����
��gOmI�s����{o��}�<��[��]�����:�7g����+P�����;�x��������_G0���,�d�K8%�<�0L�N����a5���-[��g���Eb�t�����5B��'l�^�"oB4t����C�P;A
:����H
���m���bN��r��[��m�uA����J��������g��@��4��]�v
>|��qx^,�(U��}���v�{���o��	N���:u
�)X� 	�q���m��������3~H�@<j���a8��� B��lC����V+U�D!��N�D�p�?�����`<�=��D��h���Y�v-�ON���h����������[�N����Q���=�uv�����a
�-�\U���,�������+��B�-���>�P���:�)S��4����cV3u!)D�4*���y�]wu���q����'�|�=�E��&�Y�'��Q
�l?|��U<`���y���xz�V�X�Kx����+�P���	I�Q	Vc������;�/{������<�H�"�D�����	�����R�8|��Y<�����������S�0�tY���I��#�LJy�=p���OG�j���[B� �@K?�b��M7���@����9\O�$��=��%K� @�6�-�i8���$�}����}���1Z���X�_��������1lJz��E��M��gP_���&\A|��=��5�����j��C�-upH/���P���9�/����=�,���o����V���p�q_p�]�t�
4�/��Om���Sz����^d�0Y���-O�l<��p~�I��)X�\)+��x0JaB��$�����v����:vvV��<��:�K�V��n�:��x��L����vi��h���{V�~�/��b�a\���h���i !��x��
�����^����3$�_m��������5��k�m ��1J4v,T�gn���D�4[��uj�w���6dG��k��2���*��@:i\���m7t������'����o�q��c����}�g�<��@�dck�T�>�,H����4�2������rr��x0��9��|�p��J<��l����d����h3��C��Z��};�H��K2���O���F�������5�&��	���(u<:���"Q�z�+��B�A��V��s>��I�y��tP�A���qqgJ+����	���y�������;6�UOx���#�obN���6�x���#����E���|������������7"y�V�y�40
Z�`xHs���-z_4II�3Z�"����6G�Ar1p�@rR�%J��W/:�#a�gDR����Yo�<�
���H4�O@���w��U \r�U�V!�)S��[d�6F���v�6t�F��W��������'q#����/	����z��7�������W Y�2�<�Y����d�e���={�$	���O���/G���w@��'�I������<S��I8�eh~$��Dg�?$��,a���5BX�"|��T"&��=�C���g���:-	���S�$��o��'��V��96]��u�)`�O�>��6#9GoH�H�
I>FN9������K/�t��aZ�R����;����K�)4��!J��3M�2���w��	5�c(��=��L�2h7y����O�I2@H')x��w�H ����=�����v�H��KP�ea1�8��[�!��X����{��0e���?���O?���kW����kc�|��S�E��m�=��@K��-���?I������\N�/V�Z���� VM����S��L�����pHo�������`�~�B���Y�T���s
��L���K�����Z�?jj��U����Bv�0y ��#26n�;Pe� "1D���3")��S�,��U��!9(G�8~��?h� ���~:e�����(��m�~��|�����\8A�y��k��A.��U��	^'N��'��n�����)���������y3U����F��+9r����QgL�x	x��7��!Lkf1 �Z�
���
���B�.��V�����am����Q�������':������ ��s����zG4K�0l�0�%�h�-p��rB�(�S�re��A���~��G��
}�u��*U��B����cf��S|�t2�!�#���=���h
�QC�L��6h��HL��(�1b1�-�xf��i����n�y@����!�t���U�9��mS4{F$e�xj��p|�F�A�J\<D�(
�����`���M�6t<D	�"_�>i���C��������'�J��#)���y�������Y�b�M7�
���f�@+(� :�1(F���dyTn����W�{�?�2.���������0��.h����s��M$�����@�~jA��`8���UpO{s��c�������i����k����z�\X]��x�W���r��K��O���i��/	w���2�?m����*x�������~F��E�X0�@�:�����2}<�8T��?���g����3�*�[����"����Z��0TwJ����9e*8��0�UC��1
�Y�I?4c�m���c���[Cu�5�����L�x�;8�{;�!�sx"u�2����[����'�q�����m�Yeh�N0	1D��KM���%R��C�5d�h7�^x�"+9�HI��*��)��3n����^vz �3�.�	�T��P�BQ���3")��S�,�A��F`hZ)����6X���r����?ld)Z���OQ5�[�H���Y*�n��9s��$Yg�9B�N&>=KB�zu��M�ACA<s��n'�����+N�4I�d	���/��s'�A���kR�:u.\H���t��o�>�z�F#�/���G��%Qc�wi:k$��L��N��[�����:u�1c�8�B����tCz���N�
��T�v)�� �J���s�=��� b��W/���}��7�T�s�2e����������7/u�O?�t��������A���o_�l��o��e�8�/_>��X��c���-[��YV1���C4fA�5jD���#���s�n��1C�k��y���	&|���:t8}�4@;O�<<�u�V*@t���U%J�}I��F!�$��4k�&B�]w�E��NG���6{F$e�xj�E0�yoq�$�}��%�BuPz(����+��������?���EG�75�/	?�!��{�Eit�.| %cGE�1(��o�e�����4l�����F�Z�f����z���lB������*p����:�"�4uF�������N�*�S�^����+a\8��e����;Xf
����>&�f�f����(�����z@�%K�6lQ��"�*��_�4� ]�B@"�Z�q6i�YJh	~�r�������G�^}�������!&T��>a��-DV�ti��G���t������������_D��k�s�y+!`��E�|�	jD;r���W��������/�'��"��:��u����b�H4���_�;�2>S�?������m��Y�J�g���3��0��H4�t��a�
Z���=������o�w�}���p��$��y�4���Q�1�}����{�{��h"C���m��A��v�J�����z�(��q?4�?^y���KFKP n~����_���
@����{��vR��V�Zx&MY|����qg��mH���e���A����+������d�o���"~�&���s<�H{T4@�C"4���e�{�������#)�.�GE�dD(h	1��25m��r��]m��=Cd(��B	������ ����B��hf$>�@=�7���
T����>[��9�\���a��$�l��m��<��//����J��^�]mf��������y�7���h@]��C��5}D��.��c������=�Q���U��0U��Km(�pK���)�FPn�/����>�;8�����~�<g���	/�Li�TQ��\��&�L��3+D����x�S<��l(���xpT��3�������C�:;�eH�A$-��k4�~����AX��l�4~>����p�n�r �M��Si�c����qO�#6n�g�r��#��_S;���$z�����={6.�|������	�d��:u�"_?�$1��W���Y����#:t�/�ym3Y�	�I�`�1�8.5sO�#` ��1�tU1����������?S�6/��IB�6�=>��CmqG������M�FT���UM�4�t������f�1��$/��V�XAl��P^�#MSN��=�$���*U�D��Sai����<��zv�t�_�~�����[�t)$A7�G�N���5|��%J���-[F�HKF
v�VI�5U��
`���c��4iR�f����)i�6��P���q�������
�Z�f
�]������k")r{x��E
� �r�-I}��` 9=Hl��-����
�X=e�����)!Y���_U���U�AIy&N�H�t����#!T��[x2� ����!C������;��G������a��#G�;1?��0��{�<y2���T�B��D�����#����1c��P58?j�(��N��i�&��O�|��i�f����g��y�������g���M�>���H�y�bh�{������+�+WF9P[zEB�~hH
��`��M~~��WB1���`
�7�V�ZM��1o�_��';S������)��=\���y�=h���q��}����@�v��?�@���W�X��+�Z����H����Q���`�F��(B!�5]�4����V�Zi��u��v�J>�/�gz�I�@"
�il���.���-[0����{7M��-ZT�D'�:�s�!�TP�Z�]:,Y�e��0�0������I-����cZ��AL~���-L� �����������R��>�g����@��!���|�����j��U�I����9���Y)�B�
�,Y��EPJJ����O��=�T
����S�\�qpAt�G�N�Oi��D��;���u��DY-�@[�����k��=!���j������/�bJp�
��
,�4��2�L�>�3Z�G�>�];������C!������p��n��M8��O,+\�0���"��pl��E�.��2�`���~��@�v��z�U�:pHX:���/RS��`4����O����	)O�����~��(�����*y���a�[7��� ���:-Z��\'��%9/���d�m��QG�����'�e<�^Cy\�[r�B{��`��rz�'��vt������u}�49���@"��i�	
?�1�9n�#���;Y�sF/$-�29���{�-S=7��]�`��6Upg~iQk�c�lC/���������%/�y �x�'�;5���9���,B�A^0.��A
��5c���F�;��K>�����d�t�������
�e��F)LH�K�q)�#���}�B���Xk�g��F�$�{��$t�)�O���+-���RN�����x�����o���I.5!P����q�3������;2r��y�F ��N�s��)��w/���K.���a�x��@��W�T
.�q8t�h�o�[�&��!C��b�<�XA�=�i�`.���E0Z�p����Jn��Od�5�w�^G4��`��
���U*'����V�A7U�V}���ku���-]�tQ��}���`?Q�S���A���/�2���s������7�����;T��};�e����V�\��GP28Rw���n����C�t���(���n�z������k>L�-YR �����`4�B�W�B�:��1A������d��!�f���������5k���H�(����F�M9O���;��N�<	�{��E�R�F
rPj���5>��	o2�'��Ya��G}�$A$Yp�r��0�6l����^����'#�4i
��{�a��%\EE���0�+V� -��S&�p�
:�]�v�<����������!GD���������u���"!�na�| ����:�#A��f4}�N��|�
]"H��l�x����dg�v����d���o��R�J�1�O��C�0Z��e�����0�a�``(���^�k�=����v�P�\_|�E(���Y��_�~H����F��5B�T����_��������#��/���
8�N����-9p��]�z5oDQx]��������s�������f^���-L��^C7D�%-"A=5qN�
��P���F�u��WR*���"����Pa�i!<�F��JQ��������KX���NhC	o2�'��Y�@*Au������S5�-������?���0� ��&m�%���w�����d��
��_|1%�4h�`��M(
�46M�B�H
�Akd�(?	g��U�;�FO����8n�8h��I/��2�t�L=-Z��pN�p����C�~����F
�i��A���#[Q9o��l���I�&��NG������qIrS�L�
Qb&��2&
Q�,2�5kV�r��2�����-/�����'A��9Bd��"�k��B����_�� @bE_�5��m�6����f��R0m2d�v&�CI��=�I�Z��+B�JH$�`�8��+rO���b����oo<�1F���hq�B���(�zpT���t�O<���l�D?������_�'��������o��Z�f�n�A�r�-y������/�����A{�M#F�@-
,�!�;v�t�M�K�F"���nD0e��

������&bB�������s�Tt��42�p�>�u�=C<��h�U�������e������W]u��;�^7$�q��w����������L�r���LOM�H��^p:�v�������m~�B��=6�������f-t��&�O���)�
Z{oSlR��������<�zW��PfZ���������Y��X_�Z/��y�@�`@9�R[���qkN�5E���g�CL�9�����zl����R���0������6��p��2"�W�![0kD{���9�'L������\~�?c�����A������
W:1ggf��Z�`0W'\Vd�&z�����2IEND�B`�PK��gJsettings.xml�Z[s�:~?�"��3)�i��	t��6b���������G�1���KOBpC��tz���o�����+�}��h\`F�Z����������{��������p�=������X��j�8R���,��Z�i�!�E��DEz]-�<�]�[\�L��X��R(�q�!>����P,�����j��������\c���d�B��0C�?������Lch��V�_;[
X|c	Ab����D���DV&�V�6�{����L��Bm5(g��Tj5����]��0�� �a_�7AO�����;�G���'�Q��8@�1�>L�_���]��Q��g�h������\��VK��.M�5={HY�-E_.	G�
���s���o ?�j�N���`���*&�7m��n���a��l��/�;��'F%"vH��b>�����=���^^�k��L�e�>�?|��xst�Q�y���W�f�e+X+�h�����W�u&%6OqG�cAO�d��	��H���PU��
h	����#�=fq��u6w#��V�<���.��!�s�@��7�����-�egCy�>�����R�@�ac����T}��?�����I�i��>���5����p^'�{���!.��
���������D@�z�rHqi�7DD�8�6b��\�~�������w�����#��A��S�(�������}��*$��Q@-w���b�����/�M$	�`��a���7!6Ea�YHHX��,"k|!��I�@��N�����h>�����>�`��~F�����u��{���Q��.5Xm� @n���q�l�{�.��3���rx,�	8�3�� L�?�|yk�O���D|NM��F���PYe!�C2���H������<��
�D�1�gi]��&Q2Z/�\$����)�3��hv�.�>qg���F������F�o���~�G�����;��2��qa�}���������n��9m����S}pQ�'�	f�[/ ��vf���������r�u��Z��;�7����&�{����8�?tk�����������F_�������t����u{�����cp��x<h����������}�����Z��I�G���~����n��sB�/�����l6����8o\�������u����N��t�������~�i�2�j9����p�����Z�������
�
8���3w�}$��UyAH������$k �E��7��*S���:_�E)_N)�/��MBTy����6��d/$��5�����E(��yw|�$�����*�"4�%��.�}�?r��_Y�Dt��}�%_�1�aQ"?�o��\G\����D-���#L�����M��t��e��O"��M>��\��+��{{��%S���Wci/
��PKU	���v,PK��gJcontent.xml��[s�����
�:�7��8�%�3N�L;���/��B`P������%��-����5Z�.>�|�-��g��q�E����6��5�4��q�y�����������ivt��^;��(-�a����F�:-��G����t/���K�nT���^���q����{�s
K��<�����t�2:+�m\��i��A����<8��q]����G������y�U���e|)��$N�x�v\���V��������,��6vww[�����I�^?O��a+J��dEk��Fk\������u�CJ���(�{h�2�hV{yTTU���a���t�_'��u�t���8��v6�<Ke�=?���t�nP_3�;�W���?�.\��y�U���0�{s_���t�,�&��
�7� ��������S�Oo�~��e�OUo�I8��{��U�6ZU�ftR���D�@�4�l
O*�k�~���Mxu�����+7��(��bd�z����Zy���r20G�'�j�6'������QW�����U�p�ZU�n��I��u&���a�5�4�Ool�����Ln�j�/����OGY?m��p0��^���� 4���aZp�}F��5m���DG����\���dY�[T*�Yoo�����w��������.�x���b��jn��n�����Y-�3Mm6�����\P�&G��y�Q��I���0�O������������V��q�n����[77�{��DeWtpq�����5����j����oA/+��\qX�����n��DiU�JYy�
������~T�W���\�U���8���KB{����A���js���?��l��<��e����^F�
~��<`Su�$���8./�� 
:U��g�R��]���sT��Jku�4�L����3�f���b��j�������ta�W��(/��he{�y��<���TuX�z����i��7?U�Y��������6�.��������������Y,��w���������[����XlO�n����;��7�n��[�~�������$�w���'�Fw�K���E��������,�������7�.�n����K�U%�a
���Q�9.�<��]��7G�/�f�+�n�4�[�y?�?�2�:�qa7��Py�t��xy����EM]���`;.zIp>�g�[�����6�Y��)������n�(I�GzA^?��rc�u����~]����6�����p���q�y�������P�S���A'z���]tZ_D:x~Sw����$:��|�m*��>����fI{fW;<��8H�?\?�K��Q����u�~wt�0k�_���U2��q����|��h��C��Fix�!N�rmtdzjj}3�G��U{��������n����-��u}>��>��pE�u��t�����\�s��A����y�*/�������EW�������^�����^��F��.Gpg1�q�a���C]a�BZ�h��G�����.1�w_��g�z>J7�QAc�#|��;Hv������~L����h���u��2(��,��q?Q�Y��1^�0��� Oi��Fi�(�_�[���NcRl����c���Fi��Fi�-�4/
`�[l�h�O�H#����y���$��n#H����Pg��l)6i��>4	�3�8[gN�$4�8��3�8��3�8��3�8��3�8����MB��3�8�z1I�C�����j9l�~�W�U��f�g�q�g�q�g�q���y�Ie�QFe�QFeA��R|�i�/M>��2�(��2�(�������L�H#m�����9]2���;>�R�����=}���?��/����>wn��]_B�Uc�%��������2t���w��|�v�C�9��3�8��3�8��3�8��3�8��3�������K������'
4�@�rr�����b&w�D��<
?�Uk	'X"��	�1�H��U�/�����5~���w�/�-W���g�q�g�q�g�q�g��2��x�i�jA��8��3�8��3�8���9��4	�3�8��3�8��3�8{0/8A[Ahg�q�g�q�g�q����?A��t�
�3up9u �_�q�g�q�\�oh�?�:�I��������Z-\�g�q�g�q�g�=<g���f�����$4�8��3�8�.\K�K��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8���,�������$4�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8�lY���:�$4�8��3�8��3�8�����<��4m��Ih�q�g�q�g�q�g�=ge�w�g�g�q�g�-�3�3��3�8��3�8��3�8��3�8��3�8��3�8��3�8��pz#}��Ih�q��8������U�/�� ���{���8���o�d�\�_sm��d����~�����p��eHb����g�-����2J�]Z���g������Kf"�j��M�Da�k���]a�>2�%�nzE�0�Xw����~RBlNWz9<PO���n�F�������v�P>���Q5F_0���8�8K?��.��vb:
��Ct�����r�������s��j�C���y�����Fp$AF��_���3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8��3�8���t�8��W�����(�,-�1�\T�A�8�����0k�_����~7J�f��e����PKh�q,�
��PK��gJmeta.xml��K��0�����������4#!�Xi���J�;�����L��'��B,}�w�9�N���A��:e�E!Ea�2�}�~�z��T��E	�������&���sk�zg�m:�q���^p{�J�5�'��r�������9!��)<��u-���$SwE��p����������#Q���o����d����z�c�&d>�t����.0�16���
NoQ�\�j���v�u5�QFy�h,4���>����,�N�H<�A�h�aZ���F	O2�!Kr��a���[E%_�9�1���F<Iy��i��4+rV��]AYL�e��Y���o���S������*�/�����/|��p�t�'�w�yZI�8�C���L�}+�]�W�����$1}x�+-1[\��
.�u����W"����k����oP�����ZT�|)��h�6("uEn������PK������PK��gJ
styles.xml�Ymo�6��_!(C��%;I���b��aIQ���3%s�D�����~GR����i��K�$"�;�{�Q>������\V\��Y�{��YB����������\�t����x����q!!�)be&/��+���X�d�b%.����^����V6U\�������
��E��W���t��n����M��M�4HY��D�t�����t�o�,Wa���f���Y8_.���u�WV�jT��b����yh�9�h�}
�4���[�'S�$�y��X���r���L+������f#4��'���C�8�*�IS6Gr3����&����}\�|�Z
��*����M�n�3���J�$�6wE'�yn�w�;N$�
x|#;�Y>D��! �U!o�\mzT�i�q��t������p���9OU5k�O�A(�sB�B�[�wG�Zv��e�A��uP`�
�R��[��� eU���3d��s���b���f�P������JU!��wnB5�c
]��q�-��=�R�\�b$8�b}nJ����2���	�A�����{;~��K����\���/�=���z�J&^v�f��Z��@���q���h!J"c�I[�S���BL�
pL;"������{w�}����{���em�������X��������+6]�
��k�E�@f���7�.K�z�4�v	NQE�v�j�
��0�1��������r��!�z\3h��� !B�B�����{�TQ��i;G� e+���B��B�P�$�>���*8nP����z,�����
���o�jU�C��a��!]�n����E���MOX��-�v�F~��O9)RH��\B2"�j���N�#�8�����R���]dw�e����W�Pp��2j�i{�b^[�����0�
J
�{[��wng3��R����
B�{�J�?�:,)���(M#�Rk�:v������! G��"!��E��O�=���<�,i�g�
��0�}�6	�?\�(56�{g[����G�qVx�n�yW�������[��y��������q��`q�u�;a��������m����Il�i0t���=[�`�$#�I�uU�� �\����}g��l�5�b���,�N�X}��f�>o�K��H���6�qB�����`W�AJ��r�=b���JT})��Qn��|����An��������?/�?9_������(���B)g�MN��2��;]_���;�8h���jd(�g�l�������o�z!r�������d���!���1p_�a�p��N�f���11M`�xs�j�=�k|{��I�^xD�hyvb��p�����a)���f�M
{��������j���D�J]�N�%�XUv�(�_P�������������n�����8R���z�����#����=��h��'r$�
��U���t��lf�@�3����$e�Wl06�����y��G�	�+O���h��{�����N��~Pf�>z=��5�z&XU-���x|����e�f=fm'��#M��d{O
NI����GDk��������X��:7
�5R+���� :��Q��(��P��/�58X�Y��|�X������4ZDg'��+��6=~��}����&P_l��eh����
��E8���oPKhAzPK��gJmanifest.rdf���n�0��<�e��@/r(��j��5�X/������VQ�������F3�����a�����T4c)%�Hh��+:�.���:���+��j���*�wn*9_��-7l���(x��<O�"��8qH���	�Bi��|9��	fWQt���y� =��:���
a�R��� ��@�	L��t��NK�3��Q9�����`����<`�+�������^����\��|�hz�czu����#�`�2�O��;y���.�����vDl@��g�����UG�PK��h��PK��gJConfigurations2/toolpanel/PK��gJConfigurations2/progressbar/PK��gJConfigurations2/statusbar/PK��gJ'Configurations2/accelerator/current.xmlPKPK��gJConfigurations2/floater/PK��gJConfigurations2/images/Bitmaps/PK��gJConfigurations2/menubar/PK��gJConfigurations2/toolbar/PK��gJConfigurations2/popupmenu/PK��gJMETA-INF/manifest.xml�TKn� �����fU�8YT�	�P<v�`@�%�/��OU�������cXm�7{��"v�E>���������{�*6��*t����>�����QGC�4������hKd��^��.����X/�+��<��?��C��M�w�P�@���3-t����5\��{y,ouJJLO;j�����O4����)�w��`FPS~s�
�:�;�VSz���������A��?�sL�~��
�UO�9�"n,�AKe���Y����;��_�$����E��W��W��PKB�d� EPK��gJ�l9�..mimetypePK��gJG�=�>�>�TThumbnails/thumbnail.pngPK��gJU	���v,��settings.xmlPK��gJh�q,�
����content.xmlPK��gJ��������meta.xmlPK��gJhAz
��styles.xmlPK��gJ��h��@�manifest.rdfPK��gJ�Configurations2/toolpanel/PK��gJ��Configurations2/progressbar/PK��gJ��Configurations2/statusbar/PK��gJ')�Configurations2/accelerator/current.xmlPK��gJ��Configurations2/floater/PK��gJ��Configurations2/images/Bitmaps/PK��gJ��Configurations2/menubar/PK��gJ)�Configurations2/toolbar/PK��gJ_�Configurations2/popupmenu/PK��gJB�d� E��META-INF/manifest.xmlPKp��
#15Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Rajkumar Raghuwanshi (#14)
Re: wait events for disk I/O

Thanks Rajkumar for performing tests on this patch.

Yes, I also noticed similar results in my testing. Additionally sometime I
also
noticed ReadSLRUPage event on my system.

I also run the reindex database command and I notices below IO events.

SyncImmedRelation,
WriteDataBlock
WriteBuffile,
WriteXLog,
ReadDataBlock

On Wed, Mar 8, 2017 at 6:41 PM, Rajkumar Raghuwanshi <
rajkumar.raghuwanshi@enterprisedb.com> wrote:

On Wed, Mar 8, 2017 at 4:50 PM, Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:

I am attaching another version of the patch, as I found stupid mistake
in the earlier version of patch, where I missed to initialize initial
value to
WaitEventIO enum. Also earlier version was not getting cleanly apply on
the current version of sources.

I have applied attached patch, set shared_buffers to 128kB and ran
pgbench, I am able to see below distinct IO events.

--with ./pgbench -i -s 500 postgres
application_name wait_event_type wait_event query
pgbench IO ExtendDataBlock
copy pgbench_account
pgbench IO WriteXLog
copy pgbench_account
pgbench IO WriteDataBlock
copy pgbench_account
pgbench IO ReadDataBlock
vacuum analyze pgben
pgbench IO ReadBuffile
alter table pgbench_

--with ./pgbench -T 600 postgres (readwrite)
application_name wait_event_type wait_event query
pgbench IO ReadDataBlock
UPDATE pgbench_accou
pgbench IO WriteDataBlock
UPDATE pgbench_telle
IO SyncDataBlock

pgbench IO SyncDataBlock
UPDATE pgbench_telle
IO SyncDataBlock
autovacuum: VACUUM A
pgbench IO WriteXLog
END;
pgbench IO ExtendDataBlock
copy pgbench_account

--with ./pgbench -T 600 -S postgres (select only)
application_name wait_event_type wait_event query
pgbench IO ReadDataBlock
SELECT abalance FROM

Attached excel with all IO event values.

Thanks & Regards,
Rajkumar Raghuwanshi
QMG, EnterpriseDB Corporation

--
Rushabh Lathia
www.EnterpriseDB.com

#16Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Rushabh Lathia (#15)
Re: wait events for disk I/O

On Thu, Mar 9, 2017 at 10:54 AM, Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

Thanks Rajkumar for performing tests on this patch.

Yes, I also noticed similar results in my testing. Additionally sometime I
also
noticed ReadSLRUPage event on my system.

I also run the reindex database command and I notices below IO events.

SyncImmedRelation,
WriteDataBlock
WriteBuffile,
WriteXLog,
ReadDataBlock

I have tried for generating some more events, by running pgbench on
master/slave configuration, able to see three more events.
WriteInitXLogFile
SyncInitXLogFile
ReadXLog

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#17Rahila Syed
rahilasyed90@gmail.com
In reply to: Rushabh Lathia (#13)
Re: wait events for disk I/O

Hello,

I applied and tested this patch on latest sources and it works fine.

Following are some comments,

+ /* Wait event for SNRU */
+ WAIT_EVENT_READ_SLRU_PAGE,

Typo in the comment.

FileWriteback(v->mdfd_vfd, seekpos, (off_t) BLCKSZ * nflush,

WAIT_EVENT_FLUSH_DATA_BLOCK);
This call is inside mdwriteback() which can flush more than one block so
should WAIT_EVENT _FLUSH_DATA_BLOCK
be renamed to WAIT_EVENT_FLUSH_DATA_BLOCKS?

Should calls to write() in following functions be tracked too?
qtext_store() - This is related to pg_stat_statements

dsm_impl_mmap() - This is in relation to creating dsm segments.

write_auto_conf_file()- This is called when updated configuration
parameters are
written to a temp file.

Thank you,
Rahila Syed

On Wed, Mar 8, 2017 at 4:50 PM, Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:

Show quoted text

On Wed, Mar 8, 2017 at 8:23 AM, Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Mar 7, 2017 at 9:32 PM, Amit Kapila <amit.kapila16@gmail.com>
wrote:

On Tue, Mar 7, 2017 at 9:16 PM, Robert Haas <robertmhaas@gmail.com>

wrote:

On Mon, Mar 6, 2017 at 9:09 PM, Amit Kapila <amit.kapila16@gmail.com>

wrote:

Sure, if you think both Writes and Reads at OS level can have some
chance of blocking in obscure cases, then we should add a wait event
for them.

I think writes have a chance of blocking in cases even in cases that
are not very obscure at all.

Point taken for writes, but I think in general we should have some
criteria based on which we can decide whether to have a wait event for
a particular call. It should not happen that we have tons of wait
events and out of which, only a few are helpful in most of the cases
in real-world scenarios.

Well, the problem is that if you pick and choose which wait events to
add based on what you think will be common, you're actually kind of
hosing yourself. Because now when something uncommon happens, suddenly
you don't get any wait event data and you can't tell what's happening.
I think the number of new wait events added by Rushabh's patch is
wholly reasonable. Yeah, some of those are going to be a lot more
common than others, but so what? We add wait events so that we can
find out what's going on. I don't want to sometimes know when a
backend is blocked on an I/O. I want to ALWAYS know.

Yes, I agree with Robert. Knowing what we want and what we don't
want is difficult to judge. Something which we might think its not useful
information, and later of end up into situation where we re-think about
adding those missing stuff is not good. Having more information about
the system, specially for monitoring purpose is always good.

I am attaching another version of the patch, as I found stupid mistake
in the earlier version of patch, where I missed to initialize initial
value to
WaitEventIO enum. Also earlier version was not getting cleanly apply on
the current version of sources.

--
Rushabh Lathia
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#18Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Rahila Syed (#17)
1 attachment(s)
Re: wait events for disk I/O

Thanks Rahila for reviewing this patch.

On Tue, Mar 14, 2017 at 8:13 PM, Rahila Syed <rahilasyed90@gmail.com> wrote:

Hello,

I applied and tested this patch on latest sources and it works fine.

Following are some comments,

+ /* Wait event for SNRU */
+ WAIT_EVENT_READ_SLRU_PAGE,

Typo in the comment.

Fixed.

FileWriteback(v->mdfd_vfd, seekpos, (off_t) BLCKSZ * nflush,

WAIT_EVENT_FLUSH_DATA_BLOCK);
This call is inside mdwriteback() which can flush more than one block so
should WAIT_EVENT _FLUSH_DATA_BLOCK
be renamed to WAIT_EVENT_FLUSH_DATA_BLOCKS?

Changed with WAIT_EVENT_FLUSH_DATA_BLOCKS.

Should calls to write() in following functions be tracked too?
qtext_store() - This is related to pg_stat_statements

I am not quite sure about this, as this is for stat statements. Also part
from the
place you found there are many other fwrite() call into pg_stat_statements,
and
I intentionally haven't added event here as it is very small write about
stat, and
doesn't look like we should add for those call.

dsm_impl_mmap() - This is in relation to creating dsm segments.

Added new event here. Actually particular write call is zero-filling the
DSM file.

write_auto_conf_file()- This is called when updated configuration
parameters are
written to a temp file.

write_auto_conf_file() is getting called during the ALTER SYSTEM call. Here
write
happen only when someone explicitly run the ALTER SYSTEM call. This is
administrator call and so doesn't seem like necessary to add separate wait
event
for this.

PFA latest patch with other fixes.

On Wed, Mar 8, 2017 at 4:50 PM, Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:

On Wed, Mar 8, 2017 at 8:23 AM, Robert Haas <robertmhaas@gmail.com>
wrote:

On Tue, Mar 7, 2017 at 9:32 PM, Amit Kapila <amit.kapila16@gmail.com>
wrote:

On Tue, Mar 7, 2017 at 9:16 PM, Robert Haas <robertmhaas@gmail.com>

wrote:

On Mon, Mar 6, 2017 at 9:09 PM, Amit Kapila <amit.kapila16@gmail.com>

wrote:

Sure, if you think both Writes and Reads at OS level can have some
chance of blocking in obscure cases, then we should add a wait event
for them.

I think writes have a chance of blocking in cases even in cases that
are not very obscure at all.

Point taken for writes, but I think in general we should have some
criteria based on which we can decide whether to have a wait event for
a particular call. It should not happen that we have tons of wait
events and out of which, only a few are helpful in most of the cases
in real-world scenarios.

Well, the problem is that if you pick and choose which wait events to
add based on what you think will be common, you're actually kind of
hosing yourself. Because now when something uncommon happens, suddenly
you don't get any wait event data and you can't tell what's happening.
I think the number of new wait events added by Rushabh's patch is
wholly reasonable. Yeah, some of those are going to be a lot more
common than others, but so what? We add wait events so that we can
find out what's going on. I don't want to sometimes know when a
backend is blocked on an I/O. I want to ALWAYS know.

Yes, I agree with Robert. Knowing what we want and what we don't
want is difficult to judge. Something which we might think its not useful
information, and later of end up into situation where we re-think about
adding those missing stuff is not good. Having more information about
the system, specially for monitoring purpose is always good.

I am attaching another version of the patch, as I found stupid mistake
in the earlier version of patch, where I missed to initialize initial
value to
WaitEventIO enum. Also earlier version was not getting cleanly apply on
the current version of sources.

--
Rushabh Lathia
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Regards,
Rushabh Lathia
www.EnterpriseDB.com
The Enterprise PostgreSQL Company

Attachments:

wait_event_for_disk_IO_v3.patchtext/x-patch; charset=US-ASCII; name=wait_event_for_disk_IO_v3.patchDownload
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 4d03531..45fedec 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>
@@ -1272,6 +1278,276 @@ 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>FlushDataBlocks</></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>ReadBuffile</></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>
+        <row>
+         <entry><literal>WriteZeroFillDSM</></entry>
+         <entry>Wait to write during zero-fill of DSM file.</entry>
+        </row>
+
       </tbody>
      </tgroup>
     </table>
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index c7b283c..2456500 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 1fdc591..5ca811f 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -38,6 +38,7 @@
 #include "access/xlog.h"
 #include "access/xlog_internal.h"
 #include "access/xlogdefs.h"
+#include "pgstat.h"
 #include "storage/fd.h"
 
 /*
@@ -338,7 +339,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(),
@@ -346,6 +349,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;
@@ -365,6 +369,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);
 	}
@@ -400,10 +405,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,
@@ -460,6 +467,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;
@@ -475,11 +483,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 5cefc43..35f2a25 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 c0e5362..ba18954 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2456,7 +2456,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)
@@ -3207,6 +3209,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;
@@ -3225,8 +3228,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);
@@ -3234,6 +3239,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,
@@ -3360,6 +3366,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)
@@ -3372,8 +3379,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;
@@ -3389,12 +3398,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,
@@ -4414,6 +4426,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 */
@@ -4423,11 +4436,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,
@@ -4453,10 +4469,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);
 
@@ -4634,6 +4652,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 */
@@ -4643,11 +4662,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,
@@ -5036,6 +5058,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 */
@@ -5045,11 +5068,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,
@@ -9999,11 +10025,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();
 		}
@@ -11456,6 +11484,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];
@@ -11467,6 +11496,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 8b99b78..d17d541 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"
@@ -728,7 +729,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 7cacb1e..00a0a55 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;
@@ -3439,6 +3450,251 @@ 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_BLOCKS:
+			event_name = "FlushDataBlocks";
+			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;
+		/* DSM IO wait event */
+		case WAIT_EVENT_WRITE_ZERO_FILL_DSM:
+			event_name = "WriteZeroFillDSM";
+			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 aaefdae..9328814 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -441,9 +441,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)
@@ -1001,7 +1003,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 8aac670..767ea5e 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"
@@ -2275,6 +2276,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;
@@ -2286,6 +2288,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);
 }
@@ -2366,7 +2369,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)
@@ -2393,8 +2398,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,
@@ -3047,7 +3054,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 52601a5..077878c 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -115,6 +115,8 @@
 #include "access/transam.h"
 #include "access/xact.h"
 
+#include "pgstat.h"
+
 #include "replication/logical.h"
 #include "replication/reorderbuffer.h"
 #include "replication/snapbuild.h"
@@ -1580,6 +1582,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);
@@ -1587,6 +1590,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
@@ -1596,6 +1600,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);
@@ -1603,6 +1608,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);
@@ -1677,7 +1683,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);
@@ -1703,7 +1711,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);
@@ -1717,7 +1727,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);
@@ -1731,7 +1743,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 dd3a936..9be0185 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -462,7 +462,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(),
@@ -2076,7 +2078,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 fd02fc0..16f0c92 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -1550,7 +1550,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;
@@ -1565,8 +1565,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
@@ -1576,7 +1578,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;
 
@@ -1597,11 +1599,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;
 	Vfd		   *vfdP;
@@ -1619,6 +1623,7 @@ FileRead(File file, char *buffer, int amount)
 
 	vfdP = &VfdCache[file];
 
+	pgstat_report_wait_start(wait_event_info);
 retry:
 	returnCode = read(vfdP->fd, buffer, amount);
 
@@ -1658,12 +1663,13 @@ retry:
 		/* Trouble, so assume we don't know the file position anymore */
 		vfdP->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;
 	Vfd		   *vfdP;
@@ -1719,6 +1725,7 @@ FileWrite(File file, char *buffer, int amount)
 		}
 	}
 
+	pgstat_report_wait_start(wait_event_info);
 retry:
 	errno = 0;
 	returnCode = write(vfdP->fd, buffer, amount);
@@ -1777,12 +1784,13 @@ retry:
 		/* Trouble, so assume we don't know the file position anymore */
 		vfdP->seekPos = FileUnknownPos;
 	}
+	pgstat_report_wait_end();
 
 	return returnCode;
 }
 
 int
-FileSync(File file)
+FileSync(File file, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1795,7 +1803,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
@@ -1887,7 +1899,7 @@ FileTell(File file)
 #endif
 
 int
-FileTruncate(File file, off_t offset)
+FileTruncate(File file, off_t offset, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1900,7 +1912,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/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c
index b2c9cdc..9aafea6 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -60,6 +60,7 @@
 #ifdef HAVE_SYS_SHM_H
 #include <sys/shm.h>
 #endif
+#include "pgstat.h"
 
 #include "portability/mem.h"
 #include "storage/dsm_impl.h"
@@ -911,10 +912,12 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size,
 
 			if (goal > ZBUFFER_SIZE)
 				goal = ZBUFFER_SIZE;
+			pgstat_report_wait_start(WAIT_EVENT_WRITE_ZERO_FILL_DSM);
 			if (write(fd, zbuffer, goal) == goal)
 				remaining -= goal;
 			else
 				success = false;
+			pgstat_report_wait_end();
 		}
 
 		if (!success)
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 6c17b54..1003f6b 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_BLOCKS);
 
 		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 e0298ee..90cc9bf 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -35,6 +35,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"
@@ -856,11 +857,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)
@@ -1009,6 +1012,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;
@@ -1021,6 +1025,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;
@@ -1032,6 +1039,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;
@@ -1164,7 +1172,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,
@@ -1217,6 +1227,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)
 	{
@@ -1230,6 +1241,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,
@@ -1237,6 +1250,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,
@@ -1293,7 +1307,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/include/pgstat.h b/src/include/pgstat.h
index 60c78d1..032f0c4 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
@@ -806,6 +807,100 @@ typedef enum
 } WaitEventTimeout;
 
 /* ----------
+ * Wait Events - IO
+ *
+ * Use this category when a process is waiting for a IO.
+ * ----------
+ */
+typedef enum
+{
+	WAIT_EVENT_READ_DATA_BLOCK = PG_WAIT_IO,
+	WAIT_EVENT_WRITE_DATA_BLOCK,
+	WAIT_EVENT_SYNC_DATA_BLOCK,
+	WAIT_EVENT_EXTEND_DATA_BLOCK,
+	WAIT_EVENT_FLUSH_DATA_BLOCKS,
+	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 SLRU */
+	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,
+	/* Wait event for DSM */
+	WAIT_EVENT_WRITE_ZERO_FILL_DSM
+} 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);
#19Rahila Syed
rahilasyed90@gmail.com
In reply to: Rushabh Lathia (#18)
Re: wait events for disk I/O

Thank you for the updated patch.

I have applied and tested it on latest sources and the patch looks good to
me.

I am not quite sure about this, as this is for stat statements. Also part

from the

place you found there are many other fwrite() call into

pg_stat_statements, and

I intentionally haven't added event here as it is very small write about

stat, and

doesn't look like we should add for those call.

I agree that this writes less amount of data. Although tracking this can
be useful too in scenarios where pg_stat_statements is lagging due to I/O
bottleneck.
I will leave this decision to the committer.

Thank you,
Rahila Syed

On Wed, Mar 15, 2017 at 1:03 PM, Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:

Show quoted text

Thanks Rahila for reviewing this patch.

On Tue, Mar 14, 2017 at 8:13 PM, Rahila Syed <rahilasyed90@gmail.com>
wrote:

Hello,

I applied and tested this patch on latest sources and it works fine.

Following are some comments,

+ /* Wait event for SNRU */
+ WAIT_EVENT_READ_SLRU_PAGE,

Typo in the comment.

Fixed.

FileWriteback(v->mdfd_vfd, seekpos, (off_t) BLCKSZ * nflush,

WAIT_EVENT_FLUSH_DATA_BLOCK);
This call is inside mdwriteback() which can flush more than one block so
should WAIT_EVENT _FLUSH_DATA_BLOCK
be renamed to WAIT_EVENT_FLUSH_DATA_BLOCKS?

Changed with WAIT_EVENT_FLUSH_DATA_BLOCKS.

Should calls to write() in following functions be tracked too?
qtext_store() - This is related to pg_stat_statements

I am not quite sure about this, as this is for stat statements. Also part
from the
place you found there are many other fwrite() call into
pg_stat_statements, and
I intentionally haven't added event here as it is very small write about
stat, and
doesn't look like we should add for those call.

dsm_impl_mmap() - This is in relation to creating dsm segments.

Added new event here. Actually particular write call is zero-filling the
DSM file.

write_auto_conf_file()- This is called when updated configuration
parameters are
written to a temp file.

write_auto_conf_file() is getting called during the ALTER SYSTEM call.
Here write
happen only when someone explicitly run the ALTER SYSTEM call. This is
administrator call and so doesn't seem like necessary to add separate wait
event
for this.

PFA latest patch with other fixes.

On Wed, Mar 8, 2017 at 4:50 PM, Rushabh Lathia <rushabh.lathia@gmail.com>
wrote:

On Wed, Mar 8, 2017 at 8:23 AM, Robert Haas <robertmhaas@gmail.com>
wrote:

On Tue, Mar 7, 2017 at 9:32 PM, Amit Kapila <amit.kapila16@gmail.com>
wrote:

On Tue, Mar 7, 2017 at 9:16 PM, Robert Haas <robertmhaas@gmail.com>

wrote:

On Mon, Mar 6, 2017 at 9:09 PM, Amit Kapila <amit.kapila16@gmail.com>

wrote:

Sure, if you think both Writes and Reads at OS level can have some
chance of blocking in obscure cases, then we should add a wait event
for them.

I think writes have a chance of blocking in cases even in cases that
are not very obscure at all.

Point taken for writes, but I think in general we should have some
criteria based on which we can decide whether to have a wait event for
a particular call. It should not happen that we have tons of wait
events and out of which, only a few are helpful in most of the cases
in real-world scenarios.

Well, the problem is that if you pick and choose which wait events to
add based on what you think will be common, you're actually kind of
hosing yourself. Because now when something uncommon happens, suddenly
you don't get any wait event data and you can't tell what's happening.
I think the number of new wait events added by Rushabh's patch is
wholly reasonable. Yeah, some of those are going to be a lot more
common than others, but so what? We add wait events so that we can
find out what's going on. I don't want to sometimes know when a
backend is blocked on an I/O. I want to ALWAYS know.

Yes, I agree with Robert. Knowing what we want and what we don't
want is difficult to judge. Something which we might think its not useful
information, and later of end up into situation where we re-think about
adding those missing stuff is not good. Having more information about
the system, specially for monitoring purpose is always good.

I am attaching another version of the patch, as I found stupid mistake
in the earlier version of patch, where I missed to initialize initial
value to
WaitEventIO enum. Also earlier version was not getting cleanly apply on
the current version of sources.

--
Rushabh Lathia
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Regards,
Rushabh Lathia
www.EnterpriseDB.com
The Enterprise PostgreSQL Company

#20Robert Haas
robertmhaas@gmail.com
In reply to: Rahila Syed (#19)
Re: wait events for disk I/O

On Thu, Mar 16, 2017 at 8:28 AM, Rahila Syed <rahilasyed90@gmail.com> wrote:

Thank you for the updated patch.

I have applied and tested it on latest sources and the patch looks good to
me.

The documentation puts the new wait events in a pretty random order.
I think they should be alphabetized, like we do with the IPC events.
I also suggest we change the naming scheme so that the kind of thing
being operated on is first and this is followed by the operation name.
This will let us keep related entries next to each other after
alphabetizing. So with that principle in mind:

- instead of ReadDataBlock etc. I propose DataFileRead, DataFileWrite,
DataFileSync, DataFileExtend, DataFileFlush, DataFilePrefetch,
DataFileTruncate. using file instead of block avoids singular/plural
confusion.
- instead of RelationSync and RelationImmedSync I proposed
DataFileSync and DataFileImmediateSync; these are md.c operations like
the previous set, so why name it differently?
- instead of WriteRewriteDataBlock and SyncRewriteDataBlock and
TruncateLogicalMappingRewrite, which aren't consistent with each other
even though they are related, I propose LogicalRewriteWrite,
LogicalRewriteSync, and LogicalRewriteTruncate, which are also closer
to the names of the functions that contain those wait points
- for ReadBuffile and WriteBuffile seem OK, I propose BufFileRead and
BufFileWrite, again reversing the order and also tweaking the
capitalization
- in keeping with our new policy of referring to xlog as wal in user
visible interfaces, I propose WALRead, WALCopyRead, WALWrite,
WALInitWrite, WALCopyWrite, WALBootstrapWrite, WALInitSync,
WALBootstrapSync, WALSyncMethodAssign
- for control file ops, ControlFileRead, ControlFileWrite,
ControlFileWriteUpdate, ControlFileSync, ControlFileSyncUpdate
- ReadApplyLogicalMapping and friends seem to have to do with the
reorderbuffer code, so maybe ReorderBufferRead etc.
- there seems to be some discrepancy between the documentation and
pgstat_get_wait_io for the snapbuild stuff. maybe SnapBuildWrite,
SnapBuildSync, SnapBuildRead.
- SLRURead, SLRUWrite, etc.
- TimelineHistoryRead, etc.
- the syslogger changes should be dropped, since the syslogger is not
and should not be connected to shared memory
- the replslot terminology seems like a case of odd capitalization and
overeager abbreviation. why not ReplicationSlotRead,
ReplicationSlotWrite, etc? similarly RelationMapRead,
RelationMapWrite, etc?
- CopyFileRead, CopyFileWrite
- LockFileCreateRead, etc.
- AddToDataDirLockFileRead is a little long and incomprehensible;
maybe LockFileUpdateRead etc.
- DSMWriteZeroBytes, maybe?

Of course the constants should be renamed to match.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#21Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Robert Haas (#20)
1 attachment(s)
Re: wait events for disk I/O

Thanks Robert for the review.

On Thu, Mar 16, 2017 at 8:05 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Mar 16, 2017 at 8:28 AM, Rahila Syed <rahilasyed90@gmail.com>
wrote:

Thank you for the updated patch.

I have applied and tested it on latest sources and the patch looks good

to

me.

The documentation puts the new wait events in a pretty random order.
I think they should be alphabetized, like we do with the IPC events.

Done.

I also suggest we change the naming scheme so that the kind of thing
being operated on is first and this is followed by the operation name.
This will let us keep related entries next to each other after
alphabetizing. So with that principle in mind:

Yes above naming scheme is more clear then the one i choose.

- instead of ReadDataBlock etc. I propose DataFileRead, DataFileWrite,

DataFileSync, DataFileExtend, DataFileFlush, DataFilePrefetch,
DataFileTruncate. using file instead of block avoids singular/plural
confusion.
- instead of RelationSync and RelationImmedSync I proposed
DataFileSync and DataFileImmediateSync; these are md.c operations like
the previous set, so why name it differently?

Yes, you are right, DataFileSync and DataFileImmediateSync make more
sense.

- instead of WriteRewriteDataBlock and SyncRewriteDataBlock and
TruncateLogicalMappingRewrite, which aren't consistent with each other
even though they are related, I propose LogicalRewriteWrite,
LogicalRewriteSync, and LogicalRewriteTruncate, which are also closer
to the names of the functions that contain those wait points
- for ReadBuffile and WriteBuffile seem OK, I propose BufFileRead and
BufFileWrite, again reversing the order and also tweaking the
capitalization
- in keeping with our new policy of referring to xlog as wal in user
visible interfaces, I propose WALRead, WALCopyRead, WALWrite,
WALInitWrite, WALCopyWrite, WALBootstrapWrite, WALInitSync,
WALBootstrapSync, WALSyncMethodAssign
- for control file ops, ControlFileRead, ControlFileWrite,
ControlFileWriteUpdate, ControlFileSync, ControlFileSyncUpdate

- ReadApplyLogicalMapping and friends seem to have to do with the

reorderbuffer code, so maybe ReorderBufferRead etc.
- there seems to be some discrepancy between the documentation and
pgstat_get_wait_io for the snapbuild stuff. maybe SnapBuildWrite,
SnapBuildSync, SnapBuildRead.
- SLRURead, SLRUWrite, etc.
- TimelineHistoryRead, etc.
- the syslogger changes should be dropped, since the syslogger is not
and should not be connected to shared memory

Ok removed.

- the replslot terminology seems like a case of odd capitalization and
overeager abbreviation. why not ReplicationSlotRead,
ReplicationSlotWrite, etc? similarly RelationMapRead,
RelationMapWrite, etc?
- CopyFileRead, CopyFileWrite
- LockFileCreateRead, etc.
- AddToDataDirLockFileRead is a little long and incomprehensible;
maybe LockFileUpdateRead etc.

How about LockFileAddToDataDirRead? even though its little long but it
gives clear understanding about what's going on.

- DSMWriteZeroBytes, maybe?

DSMFillZeroWrite? Basically want to keep the file IP operation at the end of
the event name.

Of course the constants should be renamed to match.

I tried to cover all the suggestion in the attached latest patch.

Thanks,
Rushabh Lathia
www.EnterpriseDB.com

Attachments:

wait_event_for_disk_IO_v4.patchtext/x-patch; charset=US-ASCII; name=wait_event_for_disk_IO_v4.patchDownload
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index 9eaf43a..acf310e 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>
@@ -1272,6 +1278,271 @@ 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="66"><literal>IO</></entry>
+         <entry><literal>BufFileRead</></entry>
+         <entry>Waiting during buffer read operation.</entry>
+        </row>
+        <row>
+         <entry><literal>BufFileWrite</></entry>
+         <entry>Waiting during buffer write operation.</entry>
+        </row>
+        <row>
+         <entry><literal>CheckpointLogicalRewriteSync</></entry>
+         <entry>Waiting to sync logical mapping during a checkpoint for logical rewrite mappings.</entry>
+        </row>
+        <row>
+         <entry><literal>ControlFileRead</></entry>
+         <entry>Waiting to read the control file.</entry>
+        </row>
+        <row>
+         <entry><literal>ControlFileSync</></entry>
+         <entry>Waiting to sync the control file.</entry>
+        </row>
+        <row>
+         <entry><literal>ControlFileSyncUpdate</></entry>
+         <entry>Waiting to sync the control file during update control file.</entry>
+        </row>
+        <row>
+         <entry><literal>ControlFileWrite</></entry>
+         <entry>Waiting to write the control file.</entry>
+        </row>
+        <row>
+         <entry><literal>ControlFileWriteUpdate</></entry>
+         <entry>Waiting to write the control file during update control file.</entry>
+        </row>
+        <row>
+         <entry><literal>CopyFileRead</></entry>
+         <entry>Waiting to read during copy file.</entry>
+        </row>
+        <row>
+         <entry><literal>CopyFileWrite</></entry>
+         <entry>Waiting to write during copy file.</entry>
+        </row>
+        <row>
+         <entry><literal>DataFileExtend</></entry>
+         <entry>Waiting during data file extent for a relation.</entry>
+        </row>
+        <row>
+         <entry><literal>DataFileFlush</></entry>
+         <entry>Waiting during write pages back to storage.</entry>
+        </row>
+        <row>
+         <entry><literal>DataFileImmediateSync</></entry>
+         <entry>Waiting during immediate sync a relation to stable storage.</entry>
+        </row>
+        <row>
+         <entry><literal>DataFilePrefetch</></entry>
+         <entry>Waiting during asynchronous read of the specified block of a relation.</entry>
+        </row>
+        <row>
+         <entry><literal>DataFileRead</></entry>
+         <entry>Waiting during relation data file read.</entry>
+        </row>
+        <row>
+         <entry><literal>DataFileSync</></entry>
+         <entry>Waiting during sync writes to stable storage.</entry>
+        </row>
+        <row>
+         <entry><literal>DataFileTruncate</></entry>
+         <entry>Waiting during truncate relation to specified number of blocks.</entry>
+        </row>
+        <row>
+         <entry><literal>DataFileWrite</></entry>
+         <entry>Waiting during relation data file write.</entry>
+        </row>
+        <row>
+         <entry><literal>DSMFillZeroWrite</></entry>
+         <entry>Wait to write during zero-fill of DSM file.</entry>
+        </row>
+        <row>
+         <entry><literal>LockFileAddToDataDirRead</></entry>
+         <entry>Wait to read lock file during add a line in the data directory lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>LockFileAddToDataDirSync</></entry>
+         <entry>Wait to sync lock file during add a line in the data directory lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>LockFileAddToDataDirWrite</></entry>
+         <entry>Wait to write lock file during add a line in the data directory lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>LockFileCreateRead</></entry>
+         <entry>Wait to read lock file during create lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>LockFileCreateSync</></entry>
+         <entry>Wait to sync lock file during create lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>LockFileCreateWrite</></entry>
+         <entry>Wait to write lock file during create lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>LockFileReCheckDataDirRead</></entry>
+         <entry>Wait to read lock file during recheck that the data directory lock file.</entry>
+        </row>
+        <row>
+         <entry><literal>LogicalRewriteSync</></entry>
+         <entry>Waiting to sync logical in-memory mappings to disk.</entry>
+        </row>
+        <row>
+         <entry><literal>LogicalRewriteWrite</></entry>
+         <entry>Waiting to write logical in-memory mappings to disk.</entry>
+        </row>
+        <row>
+         <entry><literal>RelationMapRead</></entry>
+         <entry>Waiting to read relation map file.</entry>
+        </row>
+        <row>
+         <entry><literal>RelationMapSync</></entry>
+         <entry>Waiting to sync relation map file.</entry>
+        </row>
+        <row>
+         <entry><literal>RelationMapWrite</></entry>
+         <entry>Waiting to write relation map file.</entry>
+        </row>
+        <row>
+         <entry><literal>ReplicationSlotRead</></entry>
+         <entry>Wait to read replication slot during load a single slot from disk into memory.</entry>
+        </row>
+        <row>
+         <entry><literal>ReplicationSlotRestoreSync</></entry>
+         <entry>Wait to sync replication slot during load a single slot from disk into memory.</entry>
+        </row>
+        <row>
+         <entry><literal>ReplicationSlotSync</></entry>
+         <entry>Wait to sync during save replication slot.</entry>
+        </row>
+        <row>
+         <entry><literal>ReplicationSlotWrite</></entry>
+         <entry>Wait to write replication slot.</entry>
+        </row>
+        <row>
+         <entry><literal>ReorderBufferRead</></entry>
+         <entry>Waiting to read buffer back into memory during reorder buffer management.</entry>
+        </row>
+        <row>
+         <entry><literal>ReorderBufferWrite</></entry>
+         <entry>Waiting to writ buffer to disk during reorder buffer management.</entry>
+        </row>
+        <row>
+         <entry><literal>ReorderLogicalMappingRead</></entry>
+         <entry>Waiting to read logical mapping during reorder buffer management.</entry>
+        </row>
+        <row>
+         <entry><literal>RewriteLogicalMappingSync</></entry>
+         <entry>Waiting to sync logical mapping during WAL logical rewrite.</entry>
+        </row>
+        <row>
+         <entry><literal>RewriteLogicalMappingWrite</></entry>
+         <entry>Waiting to write logical mapping during WAL logical rewrite.</entry>
+        </row>
+        <row>
+         <entry><literal>SLRURead</></entry>
+         <entry>Waiting to read page during physical read of a page into a buffer slot.</entry>
+        </row>
+        <row>
+         <entry><literal>SLRUFlushSync</></entry>
+         <entry>Waiting to sync page during flush dirty pages to disk during checkpoint or database shutdown.</entry>
+        </row>
+        <row>
+         <entry><literal>SLRUSync</></entry>
+         <entry>Waiting to sync page during physical write of a page from a buffer slot.</entry>
+        </row>
+        <row>
+         <entry><literal>SLRUWrite</></entry>
+         <entry>Waiting to write page during physical write of a page from a buffer slot.</entry>
+        </row>
+        <row>
+         <entry><literal>SnapbuildRead</></entry>
+         <entry>Waiting to read snapshot during serialize the snapshot.</entry>
+        </row>
+        <row>
+         <entry><literal>SnapbuildSync</></entry>
+         <entry>Waiting to sync snapshot during serialize the snapshot.</entry>
+        </row>
+        <row>
+         <entry><literal>SnapbuildWrite</></entry>
+         <entry>Waiting to write snapshot during serialize the snapshot.</entry>
+        </row>
+        <row>
+         <entry><literal>TimelineHistoryFileSync</></entry>
+         <entry>Waiting to sync timeline history during a history file write for given timeline and contents.</entry>
+        </row>
+        <row>
+         <entry><literal>TimelineHistoryFileWrite</></entry>
+         <entry>Waiting to write timeline history during a history file write for given timeline and contents.</entry>
+        </row>
+        <row>
+         <entry><literal>TimelineHistoryRead</></entry>
+         <entry>Waiting to read timeline history during write timeline history.</entry>
+        </row>
+        <row>
+         <entry><literal>TimelineHistorySync</></entry>
+         <entry>Waiting to sync timeline history during write timeline history</entry>
+        </row>
+        <row>
+         <entry><literal>TimelineHistoryWrite</></entry>
+         <entry>Waiting to write timeline history.</entry>
+        </row>
+        <row>
+         <entry><literal>TwophaseFileWrite</></entry>
+         <entry>Waiting to write two phase file during recreate two phase file.</entry>
+        </row>
+        <row>
+         <entry><literal>TwophaseFileSync</></entry>
+         <entry>Waiting to sync two phase file during recreate two phase file.</entry>
+        </row>
+        <row>
+         <entry><literal>TwophaseFileRead</></entry>
+         <entry>Waiting to read two phase file.</entry>
+        </row>
+        <row>
+         <entry><literal>WALBootstrapSync</></entry>
+         <entry>Waiting to sync the WAL page during bootstrap.</entry>
+        </row>
+        <row>
+         <entry><literal>WALBootstrapWrite</></entry>
+         <entry>Waiting to write the WAL page during bootstrap.</entry>
+        </row>
+        <row>
+         <entry><literal>WALCopyRead</></entry>
+         <entry>Wait to read the WAL page during create a new WAL file segment by copying a pre-existing one.</entry>
+        </row>
+        <row>
+         <entry><literal>WALCopySync</></entry>
+         <entry>Waiting to sync the WAL page during create a new WAL file segment by copying a pre-existing one.</entry>
+        </row>
+        <row>
+         <entry><literal>WALCopyWrite</></entry>
+         <entry>Waiting to write the WAL page during create a new WAL file segment by copying a pre-existing one.</entry>
+        </row>
+        <row>
+         <entry><literal>WALInitSync</></entry>
+         <entry>Waiting to sync the WAL page during WAL file initialization.</entry>
+        </row>
+        <row>
+         <entry><literal>WALInitWrite</></entry>
+         <entry>Waiting to write the WAL page during WAL file initialization.</entry>
+        </row>
+        <row>
+         <entry><literal>WALRead</></entry>
+         <entry>Waiting during WAL page read.</entry>
+        </row>
+        <row>
+         <entry><literal>WALSenderTimelineHistoryRead</></entry>
+         <entry>Waiting to read timeline history during walsander timeline command.</entry>
+        </row>
+        <row>
+         <entry><literal>WALSyncMethodAssign</></entry>
+         <entry>Waiting to assign WAL sync method.</entry>
+        </row>
+        <row>
+         <entry><literal>WALWrite</></entry>
+         <entry>Waiting during WAL page write.</entry>
+        </row>
       </tbody>
      </tgroup>
     </table>
diff --git a/src/backend/access/heap/rewriteheap.c b/src/backend/access/heap/rewriteheap.c
index c7b283c..c7e88b3 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_LOGICAL_REWRITE_WRITE);
 		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_LOGICAL_REWRITE_SYNC) != 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_LOGICAL_REWRITE_TRUNCATE);
 	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_REWRITE_LOGICAL_MAPPING_WRITE);
 	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_REWRITE_LOGICAL_MAPPING_SYNC);
 	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_CHECKPOINT_LOGICAL_REWRITE_SYNC);
+			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..edb1e25 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_SLRU_READ);
 	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_SLRU_WRITE);
 	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_SLRU_SYNC);
 		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_SLRU_FLUSH_SYNC);
 		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 1fdc591..a11f0f8 100644
--- a/src/backend/access/transam/timeline.c
+++ b/src/backend/access/transam/timeline.c
@@ -38,6 +38,7 @@
 #include "access/xlog.h"
 #include "access/xlog_internal.h"
 #include "access/xlogdefs.h"
+#include "pgstat.h"
 #include "storage/fd.h"
 
 /*
@@ -338,7 +339,9 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
 		for (;;)
 		{
 			errno = 0;
+			pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_READ);
 			nbytes = (int) read(srcfd, buffer, sizeof(buffer));
+			pgstat_report_wait_end();
 			if (nbytes < 0 || errno != 0)
 				ereport(ERROR,
 						(errcode_for_file_access(),
@@ -346,6 +349,7 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
 			if (nbytes == 0)
 				break;
 			errno = 0;
+			pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_WRITE);
 			if ((int) write(fd, buffer, nbytes) != nbytes)
 			{
 				int			save_errno = errno;
@@ -365,6 +369,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);
 	}
@@ -400,10 +405,12 @@ writeTimeLineHistory(TimeLineID newTLI, TimeLineID parentTLI,
 				 errmsg("could not write to file \"%s\": %m", tmppath)));
 	}
 
+	pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_SYNC);
 	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,
@@ -460,6 +467,7 @@ writeTimeLineHistoryFile(TimeLineID tli, char *content, int size)
 				 errmsg("could not create file \"%s\": %m", tmppath)));
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE);
 	if ((int) write(fd, content, size) != size)
 	{
 		int			save_errno = errno;
@@ -475,11 +483,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_TIMELINE_HISTORY_FILE_SYNC);
 	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 83ca6e0..ee351b7 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_TWOPHASE_FILE_READ);
 	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_TWOPHASE_FILE_WRITE);
 	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_TWOPHASE_FILE_SYNC);
 	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 64335f9..4a8d72d 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -2456,7 +2456,9 @@ XLogWrite(XLogwrtRqst WriteRqst, bool flexible)
 			do
 			{
 				errno = 0;
+				pgstat_report_wait_start(WAIT_EVENT_WAL_WRITE);
 				written = write(openLogFile, from, nleft);
+				pgstat_report_wait_end();
 				if (written <= 0)
 				{
 					if (errno == EINTR)
@@ -3207,6 +3209,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_WAL_INIT_WRITE);
 		if ((int) write(fd, zbuffer, XLOG_BLCKSZ) != (int) XLOG_BLCKSZ)
 		{
 			int			save_errno = errno;
@@ -3225,8 +3228,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_WAL_INIT_SYNC);
 	if (pg_fsync(fd) != 0)
 	{
 		close(fd);
@@ -3234,6 +3239,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,
@@ -3360,6 +3366,7 @@ XLogFileCopy(XLogSegNo destsegno, TimeLineID srcTLI, XLogSegNo srcsegno,
 			if (nread > sizeof(buffer))
 				nread = sizeof(buffer);
 			errno = 0;
+			pgstat_report_wait_start(WAIT_EVENT_WAL_COPY_READ);
 			if (read(srcfd, buffer, nread) != nread)
 			{
 				if (errno != 0)
@@ -3372,8 +3379,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_WAL_COPY_WRITE);
 		if ((int) write(fd, buffer, sizeof(buffer)) != (int) sizeof(buffer))
 		{
 			int			save_errno = errno;
@@ -3389,12 +3398,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_WAL_COPY_SYNC);
 	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,
@@ -4414,6 +4426,7 @@ WriteControlFile(void)
 						XLOG_CONTROL_FILE)));
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE);
 	if (write(fd, buffer, PG_CONTROL_SIZE) != PG_CONTROL_SIZE)
 	{
 		/* if write didn't set errno, assume problem is no disk space */
@@ -4423,11 +4436,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_CONTROL_FILE_SYNC);
 	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,
@@ -4453,10 +4469,12 @@ ReadControlFile(void)
 				 errmsg("could not open control file \"%s\": %m",
 						XLOG_CONTROL_FILE)));
 
+	pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_READ);
 	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);
 
@@ -4634,6 +4652,7 @@ UpdateControlFile(void)
 						XLOG_CONTROL_FILE)));
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE);
 	if (write(fd, ControlFile, sizeof(ControlFileData)) != sizeof(ControlFileData))
 	{
 		/* if write didn't set errno, assume problem is no disk space */
@@ -4643,11 +4662,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_CONTROL_FILE_SYNC_UPDATE);
 	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,
@@ -5036,6 +5058,7 @@ BootStrapXLOG(void)
 
 	/* Write the first page with the initial record */
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_WAL_BOOTSTRAP_WRITE);
 	if (write(openLogFile, page, XLOG_BLCKSZ) != XLOG_BLCKSZ)
 	{
 		/* if write didn't set errno, assume problem is no disk space */
@@ -5045,11 +5068,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_WAL_BOOTSTRAP_SYNC);
 	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,
@@ -9999,11 +10025,13 @@ assign_xlog_sync_method(int new_sync_method, void *extra)
 		 */
 		if (openLogFile >= 0)
 		{
+			pgstat_report_wait_start(WAIT_EVENT_WAL_SYNC_METHOD_ASSIGN);
 			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();
 		}
@@ -11456,6 +11484,7 @@ retry:
 		goto next_record_is_invalid;
 	}
 
+	pgstat_report_wait_start(WAIT_EVENT_WAL_READ);
 	if (read(readFile, readBuf, XLOG_BLCKSZ) != XLOG_BLCKSZ)
 	{
 		char		fname[MAXFNAMELEN];
@@ -11467,6 +11496,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 8b99b78..b2b9fcb 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"
@@ -728,7 +729,9 @@ XLogRead(char *buf, TimeLineID tli, XLogRecPtr startptr, Size count)
 		else
 			segbytes = nbytes;
 
+		pgstat_report_wait_start(WAIT_EVENT_WAL_READ);
 		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 7cacb1e..64a0618 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;
@@ -3439,6 +3450,241 @@ 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_DATA_FILE_READ:
+			event_name = "DataFileRead";
+			break;
+		case WAIT_EVENT_DATA_FILE_WRITE:
+			event_name = "DataFileWrite";
+			break;
+		case WAIT_EVENT_DATA_FILE_SYNC:
+			event_name = "DataFileSync";
+			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_PREFETCH:
+			event_name = "DataFilePrefetch";
+			break;
+		case WAIT_EVENT_DATA_FILE_TRUNCATE:
+			event_name = "DataFileTruncate";
+			break;
+		case WAIT_EVENT_DATA_FILE_IMMEDIATE_SYNC:
+			event_name = "DataFileImmediateSync";
+			break;
+		case WAIT_EVENT_LOGICAL_REWRITE_WRITE:
+			event_name = "LogicalRewriteWrite";
+			break;
+		case WAIT_EVENT_LOGICAL_REWRITE_SYNC:
+			event_name = "LogicalRewriteSync";
+			break;
+		case WAIT_EVENT_LOGICAL_REWRITE_TRUNCATE:
+			event_name = "LogicalRewriteTruncate";
+			break;
+		case WAIT_EVENT_BUFFILE_READ:
+			event_name = "BufFileRead";
+			break;
+		case WAIT_EVENT_BUFFILE_WRITE:
+			event_name = "BufFileWrite";
+			break;
+		/* WAL wait event */
+		case WAIT_EVENT_WAL_READ:
+			event_name = "WALRead";
+			break;
+		case WAIT_EVENT_WAL_COPY_READ:
+			event_name = "WALCopyRead";
+			break;
+		case WAIT_EVENT_WAL_WRITE:
+			event_name = "WALWrite";
+			break;
+		case WAIT_EVENT_WAL_INIT_WRITE:
+			event_name = "WALInitWrite";
+			break;
+		case WAIT_EVENT_WAL_COPY_WRITE:
+			event_name = "WALCopyWrite";
+			break;
+		case WAIT_EVENT_WAL_BOOTSTRAP_WRITE:
+			event_name = "WALBootstrapWrite";
+			break;
+		case WAIT_EVENT_WAL_INIT_SYNC:
+			event_name = "WALInitSync";
+			break;
+		case WAIT_EVENT_WAL_COPY_SYNC:
+			event_name = "WALCopySync";
+			break;
+		case WAIT_EVENT_WAL_BOOTSTRAP_SYNC:
+			event_name = "WALBootstrapSync";
+			break;
+		case WAIT_EVENT_WAL_SYNC_METHOD_ASSIGN:
+			event_name = "WALSyncMethodAssign";
+			break;
+		/* Control file wait events */
+		case WAIT_EVENT_CONTROL_FILE_READ:
+			event_name = "ControlFileRead";
+			break;
+		case WAIT_EVENT_CONTROL_FILE_WRITE:
+			event_name = "ControlFileWrite";
+			break;
+		case WAIT_EVENT_CONTROL_FILE_SYNC:
+			event_name = "ControlFileSync";
+			break;
+		case WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE:
+			event_name = "ControlFileWriteUpdate";
+			break;
+		case WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE:
+			event_name = "ControlFileSyncUpdate";
+			break;
+		/* reorder buffer wait event */
+		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;
+		/* logical mapping wait event */
+		case WAIT_EVENT_REWRITE_LOGICAL_MAPPING_WRITE:
+			event_name = "RewriteLogicalMappingWrite";
+			break;
+		case WAIT_EVENT_REWRITE_LOGICAL_MAPPING_SYNC:
+			event_name = "RewriteLogicalMappingSync";
+			break;
+		case WAIT_EVENT_CHECKPOINT_LOGICAL_REWRITE_SYNC:
+			event_name = "CheckpointLogicalRewriteSync";
+			break;
+		/* Snapbuild wait event */
+		case WAIT_EVENT_SNAPBUILD_WRITE:
+			event_name = "SnapbuildWrite";
+			break;
+		case WAIT_EVENT_SNAPBUILD_READ:
+			event_name = "SnapbuildRead";
+			break;
+		case WAIT_EVENT_SNAPBUILD_SYNC:
+			event_name = "SnapbuildSync";
+			break;
+		/* SLRU wait event */
+		case WAIT_EVENT_SLRU_READ:
+			event_name = "SLRURead";
+			break;
+		case WAIT_EVENT_SLRU_WRITE:
+			event_name = "SLRUWrite";
+			break;
+		case WAIT_EVENT_SLRU_SYNC:
+			event_name = "SLRUSync";
+			break;
+		case WAIT_EVENT_SLRU_FLUSH_SYNC:
+			event_name = "SLRUFlushSync";
+			break;
+		/* TIMELINE HISTORY wait event */
+		case WAIT_EVENT_WALSENDER_TIMELINE_HISTORY_READ:
+			event_name = "WALSenderTimelineHistoryRead";
+			break;
+		case WAIT_EVENT_TIMELINE_HISTORY_READ:
+			event_name = "TimelineHistoryRead";
+			break;
+		case WAIT_EVENT_TIMELINE_HISTORY_WRITE:
+			event_name = "TimelineHistoryWrite";
+			break;
+		case WAIT_EVENT_TIMELINE_HISTORY_SYNC:
+			event_name = "TimelineHistorySync";
+			break;
+		case WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE:
+			event_name = "TimelineHistoryFileWrite";
+			break;
+		case WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC:
+			event_name = "TimelineHistoryFileSync";
+			break;
+		/* TWOPHASE FILE wait event */
+		case WAIT_EVENT_TWOPHASE_FILE_READ:
+			event_name = "TwophaseFileRead";
+			break;
+		case WAIT_EVENT_TWOPHASE_FILE_WRITE:
+			event_name = "TwophaseFileWrite";
+			break;
+		case WAIT_EVENT_TWOPHASE_FILE_SYNC:
+			event_name = "TwophaseFileSync";
+			break;
+		/* Replication Slot wait event */
+		case WAIT_EVENT_REPLICATION_SLOT_READ:
+			event_name = "ReplicationSlotRead";
+			break;
+		case WAIT_EVENT_REPLICATION_SLOT_WRITE:
+			event_name = "ReplicationSlotWrite";
+			break;
+		case WAIT_EVENT_REPLICATION_SLOT_SYNC:
+			event_name = "ReplicationSlotSync";
+			break;
+		case WAIT_EVENT_REPLICATION_SLOT_RESTORE_SYNC:
+			event_name = "ReplicationSlotRestoreSync";
+			break;
+		/* COPYDIR IO wait event */
+		case WAIT_EVENT_COPY_FILE_READ:
+			event_name = "CopyFileRead";
+			break;
+		case WAIT_EVENT_COPY_FILE_WRITE:
+			event_name = "CopyFileWrite";
+			break;
+		/* Relation map IO wait event */
+		case WAIT_EVENT_RELATION_MAP_READ:
+			event_name = "RelationMapRead";
+			break;
+		case WAIT_EVENT_RELATION_MAP_WRITE:
+			event_name = "RelationMapWrite";
+			break;
+		case WAIT_EVENT_RELATION_MAP_SYNC:
+			event_name = "RelationMapSync";
+			break;
+		/* LOCK FILE IO wait event */
+		case WAIT_EVENT_LOCK_FILE_CREATE_READ:
+			event_name = "LockFileCreateRead";
+			break;
+		case WAIT_EVENT_LOCK_FILE_CREATE_WRITE:
+			event_name = "LockFileCreateWRITE";
+			break;
+		case WAIT_EVENT_LOCK_FILE_CREATE_SYNC:
+			event_name = "LockFileCreateSync";
+			break;
+		case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ:
+			event_name = "LockFileAddToDataDirRead";
+			break;
+		case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_WRITE:
+			event_name = "LockFileAddToDataDirWrite";
+			break;
+		case WAIT_EVENT_LOCK_FILE_ADDTODATADIR_SYNC:
+			event_name = "LockFileAddToDataDirSync";
+			break;
+		case WAIT_EVENT_LOCK_FILE_RECHECKDATADIR_READ:
+			event_name = "LockFileReCheckDataDirRead";
+			break;
+		/* DSM IO wait event */
+		case WAIT_EVENT_DSM_FILL_ZERO_WRITE:
+			event_name = "DSMFillZeroWrite";
+			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/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c
index 8aac670..b437799 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"
@@ -2275,6 +2276,7 @@ ReorderBufferSerializeChange(ReorderBuffer *rb, ReorderBufferTXN *txn,
 
 	ondisk->size = sz;
 
+	pgstat_report_wait_start(WAIT_EVENT_REORDER_BUFFER_WRITE);
 	if (write(fd, rb->outbuf, ondisk->size) != ondisk->size)
 	{
 		int			save_errno = errno;
@@ -2286,6 +2288,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);
 }
@@ -2366,7 +2369,9 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
 		 * end of this file.
 		 */
 		ReorderBufferSerializeReserve(rb, sizeof(ReorderBufferDiskChange));
+		pgstat_report_wait_start(WAIT_EVENT_REORDER_BUFFER_READ);
 		readBytes = read(*fd, rb->outbuf, sizeof(ReorderBufferDiskChange));
+		pgstat_report_wait_end();
 
 		/* eof */
 		if (readBytes == 0)
@@ -2393,8 +2398,10 @@ ReorderBufferRestoreChanges(ReorderBuffer *rb, ReorderBufferTXN *txn,
 							 sizeof(ReorderBufferDiskChange) + ondisk->size);
 		ondisk = (ReorderBufferDiskChange *) rb->outbuf;
 
+		pgstat_report_wait_start(WAIT_EVENT_REORDER_BUFFER_READ);
 		readBytes = read(*fd, rb->outbuf + sizeof(ReorderBufferDiskChange),
 						 ondisk->size - sizeof(ReorderBufferDiskChange));
+		pgstat_report_wait_end();
 
 		if (readBytes < 0)
 			ereport(ERROR,
@@ -3047,7 +3054,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_REORDER_LOGICAL_MAPPING_READ);
 		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 e129a6b..3f242a8 100644
--- a/src/backend/replication/logical/snapbuild.c
+++ b/src/backend/replication/logical/snapbuild.c
@@ -115,6 +115,8 @@
 #include "access/transam.h"
 #include "access/xact.h"
 
+#include "pgstat.h"
+
 #include "replication/logical.h"
 #include "replication/reorderbuffer.h"
 #include "replication/snapbuild.h"
@@ -1580,6 +1582,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 		ereport(ERROR,
 				(errmsg("could not open file \"%s\": %m", path)));
 
+	pgstat_report_wait_start(WAIT_EVENT_SNAPBUILD_WRITE);
 	if ((write(fd, ondisk, needed_length)) != needed_length)
 	{
 		CloseTransientFile(fd);
@@ -1587,6 +1590,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
@@ -1596,6 +1600,7 @@ SnapBuildSerialize(SnapBuild *builder, XLogRecPtr lsn)
 	 * some noticeable overhead since it's performed synchronously during
 	 * decoding?
 	 */
+	pgstat_report_wait_start(WAIT_EVENT_SNAPBUILD_SYNC);
 	if (pg_fsync(fd) != 0)
 	{
 		CloseTransientFile(fd);
@@ -1603,6 +1608,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);
@@ -1677,7 +1683,9 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
 
 
 	/* read statically sized portion of snapshot */
+	pgstat_report_wait_start(WAIT_EVENT_SNAPBUILD_READ);
 	readBytes = read(fd, &ondisk, SnapBuildOnDiskConstantSize);
+	pgstat_report_wait_end();
 	if (readBytes != SnapBuildOnDiskConstantSize)
 	{
 		CloseTransientFile(fd);
@@ -1703,7 +1711,9 @@ SnapBuildRestore(SnapBuild *builder, XLogRecPtr lsn)
 			SnapBuildOnDiskConstantSize - SnapBuildOnDiskNotChecksummedSize);
 
 	/* read SnapBuild */
+	pgstat_report_wait_start(WAIT_EVENT_SNAPBUILD_READ);
 	readBytes = read(fd, &ondisk.builder, sizeof(SnapBuild));
+	pgstat_report_wait_end();
 	if (readBytes != sizeof(SnapBuild))
 	{
 		CloseTransientFile(fd);
@@ -1717,7 +1727,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_SNAPBUILD_READ);
 	readBytes = read(fd, ondisk.builder.running.xip, sz);
+	pgstat_report_wait_end();
 	if (readBytes != sz)
 	{
 		CloseTransientFile(fd);
@@ -1731,7 +1743,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_SNAPBUILD_READ);
 	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..382a352 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_REPLICATION_SLOT_WRITE);
 	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_REPLICATION_SLOT_SYNC);
 	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_REPLICATION_SLOT_RESTORE_SYNC);
 	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_REPLICATION_SLOT_READ);
 	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_REPLICATION_SLOT_READ);
 	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 127efec..0f6b828 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -463,7 +463,9 @@ SendTimeLineHistory(TimeLineHistoryCmd *cmd)
 		char		rbuf[BLCKSZ];
 		int			nread;
 
+		pgstat_report_wait_start(WAIT_EVENT_WALSENDER_TIMELINE_HISTORY_READ);
 		nread = read(fd, rbuf, sizeof(rbuf));
+		pgstat_report_wait_end();
 		if (nread <= 0)
 			ereport(ERROR,
 					(errcode_for_file_access(),
@@ -2126,7 +2128,9 @@ retry:
 		else
 			segbytes = nbytes;
 
+		pgstat_report_wait_start(WAIT_EVENT_WAL_READ);
 		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..4ca0ea4 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_BUFFILE_READ);
 	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_BUFFILE_WRITE);
 		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..dffe283 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_COPY_FILE_READ);
 		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_COPY_FILE_WRITE);
 		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 fd02fc0..16f0c92 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -1550,7 +1550,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;
@@ -1565,8 +1565,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
@@ -1576,7 +1578,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;
 
@@ -1597,11 +1599,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;
 	Vfd		   *vfdP;
@@ -1619,6 +1623,7 @@ FileRead(File file, char *buffer, int amount)
 
 	vfdP = &VfdCache[file];
 
+	pgstat_report_wait_start(wait_event_info);
 retry:
 	returnCode = read(vfdP->fd, buffer, amount);
 
@@ -1658,12 +1663,13 @@ retry:
 		/* Trouble, so assume we don't know the file position anymore */
 		vfdP->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;
 	Vfd		   *vfdP;
@@ -1719,6 +1725,7 @@ FileWrite(File file, char *buffer, int amount)
 		}
 	}
 
+	pgstat_report_wait_start(wait_event_info);
 retry:
 	errno = 0;
 	returnCode = write(vfdP->fd, buffer, amount);
@@ -1777,12 +1784,13 @@ retry:
 		/* Trouble, so assume we don't know the file position anymore */
 		vfdP->seekPos = FileUnknownPos;
 	}
+	pgstat_report_wait_end();
 
 	return returnCode;
 }
 
 int
-FileSync(File file)
+FileSync(File file, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1795,7 +1803,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
@@ -1887,7 +1899,7 @@ FileTell(File file)
 #endif
 
 int
-FileTruncate(File file, off_t offset)
+FileTruncate(File file, off_t offset, uint32 wait_event_info)
 {
 	int			returnCode;
 
@@ -1900,7 +1912,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/ipc/dsm_impl.c b/src/backend/storage/ipc/dsm_impl.c
index b2c9cdc..e0eaefe 100644
--- a/src/backend/storage/ipc/dsm_impl.c
+++ b/src/backend/storage/ipc/dsm_impl.c
@@ -60,6 +60,7 @@
 #ifdef HAVE_SYS_SHM_H
 #include <sys/shm.h>
 #endif
+#include "pgstat.h"
 
 #include "portability/mem.h"
 #include "storage/dsm_impl.h"
@@ -911,10 +912,12 @@ dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size,
 
 			if (goal > ZBUFFER_SIZE)
 				goal = ZBUFFER_SIZE;
+			pgstat_report_wait_start(WAIT_EVENT_DSM_FILL_ZERO_WRITE);
 			if (write(fd, zbuffer, goal) == goal)
 				remaining -= goal;
 			else
 				success = false;
+			pgstat_report_wait_end();
 		}
 
 		if (!success)
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 6c17b54..b0b596d 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_DATA_FILE_EXTEND)) != 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_DATA_FILE_PREFETCH);
 #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_DATA_FILE_FLUSH);
 
 		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_DATA_FILE_READ);
 
 	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_DATA_FILE_WRITE);
 
 	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_DATA_FILE_TRUNCATE) < 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_DATA_FILE_TRUNCATE) < 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_DATA_FILE_IMMEDIATE_SYNC) < 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_DATA_FILE_SYNC) >= 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_DATA_FILE_SYNC) < 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..557f791 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_RELATION_MAP_READ);
 	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_RELATION_MAP_WRITE);
 	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_RELATION_MAP_SYNC);
 	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 e0298ee..e4dc055 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -35,6 +35,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"
@@ -856,11 +857,13 @@ CreateLockFile(const char *filename, bool amPostmaster,
 					 errmsg("could not open lock file \"%s\": %m",
 							filename)));
 		}
+		pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_CREATE_READ);
 		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)
@@ -1009,6 +1012,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
 		strlcat(buffer, "\n", sizeof(buffer));
 
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_CREATE_WRITE);
 	if (write(fd, buffer, strlen(buffer)) != strlen(buffer))
 	{
 		int			save_errno = errno;
@@ -1021,6 +1025,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_LOCK_FILE_CREATE_SYNC);
 	if (pg_fsync(fd) != 0)
 	{
 		int			save_errno = errno;
@@ -1032,6 +1039,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;
@@ -1164,7 +1172,9 @@ AddToDataDirLockFile(int target_line, const char *str)
 						DIRECTORY_LOCK_FILE)));
 		return;
 	}
+	pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ);
 	len = read(fd, srcbuffer, sizeof(srcbuffer) - 1);
+	pgstat_report_wait_end();
 	if (len < 0)
 	{
 		ereport(LOG,
@@ -1217,6 +1227,7 @@ AddToDataDirLockFile(int target_line, const char *str)
 	 */
 	len = strlen(destbuffer);
 	errno = 0;
+	pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_ADDTODATADIR_WRITE);
 	if (lseek(fd, (off_t) 0, SEEK_SET) != 0 ||
 		(int) write(fd, destbuffer, len) != len)
 	{
@@ -1230,6 +1241,8 @@ AddToDataDirLockFile(int target_line, const char *str)
 		close(fd);
 		return;
 	}
+	pgstat_report_wait_end();
+	pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_ADDTODATADIR_SYNC);
 	if (pg_fsync(fd) != 0)
 	{
 		ereport(LOG,
@@ -1237,6 +1250,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,
@@ -1293,7 +1307,9 @@ RecheckDataDirLockFile(void)
 				return true;
 		}
 	}
+	pgstat_report_wait_start(WAIT_EVENT_LOCK_FILE_RECHECKDATADIR_READ);
 	len = read(fd, buffer, sizeof(buffer) - 1);
+	pgstat_report_wait_end();
 	if (len < 0)
 	{
 		ereport(LOG,
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 60c78d1..69d6e34 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
@@ -806,6 +807,96 @@ typedef enum
 } WaitEventTimeout;
 
 /* ----------
+ * Wait Events - IO
+ *
+ * Use this category when a process is waiting for a IO.
+ * ----------
+ */
+typedef enum
+{
+	WAIT_EVENT_DATA_FILE_READ = PG_WAIT_IO,
+	WAIT_EVENT_DATA_FILE_WRITE,
+	WAIT_EVENT_DATA_FILE_SYNC,
+	WAIT_EVENT_DATA_FILE_EXTEND,
+	WAIT_EVENT_DATA_FILE_FLUSH,
+	WAIT_EVENT_DATA_FILE_PREFETCH,
+	WAIT_EVENT_DATA_FILE_TRUNCATE,
+	WAIT_EVENT_DATA_FILE_IMMEDIATE_SYNC,
+	WAIT_EVENT_LOGICAL_REWRITE_WRITE,
+	WAIT_EVENT_LOGICAL_REWRITE_SYNC,
+	WAIT_EVENT_LOGICAL_REWRITE_TRUNCATE,
+	WAIT_EVENT_BUFFILE_READ,
+	WAIT_EVENT_BUFFILE_WRITE,
+	/* Wait event for WAL */
+	WAIT_EVENT_WAL_READ,
+	WAIT_EVENT_WAL_COPY_READ,
+	WAIT_EVENT_WAL_WRITE,
+	WAIT_EVENT_WAL_INIT_WRITE,
+	WAIT_EVENT_WAL_COPY_WRITE,
+	WAIT_EVENT_WAL_BOOTSTRAP_WRITE,
+	WAIT_EVENT_WAL_INIT_SYNC,
+	WAIT_EVENT_WAL_COPY_SYNC,
+	WAIT_EVENT_WAL_BOOTSTRAP_SYNC,
+	WAIT_EVENT_WAL_SYNC_METHOD_ASSIGN,
+	/* Wait event for CONTROL_FILE */
+	WAIT_EVENT_CONTROL_FILE_READ,
+	WAIT_EVENT_CONTROL_FILE_WRITE,
+	WAIT_EVENT_CONTROL_FILE_WRITE_UPDATE,
+	WAIT_EVENT_CONTROL_FILE_SYNC,
+	WAIT_EVENT_CONTROL_FILE_SYNC_UPDATE,
+	/* Wait event for REORDER BUFFER */
+	WAIT_EVENT_REORDER_BUFFER_READ,
+	WAIT_EVENT_REORDER_BUFFER_WRITE,
+	WAIT_EVENT_REORDER_LOGICAL_MAPPING_READ,
+	/* Wait event for REWRITE LOGICAL MAPPING */
+	WAIT_EVENT_REWRITE_LOGICAL_MAPPING_WRITE,
+	WAIT_EVENT_REWRITE_LOGICAL_MAPPING_SYNC,
+	WAIT_EVENT_CHECKPOINT_LOGICAL_REWRITE_SYNC,
+	/* Wait event for SNAPBUILD */
+	WAIT_EVENT_SNAPBUILD_READ,
+	WAIT_EVENT_SNAPBUILD_WRITE,
+	WAIT_EVENT_SNAPBUILD_SYNC,
+	/* Wait event for SLRU */
+	WAIT_EVENT_SLRU_READ,
+	WAIT_EVENT_SLRU_WRITE,
+	WAIT_EVENT_SLRU_SYNC,
+	WAIT_EVENT_SLRU_FLUSH_SYNC,
+	/* Wait event for TIMELINE HISTORY */
+	WAIT_EVENT_WALSENDER_TIMELINE_HISTORY_READ,
+	WAIT_EVENT_TIMELINE_HISTORY_READ,
+	WAIT_EVENT_TIMELINE_HISTORY_WRITE,
+	WAIT_EVENT_TIMELINE_HISTORY_SYNC,
+	WAIT_EVENT_TIMELINE_HISTORY_FILE_WRITE,
+	WAIT_EVENT_TIMELINE_HISTORY_FILE_SYNC,
+	/* Wait event for TWOPHASE FILE */
+	WAIT_EVENT_TWOPHASE_FILE_READ,
+	WAIT_EVENT_TWOPHASE_FILE_WRITE,
+	WAIT_EVENT_TWOPHASE_FILE_SYNC,
+	/* Wait event for Replication Slot */
+	WAIT_EVENT_REPLICATION_SLOT_READ,
+	WAIT_EVENT_REPLICATION_SLOT_WRITE,
+	WAIT_EVENT_REPLICATION_SLOT_SYNC,
+	WAIT_EVENT_REPLICATION_SLOT_RESTORE_SYNC,
+	/* Wait event for copydir */
+	WAIT_EVENT_COPY_FILE_READ,
+	WAIT_EVENT_COPY_FILE_WRITE,
+	/* Wait event RELMAP FILE */
+	WAIT_EVENT_RELATION_MAP_READ,
+	WAIT_EVENT_RELATION_MAP_WRITE,
+	WAIT_EVENT_RELATION_MAP_SYNC,
+	/* Wait event for LOCK FILE */
+	WAIT_EVENT_LOCK_FILE_CREATE_READ,
+	WAIT_EVENT_LOCK_FILE_CREATE_WRITE,
+	WAIT_EVENT_LOCK_FILE_CREATE_SYNC,
+	WAIT_EVENT_LOCK_FILE_ADDTODATADIR_READ,
+	WAIT_EVENT_LOCK_FILE_ADDTODATADIR_WRITE,
+	WAIT_EVENT_LOCK_FILE_ADDTODATADIR_SYNC,
+	WAIT_EVENT_LOCK_FILE_RECHECKDATADIR_READ,
+	/* Wait event for DSM */
+	WAIT_EVENT_DSM_FILL_ZERO_WRITE
+} 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);
#22Robert Haas
robertmhaas@gmail.com
In reply to: Rushabh Lathia (#21)
Re: wait events for disk I/O

On Fri, Mar 17, 2017 at 10:01 AM, Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

I tried to cover all the suggestion in the attached latest patch.

Committed. I reworded the documentation entries, renamed a few of the
wait events to make things more consistent, put all three lists in
rigorous alphabetical order, and I fixed a couple of places where an
error return from a system call could lead to returning without
clearing the wait event.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#23Rushabh Lathia
rushabh.lathia@gmail.com
In reply to: Robert Haas (#22)
Re: wait events for disk I/O

On Sat, Mar 18, 2017 at 5:15 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, Mar 17, 2017 at 10:01 AM, Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

I tried to cover all the suggestion in the attached latest patch.

Committed. I reworded the documentation entries, renamed a few of the
wait events to make things more consistent, put all three lists in
rigorous alphabetical order, and I fixed a couple of places where an
error return from a system call could lead to returning without
clearing the wait event.

Thanks Robert.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Rushabh Lathia

#24Rajkumar Raghuwanshi
rajkumar.raghuwanshi@enterprisedb.com
In reply to: Rushabh Lathia (#23)
Re: wait events for disk I/O

On Sat, Mar 18, 2017 at 10:52 PM, Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

On Sat, Mar 18, 2017 at 5:15 PM, Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, Mar 17, 2017 at 10:01 AM, Rushabh Lathia
<rushabh.lathia@gmail.com> wrote:

I tried to cover all the suggestion in the attached latest patch.

Committed. I reworded the documentation entries, renamed a few of the
wait events to make things more consistent, put all three lists in
rigorous alphabetical order, and I fixed a couple of places where an
error return from a system call could lead to returning without
clearing the wait event.

Thanks, I ran pgbench with shared_buffers set to 128kB, able to see
below wait IO events.

DataFileRead
DataFileWrite
WALInitSync
WALInitWrite
WALWrite
DataFileSync
WALRead

Thanks & Regards,
Rajkumar Raghuwanshi
QMG, EnterpriseDB Corporation

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers