From ea94549cb2a44330d14a550437a70fb49b5f554e Mon Sep 17 00:00:00 2001 From: Joel Cunningham Date: Wed, 17 Feb 2016 16:33:35 -0600 Subject: [PATCH] Optimize lwip_selscan() This makes a couple of simple re-arrangements in lwip_selscan() that should improve performance in the following ways: 1) The old code linearly walked all sockets to maxfd regardless of whether they were set in the fd set. The process involved acquiring sys arch protect, looking up the socket, and then checking if the socket was present in any of the fd sets. On systems with lots of sockets and a heavy SYS_ARCH_PROTECT infrastructure (a mutex) this can result in a lot of extra work. Now we skip this process for any fd that is not in the input sets 2) If the socket from tryget_socket() is NULL we no longer continue and compare the input fd sets with a zeroed out set of events 3) We no longer need to zero out our event sets because they are only accessed when tryget_socket() is successful lwip_selscan() is called at most once per select call and sometimes up to three times --- src/api/sockets.c | 62 ++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 28 deletions(-) diff --git a/src/api/sockets.c b/src/api/sockets.c index e47aba5a..92a168f2 100644 --- a/src/api/sockets.c +++ b/src/api/sockets.c @@ -1315,38 +1315,44 @@ lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *excep /* Go through each socket in each list to count number of sockets which currently match */ for (i = LWIP_SOCKET_OFFSET; i < maxfdp1; i++) { - void* lastdata = NULL; - s16_t rcvevent = 0; - u16_t sendevent = 0; - u16_t errevent = 0; + /* if this FD is not in the set, continue */ + if (!(readset_in && FD_ISSET(i, readset_in)) && + !(writeset_in && FD_ISSET(i, writeset_in)) && + !(exceptset_in && FD_ISSET(i, exceptset_in))) { + continue; + } /* First get the socket's status (protected)... */ SYS_ARCH_PROTECT(lev); sock = tryget_socket(i); if (sock != NULL) { - lastdata = sock->lastdata; - rcvevent = sock->rcvevent; - sendevent = sock->sendevent; - errevent = sock->errevent; - } - SYS_ARCH_UNPROTECT(lev); - /* ... then examine it: */ - /* See if netconn of this socket is ready for read */ - if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { - FD_SET(i, &lreadset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); - nready++; - } - /* See if netconn of this socket is ready for write */ - if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { - FD_SET(i, &lwriteset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); - nready++; - } - /* See if netconn of this socket had an error */ - if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { - FD_SET(i, &lexceptset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); - nready++; + void* lastdata = sock->lastdata; + s16_t rcvevent = sock->rcvevent; + u16_t sendevent = sock->sendevent; + u16_t errevent = sock->errevent; + SYS_ARCH_UNPROTECT(lev); + + /* ... then examine it: */ + /* See if netconn of this socket is ready for read */ + if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { + FD_SET(i, &lreadset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); + nready++; + } + /* See if netconn of this socket is ready for write */ + if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { + FD_SET(i, &lwriteset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); + nready++; + } + /* See if netconn of this socket had an error */ + if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { + FD_SET(i, &lexceptset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); + nready++; + } + } else { + SYS_ARCH_UNPROTECT(lev); + /* continue on to next FD in list */ } } /* copy local sets to the ones provided as arguments */