diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c
index 8ca1c1c..ffa72b8 100644
--- a/contrib/postgres_fdw/connection.c
+++ b/contrib/postgres_fdw/connection.c
@@ -17,6 +17,7 @@
#include "access/xact.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "storage/latch.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
@@ -491,12 +492,18 @@ pgfdw_get_result(PGconn *conn, const char *query)
while (PQisBusy(conn))
{
int wc;
+ uint32 pgstat_desc;
+
+ /* Define event to wait for */
+ pgstat_desc = pgstat_make_wait_desc(WAIT_EXTENSION,
+ WAIT_EVENT_EXTENSION);
/* Sleep until there's something to do */
wc = WaitLatchOrSocket(MyLatch,
WL_LATCH_SET | WL_SOCKET_READABLE,
PQsocket(conn),
- -1L);
+ -1L,
+ pgstat_desc);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
diff --git a/doc/src/sgml/monitoring.sgml b/doc/src/sgml/monitoring.sgml
index f400785..bb975c1 100644
--- a/doc/src/sgml/monitoring.sgml
+++ b/doc/src/sgml/monitoring.sgml
@@ -679,6 +679,42 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
buffer in question.
+
+
+ Activity>: The server process is idle. This is used by
+ system processes waiting for activity in their main processing loop.
+ wait_event> will identify the specific wait point.
+
+
+
+
+ Extension>: The server process is waiting for activity
+ in an extension module. This category is useful for modules to
+ track custom waiting points.
+
+
+
+
+ Client>: The server process is waiting for some activity
+ on a socket from user applications, and that the server expects
+ something to happen that is independent from its internal processes.
+ wait_event> will identify the specific wait point.
+
+
+
+
+ IPC>: The server process is waiting for some activity
+ from another process in the server. wait_event> will
+ identify the specific wait point.
+
+
+
+
+ Timeout>: The server process is waiting for a timeout
+ to expire. wait_event> will identify the specific wait
+ point.
+
+
@@ -1085,6 +1121,143 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser
BufferPin>
Waiting to acquire a pin on a buffer.
+
+ Activity>
+ ArchiverMain>
+ Waiting in main loop of the archiver process.
+
+
+ AutoVacuumMain>
+ Waiting in main loop of autovacuum launcher process.
+
+
+ BgWriterHibernate>
+ Waiting in background writer process, hibernating.
+
+
+ BgWriterMain>
+ Waiting in main loop of background writer process background worker.
+
+
+ CheckpointerMain>
+ Waiting in main loop of checkpointer process.
+
+
+ PgStatMain>
+ Waiting in main loop of the statistics collector process.
+
+
+ RecoveryWalAll>
+ Waiting for WAL from any kind of source (local, archive or stream) at recovery.
+
+
+ RecoveryWalStream>
+ Waiting for WAL from a stream at recovery.
+
+
+ SysLoggerMain>
+ Waiting in main loop of syslogger process.
+
+
+ WalReceiverMain>
+ Waiting in main loop of WAL receiver process.
+
+
+ WalSenderMain>
+ Waiting in main loop of WAL sender process.
+
+
+ WalWriterMain>
+ Waiting in main loop of WAL writer process.
+
+
+ Client>
+ SecureRead>
+ Waiting to read data from a secure connection.
+
+
+ SecureWrite>
+ Waiting to write data to a secure connection.
+
+
+ SSLOpenServer>
+ Waiting for SSL while attempting connection.
+
+
+ WalReceiverWaitStart>
+ Waiting for startup process to send initial data for streaming replication.
+
+
+ WalSenderWaitForWAL>
+ Waiting for WAL to be flushed in WAL sender process.
+
+
+ WalSenderWriteData>
+ Waiting for any activity when processing replies from WAL receiver in WAL sender process.
+
+
+ Extension>
+ Extension>
+ Waiting in the code path of an extension, should be used by custom plugins and modules
+
+
+ IPC>
+ BgWorkerShutdown>
+ Waiting for background worker to shut down.
+
+
+ BgWorkerStartup>
+ Waiting for background worker to start up.
+
+
+ ExecuteGather>
+ Waiting for activity from child process when executing Gather> node.
+
+
+ MessageQueueInternal>
+ Waiting for other process to be attached in shared message queue.
+
+
+ MessageQueuePutMessage>
+ Waiting to put new message in shared message queue.
+
+
+ MessageQueueReceive>
+ Waiting to receive bytes in shared message queue.
+
+
+ MessageQueueSend>
+ Waiting to send bytes in shared message queue.
+
+
+ ParallelFinish>
+ Waiting for parallel workers to finish computing.
+
+
+ ProcSignal>
+ Waiting for signal from another backend.
+
+
+ ProcSleep>
+ Waiting for a specific lock.
+
+
+ SyncRep>
+ Waiting for WAL commit during synchronous replication.
+
+
+ Timeout>
+ BaseBackupThrottle>
+ Waiting during base backup when throttling activity.
+
+
+ PgSleep>
+ Waiting in process that called pg_sleep>.
+
+
+ RecoveryApplyDelay>
+ Waiting to apply WAL at recovery because it is delayed.
+
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index cde0ed3..dd0eb76 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -23,6 +23,7 @@
#include "libpq/pqformat.h"
#include "libpq/pqmq.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "optimizer/planmain.h"
#include "storage/ipc.h"
#include "storage/sinval.h"
@@ -540,7 +541,9 @@ WaitForParallelWorkersToFinish(ParallelContext *pcxt)
if (!anyone_alive)
break;
- WaitLatch(&MyProc->procLatch, WL_LATCH_SET, -1);
+ WaitLatch(&MyProc->procLatch, WL_LATCH_SET, -1,
+ pgstat_make_wait_desc(WAIT_IPC,
+ WAIT_EVENT_PARALLEL_FINISH));
ResetLatch(&MyProc->procLatch);
}
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index c1b9a97..8e7626f 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -5827,7 +5827,9 @@ recoveryApplyDelay(XLogReaderState *record)
WaitLatch(&XLogCtl->recoveryWakeupLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- secs * 1000L + microsecs / 1000);
+ secs * 1000L + microsecs / 1000,
+ pgstat_make_wait_desc(WAIT_TIMEOUT,
+ WAIT_EVENT_RECOVERY_APPLY_DELAY));
}
return true;
}
@@ -11380,14 +11382,19 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
long secs,
wait_time;
int usecs;
+ uint32 pgstat_desc;
TimestampDifference(last_fail_time, now, &secs, &usecs);
wait_time = wal_retrieve_retry_interval -
(secs * 1000 + usecs / 1000);
+ pgstat_desc = pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_RECOVERY_APPLY_DELAY);
WaitLatch(&XLogCtl->recoveryWakeupLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- wait_time);
+ wait_time,
+ pgstat_desc);
+
ResetLatch(&XLogCtl->recoveryWakeupLatch);
now = GetCurrentTimestamp();
}
@@ -11550,7 +11557,9 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
*/
WaitLatch(&XLogCtl->recoveryWakeupLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- 5000L);
+ 5000L,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_RECOVERY_WAL_ALL));
ResetLatch(&XLogCtl->recoveryWakeupLatch);
break;
}
diff --git a/src/backend/executor/nodeGather.c b/src/backend/executor/nodeGather.c
index 438d1b2..af2f0f1 100644
--- a/src/backend/executor/nodeGather.c
+++ b/src/backend/executor/nodeGather.c
@@ -38,6 +38,7 @@
#include "executor/nodeSubplan.h"
#include "executor/tqueue.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "utils/memutils.h"
#include "utils/rel.h"
@@ -387,7 +388,9 @@ gather_readnext(GatherState *gatherstate)
return NULL;
/* Nothing to do except wait for developments. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0);
+ WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ pgstat_make_wait_desc(WAIT_IPC,
+ WAIT_EVENT_EXECUTE_GATHER));
ResetLatch(MyLatch);
nvisited = 0;
}
diff --git a/src/backend/libpq/be-secure-openssl.c b/src/backend/libpq/be-secure-openssl.c
index fedb02c..4dfe969 100644
--- a/src/backend/libpq/be-secure-openssl.c
+++ b/src/backend/libpq/be-secure-openssl.c
@@ -60,6 +60,7 @@
#include "libpq/libpq.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "storage/latch.h"
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
@@ -419,7 +420,9 @@ aloop:
else
waitfor = WL_SOCKET_WRITEABLE;
- WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0);
+ WaitLatchOrSocket(MyLatch, waitfor, port->sock, 0,
+ pgstat_make_wait_desc(WAIT_CLIENT,
+ WAIT_EVENT_SSL_OPEN_SERVER));
goto aloop;
case SSL_ERROR_SYSCALL:
if (r < 0)
diff --git a/src/backend/libpq/be-secure.c b/src/backend/libpq/be-secure.c
index cdd07d5..323283e 100644
--- a/src/backend/libpq/be-secure.c
+++ b/src/backend/libpq/be-secure.c
@@ -33,6 +33,7 @@
#include "libpq/libpq.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "tcop/tcopprot.h"
#include "utils/memutils.h"
#include "storage/ipc.h"
@@ -146,7 +147,9 @@ retry:
ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL);
- WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1);
+ WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
+ pgstat_make_wait_desc(WAIT_CLIENT,
+ WAIT_EVENT_SECURE_READ));
/*
* If the postmaster has died, it's not safe to continue running,
@@ -247,7 +250,9 @@ retry:
ModifyWaitEvent(FeBeWaitSet, 0, waitfor, NULL);
- WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1);
+ WaitEventSetWait(FeBeWaitSet, -1 /* no timeout */ , &event, 1,
+ pgstat_make_wait_desc(WAIT_CLIENT,
+ WAIT_EVENT_SECURE_WRITE));
/* See comments in secure_read. */
if (event.events & WL_POSTMASTER_DEATH)
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index bfe66c6..3b697e6 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -17,6 +17,7 @@
#include "libpq/pqformat.h"
#include "libpq/pqmq.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "tcop/tcopprot.h"
#include "utils/builtins.h"
@@ -171,7 +172,9 @@ mq_putmessage(char msgtype, const char *s, size_t len)
if (result != SHM_MQ_WOULD_BLOCK)
break;
- WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0);
+ WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0,
+ pgstat_make_wait_desc(WAIT_IPC,
+ WAIT_EVENT_MQ_PUT_MESSAGE));
ResetLatch(&MyProc->procLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 1a92ca1..7f0ad32 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -598,7 +598,9 @@ AutoVacLauncherMain(int argc, char *argv[])
*/
rc = WaitLatch(MyLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L));
+ (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L),
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_AUTOVACUUM_MAIN));
ResetLatch(MyLatch);
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index 699c934..3f2457a 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -16,6 +16,7 @@
#include "miscadmin.h"
#include "libpq/pqsignal.h"
+#include "pgstat.h"
#include "postmaster/bgworker_internals.h"
#include "postmaster/postmaster.h"
#include "storage/barrier.h"
@@ -969,7 +970,9 @@ WaitForBackgroundWorkerStartup(BackgroundWorkerHandle *handle, pid_t *pidp)
break;
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH, 0);
+ WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
+ pgstat_make_wait_desc(WAIT_IPC,
+ WAIT_EVENT_BGWORKER_STARTUP));
if (rc & WL_POSTMASTER_DEATH)
{
@@ -1008,7 +1011,9 @@ WaitForBackgroundWorkerShutdown(BackgroundWorkerHandle *handle)
break;
rc = WaitLatch(&MyProc->procLatch,
- WL_LATCH_SET | WL_POSTMASTER_DEATH, 0);
+ WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
+ pgstat_make_wait_desc(WAIT_IPC,
+ WAIT_EVENT_BGWORKER_SHUTDOWN));
if (rc & WL_POSTMASTER_DEATH)
{
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index 1002034..1326d17 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -345,7 +345,9 @@ BackgroundWriterMain(void)
*/
rc = WaitLatch(MyLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- BgWriterDelay /* ms */ );
+ BgWriterDelay /* ms */,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_BGWRITER_MAIN));
/*
* If no latch event and BgBufferSync says nothing's happening, extend
@@ -371,8 +373,10 @@ BackgroundWriterMain(void)
StrategyNotifyBgWriter(MyProc->pgprocno);
/* Sleep ... */
rc = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- BgWriterDelay * HIBERNATE_FACTOR);
+ WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ BgWriterDelay * HIBERNATE_FACTOR,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_BGWRITER_HIBERNATE));
/* Reset the notification request in case we timed out */
StrategyNotifyBgWriter(-1);
}
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index d702a48..9d3121d 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -556,7 +556,9 @@ CheckpointerMain(void)
rc = WaitLatch(MyLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout * 1000L /* convert to ms */ );
+ cur_timeout * 1000L /* convert to ms */,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_CHECKPOINTER_MAIN));
/*
* Emergency bailout if postmaster has died. This is to avoid the
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index 1aa6466..e54e30a 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -390,7 +390,9 @@ pgarch_MainLoop(void)
rc = WaitLatch(MyLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- timeout * 1000L);
+ timeout * 1000L,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_ARCHIVER_MAIN));
if (rc & WL_TIMEOUT)
wakened = true;
}
diff --git a/src/backend/postmaster/pgstat.c b/src/backend/postmaster/pgstat.c
index 96578dc..fef1aab 100644
--- a/src/backend/postmaster/pgstat.c
+++ b/src/backend/postmaster/pgstat.c
@@ -3155,6 +3155,18 @@ pgstat_get_wait_event_type(uint32 wait_event_info)
case WAIT_BUFFER_PIN:
event_type = "BufferPin";
break;
+ case WAIT_ACTIVITY:
+ event_type = "Activity";
+ break;
+ case WAIT_CLIENT:
+ event_type = "Client";
+ break;
+ case WAIT_IPC:
+ event_type = "IPC";
+ break;
+ case WAIT_TIMEOUT:
+ event_type = "Timeout";
+ break;
default:
event_type = "???";
break;
@@ -3196,6 +3208,13 @@ pgstat_get_wait_event(uint32 wait_event_info)
case WAIT_BUFFER_PIN:
event_name = "BufferPin";
break;
+ case WAIT_ACTIVITY:
+ case WAIT_CLIENT:
+ case WAIT_EXTENSION:
+ case WAIT_IPC:
+ case WAIT_TIMEOUT:
+ event_name = GetWaitEventIdentifier(eventId);
+ break;
default:
event_name = "unknown wait event";
break;
@@ -3684,8 +3703,9 @@ PgstatCollectorMain(int argc, char *argv[])
#ifndef WIN32
wr = WaitLatchOrSocket(MyLatch,
WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_SOCKET_READABLE,
- pgStatSock,
- -1L);
+ pgStatSock, -1L,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_PGSTAT_MAIN));
#else
/*
@@ -3700,8 +3720,10 @@ PgstatCollectorMain(int argc, char *argv[])
*/
wr = WaitLatchOrSocket(MyLatch,
WL_LATCH_SET | WL_POSTMASTER_DEATH | WL_SOCKET_READABLE | WL_TIMEOUT,
- pgStatSock,
- 2 * 1000L /* msec */ );
+ pgStatSock,
+ 2 * 1000L /* msec */,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_PGSTAT_MAIN));
#endif
/*
diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c
index e7e488a..358d3ad 100644
--- a/src/backend/postmaster/syslogger.c
+++ b/src/backend/postmaster/syslogger.c
@@ -34,6 +34,7 @@
#include "lib/stringinfo.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "nodes/pg_list.h"
#include "pgtime.h"
#include "postmaster/fork_process.h"
@@ -424,7 +425,9 @@ SysLoggerMain(int argc, char *argv[])
rc = WaitLatchOrSocket(MyLatch,
WL_LATCH_SET | WL_SOCKET_READABLE | cur_flags,
syslogPipe[0],
- cur_timeout);
+ cur_timeout,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_SYSLOGGER_MAIN));
if (rc & WL_SOCKET_READABLE)
{
@@ -475,7 +478,9 @@ SysLoggerMain(int argc, char *argv[])
(void) WaitLatch(MyLatch,
WL_LATCH_SET | cur_flags,
- cur_timeout);
+ cur_timeout,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_SYSLOGGER_MAIN));
EnterCriticalSection(&sysloggerSection);
#endif /* WIN32 */
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index 11ec56a..a96c4be 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -290,7 +290,9 @@ WalWriterMain(void)
rc = WaitLatch(MyLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- cur_timeout);
+ cur_timeout,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_WAL_WRITER_MAIN));
/*
* Emergency bailout if postmaster has died. This is to avoid the
diff --git a/src/backend/replication/basebackup.c b/src/backend/replication/basebackup.c
index 1eabaef..ea6286e 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -1363,8 +1363,10 @@ throttle(size_t increment)
* the maximum time to sleep. Thus the cast to long is safe.
*/
wait_result = WaitLatch(MyLatch,
- WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- (long) (sleep / 1000));
+ WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
+ (long) (sleep / 1000),
+ pgstat_make_wait_desc(WAIT_TIMEOUT,
+ WAIT_EVENT_BASE_BACKUP_THROTTLE));
if (wait_result & WL_LATCH_SET)
CHECK_FOR_INTERRUPTS();
diff --git a/src/backend/replication/syncrep.c b/src/backend/replication/syncrep.c
index b442d06..d6b8d92 100644
--- a/src/backend/replication/syncrep.c
+++ b/src/backend/replication/syncrep.c
@@ -61,6 +61,7 @@
#include "access/xact.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "replication/syncrep.h"
#include "replication/walsender.h"
#include "replication/walsender_private.h"
@@ -258,7 +259,9 @@ SyncRepWaitForLSN(XLogRecPtr lsn, bool commit)
* Wait on latch. Any condition that should wake us up will set the
* latch, so no need for timeout.
*/
- WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1);
+ WaitLatch(MyLatch, WL_LATCH_SET | WL_POSTMASTER_DEATH, -1,
+ pgstat_make_wait_desc(WAIT_IPC,
+ WAIT_EVENT_SYNC_REP));
}
/*
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index 413ee3a..8715332 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -55,6 +55,7 @@
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "replication/walreceiver.h"
#include "replication/walsender.h"
#include "storage/ipc.h"
@@ -401,6 +402,7 @@ WalReceiverMain(void)
bool endofwal = false;
pgsocket wait_fd = PGINVALID_SOCKET;
int rc;
+ uint32 pgstat_desc;
/*
* Exit walreceiver if we're not in recovery. This should not
@@ -482,11 +484,15 @@ WalReceiverMain(void)
* avoiding some system calls.
*/
Assert(wait_fd != PGINVALID_SOCKET);
+ pgstat_desc = pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_WAL_RECEIVER_MAIN);
rc = WaitLatchOrSocket(&walrcv->latch,
WL_POSTMASTER_DEATH | WL_SOCKET_READABLE |
WL_TIMEOUT | WL_LATCH_SET,
wait_fd,
- NAPTIME_PER_CYCLE);
+ NAPTIME_PER_CYCLE,
+ pgstat_desc);
+
if (rc & WL_LATCH_SET)
{
ResetLatch(&walrcv->latch);
@@ -685,7 +691,9 @@ WalRcvWaitForStartPosition(XLogRecPtr *startpoint, TimeLineID *startpointTLI)
}
SpinLockRelease(&walrcv->mutex);
- WaitLatch(&walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0);
+ WaitLatch(&walrcv->latch, WL_LATCH_SET | WL_POSTMASTER_DEATH, 0,
+ pgstat_make_wait_desc(WAIT_CLIENT,
+ WAIT_EVENT_WAL_RECEIVER_WAIT_START));
}
if (update_process_title)
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index c7743da..573107f 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1146,7 +1146,9 @@ WalSndWriteData(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xid,
/* Sleep until something happens or we time out */
WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime);
+ MyProcPort->sock, sleeptime,
+ pgstat_make_wait_desc(WAIT_CLIENT,
+ WAIT_EVENT_WAL_SENDER_WRITE_DATA));
}
/* reactivate latch so WalSndLoop knows to continue */
@@ -1272,7 +1274,9 @@ WalSndWaitForWal(XLogRecPtr loc)
/* Sleep until something happens or we time out */
WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime);
+ MyProcPort->sock, sleeptime,
+ pgstat_make_wait_desc(WAIT_CLIENT,
+ WAIT_EVENT_WAL_SENDER_WAIT_WAL));
}
/* reactivate latch so WalSndLoop knows to continue */
@@ -1924,7 +1928,9 @@ WalSndLoop(WalSndSendDataCallback send_data)
/* Sleep until something happens or we time out */
WaitLatchOrSocket(MyLatch, wakeEvents,
- MyProcPort->sock, sleeptime);
+ MyProcPort->sock, sleeptime,
+ pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_WAL_SENDER_MAIN));
}
}
return;
diff --git a/src/backend/storage/buffer/bufmgr.c b/src/backend/storage/buffer/bufmgr.c
index 90804a3..aaeb75c 100644
--- a/src/backend/storage/buffer/bufmgr.c
+++ b/src/backend/storage/buffer/bufmgr.c
@@ -3610,6 +3610,7 @@ LockBufferForCleanup(Buffer buffer)
for (;;)
{
uint32 buf_state;
+ uint32 pgstat_desc;
/* Try to acquire lock */
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
@@ -3635,8 +3636,8 @@ LockBufferForCleanup(Buffer buffer)
UnlockBufHdr(bufHdr, buf_state);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
- /* Report the wait */
- pgstat_report_wait_start(WAIT_BUFFER_PIN, 0);
+ /* Define the event to wait for */
+ pgstat_desc = pgstat_make_wait_desc(WAIT_BUFFER_PIN, 0);
/* Wait to be signaled by UnpinBuffer() */
if (InHotStandby)
@@ -3644,14 +3645,12 @@ LockBufferForCleanup(Buffer buffer)
/* Publish the bufid that Startup process waits on */
SetStartupBufferPinWaitBufId(buffer - 1);
/* Set alarm and then wait to be signaled by UnpinBuffer() */
- ResolveRecoveryConflictWithBufferPin();
+ ResolveRecoveryConflictWithBufferPin(pgstat_desc);
/* Reset the published bufid */
SetStartupBufferPinWaitBufId(-1);
}
else
- ProcWaitForSignal();
-
- pgstat_report_wait_end();
+ ProcWaitForSignal(pgstat_desc);
/*
* Remove flag marking us as waiter. Normally this will not be set
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index 9def8a1..c29cab2 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -55,6 +55,7 @@
#endif
#include "miscadmin.h"
+#include "pgstat.h"
#include "portability/instr_time.h"
#include "postmaster/postmaster.h"
#include "storage/barrier.h"
@@ -122,6 +123,50 @@ struct WaitEventSet
#endif
};
+/*
+ * This must match enum WaitEventIdentifier!
+ */
+const char *const WaitEventNames[] = {
+ /* Activity */
+ "ArchiverMain",
+ "AutoVacuumMain",
+ "BgWriterHibernate",
+ "BgWriterMain",
+ "CheckpointerMain",
+ "PgStatMain",
+ "RecoveryWalAll",
+ "RecoveryWalStream",
+ "SysLoggerMain",
+ "WalReceiverMain",
+ "WalSenderMain",
+ "WalWriterMain",
+ /* Client */
+ "SecureRead",
+ "SecureWrite",
+ "SSLOpenServer",
+ "WalReceiverWaitStart",
+ "WalSenderWaitForWAL",
+ "WalSenderWriteData",
+ /* Extension */
+ "Extension",
+ /* IPC */
+ "BgWorkerShutdown",
+ "BgWorkerStartup",
+ "ExecuteGather",
+ "MessageQueueInternal",
+ "MessageQueuePutMessage",
+ "MessageQueueReceive",
+ "MessageQueueSend",
+ "ParallelFinish",
+ "ProcSignal",
+ "ProcSleep",
+ "SyncRep",
+ /* Timeout */
+ "BaseBackupThrottle",
+ "PgSleep",
+ "RecoveryApplyDelay"
+};
+
#ifndef WIN32
/* Are we currently in WaitLatch? The signal handler would like to know. */
static volatile sig_atomic_t waiting = false;
@@ -292,14 +337,19 @@ DisownLatch(volatile Latch *latch)
* backend-local latch initialized with InitLatch, or a shared latch
* associated with the current process by calling OwnLatch.
*
+ * pgstat_desc can be used to define what the wait event is when waiting for
+ * this latch when activity is reported to pgstat.
+ *
* Returns bit mask indicating which condition(s) caused the wake-up. Note
* that if multiple wake-up conditions are true, there is no guarantee that
* we return all of them in one call, but we will return at least one.
*/
int
-WaitLatch(volatile Latch *latch, int wakeEvents, long timeout)
+WaitLatch(volatile Latch *latch, int wakeEvents, long timeout,
+ uint32 pgstat_desc)
{
- return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout);
+ return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout,
+ pgstat_desc);
}
/*
@@ -310,13 +360,16 @@ WaitLatch(volatile Latch *latch, int wakeEvents, long timeout)
* returning the socket as readable/writable or both, depending on
* WL_SOCKET_READABLE/WL_SOCKET_WRITEABLE being specified.
*
+ * pgstat_desc can be used to define what the wait event is when waiting for
+ * this latch or socket when activity is reported to pgstat.
+ *
* NB: These days this is just a wrapper around the WaitEventSet API. When
* using a latch very frequently, consider creating a longer living
* WaitEventSet instead; that's more efficient.
*/
int
WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
- long timeout)
+ long timeout, uint32 pgstat_desc)
{
int ret = 0;
int rc;
@@ -344,7 +397,7 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
AddWaitEventToSet(set, ev, sock, NULL, NULL);
}
- rc = WaitEventSetWait(set, timeout, &event, 1);
+ rc = WaitEventSetWait(set, timeout, &event, 1, pgstat_desc);
if (rc == 0)
ret |= WL_TIMEOUT;
@@ -856,6 +909,9 @@ WaitEventAdjustWin32(WaitEventSet *set, WaitEvent *event)
* If timeout = -1, block until an event occurs; if 0, check sockets for
* readiness, but don't block; if > 0, block for at most timeout miliseconds.
*
+ * pgstat_desc can be used to define what the wait event is when waiting for
+ * events to happen when activity is reported to pgstat.
+ *
* Returns the number of events occurred, or 0 if the timeout was reached.
*
* Returned events will have the fd, pos, user_data fields set to the
@@ -863,7 +919,8 @@ WaitEventAdjustWin32(WaitEventSet *set, WaitEvent *event)
*/
int
WaitEventSetWait(WaitEventSet *set, long timeout,
- WaitEvent *occurred_events, int nevents)
+ WaitEvent *occurred_events, int nevents,
+ uint32 pgstat_desc)
{
int returned_events = 0;
instr_time start_time;
@@ -872,6 +929,8 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
Assert(nevents > 0);
+ pgstat_report_wait_start(pgstat_desc);
+
/*
* Initialize timeout if requested. We must record the current time so
* that we can determine the remaining timeout if interrupted.
@@ -960,6 +1019,8 @@ WaitEventSetWait(WaitEventSet *set, long timeout,
waiting = false;
#endif
+ pgstat_report_wait_end();
+
return returned_events;
}
@@ -1491,6 +1552,22 @@ WaitEventSetWaitBlock(WaitEventSet *set, int cur_timeout,
}
#endif
+
+/*
+ * Return an event name for a WaitEventSet event depending on the ID
+ * provided by caller, ID used for the statistics collector.
+ */
+const char *
+GetWaitEventIdentifier(uint16 eventId)
+{
+ StaticAssertStmt(lengthof(WaitEventNames) == WAIT_EVENT_LAST_TYPE + 1,
+ "WaitEventEntries must match WaitEventIdentifiers");
+ if (eventId > WAIT_EVENT_LAST_TYPE)
+ return "???";
+ return WaitEventNames[eventId];
+}
+
+
/*
* SetLatch uses SIGUSR1 to wake up the process waiting on the latch.
*
diff --git a/src/backend/storage/ipc/shm_mq.c b/src/backend/storage/ipc/shm_mq.c
index 5b32782..9019f6f 100644
--- a/src/backend/storage/ipc/shm_mq.c
+++ b/src/backend/storage/ipc/shm_mq.c
@@ -19,6 +19,7 @@
#include "postgres.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "postmaster/bgworker.h"
#include "storage/procsignal.h"
#include "storage/shm_mq.h"
@@ -894,7 +895,8 @@ shm_mq_send_bytes(shm_mq_handle *mqh, Size nbytes, const void *data,
* at top of loop, because setting an already-set latch is much
* cheaper than setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0);
+ WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ pgstat_make_wait_desc(WAIT_IPC, WAIT_EVENT_MQ_SEND));
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -991,7 +993,8 @@ shm_mq_receive_bytes(shm_mq *mq, Size bytes_needed, bool nowait,
* loop, because setting an already-set latch is much cheaper than
* setting one that has been reset.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0);
+ WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ pgstat_make_wait_desc(WAIT_IPC, WAIT_EVENT_MQ_RECEIVE));
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
@@ -1090,7 +1093,8 @@ shm_mq_wait_internal(volatile shm_mq *mq, PGPROC *volatile * ptr,
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0);
+ WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ pgstat_make_wait_desc(WAIT_IPC, WAIT_EVENT_MQ_INTERNAL));
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 547f1a8..2d824be 100644
--- a/src/backend/storage/ipc/standby.c
+++ b/src/backend/storage/ipc/standby.c
@@ -354,9 +354,12 @@ ResolveRecoveryConflictWithDatabase(Oid dbid)
*
* Deadlocks involving the Startup process and an ordinary backend process
* will be detected by the deadlock detector within the ordinary backend.
+ *
+ * pgstat_desc can be used to define the wait event this conflict resolution
+ * should wait for pgstat tracking.
*/
void
-ResolveRecoveryConflictWithLock(LOCKTAG locktag)
+ResolveRecoveryConflictWithLock(LOCKTAG locktag, uint32 pgstat_desc)
{
TimestampTz ltime;
@@ -389,7 +392,7 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag)
}
/* Wait to be signaled by the release of the Relation Lock */
- ProcWaitForSignal();
+ ProcWaitForSignal(pgstat_desc);
/*
* Clear any timeout requests established above. We assume here that the
@@ -426,9 +429,12 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag)
* Deadlocks are extremely rare, and relatively expensive to check for,
* so we don't do a deadlock check right away ... only if we have had to wait
* at least deadlock_timeout.
+ *
+ * pgstat_desc can be used to override the wait event this recovery conflict
+ * is waiting for when reporting to pgstat.
*/
void
-ResolveRecoveryConflictWithBufferPin(void)
+ResolveRecoveryConflictWithBufferPin(uint32 pgstat_desc)
{
TimestampTz ltime;
@@ -469,7 +475,7 @@ ResolveRecoveryConflictWithBufferPin(void)
}
/* Wait to be signaled by UnpinBuffer() */
- ProcWaitForSignal();
+ ProcWaitForSignal(pgstat_desc);
/*
* Clear any timeout requests established above. We assume here that the
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index dba3809..d2e2331 100644
--- a/src/backend/storage/lmgr/lock.c
+++ b/src/backend/storage/lmgr/lock.c
@@ -1659,6 +1659,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
LOCKMETHODID lockmethodid = LOCALLOCK_LOCKMETHOD(*locallock);
LockMethod lockMethodTable = LockMethods[lockmethodid];
char *volatile new_status = NULL;
+ uint32 pgstat_desc;
LOCK_PRINT("WaitOnLock: sleeping on lock",
locallock->lock, locallock->tag.mode);
@@ -1676,7 +1677,9 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
set_ps_display(new_status, false);
new_status[len] = '\0'; /* truncate off " waiting" */
}
- pgstat_report_wait_start(WAIT_LOCK, locallock->tag.lock.locktag_type);
+
+ pgstat_desc = pgstat_make_wait_desc(WAIT_LOCK,
+ locallock->tag.lock.locktag_type);
awaitedLock = locallock;
awaitedOwner = owner;
@@ -1700,7 +1703,7 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
*/
PG_TRY();
{
- if (ProcSleep(locallock, lockMethodTable) != STATUS_OK)
+ if (ProcSleep(locallock, lockMethodTable, pgstat_desc) != STATUS_OK)
{
/*
* We failed as a result of a deadlock, see CheckDeadLock(). Quit
@@ -1724,7 +1727,6 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
/* In this path, awaitedLock remains set until LockErrorCleanup */
/* Report change to non-waiting status */
- pgstat_report_wait_end();
if (update_process_title)
{
set_ps_display(new_status, false);
@@ -1739,7 +1741,6 @@ WaitOnLock(LOCALLOCK *locallock, ResourceOwner owner)
awaitedLock = NULL;
/* Report change to non-waiting status */
- 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 9d08de7..caf018b 100644
--- a/src/backend/storage/lmgr/lwlock.c
+++ b/src/backend/storage/lmgr/lwlock.c
@@ -730,11 +730,16 @@ static inline void
LWLockReportWaitStart(LWLock *lock)
{
int lockId = T_ID(lock);
+ uint32 pgstat_desc;
if (lock->tranche == 0)
- pgstat_report_wait_start(WAIT_LWLOCK_NAMED, (uint16) lockId);
+ pgstat_desc = pgstat_make_wait_desc(WAIT_LWLOCK_NAMED,
+ (uint16) lockId);
else
- pgstat_report_wait_start(WAIT_LWLOCK_TRANCHE, lock->tranche);
+ pgstat_desc = pgstat_make_wait_desc(WAIT_LWLOCK_TRANCHE,
+ lock->tranche);
+
+ pgstat_report_wait_start(pgstat_desc);
}
/*
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 4064b20..f292834 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -1518,7 +1518,7 @@ GetSafeSnapshot(Snapshot origSnapshot)
SxactIsROUnsafe(MySerializableXact)))
{
LWLockRelease(SerializableXactHashLock);
- ProcWaitForSignal();
+ ProcWaitForSignal(0);
LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
}
MySerializableXact->flags &= ~SXACT_FLAG_DEFERRABLE_WAITING;
diff --git a/src/backend/storage/lmgr/proc.c b/src/backend/storage/lmgr/proc.c
index 33e7023..6ef0d94 100644
--- a/src/backend/storage/lmgr/proc.c
+++ b/src/backend/storage/lmgr/proc.c
@@ -39,6 +39,7 @@
#include "access/twophase.h"
#include "access/xact.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "replication/slot.h"
#include "replication/syncrep.h"
@@ -977,6 +978,9 @@ ProcQueueInit(PROC_QUEUE *queue)
* The lock table's partition lock must be held at entry, and will be held
* at exit.
*
+ * pgstat_desc tracks what is the wait event caller is expecting to wait for.
+ * If set to 0 the default wait event for ProcSleep() is used.
+ *
* Result: STATUS_OK if we acquired the lock, STATUS_ERROR if not (deadlock).
*
* ASSUME: that no one will fiddle with the queue until after
@@ -985,7 +989,8 @@ ProcQueueInit(PROC_QUEUE *queue)
* NOTES: The process queue is now a priority queue for locking.
*/
int
-ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
+ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable,
+ uint32 pgstat_desc)
{
LOCKMODE lockmode = locallock->tag.mode;
LOCK *lock = locallock->lock;
@@ -1023,6 +1028,14 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
}
/*
+ * If caller did not provide the wait event it is expected to look for,
+ * set up a default one.
+ */
+ if (pgstat_desc == 0)
+ pgstat_desc = pgstat_make_wait_desc(WAIT_ACTIVITY,
+ WAIT_EVENT_PROC_SLEEP);
+
+ /*
* Determine where to add myself in the wait queue.
*
* Normally I should go at the end of the queue. However, if I already
@@ -1208,11 +1221,11 @@ ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable)
if (InHotStandby)
{
/* Set a timer and wait for that or for the Lock to be granted */
- ResolveRecoveryConflictWithLock(locallock->tag.lock);
+ ResolveRecoveryConflictWithLock(locallock->tag.lock, pgstat_desc);
}
else
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0);
+ WaitLatch(MyLatch, WL_LATCH_SET, 0, pgstat_desc);
ResetLatch(MyLatch);
/* check for deadlocks first, as that's probably log-worthy */
if (got_deadlock_timeout)
@@ -1717,14 +1730,24 @@ CheckDeadLockAlert(void)
/*
* ProcWaitForSignal - wait for a signal from another backend.
*
+ * pgstat_desc tracks what is the wait event caller is expecting to wait for.
+ * If set to 0 the default wait event for ProcWaitForSignal() is used.
+ *
* As this uses the generic process latch the caller has to be robust against
* unrelated wakeups: Always check that the desired state has occurred, and
* wait again if not.
*/
void
-ProcWaitForSignal(void)
+ProcWaitForSignal(uint32 pgstat_desc)
{
- WaitLatch(MyLatch, WL_LATCH_SET, 0);
+ /*
+ * If caller did not provide the wait event it is expected to look for,
+ * set up a default one.
+ */
+ if (pgstat_desc == 0)
+ pgstat_make_wait_desc(WAIT_IPC, WAIT_EVENT_PROC_SIGNAL);
+
+ WaitLatch(MyLatch, WL_LATCH_SET, 0, pgstat_desc);
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 5e705e9..02cabcd 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -30,6 +30,7 @@
#include "funcapi.h"
#include "miscadmin.h"
#include "parser/scansup.h"
+#include "pgstat.h"
#include "postmaster/syslogger.h"
#include "rewrite/rewriteHandler.h"
#include "storage/fd.h"
@@ -560,7 +561,9 @@ pg_sleep(PG_FUNCTION_ARGS)
(void) WaitLatch(MyLatch,
WL_LATCH_SET | WL_TIMEOUT,
- delay_ms);
+ delay_ms,
+ pgstat_make_wait_desc(WAIT_TIMEOUT,
+ WAIT_EVENT_PG_SLEEP));
ResetLatch(MyLatch);
}
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index 0c98c59..e1557da 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -721,8 +721,13 @@ typedef enum WaitClass
WAIT_LWLOCK_NAMED,
WAIT_LWLOCK_TRANCHE,
WAIT_LOCK,
- WAIT_BUFFER_PIN
-} WaitClass;
+ WAIT_BUFFER_PIN,
+ WAIT_ACTIVITY,
+ WAIT_CLIENT,
+ WAIT_EXTENSION,
+ WAIT_IPC,
+ WAIT_TIMEOUT
+} WaitClass;
/* ----------
@@ -1018,23 +1023,18 @@ extern void pgstat_initstats(Relation rel);
* ----------
*/
static inline void
-pgstat_report_wait_start(uint8 classId, uint16 eventId)
+pgstat_report_wait_start(uint32 wait_event_info)
{
volatile PGPROC *proc = MyProc;
- uint32 wait_event_val;
if (!pgstat_track_activities || !proc)
return;
- wait_event_val = classId;
- wait_event_val <<= 24;
- wait_event_val |= eventId;
-
/*
* Since this is a four-byte field which is always read and written as
* four-bytes, updates are atomic.
*/
- proc->wait_event_info = wait_event_val;
+ proc->wait_event_info = wait_event_info;
}
/* ----------
@@ -1061,6 +1061,16 @@ pgstat_report_wait_end(void)
proc->wait_event_info = 0;
}
+/* ----------
+ * pgstat_make_wait_desc()
+ *
+ * Build a value to be used for report in pgstat_report_wait_start().
+ * This respects the format per the description above.
+ * ----------
+ */
+#define pgstat_make_wait_desc(classId, eventId) \
+ ((classId << 24) | eventId)
+
/* nontransactional event counts are simple enough to inline */
#define pgstat_count_heap_scan(rel) \
diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h
index 5179ecc..baaa6b2 100644
--- a/src/include/storage/latch.h
+++ b/src/include/storage/latch.h
@@ -135,6 +135,70 @@ typedef struct WaitEvent
void *user_data; /* pointer provided in AddWaitEventToSet */
} WaitEvent;
+/*
+ * List of WaitEventSet identifiers used when reporting activity to
+ * statistics collector. Up to 256 different WaitEventIdentifier can be
+ * handled. Those are classified by category first, and then by
+ * alphabetical order. Events are classified into sub-categories following
+ * some basic hierarchy rules:
+ * - "Activity" for main loops of processes waiting for an event.
+ * - "Client" for a socket awaited when a user is connected.
+ * - "IPC", similarly to "Client", for a socket awaited from another
+ * server process.
+ * - "Timeout", for a timeout waiting to expire.
+ * - "Extension", to let extension modules a way to define a custom wait
+ * point.
+ */
+typedef enum WaitEventIdentifier
+{
+ /* Activity */
+ WAIT_EVENT_ARCHIVER_MAIN,
+ WAIT_EVENT_AUTOVACUUM_MAIN,
+ WAIT_EVENT_BGWRITER_HIBERNATE,
+ WAIT_EVENT_BGWRITER_MAIN,
+ WAIT_EVENT_CHECKPOINTER_MAIN,
+ WAIT_EVENT_PGSTAT_MAIN,
+ WAIT_EVENT_RECOVERY_WAL_ALL,
+ WAIT_EVENT_RECOVERY_WAL_STREAM,
+ WAIT_EVENT_SYSLOGGER_MAIN,
+ WAIT_EVENT_WAL_RECEIVER_MAIN,
+ WAIT_EVENT_WAL_SENDER_MAIN,
+ WAIT_EVENT_WAL_WRITER_MAIN,
+ /* Client */
+ WAIT_EVENT_SECURE_READ,
+ WAIT_EVENT_SECURE_WRITE,
+ WAIT_EVENT_SSL_OPEN_SERVER,
+ WAIT_EVENT_WAL_RECEIVER_WAIT_START,
+ WAIT_EVENT_WAL_SENDER_WAIT_WAL,
+ WAIT_EVENT_WAL_SENDER_WRITE_DATA,
+ /* Extension */
+ WAIT_EVENT_EXTENSION,
+ /* IPC */
+ WAIT_EVENT_BGWORKER_SHUTDOWN,
+ WAIT_EVENT_BGWORKER_STARTUP,
+ WAIT_EVENT_EXECUTE_GATHER,
+ WAIT_EVENT_MQ_INTERNAL,
+ WAIT_EVENT_MQ_PUT_MESSAGE,
+ WAIT_EVENT_MQ_RECEIVE,
+ WAIT_EVENT_MQ_SEND,
+ WAIT_EVENT_PARALLEL_FINISH,
+ WAIT_EVENT_PROC_SIGNAL,
+ WAIT_EVENT_PROC_SLEEP,
+ WAIT_EVENT_SYNC_REP,
+ /* Timeout */
+ WAIT_EVENT_BASE_BACKUP_THROTTLE,
+ WAIT_EVENT_PG_SLEEP,
+ WAIT_EVENT_RECOVERY_APPLY_DELAY
+} WaitEventIdentifier;
+
+#define WAIT_EVENT_LAST_TYPE WAIT_EVENT_RECOVERY_APPLY_DELAY
+
+/*
+ * The information details about each WaitEventIdentifier listed above
+ * are specified by an array of name-pair values.
+ */
+extern const char *const WaitEventName[];
+
/* forward declaration to avoid exposing latch.c implementation details */
typedef struct WaitEventSet WaitEventSet;
@@ -155,10 +219,14 @@ extern int AddWaitEventToSet(WaitEventSet *set, uint32 events, pgsocket fd,
Latch *latch, void *user_data);
extern void ModifyWaitEvent(WaitEventSet *set, int pos, uint32 events, Latch *latch);
-extern int WaitEventSetWait(WaitEventSet *set, long timeout, WaitEvent *occurred_events, int nevents);
-extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout);
+extern int WaitEventSetWait(WaitEventSet *set, long timeout,
+ WaitEvent *occurred_events, int nevents,
+ uint32 pgstat_desc);
+extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout,
+ uint32 pgstat_desc);
extern int WaitLatchOrSocket(volatile Latch *latch, int wakeEvents,
- pgsocket sock, long timeout);
+ pgsocket sock, long timeout, uint32 pgstat_desc);
+extern const char *GetWaitEventIdentifier(uint16 eventId);
/*
* Unix implementation uses SIGUSR1 for inter-process signaling.
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index f576f05..158cb26 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -284,14 +284,15 @@ extern bool HaveNFreeProcs(int n);
extern void ProcReleaseLocks(bool isCommit);
extern void ProcQueueInit(PROC_QUEUE *queue);
-extern int ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable);
+extern int ProcSleep(LOCALLOCK *locallock, LockMethod lockMethodTable,
+ uint32 pgstat_desc);
extern PGPROC *ProcWakeup(PGPROC *proc, int waitStatus);
extern void ProcLockWakeup(LockMethod lockMethodTable, LOCK *lock);
extern void CheckDeadLockAlert(void);
extern bool IsWaitingForLock(void);
extern void LockErrorCleanup(void);
-extern void ProcWaitForSignal(void);
+extern void ProcWaitForSignal(uint32 pgstat_desc);
extern void ProcSendSignal(int pid);
extern void BecomeLockGroupLeader(void);
diff --git a/src/include/storage/standby.h b/src/include/storage/standby.h
index dcebf72..9e54a3b 100644
--- a/src/include/storage/standby.h
+++ b/src/include/storage/standby.h
@@ -32,8 +32,9 @@ extern void ResolveRecoveryConflictWithSnapshot(TransactionId latestRemovedXid,
extern void ResolveRecoveryConflictWithTablespace(Oid tsid);
extern void ResolveRecoveryConflictWithDatabase(Oid dbid);
-extern void ResolveRecoveryConflictWithLock(LOCKTAG locktag);
-extern void ResolveRecoveryConflictWithBufferPin(void);
+extern void ResolveRecoveryConflictWithLock(LOCKTAG locktag,
+ uint32 pgstat_desc);
+extern void ResolveRecoveryConflictWithBufferPin(uint32 pgstat_desc);
extern void CheckRecoveryConflictDeadlock(void);
extern void StandbyDeadLockHandler(void);
extern void StandbyTimeoutHandler(void);
diff --git a/src/test/modules/test_shm_mq/setup.c b/src/test/modules/test_shm_mq/setup.c
index 143df4e..0cfb447 100644
--- a/src/test/modules/test_shm_mq/setup.c
+++ b/src/test/modules/test_shm_mq/setup.c
@@ -16,6 +16,7 @@
#include "postgres.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "postmaster/bgworker.h"
#include "storage/procsignal.h"
#include "storage/shm_toc.h"
@@ -279,7 +280,9 @@ wait_for_workers_to_become_ready(worker_state *wstate,
}
/* Wait to be signalled. */
- WaitLatch(MyLatch, WL_LATCH_SET, 0);
+ WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ pgstat_make_wait_desc(WAIT_EXTENSION,
+ WAIT_EVENT_EXTENSION));
/* Reset the latch so we don't spin. */
ResetLatch(MyLatch);
diff --git a/src/test/modules/test_shm_mq/test.c b/src/test/modules/test_shm_mq/test.c
index dd34bc7..2953062 100644
--- a/src/test/modules/test_shm_mq/test.c
+++ b/src/test/modules/test_shm_mq/test.c
@@ -15,6 +15,7 @@
#include "fmgr.h"
#include "miscadmin.h"
+#include "pgstat.h"
#include "test_shm_mq.h"
@@ -230,7 +231,9 @@ test_shm_mq_pipelined(PG_FUNCTION_ARGS)
* have read or written data and therefore there may now be work
* for us to do.
*/
- WaitLatch(MyLatch, WL_LATCH_SET, 0);
+ WaitLatch(MyLatch, WL_LATCH_SET, 0,
+ pgstat_make_wait_desc(WAIT_EXTENSION,
+ WAIT_EVENT_EXTENSION));
ResetLatch(MyLatch);
CHECK_FOR_INTERRUPTS();
}
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 7c9a3eb..531eb22 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -227,7 +227,9 @@ worker_spi_main(Datum main_arg)
*/
rc = WaitLatch(MyLatch,
WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH,
- worker_spi_naptime * 1000L);
+ worker_spi_naptime * 1000L,
+ pgstat_make_wait_desc(WAIT_EXTENSION,
+ WAIT_EVENT_EXTENSION));
ResetLatch(MyLatch);
/* emergency bailout if postmaster has died */