diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index e64b7ef..2e4e67e 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -630,6 +630,11 @@ postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: ser
      <entry>True if this backend is currently waiting on a lock</entry>
     </row>
     <row>
+     <entry><structfield>wait_event</></entry>
+     <entry><type>text</></entry>
+     <entry>Name of a current wait event in backend</entry>
+    </row>
+    <row>
      <entry><structfield>state</></entry>
      <entry><type>text</></entry>
      <entry>Current overall state of this backend.
diff --git a/src/backend/access/transam/clog.c b/src/backend/access/transam/clog.c
index 3a58f1e..10c25cf 100644
--- a/src/backend/access/transam/clog.c
+++ b/src/backend/access/transam/clog.c
@@ -457,7 +457,8 @@ CLOGShmemInit(void)
 {
 	ClogCtl->PagePrecedes = CLOGPagePrecedes;
 	SimpleLruInit(ClogCtl, "CLOG Ctl", CLOGShmemBuffers(), CLOG_LSNS_PER_PAGE,
-				  CLogControlLock, "pg_clog");
+				  CLogControlLock, "pg_clog",
+				  "CLogBufferLocks");
 }
 
 /*
diff --git a/src/backend/access/transam/commit_ts.c b/src/backend/access/transam/commit_ts.c
index 5ad35c0..dd7578f 100644
--- a/src/backend/access/transam/commit_ts.c
+++ b/src/backend/access/transam/commit_ts.c
@@ -466,7 +466,8 @@ CommitTsShmemInit(void)
 
 	CommitTsCtl->PagePrecedes = CommitTsPagePrecedes;
 	SimpleLruInit(CommitTsCtl, "CommitTs Ctl", CommitTsShmemBuffers(), 0,
-				  CommitTsControlLock, "pg_commit_ts");
+				  CommitTsControlLock, "pg_commit_ts",
+				  "CommitTSBufferLocks");
 
 	commitTsShared = ShmemInitStruct("CommitTs shared",
 									 sizeof(CommitTimestampShared),
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c
index 1933a87..b905c59 100644
--- a/src/backend/access/transam/multixact.c
+++ b/src/backend/access/transam/multixact.c
@@ -1842,10 +1842,12 @@ MultiXactShmemInit(void)
 
 	SimpleLruInit(MultiXactOffsetCtl,
 				  "MultiXactOffset Ctl", NUM_MXACTOFFSET_BUFFERS, 0,
-				  MultiXactOffsetControlLock, "pg_multixact/offsets");
+				  MultiXactOffsetControlLock, "pg_multixact/offsets",
+				  "MultiXactOffsetBufferLocks");
 	SimpleLruInit(MultiXactMemberCtl,
 				  "MultiXactMember Ctl", NUM_MXACTMEMBER_BUFFERS, 0,
-				  MultiXactMemberControlLock, "pg_multixact/members");
+				  MultiXactMemberControlLock, "pg_multixact/members",
+				  "MultiXactMemberBufferLocks");
 
 	/* Initialize our shared state struct */
 	MultiXactState = ShmemInitStruct("Shared MultiXact State",
diff --git a/src/backend/access/transam/slru.c b/src/backend/access/transam/slru.c
index 5fcea11..4bf3fee 100644
--- a/src/backend/access/transam/slru.c
+++ b/src/backend/access/transam/slru.c
@@ -156,15 +156,20 @@ SimpleLruShmemSize(int nslots, int nlsns)
 	if (nlsns > 0)
 		sz += MAXALIGN(nslots * nlsns * sizeof(XLogRecPtr));	/* group_lsn[] */
 
+	/* size of lwlocks */
+	sz = add_size(sz, LWLockTrancheShmemSize(nslots));
+
 	return BUFFERALIGN(sz) + BLCKSZ * nslots;
 }
 
 void
 SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
-			  LWLock *ctllock, const char *subdir)
+			  LWLock *ctllock, const char *subdir,
+			  const char *lwlocks_tranche)
 {
-	SlruShared	shared;
-	bool		found;
+	SlruShared    shared;
+	bool          found;
+	LWLockPadded *lwlock_array;
 
 	shared = (SlruShared) ShmemInitStruct(name,
 										  SimpleLruShmemSize(nslots, nlsns),
@@ -212,13 +217,18 @@ SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
 		}
 
 		ptr += BUFFERALIGN(offset);
+
+		/* Create tranche and lwlocks required for slots */
+		LWLockCreateTranche(lwlocks_tranche, nslots, &lwlock_array);
+
+		/* Initialize slots */
 		for (slotno = 0; slotno < nslots; slotno++)
 		{
 			shared->page_buffer[slotno] = ptr;
 			shared->page_status[slotno] = SLRU_PAGE_EMPTY;
 			shared->page_dirty[slotno] = false;
 			shared->page_lru_count[slotno] = 0;
-			shared->buffer_locks[slotno] = LWLockAssign();
+			shared->buffer_locks[slotno] = &lwlock_array[slotno].lock;
 			ptr += BLCKSZ;
 		}
 	}
diff --git a/src/backend/access/transam/subtrans.c b/src/backend/access/transam/subtrans.c
index 6b70982..eed2fd9 100644
--- a/src/backend/access/transam/subtrans.c
+++ b/src/backend/access/transam/subtrans.c
@@ -179,7 +179,8 @@ SUBTRANSShmemInit(void)
 {
 	SubTransCtl->PagePrecedes = SubTransPagePrecedes;
 	SimpleLruInit(SubTransCtl, "SUBTRANS Ctl", NUM_SUBTRANS_BUFFERS, 0,
-				  SubtransControlLock, "pg_subtrans");
+				  SubtransControlLock, "pg_subtrans",
+				  "SubtransBufferLocks");
 	/* Override default assumption that writes should be fsync'd */
 	SubTransCtl->do_fsync = false;
 }
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f06b51d..bf79504 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -4679,11 +4679,12 @@ XLOGShmemInit(void)
 
 	XLogCtl->Insert.WALInsertLockTrancheId = LWLockNewTrancheId();
 
-	XLogCtl->Insert.WALInsertLockTranche.name = "WALInsertLocks";
+	strcpy(XLogCtl->Insert.WALInsertLockTranche.name, "WALInsertLocks");
 	XLogCtl->Insert.WALInsertLockTranche.array_base = WALInsertLocks;
 	XLogCtl->Insert.WALInsertLockTranche.array_stride = sizeof(WALInsertLockPadded);
 
-	LWLockRegisterTranche(XLogCtl->Insert.WALInsertLockTrancheId, &XLogCtl->Insert.WALInsertLockTranche);
+	LWLockRegisterTranche(XLogCtl->Insert.WALInsertLockTrancheId,
+		&XLogCtl->Insert.WALInsertLockTranche);
 	for (i = 0; i < NUM_XLOGINSERT_LOCKS; i++)
 	{
 		LWLockInitialize(&WALInsertLocks[i].l.lock,
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index c0bd6fa..c4d01be 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -623,6 +623,7 @@ CREATE VIEW pg_stat_activity AS
             S.query_start,
             S.state_change,
             S.waiting,
+            S.wait_event,
             S.state,
             S.backend_xid,
             s.backend_xmin,
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 3b71174..7b5f00e 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -469,7 +469,7 @@ AsyncShmemInit(void)
 	 */
 	AsyncCtl->PagePrecedes = asyncQueuePagePrecedes;
 	SimpleLruInit(AsyncCtl, "Async Ctl", NUM_ASYNC_BUFFERS, 0,
-				  AsyncCtlLock, "pg_notify");
+				  AsyncCtlLock, "pg_notify", "AsyncBufferLocks");
 	/* Override default assumption that writes should be fsync'd */
 	AsyncCtl->do_fsync = false;
 
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index 26d8faa..d99f833 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -36,6 +36,7 @@
 #include "tcop/tcopprot.h"
 #include "utils/memutils.h"
 #include "storage/proc.h"
+#include "pgstat.h"
 
 
 char	   *ssl_cert_file;
@@ -122,6 +123,8 @@ secure_read(Port *port, void *ptr, size_t len)
 	ssize_t		n;
 	int			waitfor;
 
+	pgstat_report_wait_start(WAIT_NETWORK, WAIT_NETWORK_READ);
+
 retry:
 #ifdef USE_SSL
 	waitfor = 0;
@@ -168,6 +171,7 @@ retry:
 	 * interrupts from being processed.
 	 */
 	ProcessClientReadInterrupt(false);
+	pgstat_report_wait_end();
 
 	return n;
 }
@@ -202,6 +206,8 @@ secure_write(Port *port, void *ptr, size_t len)
 	ssize_t		n;
 	int			waitfor;
 
+	pgstat_report_wait_start(WAIT_NETWORK, WAIT_NETWORK_WRITE);
+
 retry:
 	waitfor = 0;
 #ifdef USE_SSL
@@ -247,6 +253,7 @@ retry:
 	 * interrupts from being processed.
 	 */
 	ProcessClientWriteInterrupt(false);
+	pgstat_report_wait_end();
 
 	return n;
 }
diff --git a/src/backend/port/unix_latch.c b/src/backend/port/unix_latch.c
index 90ec4f8..dcebfe4 100644
--- a/src/backend/port/unix_latch.c
+++ b/src/backend/port/unix_latch.c
@@ -55,6 +55,7 @@
 #include "storage/latch.h"
 #include "storage/pmsignal.h"
 #include "storage/shmem.h"
+#include "pgstat.h"
 
 /* Are we currently in WaitLatch? The signal handler would like to know. */
 static volatile sig_atomic_t waiting = false;
@@ -262,6 +263,8 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
 #endif
 	}
 
+	pgstat_report_wait_start(WAIT_LATCH, 0);
+
 	waiting = true;
 	do
 	{
@@ -500,6 +503,7 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
 		}
 	} while (result == 0);
 	waiting = false;
+	pgstat_report_wait_end();
 
 	return result;
 }
diff --git a/src/backend/port/win32_latch.c b/src/backend/port/win32_latch.c
index 0e3aaee..92bb5a0 100644
--- a/src/backend/port/win32_latch.c
+++ b/src/backend/port/win32_latch.c
@@ -177,6 +177,8 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
 	/* Ensure that signals are serviced even if latch is already set */
 	pgwin32_dispatch_queued_signals();
 
+	pgstat_report_wait_start(WAIT_LATCH, 0);
+
 	do
 	{
 		/*
@@ -278,6 +280,8 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
 		}
 	} while (result == 0);
 
+	pgstat_report_wait_end();
+
 	/* Clean up the event object we created for the socket */
 	if (sockevent != WSA_INVALID_EVENT)
 	{
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index ab018c4..62ef17e 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -54,6 +54,7 @@
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
+#include "storage/lwlock.h"
 #include "storage/pg_shmem.h"
 #include "storage/procsignal.h"
 #include "storage/sinvaladt.h"
@@ -99,7 +100,6 @@
 #define PGSTAT_TAB_HASH_SIZE	512
 #define PGSTAT_FUNCTION_HASH_SIZE	512
 
-
 /* ----------
  * GUC parameters
  * ----------
@@ -242,6 +242,16 @@ static volatile bool got_SIGHUP = false;
  */
 static instr_time total_func_time;
 
+/* Names of WAIT_CLASSES */
+static const char *WAIT_CLASS_NAMES[] =
+{
+	"",
+	"LWLocks",
+	"Locks",
+	"Storage",
+	"Latch",
+	"Network"
+};
 
 /* ----------
  * Local function forward declarations
@@ -2929,6 +2939,89 @@ pgstat_report_waiting(bool waiting)
 	beentry->st_waiting = waiting;
 }
 
+/*
+ * pgstat_get_wait_class_name() -
+ *
+ * Return wait class name for given class
+ */
+
+const char *
+pgstat_get_wait_class_name(uint8 classId)
+{
+	return WAIT_CLASS_NAMES[classId];
+}
+
+/*
+ * pgstat_get_wait_event_name() -
+ *
+ * Return wait event name for the given class and event
+ */
+const char *
+pgstat_get_wait_event_name(uint8 classId, uint8 eventId)
+{
+	static const char *eventsIO[] = {"READ", "WRITE"};
+	static const char *empty = "";
+
+	switch (classId)
+	{
+		case WAIT_LOCK: return LOCK_NAMES[eventId];
+		case WAIT_LWLOCK: return LWLOCK_TRANCHE_NAME(eventId);
+		case WAIT_IO: /* fallthrough */;
+		case WAIT_NETWORK: return eventsIO[eventId];
+		case WAIT_LATCH: return WAIT_CLASS_NAMES[WAIT_LATCH];
+	};
+	return empty;
+}
+
+/* ----------
+ * pgstat_report_wait_start() -
+ *
+ *	Called from backends to report wait event type information.
+ *
+ * NB: this *must* be able to survive being called before MyBEEntry has been
+ * initialized.
+ * ----------
+ */
+void
+pgstat_report_wait_start(uint8 classId, uint8 eventId)
+{
+	volatile PgBackendStatus *beentry = MyBEEntry;
+
+	if (!pgstat_track_activities || !beentry)
+		return;
+
+	/* prevent nested waits */
+	if (beentry->st_wait_nested++ > 0)
+		return;
+
+	/*
+	 * Since this is a uint16 field in a struct that only this process
+	 * may modify, there seems no need to bother with the st_changecount
+	 * protocol.  The update must appear atomic in any case.
+	 */
+	beentry->st_wait_data = ((uint16)classId << 8) + eventId;
+}
+
+/* ----------
+ * pgstat_report_wait_end() -
+ *
+ *  Called from backends, indicates that wait was ended
+ * ---------
+ */
+void
+pgstat_report_wait_end()
+{
+	volatile PgBackendStatus *beentry = MyBEEntry;
+
+	if (!pgstat_track_activities || !beentry)
+		return;
+
+	/* prevent nested waits */
+	if ((--beentry->st_wait_nested) > 0)
+		return;
+
+	beentry->st_wait_data = 0;
+}
 
 /* ----------
  * pgstat_read_current_status() -
diff --git a/src/backend/replication/logical/origin.c b/src/backend/replication/logical/origin.c
index f4ba86e..c254a62 100644
--- a/src/backend/replication/logical/origin.c
+++ b/src/backend/replication/logical/origin.c
@@ -470,7 +470,7 @@ ReplicationOriginShmemInit(void)
 		int			i;
 
 		replication_states_ctl->tranche_id = LWLockNewTrancheId();
-		replication_states_ctl->tranche.name = "ReplicationOrigins";
+		strcpy(replication_states_ctl->tranche.name, "ReplicationOrigins");
 		replication_states_ctl->tranche.array_base =
 			&replication_states[0].lock;
 		replication_states_ctl->tranche.array_stride =
diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c
index f8544de..04b0805 100644
--- a/src/backend/replication/slot.c
+++ b/src/backend/replication/slot.c
@@ -118,6 +118,9 @@ ReplicationSlotsShmemSize(void)
 	size = add_size(size,
 					mul_size(max_replication_slots, sizeof(ReplicationSlot)));
 
+	/* size of lwlocks */
+	size = add_size(size, LWLockTrancheShmemSize(max_replication_slots));
+
 	return size;
 }
 
@@ -127,7 +130,8 @@ ReplicationSlotsShmemSize(void)
 void
 ReplicationSlotsShmemInit(void)
 {
-	bool		found;
+	bool         found;
+	LWLockPadded *lwlocks_array;
 
 	if (max_replication_slots == 0)
 		return;
@@ -143,13 +147,17 @@ ReplicationSlotsShmemInit(void)
 		/* First time through, so initialize */
 		MemSet(ReplicationSlotCtl, 0, ReplicationSlotsShmemSize());
 
+		/* Create lwlocks */
+		LWLockCreateTranche("ReplicationSlotLocks", max_replication_slots,
+			&lwlocks_array);
+
 		for (i = 0; i < max_replication_slots; i++)
 		{
 			ReplicationSlot *slot = &ReplicationSlotCtl->replication_slots[i];
 
 			/* everything else is zeroed by the memset above */
 			SpinLockInit(&slot->mutex);
-			slot->io_in_progress_lock = LWLockAssign();
+			slot->io_in_progress_lock = &lwlocks_array[i].lock;
 		}
 	}
 }
diff --git a/src/backend/storage/buffer/buf_init.c b/src/backend/storage/buffer/buf_init.c
index 3ae2848..40cf33f 100644
--- a/src/backend/storage/buffer/buf_init.c
+++ b/src/backend/storage/buffer/buf_init.c
@@ -18,8 +18,9 @@
 #include "storage/buf_internals.h"
 
 
-BufferDescPadded *BufferDescriptors;
-char	   *BufferBlocks;
+BufferDescPadded  *BufferDescriptors;
+char              *BufferBlocks;
+LWLockPadded      *BufferLWLockArray;
 
 
 /*
@@ -64,8 +65,9 @@ char	   *BufferBlocks;
 void
 InitBufferPool(void)
 {
-	bool		foundBufs,
-				foundDescs;
+	bool          foundBufs;
+	bool          foundDescs;
+	LWLockPadded *lwlocks_array;
 
 	/* Align descriptors to a cacheline boundary. */
 	BufferDescriptors = (BufferDescPadded *) CACHELINEALIGN(
@@ -77,6 +79,10 @@ InitBufferPool(void)
 		ShmemInitStruct("Buffer Blocks",
 						NBuffers * (Size) BLCKSZ, &foundBufs);
 
+	/* Init LWLocks for buffer headers */
+	LWLockCreateTranche("BufferMgrLocks", 2 * NBuffers,
+		&lwlocks_array);
+
 	if (foundDescs || foundBufs)
 	{
 		/* both should be present or neither */
@@ -110,14 +116,18 @@ InitBufferPool(void)
 			 */
 			buf->freeNext = i + 1;
 
-			buf->io_in_progress_lock = LWLockAssign();
-			buf->content_lock = LWLockAssign();
+			buf->io_in_progress_lock = &lwlocks_array[i * 2].lock;
+			buf->content_lock = &lwlocks_array[i * 2 + 1].lock;
 		}
 
 		/* Correct last entry of linked list */
 		GetBufferDescriptor(NBuffers - 1)->freeNext = FREENEXT_END_OF_LIST;
 	}
 
+	/* Init bufmgr LWLocks */
+	LWLockCreateTranche("BufferLWLocks", NUM_BUFFER_PARTITIONS,
+		&BufferLWLockArray);
+
 	/* Init other shared buffer-management stuff */
 	StrategyInitialize(!foundDescs);
 }
@@ -144,5 +154,9 @@ BufferShmemSize(void)
 	/* size of stuff controlled by freelist.c */
 	size = add_size(size, StrategyShmemSize());
 
+	/* size of LWLock structures required for buffers */
+	size = add_size(size, LWLockTrancheShmemSize(NUM_BUFFER_PARTITIONS));
+	size = add_size(size, LWLockTrancheShmemSize(2 * NBuffers));
+
 	return size;
 }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index 1eb2d4b..85e758e 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -48,12 +48,29 @@
 #include "utils/resowner_private.h"
 
 
+/* LWLocks tranche and array */
+LWLockPadded		    *LockMgrLWLockArray;
+
 /* This configuration variable is used to set the lock table size */
 int			max_locks_per_xact; /* set by guc.c */
 
 #define NLOCKENTS() \
 	mul_size(max_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
 
+/* Lock names. For monitoring purposes */
+const char *LOCK_NAMES[] =
+{
+	"Relation",
+	"RelationExtend",
+	"Page",
+	"Tuple",
+	"Transaction",
+	"VirtualTransaction",
+	"SpeculativeToken",
+	"Object",
+	"Userlock",
+	"Advisory"
+};
 
 /*
  * Data structures defining the semantics of the standard lock methods.
@@ -446,6 +463,10 @@ InitLocks(void)
 									  16,
 									  &info,
 									  HASH_ELEM | HASH_BLOBS);
+
+	/* Init LWLocks tranche and array */
+	LWLockCreateTranche("LockMgrLWLocks", NUM_LOCK_PARTITIONS,
+		&LockMgrLWLockArray);
 }
 
 
@@ -1591,6 +1612,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
 		new_status[len] = '\0'; /* truncate off " waiting" */
 	}
 	pgstat_report_waiting(true);
+	pgstat_report_wait_start(WAIT_LOCK, locallock->tag.lock.locktag_type);
 
 	awaitedLock = locallock;
 	awaitedOwner = owner;
@@ -1639,6 +1661,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
 
 		/* Report change to non-waiting status */
 		pgstat_report_waiting(false);
+		pgstat_report_wait_end();
 		if (update_process_title)
 		{
 			set_ps_display(new_status, false);
@@ -1654,6 +1677,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
 
 	/* Report change to non-waiting status */
 	pgstat_report_waiting(false);
+	pgstat_report_wait_end();
 	if (update_process_title)
 	{
 		set_ps_display(new_status, false);
@@ -3282,6 +3306,9 @@ LockShmemSize(void)
 	 */
 	size = add_size(size, size / 10);
 
+	/* Lock Manager LWLock structures */
+	size = add_size(size, LWLockTrancheShmemSize(NUM_LOCK_PARTITIONS));
+
 	return size;
 }
 
diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index 687ed63..6a665cf 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -82,6 +82,7 @@
 #include "access/subtrans.h"
 #include "commands/async.h"
 #include "miscadmin.h"
+#include "pgstat.h"
 #include "pg_trace.h"
 #include "postmaster/postmaster.h"
 #include "replication/slot.h"
@@ -110,11 +111,9 @@ extern slock_t *ShmemLock;
 #define LW_SHARED_MASK				((uint32)(1 << 23))
 
 /*
- * This is indexed by tranche ID and stores metadata for all tranches known
- * to the current backend.
+ * This is indexed by tranche ID and stores metadata for all tranches
  */
-static LWLockTranche **LWLockTrancheArray = NULL;
-static int	LWLockTranchesAllocated = 0;
+LWLockTranche **LWLockTrancheArray = NULL;
 
 #define T_NAME(lock) \
 	(LWLockTrancheArray[(lock)->tranche]->name)
@@ -129,7 +128,9 @@ static int	LWLockTranchesAllocated = 0;
  * where we have special measures to pass it down).
  */
 LWLockPadded *MainLWLockArray = NULL;
-static LWLockTranche MainLWLockTranche;
+
+/* Points to the array of user defined LWLocks in shared memory */
+static LWLockPadded *userdef_lwlocks_array;
 
 /*
  * We use this structure to keep track of locked LWLocks for release
@@ -173,6 +174,9 @@ static HTAB *lwlock_stats_htab;
 static lwlock_stats lwlock_stats_dummy;
 #endif
 
+/* Wraps pgstat_report_wait_start for LWLocks */
+static inline void lwlock_report_stat(LWLock *lock);
+
 #ifdef LOCK_DEBUG
 bool		Trace_lwlocks = false;
 
@@ -316,64 +320,66 @@ get_lwlock_stats_entry(LWLock *lock)
 }
 #endif   /* LWLOCK_STATS */
 
+#define INIT_LWLOCK_NAME(lock) \
+	strcpy(LWLockTrancheArray[T_ID(lock)]->name, #lock);
 
 /*
- * Compute number of LWLocks to allocate in the main array.
+ * Fill name in individual LWLock tranches. Must be called
+ * after tranches creation
  */
-static int
-NumLWLocks(void)
+static void
+InitLWLockNames(void)
 {
-	int			numLocks;
-
-	/*
-	 * Possibly this logic should be spread out among the affected modules,
-	 * the same way that shmem space estimation is done.  But for now, there
-	 * are few enough users of LWLocks that we can get away with just keeping
-	 * the knowledge here.
-	 */
-
-	/* Predefined LWLocks */
-	numLocks = NUM_FIXED_LWLOCKS;
-
-	/* bufmgr.c needs two for each shared buffer */
-	numLocks += 2 * NBuffers;
-
-	/* proc.c needs one for each backend or auxiliary process */
-	numLocks += MaxBackends + NUM_AUXILIARY_PROCS;
-
-	/* clog.c needs one per CLOG buffer */
-	numLocks += CLOGShmemBuffers();
-
-	/* commit_ts.c needs one per CommitTs buffer */
-	numLocks += CommitTsShmemBuffers();
-
-	/* subtrans.c needs one per SubTrans buffer */
-	numLocks += NUM_SUBTRANS_BUFFERS;
-
-	/* multixact.c needs two SLRU areas */
-	numLocks += NUM_MXACTOFFSET_BUFFERS + NUM_MXACTMEMBER_BUFFERS;
-
-	/* async.c needs one per Async buffer */
-	numLocks += NUM_ASYNC_BUFFERS;
-
-	/* predicate.c needs one per old serializable xid buffer */
-	numLocks += NUM_OLDSERXID_BUFFERS;
-
-	/* slot.c needs one for each slot */
-	numLocks += max_replication_slots;
-
-	/*
-	 * Add any requested by loadable modules; for backwards-compatibility
-	 * reasons, allocate at least NUM_USER_DEFINED_LWLOCKS of them even if
-	 * there are no explicit requests.
-	 */
-	lock_addin_request_allowed = false;
-	numLocks += Max(lock_addin_request, NUM_USER_DEFINED_LWLOCKS);
-
-	return numLocks;
+	int i;
+
+	INIT_LWLOCK_NAME(ShmemIndexLock);
+	INIT_LWLOCK_NAME(OidGenLock);
+	INIT_LWLOCK_NAME(XidGenLock);
+	INIT_LWLOCK_NAME(ProcArrayLock);
+	INIT_LWLOCK_NAME(SInvalReadLock);
+	INIT_LWLOCK_NAME(SInvalWriteLock);
+	INIT_LWLOCK_NAME(WALBufMappingLock);
+	INIT_LWLOCK_NAME(WALWriteLock);
+	INIT_LWLOCK_NAME(ControlFileLock);
+	INIT_LWLOCK_NAME(CheckpointLock);
+	INIT_LWLOCK_NAME(CLogControlLock);
+	INIT_LWLOCK_NAME(SubtransControlLock);
+	INIT_LWLOCK_NAME(MultiXactGenLock);
+	INIT_LWLOCK_NAME(MultiXactOffsetControlLock);
+	INIT_LWLOCK_NAME(MultiXactMemberControlLock);
+	INIT_LWLOCK_NAME(RelCacheInitLock);
+	INIT_LWLOCK_NAME(CheckpointerCommLock);
+	INIT_LWLOCK_NAME(TwoPhaseStateLock);
+	INIT_LWLOCK_NAME(TablespaceCreateLock);
+	INIT_LWLOCK_NAME(BtreeVacuumLock);
+	INIT_LWLOCK_NAME(AddinShmemInitLock);
+	INIT_LWLOCK_NAME(AutovacuumLock);
+	INIT_LWLOCK_NAME(AutovacuumScheduleLock);
+	INIT_LWLOCK_NAME(SyncScanLock);
+	INIT_LWLOCK_NAME(RelationMappingLock);
+	INIT_LWLOCK_NAME(AsyncCtlLock);
+	INIT_LWLOCK_NAME(AsyncQueueLock);
+	INIT_LWLOCK_NAME(SerializableXactHashLock);
+	INIT_LWLOCK_NAME(SerializableFinishedListLock);
+	INIT_LWLOCK_NAME(SerializablePredicateLockListLock);
+	INIT_LWLOCK_NAME(OldSerXidLock);
+	INIT_LWLOCK_NAME(SyncRepLock);
+	INIT_LWLOCK_NAME(BackgroundWorkerLock);
+	INIT_LWLOCK_NAME(DynamicSharedMemoryControlLock);
+	INIT_LWLOCK_NAME(AutoFileLock);
+	INIT_LWLOCK_NAME(ReplicationSlotAllocationLock);
+	INIT_LWLOCK_NAME(ReplicationSlotControlLock);
+	INIT_LWLOCK_NAME(CommitTsControlLock);
+	INIT_LWLOCK_NAME(CommitTsLock);
+	INIT_LWLOCK_NAME(ReplicationOriginLock);
+
+	/* Check that every individual LWLock has name */
+	for (i = 1; i < NUM_INDIVIDUAL_LWLOCKS; i++)
+		if (strncmp(LWLOCK_TRANCHE_NAME(i), "", 2) == 0)
+			elog(ERROR, "Individual LWLock at %d index still hasn't a name. "\
+				"It must be registered in InitLWLockNames function", i);
 }
 
-
 /*
  * RequestAddinLWLocks
  *		Request that extra LWLocks be allocated for use by
@@ -393,21 +399,59 @@ RequestAddinLWLocks(int n)
 	lock_addin_request += n;
 }
 
+/*
+ * Return number of user defined LWLocks
+ */
+static int
+NumUserDefinedLWLocks()
+{
+	/*
+	 * Add any requested by loadable modules; for backwards-compatibility
+	 * reasons, allocate at least NUM_USER_DEFINED_LWLOCKS of them even if
+	 * there are no explicit requests.
+	 */
+
+	lock_addin_request_allowed = false;
+	return Max(lock_addin_request, NUM_USER_DEFINED_LWLOCKS);
+}
+
+/*
+ * Compute shmem space for LWLock counters, individual LWLocks array
+ * and tranches
+ */
+static Size
+LWLocksIndividualShmemSize(void)
+{
+	Size		size;
+
+	/* Space for dynamic allocation counter, plus room for alignment. */
+	size = 3 * sizeof(int) + LWLOCK_PADDED_SIZE;
+
+	/* Space for individual LWLock tranches */
+	size = add_size(size,
+		mul_size(sizeof(LWLockTranche), NUM_INDIVIDUAL_LWLOCKS));
+
+	/* Space for individual LWLocks */
+	size = add_size(size,
+		mul_size(sizeof(LWLockPadded), NUM_INDIVIDUAL_LWLOCKS));
+
+	return size;
+}
 
 /*
- * Compute shmem space needed for LWLocks.
+ * Compute shmem space needed by LWLocks initialization
  */
 Size
 LWLockShmemSize(void)
 {
-	Size		size;
-	int			numLocks = NumLWLocks();
+	Size size = LWLocksIndividualShmemSize();
 
-	/* Space for the LWLock array. */
-	size = mul_size(numLocks, sizeof(LWLockPadded));
+	/* Space for tranches array */
+	size = add_size(size,
+		mul_size(sizeof(LWLockTranche **), NUM_LWLOCK_TRANCHES));
 
-	/* Space for dynamic allocation counter, plus room for alignment. */
-	size = add_size(size, 3 * sizeof(int) + LWLOCK_PADDED_SIZE);
+	/* Space for user defined lwlocks */
+	size = add_size(size, LWLockTrancheShmemSize(NumUserDefinedLWLocks()));
 
 	return size;
 }
@@ -415,7 +459,7 @@ LWLockShmemSize(void)
 
 /*
  * Allocate shmem space for the main LWLock array and initialize it.  We also
- * register the main tranch here.
+ * register the tranches for individual LWLocks here.
  */
 void
 CreateLWLocks(void)
@@ -425,12 +469,17 @@ CreateLWLocks(void)
 
 	if (!IsUnderPostmaster)
 	{
-		int			numLocks = NumLWLocks();
-		Size		spaceLocks = LWLockShmemSize();
-		LWLockPadded *lock;
-		int		   *LWLockCounter;
-		char	   *ptr;
-		int			id;
+		int           *LWLockCounter;
+		int            i;
+		char          *ptr;
+		Size           spaceLocks = LWLocksIndividualShmemSize();
+		int            numUserLocks = NumUserDefinedLWLocks();
+		LWLockTranche *tranche;
+
+
+		/* Init LWLock tranches array */
+		LWLockTrancheArray = (LWLockTranche **)ShmemAlloc(
+			mul_size(sizeof(LWLockTranche**), NUM_LWLOCK_TRANCHES));
 
 		/* Allocate space */
 		ptr = (char *) ShmemAlloc(spaceLocks);
@@ -443,35 +492,52 @@ CreateLWLocks(void)
 
 		MainLWLockArray = (LWLockPadded *) ptr;
 
-		/* Initialize all LWLocks in main array */
-		for (id = 0, lock = MainLWLockArray; id < numLocks; id++, lock++)
-			LWLockInitialize(&lock->lock, 0);
+		/* Now points to individual LWlock tranches */
+		ptr += mul_size(sizeof(LWLockPadded), NUM_INDIVIDUAL_LWLOCKS);
 
 		/*
 		 * Initialize the dynamic-allocation counters, which are stored just
 		 * before the first LWLock.  LWLockCounter[0] is the allocation
 		 * counter for lwlocks, LWLockCounter[1] is the maximum number that
-		 * can be allocated from the main array, and LWLockCounter[2] is the
-		 * allocation counter for tranches.
+		 * can be allocated from the user defined lwlocks array,
+		 * and LWLockCounter[2] is the allocation counter for tranches.
 		 */
 		LWLockCounter = (int *) ((char *) MainLWLockArray - 3 * sizeof(int));
-		LWLockCounter[0] = NUM_FIXED_LWLOCKS;
-		LWLockCounter[1] = numLocks;
-		LWLockCounter[2] = 1;	/* 0 is the main array */
-	}
+		LWLockCounter[0] = 0;
+		LWLockCounter[1] = numUserLocks;
+		LWLockCounter[2] = 0;
 
-	if (LWLockTrancheArray == NULL)
-	{
-		LWLockTranchesAllocated = 16;
-		LWLockTrancheArray = (LWLockTranche **)
-			MemoryContextAlloc(TopMemoryContext,
-						  LWLockTranchesAllocated * sizeof(LWLockTranche *));
-	}
+		tranche = (LWLockTranche *) ptr;
+
+		/* Create tranches for individual LWLocks */
+		for (i = 0; i < NUM_INDIVIDUAL_LWLOCKS; i++, tranche++)
+		{
+			int id = LWLockNewTrancheId();
+
+			/*
+			 * We need to be sure that generated id is equal to index
+			 * for individual LWLocks
+			 */
+			Assert(id == i);
+
+			tranche->array_base = MainLWLockArray;
+			tranche->array_stride = sizeof(LWLockPadded);
+			MemSet(tranche->name, 0, LWLOCK_MAX_TRANCHE_NAME);
+
+			/* Initialize individual LWLock */
+			LWLockInitialize(&MainLWLockArray[i].lock, id);
+
+			/* Register new tranche in tranches array */
+			LWLockRegisterTranche(id, tranche);
+		}
+
+		/* Fill individual LWLock names */
+		InitLWLockNames();
 
-	MainLWLockTranche.name = "main";
-	MainLWLockTranche.array_base = MainLWLockArray;
-	MainLWLockTranche.array_stride = sizeof(LWLockPadded);
-	LWLockRegisterTranche(0, &MainLWLockTranche);
+		/* Create tranche for user defined LWLocks */
+		LWLockCreateTranche("UserDefinedLocks", numUserLocks,
+			&userdef_lwlocks_array);
+	}
 }
 
 /*
@@ -506,7 +572,8 @@ LWLockAssign(void)
 		SpinLockRelease(ShmemLock);
 		elog(ERROR, "no more LWLocks available");
 	}
-	result = &MainLWLockArray[LWLockCounter[0]++].lock;
+	result = &userdef_lwlocks_array[LWLockCounter[0]++].lock;
+
 	SpinLockRelease(ShmemLock);
 	return result;
 }
@@ -525,34 +592,84 @@ LWLockNewTrancheId(void)
 	result = LWLockCounter[2]++;
 	SpinLockRelease(ShmemLock);
 
+	if (result == NUM_LWLOCK_TRANCHES)
+		elog(ERROR, "LWLock tranches count exceeded. Consider increasing"\
+			" NUM_LWLOCK_TRANCHES value.");
+
 	return result;
 }
 
 /*
- * Register a tranche ID in the lookup table for the current process.  This
- * routine will save a pointer to the tranche object passed as an argument,
- * so that object should be allocated in a backend-lifetime context
- * (TopMemoryContext, static variable, or similar).
+ * Register a tranche ID in the lookup table in shared memory.
+ * Tranche object must be allocated in shared memory previously
  */
 void
 LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche)
 {
-	Assert(LWLockTrancheArray != NULL);
+	Assert(ShmemAddrIsValid((void *)tranche));
+	LWLockTrancheArray[tranche_id] = tranche;
+}
 
-	if (tranche_id >= LWLockTranchesAllocated)
-	{
-		int			i = LWLockTranchesAllocated;
+/*
+ * LWLockCreateTranche - create new tranche for LWLockPadded based LWLocks
+ *
+ * Space for LWLocks and LWLockTranche must be already acquired in
+ * shared memory.
+ * If LWLocks are not based on LWLockPadded then backend must register
+ * tranche itself with LWLockNewTrancheId and LWLockRegisterTranche functions
+ */
+void
+LWLockCreateTranche(const char *tranche_name, int locks_count,
+	LWLockPadded **array)
+{
+	LWLockTranche *tranche;
+	int tranche_id;
 
-		while (i <= tranche_id)
-			i *= 2;
+	Assert(strlen(tranche_name) < LWLOCK_MAX_TRANCHE_NAME);
 
-		LWLockTrancheArray = (LWLockTranche **)
-			repalloc(LWLockTrancheArray,
-					 i * sizeof(LWLockTranche *));
-		LWLockTranchesAllocated = i;
-	}
+	/* Generate id for new tranche */
+	tranche_id = LWLockNewTrancheId();
 
-	LWLockTrancheArray[tranche_id] = tranche;
+	/* Allocate space in shared memory for tranche */
+	tranche = (LWLockTranche *) ShmemAlloc(sizeof(LWLockTranche));
+
+	if (tranche == NULL)
+		ereport(PANIC, (errcode(ERRCODE_OUT_OF_MEMORY),
+						errmsg("out of memory")));
+
+	/* Allocate space in shared memory for lwlocks */
+	*array = (LWLockPadded *) ShmemAlloc(
+		mul_size(sizeof(LWLockPadded), locks_count));
+
+	if (*array == NULL)
+		ereport(PANIC, (errcode(ERRCODE_OUT_OF_MEMORY),
+						errmsg("out of memory")));
+
+	/* Init tranche fields */
+	strcpy(tranche->name, tranche_name);
+	tranche->array_base = (void *)*array;
+	tranche->array_stride = sizeof(LWLockPadded);
+
+	LWLockRegisterTranche(tranche_id, tranche);
+
+	/* Initialize new LWLocks within created tranche */
+	for (int i=0; i < locks_count; i++)
+		LWLockInitialize(&(*array)[i].lock, tranche_id);
+}
+
+/*
+ * LWLockTrancheShmemSize - calculate size required in shared memory for
+ * for tranche with locks_count of LWLocks.
+ *
+ * This function used in pair with LWLockCreateTranche
+ */
+Size
+LWLockTrancheShmemSize(int locks_count)
+{
+	Size size;
+	size = MAXALIGN(sizeof(LWLockTranche));
+	size = add_size(size, mul_size(sizeof(LWLockPadded), locks_count));
+	return size;
 }
 
 /*
@@ -571,6 +688,18 @@ LWLockInitialize(LWLock *lock, int tranche_id)
 }
 
 /*
+ * Report wait event for light-weight locks.
+ *
+ * This function will be used by all the light-weight lock calls which
+ * needs to wait to acquire the lock.
+ */
+static inline void
+lwlock_report_stat(LWLock *lock)
+{
+	pgstat_report_wait_start(WAIT_LWLOCK, lock->tranche);
+}
+
+/*
  * Internal function that tries to atomically acquire the lwlock in the passed
  * in mode.
  *
@@ -1021,6 +1150,9 @@ LWLockAcquire(LWLock *lock, LWLockMode mode)
 
 		TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode);
 
+		/* Report the wait */
+		lwlock_report_stat(lock);
+
 		for (;;)
 		{
 			PGSemaphoreLock(&proc->sem);
@@ -1041,6 +1173,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode)
 		}
 #endif
 
+		pgstat_report_wait_end();
 		TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode);
 
 		LOG_LWDEBUG("LWLockAcquire", lock, "awakened");
@@ -1179,6 +1312,9 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
 #endif
 			TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode);
 
+			/* Report the wait */
+			lwlock_report_stat(lock);
+
 			for (;;)
 			{
 				PGSemaphoreLock(&proc->sem);
@@ -1195,6 +1331,8 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode)
 				Assert(nwaiters < MAX_BACKENDS);
 			}
 #endif
+
+			pgstat_report_wait_end();
 			TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode);
 
 			LOG_LWDEBUG("LWLockAcquireOrWait", lock, "awakened");
@@ -1404,6 +1542,9 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
 		TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock),
 										   LW_EXCLUSIVE);
 
+		/* Report the wait */
+		lwlock_report_stat(lock);
+
 		for (;;)
 		{
 			PGSemaphoreLock(&proc->sem);
@@ -1421,6 +1562,7 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval)
 		}
 #endif
 
+		pgstat_report_wait_end();
 		TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock),
 										  LW_EXCLUSIVE);
 
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index bad5618..af4bb25 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -239,13 +239,20 @@
  * apply one of these macros.
  * NB: NUM_PREDICATELOCK_PARTITIONS must be a power of 2!
  */
+
+/* Number of partitions the shared predicate lock tables are divided into */
+#define LOG2_NUM_PREDICATELOCK_PARTITIONS  4
+#define NUM_PREDICATELOCK_PARTITIONS  (1 << LOG2_NUM_PREDICATELOCK_PARTITIONS)
+
+/* LWLocks tranche and array */
+static LWLockPadded		*PredLWLockArray;
+
 #define PredicateLockHashPartition(hashcode) \
 	((hashcode) % NUM_PREDICATELOCK_PARTITIONS)
 #define PredicateLockHashPartitionLock(hashcode) \
-	(&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + \
-		PredicateLockHashPartition(hashcode)].lock)
+	(&PredLWLockArray[PredicateLockHashPartition(hashcode)].lock)
 #define PredicateLockHashPartitionLockByIndex(i) \
-	(&MainLWLockArray[PREDICATELOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
+	(&PredLWLockArray[i].lock)
 
 #define NPREDICATELOCKTARGETENTS() \
 	mul_size(max_predicate_locks_per_xact, add_size(MaxBackends, max_prepared_xacts))
@@ -395,6 +402,8 @@ static LWLock *ScratchPartitionLock;
  */
 static HTAB *LocalPredicateLockHash = NULL;
 
+
+
 /*
  * Keep a pointer to the currently-running serializable transaction (if any)
  * for quick reference. Also, remember if we have written anything that could
@@ -795,7 +804,8 @@ OldSerXidInit(void)
 	 */
 	OldSerXidSlruCtl->PagePrecedes = OldSerXidPagePrecedesLogically;
 	SimpleLruInit(OldSerXidSlruCtl, "OldSerXid SLRU Ctl",
-				  NUM_OLDSERXID_BUFFERS, 0, OldSerXidLock, "pg_serial");
+				  NUM_OLDSERXID_BUFFERS, 0, OldSerXidLock, "pg_serial",
+				  "OldSerXidBufferLocks");
 	/* Override default assumption that writes should be fsync'd */
 	OldSerXidSlruCtl->do_fsync = false;
 
@@ -1289,6 +1299,9 @@ InitPredicateLocks(void)
 	/* Pre-calculate the hash and partition lock of the scratch entry */
 	ScratchTargetTagHash = PredicateLockTargetTagHashCode(&ScratchTargetTag);
 	ScratchPartitionLock = PredicateLockHashPartitionLock(ScratchTargetTagHash);
+
+	LWLockCreateTranche("PredicateLWLocks", NUM_PREDICATELOCK_PARTITIONS,
+		&PredLWLockArray);
 }
 
 /*
@@ -1340,6 +1353,9 @@ PredicateLockShmemSize(void)
 	size = add_size(size, sizeof(OldSerXidControlData));
 	size = add_size(size, SimpleLruShmemSize(NUM_OLDSERXID_BUFFERS, 0));
 
+	/* LWLocks */
+	size = add_size(size, LWLockTrancheShmemSize(NUM_PREDICATELOCK_PARTITIONS));
+
 	return size;
 }
 
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 884e91b..a0b4170 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -114,6 +114,10 @@ ProcGlobalShmemSize(void)
 	size = add_size(size, mul_size(NUM_AUXILIARY_PROCS, sizeof(PGXACT)));
 	size = add_size(size, mul_size(max_prepared_xacts, sizeof(PGXACT)));
 
+	/* LWLocks */
+	size = add_size(size,
+		LWLockTrancheShmemSize(MaxBackends + NUM_AUXILIARY_PROCS));
+
 	return size;
 }
 
@@ -157,12 +161,13 @@ ProcGlobalSemas(void)
 void
 InitProcGlobal(void)
 {
-	PGPROC	   *procs;
-	PGXACT	   *pgxacts;
-	int			i,
-				j;
-	bool		found;
-	uint32		TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS + max_prepared_xacts;
+	PGPROC       *procs;
+	PGXACT       *pgxacts;
+	LWLockPadded *lwlocks_array;
+	int           i, j;
+	bool          found;
+	uint32        TotalProcs = MaxBackends + NUM_AUXILIARY_PROCS
+		+ max_prepared_xacts;
 
 	/* Create the ProcGlobal shared structure */
 	ProcGlobal = (PROC_HDR *)
@@ -212,6 +217,10 @@ InitProcGlobal(void)
 	MemSet(pgxacts, 0, TotalProcs * sizeof(PGXACT));
 	ProcGlobal->allPgXact = pgxacts;
 
+	/* Create LWLocks */
+	LWLockCreateTranche("ProcessLocks", MaxBackends + NUM_AUXILIARY_PROCS,
+		&lwlocks_array);
+
 	for (i = 0; i < TotalProcs; i++)
 	{
 		/* Common initialization for all PGPROCs, regardless of type. */
@@ -225,7 +234,7 @@ InitProcGlobal(void)
 		{
 			PGSemaphoreCreate(&(procs[i].sem));
 			InitSharedLatch(&(procs[i].procLatch));
-			procs[i].backendLock = LWLockAssign();
+			procs[i].backendLock = &lwlocks_array[i].lock;
 		}
 		procs[i].pgprocno = i;
 
diff --git a/src/backend/storage/smgr/md.c b/src/backend/storage/smgr/md.c
index 42a43bb..71661d3 100644
--- a/src/backend/storage/smgr/md.c
+++ b/src/backend/storage/smgr/md.c
@@ -37,6 +37,7 @@
 #include "utils/hsearch.h"
 #include "utils/memutils.h"
 #include "pg_trace.h"
+#include "pgstat.h"
 
 
 /* intervals for calling AbsorbFsyncRequests in mdsync and mdpostckpt */
@@ -674,6 +675,8 @@ mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 	int			nbytes;
 	MdfdVec    *v;
 
+	pgstat_report_wait_start(WAIT_IO, WAIT_IO_READ);
+
 	TRACE_POSTGRESQL_SMGR_MD_READ_START(forknum, blocknum,
 										reln->smgr_rnode.node.spcNode,
 										reln->smgr_rnode.node.dbNode,
@@ -702,6 +705,8 @@ mdread(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 									   nbytes,
 									   BLCKSZ);
 
+	pgstat_report_wait_end();
+
 	if (nbytes != BLCKSZ)
 	{
 		if (nbytes < 0)
@@ -749,6 +754,8 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 	Assert(blocknum < mdnblocks(reln, forknum));
 #endif
 
+	pgstat_report_wait_start(WAIT_IO, WAIT_IO_WRITE);
+
 	TRACE_POSTGRESQL_SMGR_MD_WRITE_START(forknum, blocknum,
 										 reln->smgr_rnode.node.spcNode,
 										 reln->smgr_rnode.node.dbNode,
@@ -777,6 +784,8 @@ mdwrite(SMgrRelation reln, ForkNumber forknum, BlockNumber blocknum,
 										nbytes,
 										BLCKSZ);
 
+	pgstat_report_wait_end();
+
 	if (nbytes != BLCKSZ)
 	{
 		if (nbytes < 0)
diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c
index f7c9bf6..bb67850 100644
--- a/src/backend/utils/adt/pgstatfuncs.c
+++ b/src/backend/utils/adt/pgstatfuncs.c
@@ -530,7 +530,7 @@ pg_stat_get_backend_idset(PG_FUNCTION_ARGS)
 Datum
 pg_stat_get_activity(PG_FUNCTION_ARGS)
 {
-#define PG_STAT_GET_ACTIVITY_COLS	22
+#define PG_STAT_GET_ACTIVITY_COLS	23
 	int			num_backends = pgstat_fetch_stat_numbackends();
 	int			curr_backend;
 	int			pid = PG_ARGISNULL(0) ? -1 : PG_GETARG_INT32(0);
@@ -617,28 +617,28 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			nulls[3] = true;
 
 		if (TransactionIdIsValid(local_beentry->backend_xid))
-			values[14] = TransactionIdGetDatum(local_beentry->backend_xid);
+			values[15] = TransactionIdGetDatum(local_beentry->backend_xid);
 		else
-			nulls[14] = true;
+			nulls[15] = true;
 
 		if (TransactionIdIsValid(local_beentry->backend_xmin))
-			values[15] = TransactionIdGetDatum(local_beentry->backend_xmin);
+			values[16] = TransactionIdGetDatum(local_beentry->backend_xmin);
 		else
-			nulls[15] = true;
+			nulls[16] = true;
 
 		if (beentry->st_ssl)
 		{
-			values[16] = BoolGetDatum(true);	/* ssl */
-			values[17] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
-			values[18] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
-			values[19] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
-			values[20] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
-			values[21] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
+			values[17] = BoolGetDatum(true);	/* ssl */
+			values[18] = CStringGetTextDatum(beentry->st_sslstatus->ssl_version);
+			values[19] = CStringGetTextDatum(beentry->st_sslstatus->ssl_cipher);
+			values[20] = Int32GetDatum(beentry->st_sslstatus->ssl_bits);
+			values[21] = BoolGetDatum(beentry->st_sslstatus->ssl_compression);
+			values[22] = CStringGetTextDatum(beentry->st_sslstatus->ssl_clientdn);
 		}
 		else
 		{
-			values[16] = BoolGetDatum(false);	/* ssl */
-			nulls[17] = nulls[18] = nulls[19] = nulls[20] = nulls[21] = true;
+			values[17] = BoolGetDatum(false);	/* ssl */
+			nulls[18] = nulls[19] = nulls[20] = nulls[21] = nulls[22] = true;
 		}
 
 		/* Values only available to role member */
@@ -674,34 +674,58 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			values[5] = CStringGetTextDatum(beentry->st_activity);
 			values[6] = BoolGetDatum(beentry->st_waiting);
 
-			if (beentry->st_xact_start_timestamp != 0)
-				values[7] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
+			if (beentry->st_wait_data > 0)
+			{
+				/*
+				 * Reassigning of value is important, because st_wait_data
+				 * can change if we read class and event separately
+				 */
+
+				uint16 wait_data = beentry->st_wait_data;
+				uint8 classId = (uint8)(wait_data >> 8);
+				uint8 eventId = (uint8)wait_data;
+				const char *class_name = pgstat_get_wait_class_name(classId);
+				const char *event_name = pgstat_get_wait_event_name(classId,
+					eventId);
+
+				int size = strlen(class_name) + strlen(event_name) + 3;
+				char *wait_name = (char *)palloc(size);
+				snprintf(wait_name, size, "%s: %s", class_name, event_name);
+
+				values[7] = CStringGetTextDatum(wait_name);
+				pfree(wait_name);
+			}
 			else
 				nulls[7] = true;
 
-			if (beentry->st_activity_start_timestamp != 0)
-				values[8] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
+			if (beentry->st_xact_start_timestamp != 0)
+				values[8] = TimestampTzGetDatum(beentry->st_xact_start_timestamp);
 			else
 				nulls[8] = true;
 
-			if (beentry->st_proc_start_timestamp != 0)
-				values[9] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
+			if (beentry->st_activity_start_timestamp != 0)
+				values[9] = TimestampTzGetDatum(beentry->st_activity_start_timestamp);
 			else
 				nulls[9] = true;
 
-			if (beentry->st_state_start_timestamp != 0)
-				values[10] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
+			if (beentry->st_proc_start_timestamp != 0)
+				values[10] = TimestampTzGetDatum(beentry->st_proc_start_timestamp);
 			else
 				nulls[10] = true;
 
+			if (beentry->st_state_start_timestamp != 0)
+				values[11] = TimestampTzGetDatum(beentry->st_state_start_timestamp);
+			else
+				nulls[11] = true;
+
 			/* A zeroed client addr means we don't know */
 			memset(&zero_clientaddr, 0, sizeof(zero_clientaddr));
 			if (memcmp(&(beentry->st_clientaddr), &zero_clientaddr,
 					   sizeof(zero_clientaddr)) == 0)
 			{
-				nulls[11] = true;
 				nulls[12] = true;
 				nulls[13] = true;
+				nulls[14] = true;
 			}
 			else
 			{
@@ -725,20 +749,20 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					if (ret == 0)
 					{
 						clean_ipv6_addr(beentry->st_clientaddr.addr.ss_family, remote_host);
-						values[11] = DirectFunctionCall1(inet_in,
+						values[12] = DirectFunctionCall1(inet_in,
 											   CStringGetDatum(remote_host));
 						if (beentry->st_clienthostname &&
 							beentry->st_clienthostname[0])
-							values[12] = CStringGetTextDatum(beentry->st_clienthostname);
+							values[13] = CStringGetTextDatum(beentry->st_clienthostname);
 						else
-							nulls[12] = true;
-						values[13] = Int32GetDatum(atoi(remote_port));
+							nulls[13] = true;
+						values[14] = Int32GetDatum(atoi(remote_port));
 					}
 					else
 					{
-						nulls[11] = true;
 						nulls[12] = true;
 						nulls[13] = true;
+						nulls[14] = true;
 					}
 				}
 				else if (beentry->st_clientaddr.addr.ss_family == AF_UNIX)
@@ -749,16 +773,16 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 					 * connections we have no permissions to view, or with
 					 * errors.
 					 */
-					nulls[11] = true;
 					nulls[12] = true;
-					values[13] = DatumGetInt32(-1);
+					nulls[13] = true;
+					values[14] = DatumGetInt32(-1);
 				}
 				else
 				{
 					/* Unknown address type, should never happen */
-					nulls[11] = true;
 					nulls[12] = true;
 					nulls[13] = true;
+					nulls[14] = true;
 				}
 			}
 		}
@@ -775,6 +799,7 @@ pg_stat_get_activity(PG_FUNCTION_ARGS)
 			nulls[11] = true;
 			nulls[12] = true;
 			nulls[13] = true;
+			nulls[14] = true;
 		}
 
 		tuplestore_putvalues(tupstore, tupdesc, values, nulls);
diff --git a/src/include/access/slru.h b/src/include/access/slru.h
index 9c7f019..d9e9582 100644
--- a/src/include/access/slru.h
+++ b/src/include/access/slru.h
@@ -136,7 +136,8 @@ typedef SlruCtlData *SlruCtl;
 
 extern Size SimpleLruShmemSize(int nslots, int nlsns);
 extern void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns,
-			  LWLock *ctllock, const char *subdir);
+			  LWLock *ctllock, const char *subdir,
+			  const char *lwlocks_tranche);
 extern int	SimpleLruZeroPage(SlruCtl ctl, int pageno);
 extern int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok,
 				  TransactionId xid);
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c9fe0f8..c08e69a 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -2777,7 +2777,7 @@ DATA(insert OID = 3057 ( pg_stat_get_autoanalyze_count PGNSP PGUID 12 1 0 0 0 f
 DESCR("statistics: number of auto analyzes for a table");
 DATA(insert OID = 1936 (  pg_stat_get_backend_idset		PGNSP PGUID 12 1 100 0 0 f f f f t t s 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_stat_get_backend_idset _null_ _null_ _null_ ));
 DESCR("statistics: currently active backend IDs");
-DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,25,16,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
+DATA(insert OID = 2022 (  pg_stat_get_activity			PGNSP PGUID 12 1 100 0 0 f f f f f t s 1 0 2249 "23" "{23,26,23,26,25,25,25,16,25,1184,1184,1184,1184,869,25,23,28,28,16,25,25,23,16,25}" "{i,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}" "{pid,datid,pid,usesysid,application_name,state,query,waiting,wait_event,xact_start,query_start,backend_start,state_change,client_addr,client_hostname,client_port,backend_xid,backend_xmin,ssl,sslversion,sslcipher,sslbits,sslcompression,sslclientdn}" _null_ _null_ pg_stat_get_activity _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active backends");
 DATA(insert OID = 3099 (  pg_stat_get_wal_senders	PGNSP PGUID 12 1 10 0 0 f f f f f t s 0 0 2249 "" "{23,25,3220,3220,3220,3220,23,25}" "{o,o,o,o,o,o,o,o}" "{pid,state,sent_location,write_location,flush_location,replay_location,sync_priority,sync_state}" _null_ _null_ pg_stat_get_wal_senders _null_ _null_ _null_ ));
 DESCR("statistics: information about currently active replication");
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 9ecc163..a73e047 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -67,6 +67,33 @@ typedef enum StatMsgType
 } StatMsgType;
 
 /* ----------
+ * Wait definitions
+ * ----------
+ */
+
+typedef enum WAIT_CLASSES
+{
+	WAIT_UNDEFINED,
+	WAIT_LWLOCK,
+	WAIT_LOCK,
+	WAIT_IO,
+	WAIT_LATCH,
+	WAIT_NETWORK
+} WAIT_CLASSES;
+
+typedef enum WAIT_EVENTS_IO
+{
+	WAIT_IO_READ,
+	WAIT_IO_WRITE
+} WAIT_EVENTS_IO;
+
+typedef enum WAIT_EVENTS_NETWORK
+{
+	WAIT_NETWORK_READ,
+	WAIT_NETWORK_WRITE
+} WAIT_EVENT_NETWORK;
+
+/* ----------
  * The data type used for counters.
  * ----------
  */
@@ -768,6 +795,14 @@ typedef struct PgBackendStatus
 	/* Is backend currently waiting on an lmgr lock? */
 	bool		st_waiting;
 
+	/* Contains class end event of wait. It's in one
+	 * variable because we need read it atomically
+	 */
+	volatile uint16 st_wait_data;
+
+	/* keep track of nested waits, and skip them */
+	int             st_wait_nested;
+
 	/* current state */
 	BackendState st_state;
 
@@ -932,6 +967,12 @@ extern void pgstat_report_tempfile(size_t filesize);
 extern void pgstat_report_appname(const char *appname);
 extern void pgstat_report_xact_timestamp(TimestampTz tstamp);
 extern void pgstat_report_waiting(bool waiting);
+
+extern void pgstat_report_wait_start(uint8 classId, uint8 eventId);
+extern void pgstat_report_wait_end(void);
+extern const char *pgstat_get_wait_class_name(uint8 classId);
+extern const char *pgstat_get_wait_event_name(uint8 classId, uint8 eventId);
+
 extern const char *pgstat_get_backend_current_activity(int pid, bool checkUser);
 extern const char *pgstat_get_crashed_backend_activity(int pid, char *buffer,
 									int buflen);
diff --git a/src/include/storage/buf_internals.h b/src/include/storage/buf_internals.h
index 521ee1c..1c50d68 100644
--- a/src/include/storage/buf_internals.h
+++ b/src/include/storage/buf_internals.h
@@ -53,6 +53,10 @@ typedef bits16 BufFlags;
  */
 #define BM_MAX_USAGE_COUNT	5
 
+/* Number of partitions of the shared buffer mapping hashtable */
+#define NUM_BUFFER_PARTITIONS  128
+
+
 /*
  * Buffer tag identifies which disk block the buffer contains.
  *
@@ -104,10 +108,8 @@ typedef struct buftag
 #define BufTableHashPartition(hashcode) \
 	((hashcode) % NUM_BUFFER_PARTITIONS)
 #define BufMappingPartitionLock(hashcode) \
-	(&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + \
-		BufTableHashPartition(hashcode)].lock)
-#define BufMappingPartitionLockByIndex(i) \
-	(&MainLWLockArray[BUFFER_MAPPING_LWLOCK_OFFSET + (i)].lock)
+	(&BufferLWLockArray[BufTableHashPartition(hashcode)].lock)
+#define BufMappingPartitionLockByIndex(i) (&BufferLWLockArray[i].lock)
 
 /*
  *	BufferDesc -- shared descriptor/state data for a single shared buffer.
@@ -206,6 +208,7 @@ typedef union BufferDescPadded
 
 /* in buf_init.c */
 extern PGDLLIMPORT BufferDescPadded *BufferDescriptors;
+extern PGDLLIMPORT LWLockPadded *BufferLWLockArray;
 
 /* in localbuf.c */
 extern BufferDesc *LocalBufferDescriptors;
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 96fe3a6..b357c2d 100644
--- a/src/include/storage/lock.h
+++ b/src/include/storage/lock.h
@@ -39,6 +39,9 @@ extern int	Trace_lock_table;
 extern bool Debug_deadlocks;
 #endif   /* LOCK_DEBUG */
 
+/* Contains names of all heavyweight locks */
+extern PGDLLIMPORT const char *LOCK_NAMES[];
+
 
 /*
  * Top-level transactions are identified by VirtualTransactionIDs comprising
@@ -490,13 +493,19 @@ typedef enum
  * hash code with LockTagHashCode(), then apply one of these macros.
  * NB: NUM_LOCK_PARTITIONS must be a power of 2!
  */
+
+/* Number of partitions the shared lock tables are divided into */
+#define LOG2_NUM_LOCK_PARTITIONS  4
+#define NUM_LOCK_PARTITIONS  (1 << LOG2_NUM_LOCK_PARTITIONS)
+
+extern PGDLLIMPORT LWLockPadded *LockMgrLWLockArray;
+
 #define LockHashPartition(hashcode) \
 	((hashcode) % NUM_LOCK_PARTITIONS)
 #define LockHashPartitionLock(hashcode) \
-	(&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + \
-		LockHashPartition(hashcode)].lock)
+	(&LockMgrLWLockArray[LockHashPartition(hashcode)].lock)
 #define LockHashPartitionLockByIndex(i) \
-	(&MainLWLockArray[LOCK_MANAGER_LWLOCK_OFFSET + (i)].lock)
+	(&LockMgrLWLockArray[i].lock)
 
 /*
  * function prototypes
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index cbd6318..e2211ed 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -33,13 +33,22 @@ struct PGPROC;
  * be an array of lwlocks, but rather some larger data structure that includes
  * one or more lwlocks per element.
  */
+
+#define NUM_LWLOCK_TRANCHES 64
+#define LWLOCK_MAX_TRANCHE_NAME 64
+
 typedef struct LWLockTranche
 {
-	const char *name;
+	char name[LWLOCK_MAX_TRANCHE_NAME];
 	void	   *array_base;
 	Size		array_stride;
 } LWLockTranche;
 
+extern PGDLLIMPORT LWLockTranche **LWLockTrancheArray;
+
+#define LWLOCK_TRANCHE_NAME(tranche_id) \
+	(LWLockTrancheArray[tranche_id]->name)
+
 /*
  * Code outside of lwlock.c should not manipulate the contents of this
  * structure directly, but we have to declare it here to allow LWLocks to be
@@ -85,6 +94,7 @@ typedef union LWLockPadded
 	LWLock		lock;
 	char		pad[LWLOCK_PADDED_SIZE];
 } LWLockPadded;
+
 extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
 
 /*
@@ -92,7 +102,8 @@ extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
  * defining macros here makes it much easier to keep track of these.  If you
  * add a lock, add it to the end to avoid renumbering the existing locks;
  * if you remove a lock, consider leaving a gap in the numbering sequence for
- * the benefit of DTrace and other external debugging scripts.
+ * the benefit of DTrace and other external debugging scripts; names for
+ * individual locks keeped in corresponding array, don't forget add it
  */
 /* 0 is available; was formerly BufFreelistLock */
 #define ShmemIndexLock				(&MainLWLockArray[1].lock)
@@ -138,32 +149,6 @@ extern PGDLLIMPORT LWLockPadded *MainLWLockArray;
 
 #define NUM_INDIVIDUAL_LWLOCKS		41
 
-/*
- * It's a bit odd to declare NUM_BUFFER_PARTITIONS and NUM_LOCK_PARTITIONS
- * here, but we need them to figure out offsets within MainLWLockArray, and
- * having this file include lock.h or bufmgr.h would be backwards.
- */
-
-/* Number of partitions of the shared buffer mapping hashtable */
-#define NUM_BUFFER_PARTITIONS  128
-
-/* Number of partitions the shared lock tables are divided into */
-#define LOG2_NUM_LOCK_PARTITIONS  4
-#define NUM_LOCK_PARTITIONS  (1 << LOG2_NUM_LOCK_PARTITIONS)
-
-/* Number of partitions the shared predicate lock tables are divided into */
-#define LOG2_NUM_PREDICATELOCK_PARTITIONS  4
-#define NUM_PREDICATELOCK_PARTITIONS  (1 << LOG2_NUM_PREDICATELOCK_PARTITIONS)
-
-/* Offsets for various chunks of preallocated lwlocks. */
-#define BUFFER_MAPPING_LWLOCK_OFFSET	NUM_INDIVIDUAL_LWLOCKS
-#define LOCK_MANAGER_LWLOCK_OFFSET		\
-	(BUFFER_MAPPING_LWLOCK_OFFSET + NUM_BUFFER_PARTITIONS)
-#define PREDICATELOCK_MANAGER_LWLOCK_OFFSET \
-	(LOCK_MANAGER_LWLOCK_OFFSET + NUM_LOCK_PARTITIONS)
-#define NUM_FIXED_LWLOCKS \
-	(PREDICATELOCK_MANAGER_LWLOCK_OFFSET + NUM_PREDICATELOCK_PARTITIONS)
-
 typedef enum LWLockMode
 {
 	LW_EXCLUSIVE,
@@ -173,7 +158,6 @@ typedef enum LWLockMode
 								 * to be used as LWLockAcquire argument */
 } LWLockMode;
 
-
 #ifdef LOCK_DEBUG
 extern bool Trace_lwlocks;
 #endif
@@ -218,6 +202,9 @@ extern LWLock *LWLockAssign(void);
 extern int	LWLockNewTrancheId(void);
 extern void LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche);
 extern void LWLockInitialize(LWLock *lock, int tranche_id);
+extern void LWLockCreateTranche(const char *tranche_name, int locks_count,
+	LWLockPadded **array);
+extern Size LWLockTrancheShmemSize(int locks_count);
 
 /*
  * Prior to PostgreSQL 9.4, we used an enum type called LWLockId to refer
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 6206c81..7fda57d 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1647,12 +1647,13 @@ pg_stat_activity| SELECT s.datid,
     s.query_start,
     s.state_change,
     s.waiting,
+    s.wait_event,
     s.state,
     s.backend_xid,
     s.backend_xmin,
     s.query
    FROM pg_database d,
-    pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn),
+    pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn),
     pg_authid u
   WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
 pg_stat_all_indexes| SELECT c.oid AS relid,
@@ -1758,7 +1759,7 @@ pg_stat_replication| SELECT s.pid,
     w.replay_location,
     w.sync_priority,
     w.sync_state
-   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn),
+   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn),
     pg_authid u,
     pg_stat_get_wal_senders() w(pid, state, sent_location, write_location, flush_location, replay_location, sync_priority, sync_state)
   WHERE ((s.usesysid = u.oid) AND (s.pid = w.pid));
@@ -1769,7 +1770,7 @@ pg_stat_ssl| SELECT s.pid,
     s.sslbits AS bits,
     s.sslcompression AS compression,
     s.sslclientdn AS clientdn
-   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
+   FROM pg_stat_get_activity(NULL::integer) s(datid, pid, usesysid, application_name, state, query, waiting, wait_event, xact_start, query_start, backend_start, state_change, client_addr, client_hostname, client_port, backend_xid, backend_xmin, ssl, sslversion, sslcipher, sslbits, sslcompression, sslclientdn);
 pg_stat_sys_indexes| SELECT pg_stat_all_indexes.relid,
     pg_stat_all_indexes.indexrelid,
     pg_stat_all_indexes.schemaname,
