diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index 4f88d3f..c1da2a8 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -32,6 +32,10 @@ #include "storage/proc.h" #include "storage/spin.h" +#ifdef LWLOCK_STATS +#include "utils/hsearch.h" +#endif + /* We use the ShmemLock spinlock to protect LWLockAssign */ extern slock_t *ShmemLock; @@ -91,11 +95,17 @@ static int lock_addin_request = 0; static bool lock_addin_request_allowed = true; #ifdef LWLOCK_STATS +typedef struct lwlock_stats +{ + LWLockId lockid; + int sh_acquire_count; + int ex_acquire_count; + int block_count; + int spin_delay_count; +} lwlock_stats; + static int counts_for_pid = 0; -static int *sh_acquire_counts; -static int *ex_acquire_counts; -static int *block_counts; -static int *spin_delay_counts; +static HTAB *lwlock_stats_htab; #endif #ifdef LOCK_DEBUG @@ -126,17 +136,25 @@ LOG_LWDEBUG(const char *where, LWLockId lockid, const char *msg) static void init_lwlock_stats(void); static void print_lwlock_stats(int code, Datum arg); +static lwlock_stats *get_lwlock_stats_entry(LWLockId lockid); static void init_lwlock_stats(void) { - int *LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int)); - int numLocks = LWLockCounter[1]; + HASHCTL ctl; + + if (lwlock_stats_htab != NULL) + { + hash_destroy(lwlock_stats_htab); + lwlock_stats_htab = NULL; + } - sh_acquire_counts = calloc(numLocks, sizeof(int)); - ex_acquire_counts = calloc(numLocks, sizeof(int)); - spin_delay_counts = calloc(numLocks, sizeof(int)); - block_counts = calloc(numLocks, sizeof(int)); + MemSet(&ctl, 0, sizeof(ctl)); + ctl.keysize = sizeof(LWLockId); + ctl.entrysize = sizeof(lwlock_stats); + ctl.hash = tag_hash; + lwlock_stats_htab = hash_create("lwlock stats", 16384, &ctl, + HASH_ELEM | HASH_FUNCTION); counts_for_pid = MyProcPid; on_shmem_exit(print_lwlock_stats, 0); } @@ -144,23 +162,47 @@ init_lwlock_stats(void) static void print_lwlock_stats(int code, Datum arg) { - int i; - int *LWLockCounter = (int *) ((char *) LWLockArray - 2 * sizeof(int)); - int numLocks = LWLockCounter[1]; + HASH_SEQ_STATUS scan; + lwlock_stats *lwstats; + + hash_seq_init(&scan, lwlock_stats_htab); /* Grab an LWLock to keep different backends from mixing reports */ LWLockAcquire(0, LW_EXCLUSIVE); - for (i = 0; i < numLocks; i++) + while ((lwstats = (lwlock_stats *) hash_seq_search(&scan)) != NULL) { - if (sh_acquire_counts[i] || ex_acquire_counts[i] || block_counts[i] || spin_delay_counts[i]) - fprintf(stderr, "PID %d lwlock %d: shacq %u exacq %u blk %u spindelay %u\n", - MyProcPid, i, sh_acquire_counts[i], ex_acquire_counts[i], - block_counts[i], spin_delay_counts[i]); + fprintf(stderr, + "PID %d lwlock %d: shacq %u exacq %u blk %u spindelay %u\n", + MyProcPid, lwstats->lockid, lwstats->sh_acquire_count, + lwstats->ex_acquire_count, lwstats->block_count, + lwstats->spin_delay_count); } LWLockRelease(0); } + +static lwlock_stats * +get_lwlock_stats_entry(LWLockId lockid) +{ + lwlock_stats *lwstats; + bool found; + + /* Set up local count state first time through in a given process */ + if (counts_for_pid != MyProcPid) + init_lwlock_stats(); + + /* Fetch or create the entry. */ + lwstats = hash_search(lwlock_stats_htab, &lockid, HASH_ENTER, &found); + if (!found) + { + lwstats->sh_acquire_count = 0; + lwstats->ex_acquire_count = 0; + lwstats->block_count = 0; + lwstats->spin_delay_count = 0; + } + return lwstats; +} #endif /* LWLOCK_STATS */ @@ -344,18 +386,20 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode) PGPROC *proc = MyProc; bool retry = false; int extraWaits = 0; +#ifdef LWLOCK_STATS + lwlock_stats *lwstats; +#endif 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) - init_lwlock_stats(); + lwstats = get_lwlock_stats_entry(lockid); + /* Count lock acquisition attempts */ if (mode == LW_EXCLUSIVE) - ex_acquire_counts[lockid]++; + lwstats->ex_acquire_count++; else - sh_acquire_counts[lockid]++; + lwstats->sh_acquire_count++; #endif /* LWLOCK_STATS */ /* @@ -398,7 +442,7 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode) /* Acquire mutex. Time spent holding mutex should be short! */ #ifdef LWLOCK_STATS - spin_delay_counts[lockid] += SpinLockAcquire(&lock->mutex); + lwstats->spin_delay_count += SpinLockAcquire(&lock->mutex); #else SpinLockAcquire(&lock->mutex); #endif @@ -469,7 +513,7 @@ LWLockAcquire(LWLockId lockid, LWLockMode mode) LOG_LWDEBUG("LWLockAcquire", lockid, "waiting"); #ifdef LWLOCK_STATS - block_counts[lockid]++; + lwstats->block_count++; #endif TRACE_POSTGRESQL_LWLOCK_WAIT_START(lockid, mode); @@ -598,13 +642,14 @@ LWLockAcquireOrWait(LWLockId lockid, LWLockMode mode) PGPROC *proc = MyProc; bool mustwait; int extraWaits = 0; +#ifdef LWLOCK_STATS + lwlock_stats *lwstats; +#endif PRINT_LWDEBUG("LWLockAcquireOrWait", lockid, lock); #ifdef LWLOCK_STATS - /* Set up local count state first time through in a given process */ - if (counts_for_pid != MyProcPid) - init_lwlock_stats(); + lwstats = get_lwlock_stats_entry(lockid); #endif /* Ensure we will have room to remember the lock */ @@ -674,7 +719,7 @@ LWLockAcquireOrWait(LWLockId lockid, LWLockMode mode) LOG_LWDEBUG("LWLockAcquireOrWait", lockid, "waiting"); #ifdef LWLOCK_STATS - block_counts[lockid]++; + lwstats->block_count++; #endif TRACE_POSTGRESQL_LWLOCK_WAIT_START(lockid, mode);