Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c4901a1

Browse files
committed
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
1 parent c179662 commit c4901a1

File tree

2 files changed

+65
-35
lines changed

2 files changed

+65
-35
lines changed

src/backend/port/unix_latch.c

+55-26
Original file line numberDiff line numberDiff line change
@@ -283,27 +283,31 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
283283
do
284284
{
285285
/*
286-
* Clear the pipe, then check if the latch is set already. If someone
287-
* sets the latch between this and the poll()/select() below, the
288-
* setter will write a byte to the pipe (or signal us and the signal
289-
* handler will do that), and the poll()/select() will return
290-
* immediately.
286+
* Check if the latch is set already. If so, leave loop immediately,
287+
* avoid blocking again. We don't attempt to report any other events
288+
* that might also be satisfied.
289+
*
290+
* If someone sets the latch between this and the poll()/select()
291+
* below, the setter will write a byte to the pipe (or signal us and
292+
* the signal handler will do that), and the poll()/select() will
293+
* return immediately.
294+
*
295+
* If there's a pending byte in the self pipe, we'll notice whenever
296+
* blocking. Only clearing the pipe in that case avoids having to
297+
* drain it every time WaitLatchOrSocket() is used. Should the
298+
* pipe-buffer fill up we're still ok, because the pipe is in
299+
* nonblocking mode. It's unlikely for that to happen, because the
300+
* self pipe isn't filled unless we're blocking (waiting = true), or
301+
* from inside a signal handler in latch_sigusr1_handler().
291302
*
292303
* Note: we assume that the kernel calls involved in drainSelfPipe()
293304
* and SetLatch() will provide adequate synchronization on machines
294305
* with weak memory ordering, so that we cannot miss seeing is_set if
295306
* the signal byte is already in the pipe when we drain it.
296307
*/
297-
drainSelfPipe();
298-
299308
if ((wakeEvents & WL_LATCH_SET) && latch->is_set)
300309
{
301310
result |= WL_LATCH_SET;
302-
303-
/*
304-
* Leave loop immediately, avoid blocking again. We don't attempt
305-
* to report any other events that might also be satisfied.
306-
*/
307311
break;
308312
}
309313

@@ -313,24 +317,26 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
313317
*/
314318
#if defined(LATCH_USE_POLL)
315319
nfds = 0;
320+
321+
/* selfpipe is always in pfds[0] */
322+
pfds[0].fd = selfpipe_readfd;
323+
pfds[0].events = POLLIN;
324+
pfds[0].revents = 0;
325+
nfds++;
326+
316327
if (wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE))
317328
{
318-
/* socket, if used, is always in pfds[0] */
319-
pfds[0].fd = sock;
320-
pfds[0].events = 0;
329+
/* socket, if used, is always in pfds[1] */
330+
pfds[1].fd = sock;
331+
pfds[1].events = 0;
321332
if (wakeEvents & WL_SOCKET_READABLE)
322-
pfds[0].events |= POLLIN;
333+
pfds[1].events |= POLLIN;
323334
if (wakeEvents & WL_SOCKET_WRITEABLE)
324-
pfds[0].events |= POLLOUT;
325-
pfds[0].revents = 0;
335+
pfds[1].events |= POLLOUT;
336+
pfds[1].revents = 0;
326337
nfds++;
327338
}
328339

329-
pfds[nfds].fd = selfpipe_readfd;
330-
pfds[nfds].events = POLLIN;
331-
pfds[nfds].revents = 0;
332-
nfds++;
333-
334340
if (wakeEvents & WL_POSTMASTER_DEATH)
335341
{
336342
/* postmaster fd, if used, is always in pfds[nfds - 1] */
@@ -364,19 +370,27 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
364370
else
365371
{
366372
/* at least one event occurred, so check revents values */
373+
374+
if (pfds[0].revents & POLLIN)
375+
{
376+
/* There's data in the self-pipe, clear it. */
377+
drainSelfPipe();
378+
}
379+
367380
if ((wakeEvents & WL_SOCKET_READABLE) &&
368-
(pfds[0].revents & POLLIN))
381+
(pfds[1].revents & POLLIN))
369382
{
370383
/* data available in socket, or EOF/error condition */
371384
result |= WL_SOCKET_READABLE;
372385
}
373386
if ((wakeEvents & WL_SOCKET_WRITEABLE) &&
374-
(pfds[0].revents & POLLOUT))
387+
(pfds[1].revents & POLLOUT))
375388
{
376389
/* socket is writable */
377390
result |= WL_SOCKET_WRITEABLE;
378391
}
379-
if (pfds[0].revents & (POLLHUP | POLLERR | POLLNVAL))
392+
if ((wakeEvents & WL_SOCKET_WRITEABLE) &&
393+
(pfds[1].revents & (POLLHUP | POLLERR | POLLNVAL)))
380394
{
381395
/* EOF/error condition */
382396
if (wakeEvents & WL_SOCKET_READABLE)
@@ -468,6 +482,11 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
468482
else
469483
{
470484
/* at least one event occurred, so check masks */
485+
if (FD_ISSET(selfpipe_readfd, &input_mask))
486+
{
487+
/* There's data in the self-pipe, clear it. */
488+
drainSelfPipe();
489+
}
471490
if ((wakeEvents & WL_SOCKET_READABLE) && FD_ISSET(sock, &input_mask))
472491
{
473492
/* data available in socket, or EOF */
@@ -498,6 +517,16 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
498517
}
499518
#endif /* LATCH_USE_SELECT */
500519

520+
/*
521+
* Check again whether latch is set, the arrival of a signal/self-byte
522+
* might be what stopped our sleep. It's not required for correctness
523+
* to signal the latch as being set (we'd just loop if there's no
524+
* other event), but it seems good to report an arrived latch asap.
525+
* This way we also don't have to compute the current timestamp again.
526+
*/
527+
if ((wakeEvents & WL_LATCH_SET) && latch->is_set)
528+
result |= WL_LATCH_SET;
529+
501530
/* If we're not done, update cur_timeout for next iteration */
502531
if (result == 0 && (wakeEvents & WL_TIMEOUT))
503532
{

src/backend/port/win32_latch.c

+10-9
Original file line numberDiff line numberDiff line change
@@ -181,14 +181,11 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
181181
do
182182
{
183183
/*
184-
* Reset the event, and check if the latch is set already. If someone
185-
* sets the latch between this and the WaitForMultipleObjects() call
186-
* below, the setter will set the event and WaitForMultipleObjects()
187-
* will return immediately.
184+
* The comment in unix_latch.c's equivalent to this applies here as
185+
* well. At least after mentally replacing self-pipe with windows
186+
* event. There's no danger of overflowing, as "Setting an event that
187+
* is already set has no effect.".
188188
*/
189-
if (!ResetEvent(latchevent))
190-
elog(ERROR, "ResetEvent failed: error code %lu", GetLastError());
191-
192189
if ((wakeEvents & WL_LATCH_SET) && latch->is_set)
193190
{
194191
result |= WL_LATCH_SET;
@@ -217,9 +214,13 @@ WaitLatchOrSocket(volatile Latch *latch, int wakeEvents, pgsocket sock,
217214
else if (rc == WAIT_OBJECT_0 + 1)
218215
{
219216
/*
220-
* Latch is set. We'll handle that on next iteration of loop, but
221-
* let's not waste the cycles to update cur_timeout below.
217+
* Reset the event. We'll re-check the, potentially, set latch on
218+
* next iteration of loop, but let's not waste the cycles to
219+
* update cur_timeout below.
222220
*/
221+
if (!ResetEvent(latchevent))
222+
elog(ERROR, "ResetEvent failed: error code %lu", GetLastError());
223+
223224
continue;
224225
}
225226
else if ((wakeEvents & (WL_SOCKET_READABLE | WL_SOCKET_WRITEABLE)) &&

0 commit comments

Comments
 (0)