>From 6f03263910713b66af548b86389ce842cb048caa Mon Sep 17 00:00:00 2001
From: Jesper Pedersen <jesper.pedersen@redhat.com>
Date: Fri, 11 Dec 2015 05:52:29 -0500
Subject: [PATCH] Additional LWLOCK_STATS statistics

---
 src/backend/storage/lmgr/lwlock.c | 83 ++++++++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 6 deletions(-)

diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index d43fb61..50d8465 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -158,10 +158,13 @@ typedef struct lwlock_stats
 {
 	lwlock_stats_key key;
 	int			sh_acquire_count;
+	int			sh_acquire_max;
 	int			ex_acquire_count;
+	int			ex_acquire_max;
 	int			block_count;
 	int			dequeue_self_count;
 	int			spin_delay_count;
+	int			max_waiters;
 }	lwlock_stats;
 
 static HTAB *lwlock_stats_htab;
@@ -292,12 +295,26 @@ print_lwlock_stats(int code, Datum arg)
 
 	while ((lwstats = (lwlock_stats *) hash_seq_search(&scan)) != NULL)
 	{
-		fprintf(stderr,
-				"PID %d lwlock %s %d: shacq %u exacq %u blk %u spindelay %u dequeue self %u\n",
-				MyProcPid, LWLockTrancheArray[lwstats->key.tranche]->name,
-				lwstats->key.instance, lwstats->sh_acquire_count,
-				lwstats->ex_acquire_count, lwstats->block_count,
-				lwstats->spin_delay_count, lwstats->dequeue_self_count);
+		if (lwstats->key.tranche == 0 && lwstats->key.instance < NUM_INDIVIDUAL_LWLOCKS)
+		{
+			/* We ignore information from MainLWLockArray[0] since it isn't in real use */
+			if (lwstats->key.instance != 0)
+				fprintf(stderr,
+						"PID %d lwlock %s: shacq %u shmax %u exacq %u exmax %u blk %u spindelay %u dequeue self %u maxw %u\n",
+						MyProcPid, MainLWLockNames[lwstats->key.instance],
+						lwstats->sh_acquire_count, lwstats->sh_acquire_max,
+						lwstats->ex_acquire_count, lwstats->ex_acquire_max,
+						lwstats->block_count, lwstats->spin_delay_count, lwstats->dequeue_self_count,
+						lwstats->max_waiters);
+		}
+		else
+			fprintf(stderr,
+					"PID %d lwlock %s %d: shacq %u shmax %u exacq %u exmax %u blk %u spindelay %u dequeue self %u maxw %u\n",
+					MyProcPid, LWLockTrancheArray[lwstats->key.tranche]->name,
+					lwstats->key.instance, lwstats->sh_acquire_count, lwstats->sh_acquire_max,
+					lwstats->ex_acquire_count, lwstats->ex_acquire_max,
+					lwstats->block_count, lwstats->spin_delay_count, lwstats->dequeue_self_count,
+					lwstats->max_waiters);
 	}
 
 	LWLockRelease(&MainLWLockArray[0].lock);
@@ -325,10 +342,13 @@ get_lwlock_stats_entry(LWLock *lock)
 	if (!found)
 	{
 		lwstats->sh_acquire_count = 0;
+		lwstats->sh_acquire_max = 0;
 		lwstats->ex_acquire_count = 0;
+		lwstats->ex_acquire_max = 0;
 		lwstats->block_count = 0;
 		lwstats->dequeue_self_count = 0;
 		lwstats->spin_delay_count = 0;
+		lwstats->max_waiters = 0;
 	}
 	return lwstats;
 }
@@ -753,6 +773,9 @@ static void
 LWLockQueueSelf(LWLock *lock, LWLockMode mode)
 {
 #ifdef LWLOCK_STATS
+	bool include;
+	int counter, size;
+	dlist_iter iter;
 	lwlock_stats *lwstats;
 
 	lwstats = get_lwlock_stats_entry(lock);
@@ -771,6 +794,46 @@ LWLockQueueSelf(LWLock *lock, LWLockMode mode)
 
 #ifdef LWLOCK_STATS
 	lwstats->spin_delay_count += SpinLockAcquire(&lock->mutex);
+
+	/*
+	 * We scan the list of waiters from the back in order to find
+	 * out how many of the same lock type are waiting for a lock.
+	 * Similar types have the potential to be groupped together.
+	 *
+	 * We also count the number of waiters, including ourself.
+	 */
+	include = true;
+	size = 1;
+	counter = 1;
+
+	dlist_reverse_foreach(iter, &lock->waiters)
+	{
+		if (include)
+		{
+			PGPROC	   *waiter = dlist_container(PGPROC, lwWaitLink, iter.cur);
+
+			if (waiter->lwWaitMode == mode)
+				counter += 1;
+			else
+				include = false;
+		}
+		
+		size += 1;
+	}
+
+	if (mode == LW_EXCLUSIVE || mode == LW_WAIT_UNTIL_FREE)
+	{
+		if (counter > lwstats->ex_acquire_max)
+			lwstats->ex_acquire_max = counter;
+	}
+	else if (mode == LW_SHARED)
+	{
+		if (counter > lwstats->sh_acquire_max)
+			lwstats->sh_acquire_max = counter;
+	}
+
+	if (size > lwstats->max_waiters)
+		lwstats->max_waiters = size;
 #else
 	SpinLockAcquire(&lock->mutex);
 #endif
@@ -922,9 +985,17 @@ LWLockAcquire(LWLock *lock, LWLockMode mode)
 #ifdef LWLOCK_STATS
 	/* Count lock acquisition attempts */
 	if (mode == LW_EXCLUSIVE)
+	{
 		lwstats->ex_acquire_count++;
+		if (lwstats->ex_acquire_max == 0)
+			lwstats->ex_acquire_max = 1;
+	}
 	else
+	{
 		lwstats->sh_acquire_count++;
+		if (lwstats->sh_acquire_max == 0)
+			lwstats->sh_acquire_max = 1;
+	}
 #endif   /* LWLOCK_STATS */
 
 	/*
-- 
2.1.0

