lots of useless recvfrom() calls
Lennert Buytenhek
buytenh at wantstofly.org
Sun Jun 3 00:59:31 MSK 2018
On Mon, May 21, 2018 at 09:41:11AM +0300, Lennert Buytenhek wrote:
> > > > I am using the patch below to avoid one useless recvfrom() call (that
> > > > returns EAGAIN) for every call to dns_ioevent(). Under low load, where
> > > > every call to dns_ioevent() processes one DNS reply, this saves half of
> > > > the total number of recvfrom() calls.
> > >
> > > Is it really a problem under low load? If the load is low, it doesn't
> > > really matter how many recvfrom() system calls are made, I think.
> >
> > 'low load' here is 'a low expected number of reply packets per POLLIN
> > cycle', but even for a large number of queries per second and multiple
> > parallel queries, I would not expect there to be more than one reply
> > packet per POLLIN cycle very often.
>
> Another option is to try to recv() a packet up to as many times as we
> have an outstanding DNS query on this context. So if there is one
> outstanding DNS query, always return after one recv() call, if there
> are five, then try up to five times (but return as soon as we get
> EAGAIN), etc.
This patch does that, and it seems to work, but it does break the
implicit guarantee that dns_ioevent() can be used with an
edge-triggered poll method. :(
diff --git a/udns_resolver.c b/udns_resolver.c
index be8ce8a..5711921 100644
--- a/udns_resolver.c
+++ b/udns_resolver.c
@@ -167,7 +167,8 @@ struct dns_ctx { /* resolver context */
unsigned dnsc_nextid; /* next queue ID to use if !0 */
int dnsc_udpsock; /* UDP socket */
struct dns_qlist dnsc_qactive; /* active list sorted by deadline */
- int dnsc_nactive; /* number entries in dnsc_qactive */
+ unsigned dnsc_nqueued; /* number entries in dnsc_qactive */
+ unsigned dnsc_ndequeued;
dnsc_t *dnsc_pbuf; /* packet buffer (udpbuf size) */
int dnsc_qstatus; /* last query status value */
};
@@ -200,7 +201,8 @@ struct dns_ctx dns_defctx;
#define CTXINITED(ctx) (ctx->dnsc_flags & DNS_INITED)
#define SETCTXFRESH(ctx) SETCTXINITED(ctx); assert(!CTXOPEN(ctx))
#define SETCTXINACTIVE(ctx) \
- SETCTXINITED(ctx); assert(!ctx->dnsc_nactive)
+ SETCTXINITED(ctx); \
+ assert(ctx->dnsc_nqueued == ctx->dnsc_ndequeued)
#define SETCTXOPEN(ctx) SETCTXINITED(ctx); assert(CTXOPEN(ctx))
#define CTXOPEN(ctx) (ctx->dnsc_udpsock >= 0)
@@ -218,7 +220,7 @@ static void dns_assert_ctx(const struct dns_ctx *ctx) {
q->dnsq_prev->dnsq_next : ctx->dnsc_qactive.head));
++nactive;
}
- assert(nactive == ctx->dnsc_nactive);
+ assert(nactive == ctx->dnsc_nqueued - ctx->dnsc_ndequeued);
}
#endif
@@ -431,7 +433,7 @@ void dns_close(struct dns_ctx *ctx) {
free(p);
}
qlist_init(&ctx->dnsc_qactive);
- ctx->dnsc_nactive = 0;
+ ctx->dnsc_ndequeued = ctx->dnsc_nqueued;
dns_drop_utm(ctx);
}
}
@@ -462,7 +464,8 @@ struct dns_ctx *dns_new(const struct dns_ctx *copy) {
*ctx = *copy;
ctx->dnsc_udpsock = -1;
qlist_init(&ctx->dnsc_qactive);
- ctx->dnsc_nactive = 0;
+ ctx->dnsc_nqueued = 0;
+ ctx->dnsc_ndequeued = 0;
ctx->dnsc_pbuf = NULL;
ctx->dnsc_qstatus = 0;
ctx->dnsc_srchend = ctx->dnsc_srchbuf +
@@ -588,7 +591,7 @@ int dns_sock(const struct dns_ctx *ctx) {
int dns_active(const struct dns_ctx *ctx) {
SETCTXINITED(ctx);
dns_assert_ctx(ctx);
- return ctx->dnsc_nactive;
+ return ctx->dnsc_nqueued - ctx->dnsc_ndequeued;
}
int dns_status(const struct dns_ctx *ctx) {
@@ -611,8 +614,8 @@ dns_end_query(struct dns_ctx *ctx, struct dns_query *q,
ctx->dnsc_qstatus = status;
assert((status < 0 && result == 0) || (status >= 0 && result != 0));
assert(cbck != 0); /*XXX callback may be NULL */
- assert(ctx->dnsc_nactive > 0);
- --ctx->dnsc_nactive;
+ assert(ctx->dnsc_nqueued > ctx->dnsc_ndequeued);
+ ctx->dnsc_ndequeued++;
qlist_remove(&ctx->dnsc_qactive, q);
/* force the query to be unconnected */
/*memset(q, 0, sizeof(*q));*/
@@ -925,7 +928,7 @@ dns_submit_dn(struct dns_ctx *ctx,
* will actually send it.
*/
qlist_add_head(&ctx->dnsc_qactive, q);
- ++ctx->dnsc_nactive;
+ ++ctx->dnsc_nqueued;
dns_request_utm(ctx, 0);
return q;
@@ -1188,6 +1191,8 @@ static int dns_ioevent_internal(struct dns_ctx *ctx, time_t now) {
* loop forever if an error IS fatal.
*/
void dns_ioevent(struct dns_ctx *ctx, time_t now) {
+ unsigned nqueued;
+
SETCTX(ctx);
if (!CTXOPEN(ctx))
return;
@@ -1195,7 +1200,8 @@ void dns_ioevent(struct dns_ctx *ctx, time_t now) {
if (!now) now = time(NULL);
- while (dns_ioevent_internal(ctx, now));
+ nqueued = ctx->dnsc_nqueued;
+ while (nqueued > ctx->dnsc_ndequeued && dns_ioevent_internal(ctx, now));
dns_request_utm(ctx, now);
}
@@ -1317,7 +1323,7 @@ int dns_cancel(struct dns_ctx *ctx, struct dns_query *q) {
if (q->dnsq_cbck == dns_resolve_cb)
return (ctx->dnsc_qstatus = DNS_E_BADQUERY);
qlist_remove(&ctx->dnsc_qactive, q);
- --ctx->dnsc_nactive;
+ ++ctx->dnsc_ndequeued;
dns_request_utm(ctx, 0);
return 0;
}
More information about the udns
mailing list