From: Aaron Hopkins Subject: Reducing select() usage under load NSD currently only processes one UDP packet per socket per select(). Under load removing this restriction increases NSD's peak throughput by 12% on my hardware on Linux 2.6. This patch loops on recvfrom() until either 100 packets have been processed or recvfrom() it returns -1, ignoring any EAGAIN errors. Under light load, this results in an extra recvfrom() every packet. But under heavy load, this amortizes the cost of the select() across up to 100 packets. Ignoring the change in indenting, this is a very small patch. It basically just wraps a loop around the UDP recvfrom() and subsequent packet processing and breaks out of that if there's an error. diff -u nsd-3.2.1/server.c nsd-3.2.1-fewerselects/server.c --- nsd-3.2.1/server.c 2009-01-16 14:48:35.000000000 -0800 +++ nsd-3.2.1-fewerselects/server.c 2009-04-10 10:57:41.000000000 -0700 @@ -1358,69 +1358,73 @@ { struct udp_handler_data *data = (struct udp_handler_data *) handler->user_data; - int received, sent; + int received, sent, tries; struct query *q = data->query; if (!(event_types & NETIO_EVENT_READ)) { return; } - /* Account... */ - if (data->socket->addr->ai_family == AF_INET) { - STATUP(data->nsd, qudp); - } else if (data->socket->addr->ai_family == AF_INET6) { - STATUP(data->nsd, qudp6); - } - - /* Initialize the query... */ - query_reset(q, UDP_MAX_MESSAGE_LEN, 0); - - received = recvfrom(handler->fd, - buffer_begin(q->packet), - buffer_remaining(q->packet), - 0, - (struct sockaddr *)&q->addr, - &q->addrlen); - if (received == -1) { - if (errno != EAGAIN && errno != EINTR) { - log_msg(LOG_ERR, "recvfrom failed: %s", strerror(errno)); - STATUP(data->nsd, rxerr); - } - } else { - buffer_skip(q->packet, received); - buffer_flip(q->packet); - - /* Process and answer the query... */ - if (server_process_query(data->nsd, q) != QUERY_DISCARDED) { - if (RCODE(q->packet) == RCODE_OK && !AA(q->packet)) - STATUP(data->nsd, nona); - - /* Add EDNS0 and TSIG info if necessary. */ - query_add_optional(q, data->nsd); + /* Process up to 100 queries per fd per select(). */ + for (tries = 0; tries < 100; tries++) { + /* Initialize the query... */ + query_reset(q, UDP_MAX_MESSAGE_LEN, 0); + + received = recvfrom(handler->fd, + buffer_begin(q->packet), + buffer_remaining(q->packet), + 0, + (struct sockaddr *)&q->addr, + &q->addrlen); + if (received == -1) { + if (errno != EAGAIN && errno != EINTR) { + log_msg(LOG_ERR, "recvfrom failed: %s", strerror(errno)); + STATUP(data->nsd, rxerr); + } + break; + } else { + /* Account... */ + if (data->socket->addr->ai_family == AF_INET) { + STATUP(data->nsd, qudp); + } else if (data->socket->addr->ai_family == AF_INET6) { + STATUP(data->nsd, qudp6); + } + buffer_skip(q->packet, received); buffer_flip(q->packet); - sent = sendto(handler->fd, - buffer_begin(q->packet), - buffer_remaining(q->packet), - 0, - (struct sockaddr *) &q->addr, - q->addrlen); - if (sent == -1) { - log_msg(LOG_ERR, "sendto failed: %s", strerror(errno)); - STATUP(data->nsd, txerr); - } else if ((size_t) sent != buffer_remaining(q->packet)) { - log_msg(LOG_ERR, "sent %d in place of %d bytes", sent, (int) buffer_remaining(q->packet)); - } else { + /* Process and answer the query... */ + if (server_process_query(data->nsd, q) != QUERY_DISCARDED) { + if (RCODE(q->packet) == RCODE_OK && !AA(q->packet)) + STATUP(data->nsd, nona); + + /* Add EDNS0 and TSIG info if necessary. */ + query_add_optional(q, data->nsd); + + buffer_flip(q->packet); + + sent = sendto(handler->fd, + buffer_begin(q->packet), + buffer_remaining(q->packet), + 0, + (struct sockaddr *) &q->addr, + q->addrlen); + if (sent == -1) { + log_msg(LOG_ERR, "sendto failed: %s", strerror(errno)); + STATUP(data->nsd, txerr); + } else if ((size_t) sent != buffer_remaining(q->packet)) { + log_msg(LOG_ERR, "sent %d in place of %d bytes", sent, (int) buffer_remaining(q->packet)); + } else { #ifdef BIND8_STATS - /* Account the rcode & TC... */ - STATUP2(data->nsd, rcode, RCODE(q->packet)); - if (TC(q->packet)) - STATUP(data->nsd, truncated); + /* Account the rcode & TC... */ + STATUP2(data->nsd, rcode, RCODE(q->packet)); + if (TC(q->packet)) + STATUP(data->nsd, truncated); #endif /* BIND8_STATS */ + } + } else { + STATUP(data->nsd, dropped); } - } else { - STATUP(data->nsd, dropped); } } }