From: Willy Tarreau Date: Wed, 8 Jan 2020 08:54:02 +0000 (+0100) Subject: MINOR: raw_sock: make sure to disable polling once everything is sent X-Git-Tag: v2.2-dev1~130 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=08fa16e397ffb1c6511b98ade2a3bfff9435e521;p=thirdparty%2Fhaproxy.git MINOR: raw_sock: make sure to disable polling once everything is sent Analysing traces revealed a rare but surprizing pattern : connect() = -1 EAGAIN send() = success epoll_ctl(ADD, EPOLLOUT) epoll_wait() recvfrom() = success close() What happens is that the failed connect() creates an FD update for pollout, but the successful synchronous send() doesn't disable it because polling was only disabled in the FD handler. But a successful synchronous connect() cancellation is a good opportunity to disable polling before it's effectively enabled in the next loop, so better disable it when reaching the end. The cost is very low if it was already disabled anyway (one atomic op). This only affects local connections but with this the typical number of epoll_ctl() calls per connection dropped from ~4.2 to ~3.8 for plain TCP and 10k transfers. --- diff --git a/src/raw_sock.c b/src/raw_sock.c index 64f7a05d1e..ed90a02dc7 100644 --- a/src/raw_sock.c +++ b/src/raw_sock.c @@ -378,6 +378,8 @@ static size_t raw_sock_from_buf(struct connection *conn, void *xprt_ctx, const s /* if the system buffer is full, don't insist */ if (ret < try) break; + if (!count) + fd_stop_send(conn->handle.fd); } else if (ret == 0 || errno == EAGAIN || errno == ENOTCONN || errno == EINPROGRESS) { /* nothing written, we need to poll for write first */