]> git.gsnw.org Git - fping.git/commitdiff
Performance: use MSG_DONTWAIT instead of select.
authorDavid Schweikert <david@schweikert.ch>
Fri, 2 Jan 2026 07:49:06 +0000 (08:49 +0100)
committerDavid Schweikert <david@schweikert.ch>
Sun, 4 Jan 2026 17:34:36 +0000 (18:34 +0100)
This also improves a bit the conversion from nanoseconds to
seconds + microseconds.

CHANGELOG.md
configure.ac
src/fping.c

index 877b703c50b018c1165b4bd69686199ecb84b084..d83086d3e361f7ee36e2fa517e8293524502e8cf 100644 (file)
@@ -5,7 +5,9 @@ Next
 
 ## Bugfixes and other changes
 
-- ci: Removing travis-ci (#446, thanks @gsnw-sebast)
+- ci: Removed travis-ci (#446, thanks @gsnw-sebast)
+- Performance optimization: reduce number of select calls and use
+  recvmsg with MSG_DONTWAIT instead (#449)
 
 fping 5.5 (2025-12-31)
 ======================
index b2b7f1bb9406ffeb94043a0a2f246f98d8d6a87f..115f9060408b0ffb01df6f8e62897764e6f06001 100644 (file)
@@ -129,6 +129,9 @@ AH_BOTTOM([
 dnl Checks for header files.
 AC_CHECK_HEADERS([unistd.h sys/file.h stdlib.h sys/select.h])
 
+AC_CHECK_DECL([MSG_DONTWAIT], [AC_DEFINE(HAVE_MSG_DONTWAIT, [1], [MSG_DONTWAIT is defined])], [], [#include <sys/types.h>
+#include <sys/socket.h>])
+
 AC_CONFIG_FILES([Makefile
                  doc/Makefile
                  src/Makefile])
index ecba673bf54f7466c685b39f9fa52f394eb55ddc..ada52550b36ced9c2d24eb7f58d6bce11a8ae573 100644 (file)
@@ -2806,24 +2806,36 @@ int receive_packet(int64_t wait_time,
     struct cmsghdr *cmsg;
 
     /* Wait for a socket to become ready */
-    if (wait_time) {
-        to.tv_sec = wait_time / UINT64_C(1000000000);
-        to.tv_usec = (wait_time % UINT64_C(1000000000)) / 1000 + 1;
-    }
-    else {
-        to.tv_sec = 0;
-        to.tv_usec = 0;
-    }
-    s = socket_can_read(&to);
-    if (s == -1) {
-        return 0; /* timeout */
+#if HAVE_MSG_DONTWAIT
+    if (wait_time == 0) {
+        /* Optimization: if wait_time is 0, we can skip select() and just try to
+         * read from the sockets with MSG_DONTWAIT */
+        recv_len = (socket4 >= 0) ? recvmsg(socket4, &recv_msghdr, MSG_TRUNC | MSG_DONTWAIT) : -1;
+#ifdef IPV6
+        if (recv_len <= 0 && socket6 >= 0) {
+            /* Reset fields potentially modified by failed recvmsg */
+            recv_msghdr.msg_namelen = reply_src_addr_len;
+            recv_msghdr.msg_controllen = sizeof(msg_control);
+            recv_len = recvmsg(socket6, &recv_msghdr, MSG_TRUNC | MSG_DONTWAIT);
+        }
+#endif
+        if (recv_len > 0) {
+            goto packet_received;
+        }
+        return 0;
     }
+#endif
+
+    int64_t wait_us = (wait_time + 999) / 1000; // round up (1 ns -> 1 us)
+    to.tv_sec = wait_us / 1000000;
+    to.tv_usec = wait_us % 1000000;
 
-    recv_len = recvmsg(s, &recv_msghdr, MSG_TRUNC);
-    if (recv_len <= 0) {
+    s = socket_can_read(&to);
+    if (s == -1 || (recv_len = recvmsg(s, &recv_msghdr, MSG_TRUNC)) <= 0) {
         return 0;
     }
 
+packet_received:
     /* ancilliary data */
     {
 #if HAVE_SO_TIMESTAMPNS