diff options
author | Robert Haas <rhaas@postgresql.org> | 2016-03-10 12:44:09 -0500 |
---|---|---|
committer | Robert Haas <rhaas@postgresql.org> | 2016-03-10 12:44:09 -0500 |
commit | 53be0b1add7064ca5db3cd884302dfc3268d884e (patch) | |
tree | 913271b90f5a41778fe5bdbe2ac200c785dd6778 /src/backend/storage | |
parent | a3a8309d450f7c4d1b743e84ba54ef5f7877d7be (diff) | |
download | postgresql-53be0b1add7064ca5db3cd884302dfc3268d884e.tar.gz postgresql-53be0b1add7064ca5db3cd884302dfc3268d884e.zip |
Provide much better wait information in pg_stat_activity.
When a process is waiting for a heavyweight lock, we will now indicate
the type of heavyweight lock for which it is waiting. Also, you can
now see when a process is waiting for a lightweight lock - in which
case we will indicate the individual lock name or the tranche, as
appropriate - or for a buffer pin.
Amit Kapila, Ildus Kurbangaliev, reviewed by me. Lots of helpful
discussion and suggestions by many others, including Alexander
Korotkov, Vladimir Borodin, and many others.
Diffstat (limited to 'src/backend/storage')
-rw-r--r-- | src/backend/storage/buffer/bufmgr.c | 5 | ||||
-rw-r--r-- | src/backend/storage/lmgr/lmgr.c | 23 | ||||
-rw-r--r-- | src/backend/storage/lmgr/lock.c | 6 | ||||
-rw-r--r-- | src/backend/storage/lmgr/lwlock.c | 67 | ||||
-rw-r--r-- | src/backend/storage/lmgr/proc.c | 3 |
5 files changed, 100 insertions, 4 deletions
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c index 68cf5cc9f61..e8e0825eb0c 100644 --- a/src/backend/storage/buffer/bufmgr.c +++ b/src/backend/storage/buffer/bufmgr.c @@ -3351,6 +3351,9 @@ LockBufferForCleanup(Buffer buffer) UnlockBufHdr(bufHdr); LockBuffer(buffer, BUFFER_LOCK_UNLOCK); + /* Report the wait */ + pgstat_report_wait_start(WAIT_BUFFER_PIN, 0); + /* Wait to be signaled by UnpinBuffer() */ if (InHotStandby) { @@ -3364,6 +3367,8 @@ LockBufferForCleanup(Buffer buffer) else ProcWaitForSignal(); + pgstat_report_wait_end(); + /* * Remove flag marking us as waiter. Normally this will not be set * anymore, but ProcWaitForSignal() can return for other signals as diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index 9d16afb5a1b..9d2663e2f9d 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -994,3 +994,26 @@ DescribeLockTag(StringInfo buf, const LOCKTAG *tag) break; } } + +/* + * GetLockNameFromTagType + * + * Given locktag type, return the corresponding lock name. + */ +const char * +GetLockNameFromTagType(uint16 locktag_type) +{ + const char *locktypename; + char tnbuf[32]; + + if (locktag_type <= LOCKTAG_LAST_TYPE) + locktypename = LockTagTypeNames[locktag_type]; + else + { + snprintf(tnbuf, sizeof(tnbuf), "unknown %d", + (int) locktag_type); + locktypename = tnbuf; + } + + return locktypename; +} diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index a458c68b9e9..b30b7b1009b 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -1676,7 +1676,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner) set_ps_display(new_status, false); 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; @@ -1724,7 +1724,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner) /* In this path, awaitedLock remains set until LockErrorCleanup */ /* Report change to non-waiting status */ - pgstat_report_waiting(false); + pgstat_report_wait_end(); if (update_process_title) { set_ps_display(new_status, false); @@ -1739,7 +1739,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner) awaitedLock = NULL; /* Report change to non-waiting status */ - pgstat_report_waiting(false); + pgstat_report_wait_end(); if (update_process_title) { set_ps_display(new_status, false); diff --git a/src/backend/storage/lmgr/lwlock.c b/src/backend/storage/lmgr/lwlock.c index d245857a814..76d75a914f3 100644 --- a/src/backend/storage/lmgr/lwlock.c +++ b/src/backend/storage/lmgr/lwlock.c @@ -77,6 +77,7 @@ #include "postgres.h" #include "miscadmin.h" +#include "pgstat.h" #include "pg_trace.h" #include "postmaster/postmaster.h" #include "replication/slot.h" @@ -165,6 +166,9 @@ static bool lock_named_request_allowed = true; static void InitializeLWLocks(void); static void RegisterLWLockTranches(void); +static inline void LWLockReportWaitStart(LWLock *lock); +static inline void LWLockReportWaitEnd(); + #ifdef LWLOCK_STATS typedef struct lwlock_stats_key { @@ -525,7 +529,7 @@ RegisterLWLockTranches(void) { LWLockTranchesAllocated = 32; LWLockTrancheArray = (LWLockTranche **) - MemoryContextAlloc(TopMemoryContext, + MemoryContextAllocZero(TopMemoryContext, LWLockTranchesAllocated * sizeof(LWLockTranche *)); Assert(LWLockTranchesAllocated >= LWTRANCHE_FIRST_USER_DEFINED); } @@ -636,6 +640,7 @@ LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche) if (tranche_id >= LWLockTranchesAllocated) { int i = LWLockTranchesAllocated; + int j = LWLockTranchesAllocated; while (i <= tranche_id) i *= 2; @@ -644,6 +649,8 @@ LWLockRegisterTranche(int tranche_id, LWLockTranche *tranche) repalloc(LWLockTrancheArray, i * sizeof(LWLockTranche *)); LWLockTranchesAllocated = i; + while (j < LWLockTranchesAllocated) + LWLockTrancheArray[j++] = NULL; } LWLockTrancheArray[tranche_id] = tranche; @@ -714,6 +721,57 @@ LWLockInitialize(LWLock *lock, int tranche_id) } /* + * Report start of 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. This function distinguishes wait + * event based on tranche and lock id. + */ +static inline void +LWLockReportWaitStart(LWLock *lock) +{ + int lockId = T_ID(lock); + + if (lock->tranche == 0) + pgstat_report_wait_start(WAIT_LWLOCK_NAMED, (uint16) lockId); + else + pgstat_report_wait_start(WAIT_LWLOCK_TRANCHE, lock->tranche); +} + +/* + * Report end of wait event for light-weight locks. + */ +static inline void +LWLockReportWaitEnd() +{ + pgstat_report_wait_end(); +} + +/* + * Return an identifier for an LWLock based on the wait class and event. + */ +const char * +GetLWLockIdentifier(uint8 classId, uint16 eventId) +{ + if (classId == WAIT_LWLOCK_NAMED) + return MainLWLockNames[eventId]; + + Assert(classId == WAIT_LWLOCK_TRANCHE); + + /* + * It is quite possible that user has registered tranche in one of the + * backends (e.g. by allocation lwlocks in dynamic shared memory) but not + * all of them, so we can't assume the tranche is registered here. + * extension for such cases. + */ + if (eventId >= LWLockTranchesAllocated || + LWLockTrancheArray[eventId]->name == NULL) + return "extension"; + + return LWLockTrancheArray[eventId]->name; +} + +/* * Internal function that tries to atomically acquire the lwlock in the passed * in mode. * @@ -1162,6 +1220,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode) lwstats->block_count++; #endif + LWLockReportWaitStart(lock); TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode); for (;;) @@ -1185,6 +1244,7 @@ LWLockAcquire(LWLock *lock, LWLockMode mode) #endif TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode); + LWLockReportWaitEnd(); LOG_LWDEBUG("LWLockAcquire", lock, "awakened"); @@ -1320,6 +1380,8 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode) #ifdef LWLOCK_STATS lwstats->block_count++; #endif + + LWLockReportWaitStart(lock); TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), mode); for (;;) @@ -1339,6 +1401,7 @@ LWLockAcquireOrWait(LWLock *lock, LWLockMode mode) } #endif TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), mode); + LWLockReportWaitEnd(); LOG_LWDEBUG("LWLockAcquireOrWait", lock, "awakened"); } @@ -1544,6 +1607,7 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval) lwstats->block_count++; #endif + LWLockReportWaitStart(lock); TRACE_POSTGRESQL_LWLOCK_WAIT_START(T_NAME(lock), T_ID(lock), LW_EXCLUSIVE); @@ -1566,6 +1630,7 @@ LWLockWaitForVar(LWLock *lock, uint64 *valptr, uint64 oldval, uint64 *newval) TRACE_POSTGRESQL_LWLOCK_WAIT_DONE(T_NAME(lock), T_ID(lock), LW_EXCLUSIVE); + LWLockReportWaitEnd(); LOG_LWDEBUG("LWLockWaitForVar", lock, "awakened"); diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c index 6453b88a5b8..46838d852e5 100644 --- a/src/backend/storage/lmgr/proc.c +++ b/src/backend/storage/lmgr/proc.c @@ -404,6 +404,9 @@ InitProcess(void) Assert(MyProc->lockGroupLeader == NULL); Assert(dlist_is_empty(&MyProc->lockGroupMembers)); + /* Initialize wait event information. */ + MyProc->wait_event_info = 0; + /* * Acquire ownership of the PGPROC's latch, so that we can use WaitLatch * on it. That allows us to repoint the process latch, which so far |