diff options
author | Andres Freund <andres@anarazel.de> | 2016-03-18 11:43:59 -0700 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2016-03-18 11:47:05 -0700 |
commit | c4901a1e03a7730e4471fd1143f1caf79695493d (patch) | |
tree | 179283f34e306ff45e71a7aa98ad9b06f7c4f864 /src/backend/port/unix_latch.c | |
parent | c17966201c7de2a4c437bed6d83c6a7f2e7108f4 (diff) | |
download | postgresql-c4901a1e03a7730e4471fd1143f1caf79695493d.tar.gz postgresql-c4901a1e03a7730e4471fd1143f1caf79695493d.zip |
Only clear latch self-pipe/event if there is a pending notification.
This avoids a good number of, individually quite fast, system calls in
scenarios with many quick queries. Besides the aesthetic benefit of
seing fewer superflous system calls with strace, it also improves
performance by ~2% measured by pgbench -M prepared -c 96 -j 8 -S (scale
100).
Without having benchmarked it, this patch also adjust the windows code,
as that makes it easier to unify the unix/windows codepaths in a later
patch. There's little reason to diverge in behaviour between the
platforms.
Discussion: CA+TgmoYc1Zm+Szoc_Qbzi92z2c1vRHZmjhfPn5uC=w8bXv6Avg@mail.gmail.com
Reviewed-By: Robert Haas
Diffstat (limited to 'src/backend/port/unix_latch.c')
-rw-r--r-- | src/backend/port/unix_latch.c | 81 |
1 files changed, 55 insertions, 26 deletions
diff --git a/src/backend/port/unix_latch.c b/src/backend/port/unix_latch.c index e7be7ec1179..104401d0feb 100644 --- a/src/backend/port/unix_latch.c +++ b/src/backend/port/unix_latch.c @@ -283,27 +283,31 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, do { /* - * Clear the pipe, then check if the latch is set already. If someone - * sets the latch between this and the poll()/select() below, the - * setter will write a byte to the pipe (or signal us and the signal - * handler will do that), and the poll()/select() will return - * immediately. + * Check if the latch is set already. If so, leave loop immediately, + * avoid blocking again. We don't attempt to report any other events + * that might also be satisfied. + * + * If someone sets the latch between this and the poll()/select() + * below, the setter will write a byte to the pipe (or signal us and + * the signal handler will do that), and the poll()/select() will + * return immediately. + * + * If there's a pending byte in the self pipe, we'll notice whenever + * blocking. Only clearing the pipe in that case avoids having to + * drain it every time WaitLatchOrSocket() is used. Should the + * pipe-buffer fill up we're still ok, because the pipe is in + * nonblocking mode. It's unlikely for that to happen, because the + * self pipe isn't filled unless we're blocking (waiting = true), or + * from inside a signal handler in latch_sigusr1_handler(). * * Note: we assume that the kernel calls involved in drainSelfPipe() * and SetLatch() will provide adequate synchronization on machines * with weak memory ordering, so that we cannot miss seeing is_set if * the signal byte is already in the pipe when we drain it. */ - drainSelfPipe(); - if ((wakeEvents & WL_LATCH_SET) && latch->is_set) { result |= WL_LATCH_SET; - - /* - * Leave loop immediately, avoid blocking again. We don't attempt - * to report any other events that might also be satisfied. - */ break; } @@ -313,24 +317,26 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, */ #if defined(LATCH_USE_POLL) nfds = 0; + + /* selfpipe is always in pfds[0] */ + pfds[0].fd = selfpipe_readfd; + pfds[0].events = POLLIN; + pfds[0].revents = 0; + nfds++; + if (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) { - /* socket, if used, is always in pfds[0] */ - pfds[0].fd = sock; - pfds[0].events = 0; + /* socket, if used, is always in pfds[1] */ + pfds[1].fd = sock; + pfds[1].events = 0; if (wakeEvents & WL_SOCKET_READABLE) - pfds[0].events |= POLLIN; + pfds[1].events |= POLLIN; if (wakeEvents & WL_SOCKET_WRITEABLE) - pfds[0].events |= POLLOUT; - pfds[0].revents = 0; + pfds[1].events |= POLLOUT; + pfds[1].revents = 0; nfds++; } - pfds[nfds].fd = selfpipe_readfd; - pfds[nfds].events = POLLIN; - pfds[nfds].revents = 0; - nfds++; - if (wakeEvents & WL_POSTMASTER_DEATH) { /* postmaster fd, if used, is always in pfds[nfds - 1] */ @@ -364,19 +370,27 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, else { /* at least one event occurred, so check revents values */ + + if (pfds[0].revents & POLLIN) + { + /* There's data in the self-pipe, clear it. */ + drainSelfPipe(); + } + if ((wakeEvents & WL_SOCKET_READABLE) && - (pfds[0].revents & POLLIN)) + (pfds[1].revents & POLLIN)) { /* data available in socket, or EOF/error condition */ result |= WL_SOCKET_READABLE; } if ((wakeEvents & WL_SOCKET_WRITEABLE) && - (pfds[0].revents & POLLOUT)) + (pfds[1].revents & POLLOUT)) { /* socket is writable */ result |= WL_SOCKET_WRITEABLE; } - if (pfds[0].revents & (POLLHUP | POLLERR | POLLNVAL)) + if ((wakeEvents & WL_SOCKET_WRITEABLE) && + (pfds[1].revents & (POLLHUP | POLLERR | POLLNVAL))) { /* EOF/error condition */ if (wakeEvents & WL_SOCKET_READABLE) @@ -468,6 +482,11 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, else { /* at least one event occurred, so check masks */ + if (FD_ISSET(selfpipe_readfd, &input_mask)) + { + /* There's data in the self-pipe, clear it. */ + drainSelfPipe(); + } if ((wakeEvents & WL_SOCKET_READABLE) && FD_ISSET(sock, &input_mask)) { /* data available in socket, or EOF */ @@ -498,6 +517,16 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock, } #endif /* LATCH_USE_SELECT */ + /* + * Check again whether latch is set, the arrival of a signal/self-byte + * might be what stopped our sleep. It's not required for correctness + * to signal the latch as being set (we'd just loop if there's no + * other event), but it seems good to report an arrived latch asap. + * This way we also don't have to compute the current timestamp again. + */ + if ((wakeEvents & WL_LATCH_SET) && latch->is_set) + result |= WL_LATCH_SET; + /* If we're not done, update cur_timeout for next iteration */ if (result == 0 && (wakeEvents & WL_TIMEOUT)) { |