On Fri, Sep 30, 2016 at 1:48 AM, Robert Haas <robertmh...@gmail.com> wrote: > It seems to me that you haven't tested this patch very carefully, > because as far as I can see it breaks wait event reporting for both > heavyweight locks and buffer pins - or in other words two out of the > three existing cases covered by the mechanism you are patching.
Oops. The WaitLatch calls overlap the other things if another event is reported. > The heavyweight lock portion is broken because WaitOnLock() reports a > Lock wait before calling ProcSleep(), which now clobbers it. Instead > of reporting that we're waiting for Lock/relation, a LOCK TABLE > statement that hangs now reports IPC/ProcSleep. Similarly, a conflict > over a tuple lock is now also reported as IPC/ProcSleep, and ditto for > any other kind of lock, which were all reported separately before. > Obviously, that's no good. I think it would be just fine to push down > setting the wait event into ProcSleep(), doing it when we actually > WaitLatch() or ResolveRecoveryConflictWithLock(), but we ought to > report that we're waiting for the heavyweight lock, not ProcSleep(). Somewhat similar problem with ResolveRecoveryConflictWithBufferPin(), per this reasoning what we should wait for here is a buffer pin and not a IPC/WaitForSignal. > As for buffer pins, note that LockBufferForCleanup() calls > ProcWaitForSignal(), which now overwrites the wait event set in by its > caller. I think we could just make ProcWaitForSignal() take a wait > event as an argument; then LockBufferForCleanup() could pass an > appropriate constant and other callers of ProcWaitForSignal() could > pass their own wait events. Agreed. So changed the patch this way. > The way that we're constructing the wait event ID that ultimately gets > advertised in pg_stat_activity is a bit silly in this patch. We start > with an event ID (which is an integer) and we then do an array lookup > (via GetWaitEventClass) to get a second integer which is then XOR'd > back into the first integer (via pgstat_report_wait_start) before > storing it in the PGPROC. New idea: let's change > pgstat_report_wait_start() to take a single integer argument which it > stores without interpretation. Let's separate the construction of the > wait event into a separate macro, say make_wait_event(). Then > existing callers of pgstat_report_wait_start(a, b) will instead do > pgstat_report_wait_start(make_wait_event(a, b)), but callers that want > to construct the wait event and push it through a few levels of the > call stack before advertising it only need to pass one integer. If > done correctly, this should be cleaner and faster than what you've got > right now. Hm, OK.... So ProcSleep() and ProcWaitForSignal() need an additional argument in the shape of a uint32 wait_event. So we need to change the shape of WaitLatch&friends to have also just a uint32 as an extra argument. This has as result to force all the callers of WaitLatch to use the new routine pgstat_make_wait_event() (renamed it), so pgstat.h needs to be included where WaitLatch() is called. And this has as consequence to make the addition of classId in WaitEventEntries completely useless, because including them has the advantage to reduce the places where pgstat.h is included, but as make_wait_event is needed to the wait_event value... > I am not a huge fan of the "WE_" prefix you've used. It's not > terrible, but "we" doesn't obviously stand for "wait event" and it's > also a word itself. I think a little more verbosity would add > clarity. Maybe we could go with WAIT_EVENT_ instead. OK. Switched that back. Hopefully you find the result cleaner. -- Michael
diff --git a/contrib/postgres_fdw/connection.c b/contrib/postgres_fdw/connection.c index 8ca1c1c..0841fd7 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 wait_event; + + /* Define event to wait for */ + wait_event = pgstat_make_wait_event(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, + wait_event); 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..58843ec 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_event(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..52362d6 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_event(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 wait_event; TimestampDifference(last_fail_time, now, &secs, &usecs); wait_time = wal_retrieve_retry_interval - (secs * 1000 + usecs / 1000); + wait_event = pgstat_make_wait_event(WAIT_ACTIVITY, + WAIT_EVENT_RECOVERY_APPLY_DELAY); WaitLatch(&XLogCtl->recoveryWakeupLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - wait_time); + wait_time, + wait_event); + 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_event(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..1a7b303 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_event(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..bc87a47 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_event(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..9f89491 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_event(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_event(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..5121335 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_event(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..93e4567 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_event(WAIT_ACTIVITY, + WAIT_EVENT_AUTOVACUUM_MAIN)); ResetLatch(MyLatch); diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c index 699c934..62ce3c8 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_event(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_event(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..8683323 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_event(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_event(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..512ce20 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_event(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..249674f 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_event(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..97fd4ea 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_event(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_event(WAIT_ACTIVITY, + WAIT_EVENT_PGSTAT_MAIN)); #endif /* diff --git a/src/backend/postmaster/syslogger.c b/src/backend/postmaster/syslogger.c index e7e488a..5658454 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_event(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_event(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..1b31582 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_event(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..76571e5 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_event(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..47e33b1 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_event(WAIT_IPC, + WAIT_EVENT_SYNC_REP)); } /* diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 413ee3a..f7839c9 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 wait_event; /* * 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); + wait_event = pgstat_make_wait_event(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, + wait_event); + 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_event(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..715785c 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_event(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_event(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_event(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..84715ae 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 wait_event; /* 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 */ + wait_event = pgstat_make_wait_event(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(wait_event); /* Reset the published bufid */ SetStartupBufferPinWaitBufId(-1); } else - ProcWaitForSignal(); - - pgstat_report_wait_end(); + ProcWaitForSignal(wait_event); /* * 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..b91568b 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; @@ -297,9 +342,11 @@ DisownLatch(volatile Latch *latch) * 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 wait_event) { - return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout); + return WaitLatchOrSocket(latch, wakeEvents, PGINVALID_SOCKET, timeout, + wait_event); } /* @@ -316,7 +363,7 @@ WaitLatch(volatile Latch *latch, int wakeEvents, long timeout) */ int WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, - long timeout) + long timeout, uint32 wait_event) { int ret = 0; int rc; @@ -344,7 +391,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, wait_event); if (rc == 0) ret |= WL_TIMEOUT; @@ -863,7 +910,8 @@ WaitEventAdjustWin32(WaitEventSet *set, WaitEvent *event) */ int WaitEventSetWait(WaitEventSet *set, long timeout, - WaitEvent *occurred_events, int nevents) + WaitEvent *occurred_events, int nevents, + uint32 wait_event) { int returned_events = 0; instr_time start_time; @@ -872,6 +920,8 @@ WaitEventSetWait(WaitEventSet *set, long timeout, Assert(nevents > 0); + pgstat_report_wait_start(wait_event); + /* * Initialize timeout if requested. We must record the current time so * that we can determine the remaining timeout if interrupted. @@ -960,6 +1010,8 @@ WaitEventSetWait(WaitEventSet *set, long timeout, waiting = false; #endif + pgstat_report_wait_end(); + return returned_events; } @@ -1491,6 +1543,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..4eea77d 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_event(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_event(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_event(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..bf0efef 100644 --- a/src/backend/storage/ipc/standby.c +++ b/src/backend/storage/ipc/standby.c @@ -356,7 +356,7 @@ ResolveRecoveryConflictWithDatabase(Oid dbid) * will be detected by the deadlock detector within the ordinary backend. */ void -ResolveRecoveryConflictWithLock(LOCKTAG locktag) +ResolveRecoveryConflictWithLock(LOCKTAG locktag, uint32 wait_event) { TimestampTz ltime; @@ -389,7 +389,7 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag) } /* Wait to be signaled by the release of the Relation Lock */ - ProcWaitForSignal(); + ProcWaitForSignal(wait_event); /* * Clear any timeout requests established above. We assume here that the @@ -428,7 +428,7 @@ ResolveRecoveryConflictWithLock(LOCKTAG locktag) * at least deadlock_timeout. */ void -ResolveRecoveryConflictWithBufferPin(void) +ResolveRecoveryConflictWithBufferPin(uint32 wait_event) { TimestampTz ltime; @@ -469,7 +469,7 @@ ResolveRecoveryConflictWithBufferPin(void) } /* Wait to be signaled by UnpinBuffer() */ - ProcWaitForSignal(); + ProcWaitForSignal(wait_event); /* * 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..8fa0b1f 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 wait_event; 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); + + wait_event = pgstat_make_wait_event(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, wait_event) != 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..cc7bef9 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 wait_event; if (lock->tranche == 0) - pgstat_report_wait_start(WAIT_LWLOCK_NAMED, (uint16) lockId); + wait_event = pgstat_make_wait_event(WAIT_LWLOCK_NAMED, + (uint16) lockId); else - pgstat_report_wait_start(WAIT_LWLOCK_TRANCHE, lock->tranche); + wait_event = pgstat_make_wait_event(WAIT_LWLOCK_TRANCHE, + lock->tranche); + + pgstat_report_wait_start(wait_event); } /* 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..7353094 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. * + * wait_event 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 wait_event) { 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 (wait_event == 0) + wait_event = pgstat_make_wait_event(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, wait_event); } else { - WaitLatch(MyLatch, WL_LATCH_SET, 0); + WaitLatch(MyLatch, WL_LATCH_SET, 0, wait_event); 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. * + * wait_event 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 wait_event) { - 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 (wait_event == 0) + pgstat_make_wait_event(WAIT_IPC, WAIT_EVENT_PROC_SIGNAL); + + WaitLatch(MyLatch, WL_LATCH_SET, 0, wait_event); ResetLatch(MyLatch); CHECK_FOR_INTERRUPTS(); } diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index 5e705e9..880e72c 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_event(WAIT_TIMEOUT, + WAIT_EVENT_PG_SLEEP)); ResetLatch(MyLatch); } diff --git a/src/include/pgstat.h b/src/include/pgstat.h index 0c98c59..bc8081b 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) { 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; } /* ---------- @@ -1061,6 +1061,16 @@ pgstat_report_wait_end(void) proc->wait_event_info = 0; } +/* ---------- + * pgstat_make_wait_event() + * + * 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_event(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..293ea99 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 wait_event); +extern int WaitLatch(volatile Latch *latch, int wakeEvents, long timeout, + uint32 wait_event); extern int WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, - pgsocket sock, long timeout); + pgsocket sock, long timeout, uint32 wait_event); +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..65212ac 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 wait_event); 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 wait_event); 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..3c189c2 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 wait_event); +extern void ResolveRecoveryConflictWithBufferPin(uint32 wait_event); 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..64f9b8b 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_event(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..9b3e80e 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_event(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..d738f21 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_event(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