Add some optional code (conditionally compiled under #ifdef LWLOCK_STATS)
authorTom Lane
Fri, 21 Apr 2006 16:45:12 +0000 (16:45 +0000)
committerTom Lane
Fri, 21 Apr 2006 16:45:12 +0000 (16:45 +0000)
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

index a2a6592d5a0479073af4c6ca65bb5bbbff0da0cd..f63318cf0e47fd687ee3cdf1b3766c8d2a9bf320 100644 (file)
@@ -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. */