On Mon, Oct 3, 2016 at 12:35 PM, Thomas Munro <thomas.mu...@enterprisedb.com> wrote: > Hmm. I like the use of pgstat in that name. It helps with the > confusion created by the overloading of the term 'wait event' in the > pg_stat_activity view and the WaitEventSet API, by putting it into a > different pseudo-namespace. > > + uint32 wait_event; > > How about a typedef for that instead of using raw uint32 everywhere? > Something like pgstat_wait_descriptor? Then a variable name like > pgstat_desc, since this is most definitely not just a wait_event > anymore.
We cannot do that because of latch.h, which now only includes <signal.h> and it would be a bad idea to add more dependencies to PG-specific headers. > + /* Define event to wait for */ > > It's not defining the event to wait for at all, it's building a > description for pgstat. > > + wait_event = pgstat_make_wait_event(WAIT_EXTENSION, > + WAIT_EVENT_EXTENSION); > > It's not making a wait event, it's combining a class and an event. > How about something like this: > > pgstat_desc = pgstat_make_wait_descriptor(WAIT_CLASS_EXTENSION, > WAIT_EVENT_EXTENSION)? Maybe I sound stupid here, but I am trying to keep the same of this macro short so I'd go for pgstat_make_wait_desc(). > /* Sleep until there's something to do */ > wc = WaitLatchOrSocket(MyLatch, > WL_LATCH_SET | WL_SOCKET_READABLE, > PQsocket(conn), > - -1L); > + -1L, > + wait_event); > > ... then use 'pgstat_desc' here. For this one I agree, your naming is better. It is kind of good to let callers of WaitLatch know where this is actually used. I have added as well comments on top of WaitLatch & friends to mention what pgstat_desc does, that's useful for the user. -- Michael
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. </para> </listitem> + <listitem> + <para> + <literal>Activity</>: The server process is idle. This is used by + system processes waiting for activity in their main processing loop. + <literal>wait_event</> will identify the specific wait point. + </para> + </listitem> + <listitem> + <para> + <literal>Extension</>: The server process is waiting for activity + in an extension module. This category is useful for modules to + track custom waiting points. + </para> + </listitem> + <listitem> + <para> + <literal>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. + <literal>wait_event</> will identify the specific wait point. + </para> + </listitem> + <listitem> + <para> + <literal>IPC</>: The server process is waiting for some activity + from another process in the server. <literal>wait_event</> will + identify the specific wait point. + </para> + </listitem> + <listitem> + <para> + <literal>Timeout</>: The server process is waiting for a timeout + to expire. <literal>wait_event</> will identify the specific wait + point. + </para> + </listitem> </itemizedlist> </entry> </row> @@ -1085,6 +1121,143 @@ postgres 27093 0.0 0.0 30096 2752 ? Ss 11:34 0:00 postgres: ser <entry><literal>BufferPin</></entry> <entry>Waiting to acquire a pin on a buffer.</entry> </row> + <row> + <entry morerows="11"><literal>Activity</></entry> + <entry><literal>ArchiverMain</></entry> + <entry>Waiting in main loop of the archiver process.</entry> + </row> + <row> + <entry><literal>AutoVacuumMain</></entry> + <entry>Waiting in main loop of autovacuum launcher process.</entry> + </row> + <row> + <entry><literal>BgWriterHibernate</></entry> + <entry>Waiting in background writer process, hibernating.</entry> + </row> + <row> + <entry><literal>BgWriterMain</></entry> + <entry>Waiting in main loop of background writer process background worker.</entry> + </row> + <row> + <entry><literal>CheckpointerMain</></entry> + <entry>Waiting in main loop of checkpointer process.</entry> + </row> + <row> + <entry><literal>PgStatMain</></entry> + <entry>Waiting in main loop of the statistics collector process.</entry> + </row> + <row> + <entry><literal>RecoveryWalAll</></entry> + <entry>Waiting for WAL from any kind of source (local, archive or stream) at recovery.</entry> + </row> + <row> + <entry><literal>RecoveryWalStream</></entry> + <entry>Waiting for WAL from a stream at recovery.</entry> + </row> + <row> + <entry><literal>SysLoggerMain</></entry> + <entry>Waiting in main loop of syslogger process.</entry> + </row> + <row> + <entry><literal>WalReceiverMain</></entry> + <entry>Waiting in main loop of WAL receiver process.</entry> + </row> + <row> + <entry><literal>WalSenderMain</></entry> + <entry>Waiting in main loop of WAL sender process.</entry> + </row> + <row> + <entry><literal>WalWriterMain</></entry> + <entry>Waiting in main loop of WAL writer process.</entry> + </row> + <row> + <entry morerows="5"><literal>Client</></entry> + <entry><literal>SecureRead</></entry> + <entry>Waiting to read data from a secure connection.</entry> + </row> + <row> + <entry><literal>SecureWrite</></entry> + <entry>Waiting to write data to a secure connection.</entry> + </row> + <row> + <entry><literal>SSLOpenServer</></entry> + <entry>Waiting for SSL while attempting connection.</entry> + </row> + <row> + <entry><literal>WalReceiverWaitStart</></entry> + <entry>Waiting for startup process to send initial data for streaming replication.</entry> + </row> + <row> + <entry><literal>WalSenderWaitForWAL</></entry> + <entry>Waiting for WAL to be flushed in WAL sender process.</entry> + </row> + <row> + <entry><literal>WalSenderWriteData</></entry> + <entry>Waiting for any activity when processing replies from WAL receiver in WAL sender process.</entry> + </row> + <row> + <entry><literal>Extension</></entry> + <entry><literal>Extension</></entry> + <entry>Waiting in the code path of an extension, should be used by custom plugins and modules</entry> + </row> + <row> + <entry morerows="10"><literal>IPC</></entry> + <entry><literal>BgWorkerShutdown</></entry> + <entry>Waiting for background worker to shut down.</entry> + </row> + <row> + <entry><literal>BgWorkerStartup</></entry> + <entry>Waiting for background worker to start up.</entry> + </row> + <row> + <entry><literal>ExecuteGather</></entry> + <entry>Waiting for activity from child process when executing <literal>Gather</> node.</entry> + </row> + <row> + <entry><literal>MessageQueueInternal</></entry> + <entry>Waiting for other process to be attached in shared message queue.</entry> + </row> + <row> + <entry><literal>MessageQueuePutMessage</></entry> + <entry>Waiting to put new message in shared message queue.</entry> + </row> + <row> + <entry><literal>MessageQueueReceive</></entry> + <entry>Waiting to receive bytes in shared message queue.</entry> + </row> + <row> + <entry><literal>MessageQueueSend</></entry> + <entry>Waiting to send bytes in shared message queue.</entry> + </row> + <row> + <entry><literal>ParallelFinish</></entry> + <entry>Waiting for parallel workers to finish computing.</entry> + </row> + <row> + <entry><literal>ProcSignal</></entry> + <entry>Waiting for signal from another backend.</entry> + </row> + <row> + <entry><literal>ProcSleep</></entry> + <entry>Waiting for a specific lock.</entry> + </row> + <row> + <entry><literal>SyncRep</></entry> + <entry>Waiting for WAL commit during synchronous replication.</entry> + </row> + <row> + <entry morerows="2"><literal>Timeout</></entry> + <entry><literal>BaseBackupThrottle</></entry> + <entry>Waiting during base backup when throttling activity.</entry> + </row> + <row> + <entry><literal>PgSleep</></entry> + <entry>Waiting in process that called <function>pg_sleep</>.</entry> + </row> + <row> + <entry><literal>RecoveryApplyDelay</></entry> + <entry>Waiting to apply WAL at recovery because it is delayed.</entry> + </row> </tbody> </tgroup> </table> 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 */
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers