From b5498a26deba8d3112dbf4da5375ccd9db4ff375 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Fri, 21 Apr 2006 16:45:12 +0000
Subject: [PATCH] Add some optional code (conditionally compiled under #ifdef
 LWLOCK_STATS) to track the number of LWLock acquisitions and the number of
 times we block waiting for an LWLock, on a per-process basis.  After having
 needed this twice in the past few months, seems like it should go into CVS.

---
 src/backend/storage/lmgr/lwlock.c | 59 ++++++++++++++++++++++++++++++-
 1 file changed, 58 insertions(+), 1 deletion(-)

diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c
index a2a6592d5a0..f63318cf0e4 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.38 2006/03/05 15:58:39 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/storage/lmgr/lwlock.c,v 1.39 2006/04/21 16:45:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,6 +25,7 @@
 #include "access/multixact.h"
 #include "access/subtrans.h"
 #include "miscadmin.h"
+#include "storage/ipc.h"
 #include "storage/lwlock.h"
 #include "storage/proc.h"
 #include "storage/spin.h"
@@ -84,6 +85,13 @@ NON_EXEC_STATIC LWLockPadded *LWLockArray = NULL;
 static int	num_held_lwlocks = 0;
 static LWLockId held_lwlocks[MAX_SIMUL_LWLOCKS];
 
+#ifdef LWLOCK_STATS
+static int	counts_for_pid = 0;
+static int *sh_acquire_counts;
+static int *ex_acquire_counts;
+static int *block_counts;
+#endif
+
 
 #ifdef LOCK_DEBUG
 bool		Trace_lwlocks = false;
@@ -109,6 +117,31 @@ LOG_LWDEBUG(const char *where, LWLockId lockid, const char *msg)
 #define LOG_LWDEBUG(a,b,c)
 #endif   /* LOCK_DEBUG */
 
+#ifdef LWLOCK_STATS
+
+static void
+print_lwlock_stats(int code, Datum arg)
+{
+	int			i;
+	int		   *LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
+	int			numLocks = LWLockCounter[1];
+
+	/* Grab an LWLock to keep different backends from mixing reports */
+	LWLockAcquire(0, LW_EXCLUSIVE);
+
+	for (i = 0; i < numLocks; i++)
+	{
+		if (sh_acquire_counts[i] || ex_acquire_counts[i] || block_counts[i])
+			fprintf(stderr, "PID %d lwlock %d: shacq %u exacq %u blk %u\n",
+					MyProcPid, i, sh_acquire_counts[i], ex_acquire_counts[i],
+					block_counts[i]);
+	}
+
+	LWLockRelease(0);
+}
+
+#endif /* LWLOCK_STATS */
+
 
 /*
  * Compute number of LWLocks to allocate.
@@ -263,6 +296,26 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode)
 
 	PRINT_LWDEBUG("LWLockAcquire", lockid, lock);
 
+#ifdef LWLOCK_STATS
+	/* Set up local count state first time through in a given process */
+	if (counts_for_pid != MyProcPid)
+	{
+		int	   *LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int));
+		int		numLocks = LWLockCounter[1];
+
+		sh_acquire_counts = calloc(numLocks, sizeof(int));
+		ex_acquire_counts = calloc(numLocks, sizeof(int));
+		block_counts = calloc(numLocks, sizeof(int));
+		counts_for_pid = MyProcPid;
+		on_shmem_exit(print_lwlock_stats, 0);
+	}
+	/* Count lock acquisition attempts */
+	if (mode == LW_EXCLUSIVE)
+		ex_acquire_counts[lockid]++;
+	else
+		sh_acquire_counts[lockid]++;
+#endif /* LWLOCK_STATS */
+
 	/*
 	 * We can't wait if we haven't got a PGPROC.  This should only occur
 	 * during bootstrap or shared memory initialization.  Put an Assert here
@@ -369,6 +422,10 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode)
 		 */
 		LOG_LWDEBUG("LWLockAcquire", lockid, "waiting");
 
+#ifdef LWLOCK_STATS
+		block_counts[lockid]++;
+#endif
+
 		for (;;)
 		{
 			/* "false" means cannot accept cancel/die interrupt here. */
-- 
GitLab