View Issue Details

IDProjectCategoryView StatusLast Update
0001735GNUnetutil librarypublic2011-07-18 19:56
ReporterLRN Assigned ToLRN  
PrioritynormalSeveritymajorReproducibilityalways
Status closedResolutionfixed 
Product VersionGit master 
Summary0001735: Introduce adaptive poll cycle length in GNUNET_NETWORK_socket_select ()
DescriptionThis patch uses variable select()/sleep() timeout instead of fixing it at 100000 microseconds.
Timeout starts at 20 microseconds.
Timeout is multiplied by 1.4 every time the cycle selects nothing (select() returns 0 on sockets, and polling pipes yields nothing).
Timeout is decreased by 2 microseconds every time the cycle selects something (either select() detects a socket state change, or pipe polling detects a pipe state change).
TagsNo tags attached.
Attached Files
0001-Use-adaptive-cycle-delay-in-w32-select.patch (2,934 bytes)   
From c3aafd522486c12776db69ac301d77f730291e1b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1?=
 =?UTF-8?q?=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Wed, 13 Jul 2011 04:07:04 +0400
Subject: [PATCH] Use adaptive cycle delay in w32 select()

---
 src/util/network.c |   34 +++++++++++++++++++++++++++++++---
 1 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/src/util/network.c b/src/util/network.c
index 726e295..48bd863 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -29,7 +29,9 @@
 #include "disk.h"
 #include "gnunet_container_lib.h"
 
-#define DEBUG_NETWORK GNUNET_YES
+#define DEBUG_NETWORK GNUNET_NO
+
+#define DEBUG_W32_CYCLES GNUNET_NO
 
 #ifndef INVALID_SOCKET
 #define INVALID_SOCKET -1
@@ -1106,6 +1108,8 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
   struct timeval tvslice;
   int retcode;
   DWORD ms_total;
+  /* Number of milliseconds per cycle. Adapted on the fly */
+  static unsigned int cycle_delay = 20;
 
 #define SAFE_FD_ISSET(fd, set)  (set != NULL && FD_ISSET(fd, set))
 
@@ -1145,6 +1149,12 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
   FD_ZERO (&aread);
   FD_ZERO (&awrite);
   FD_ZERO (&aexcept);
+
+#if DEBUG_W32_CYCLES
+  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+              "Starting a cycle, delay is %dms\n", cycle_delay);
+#endif
+
   limit = GetTickCount () + ms_total;
 
   do
@@ -1160,7 +1170,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
           FD_COPY (&sock_write, &awrite);
           FD_COPY (&sock_except, &aexcept);
           tvslice.tv_sec = 0;
-          tvslice.tv_usec = 100000;
+          tvslice.tv_usec = cycle_delay;
           if ((retcode =
                select (nfds + 1, &aread, &awrite, &aexcept,
                        &tvslice)) == SOCKET_ERROR)
@@ -1301,8 +1311,26 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
             }
         }
     select_loop_end:
+      if (retcode == 0)
+      {
+        /* Missed an I/O - double the cycle time */
+        cycle_delay = cycle_delay * 2 > 250 ? 250 : cycle_delay * 1.4;
+#if DEBUG_W32_CYCLES
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "The cycle missed, increased the delay to %dms\n", cycle_delay);
+#endif
+      }
+      else
+      {
+        /* Successfully selected something - decrease the cycle time */
+        cycle_delay -= cycle_delay > 2 ? 2 : 0;
+#if DEBUG_W32_CYCLES
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "The cycle hit, decreased the delay to %dms\n", cycle_delay);
+#endif
+      }
       if (retcode == 0 && nfds == 0)
-        Sleep (GNUNET_MIN (100, limit - GetTickCount ()));
+        Sleep (GNUNET_MIN (cycle_delay * 1000, limit - GetTickCount ()));
     }
   while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));
 
-- 
1.7.4

0001-Change-the-cycle-timeout-adjustment-for-w32-select.patch (6,342 bytes)   
From a37445b81ca9ad088bacca7064c021016a2a2ea2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1=D1?=
 =?UTF-8?q?=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= <lrn1986@gmail.com>
Date: Mon, 18 Jul 2011 20:47:46 +0400
Subject: [PATCH] Change the cycle timeout adjustment for w32 select

---
 src/util/network.c |   69 ++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 64 insertions(+), 5 deletions(-)

diff --git a/src/util/network.c b/src/util/network.c
index bef285b..6a74535 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -1152,7 +1152,7 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 
 #if DEBUG_W32_CYCLES
   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
-              "Starting a cycle, delay is %dms\n", cycle_delay);
+              "Starting a cycle, delay is %dms. nfds is %d.\n", cycle_delay, nfds);
 #endif
 
   limit = GetTickCount () + ms_total;
@@ -1171,6 +1171,30 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
           FD_COPY (&sock_except, &aexcept);
           tvslice.tv_sec = 0;
           tvslice.tv_usec = cycle_delay;
+#if DEBUG_W32_CYCLES
+          {
+            for (i = 0; i < nfds; i++)
+            {
+              if (SAFE_FD_ISSET (i, &sock_read))
+              {
+                GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Going to select socket %d for reading\n", i);
+              }
+              if (SAFE_FD_ISSET (i, &sock_write))
+              {
+                GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Going to select socket %d for writing\n", i);
+              }
+              if (SAFE_FD_ISSET (i, &sock_except))
+              {
+                GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Going to select socket %d for exceptions\n", i);
+              }
+            }
+          }
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Waiting for %d microseconds, %d left\n", cycle_delay, (limit - GetTickCount ())*1000);
+#endif
           if ((retcode =
                select (nfds + 1, &aread, &awrite, &aexcept,
                        &tvslice)) == SOCKET_ERROR)
@@ -1186,13 +1210,20 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
 #endif
               goto select_loop_end;
             }
+#if DEBUG_W32_CYCLES
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Select () returned %d, GLE is %d\n", retcode, GetLastError ());
+#endif
         }
 
       /* Poll read pipes */
       if (rfds)
-
         {
           struct GNUNET_CONTAINER_SList_Iterator *i;
+#if DEBUG_W32_CYCLES
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Polling rfds for readable pipes\n");
+#endif
           for (i = GNUNET_CONTAINER_slist_begin (rfds->handles);
                GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
                GNUNET_CONTAINER_slist_next (i))
@@ -1203,6 +1234,10 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
               fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (i, NULL);
               if (fh->type == GNUNET_PIPE)
                 {
+#if DEBUG_W32_CYCLES
+                  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Polling pipe 0x%x (0x%x)\n", fh, fh->h);
+#endif
                   if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
                     {
                       DWORD error_code = GetLastError ();
@@ -1250,6 +1285,10 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
       if (efds)
 
         {
+#if DEBUG_W32_CYCLES
+          GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                     "Polling efds for broken pipes\n");
+#endif
           struct GNUNET_CONTAINER_SList_Iterator *i;
           for (i = GNUNET_CONTAINER_slist_begin (efds->handles);
                GNUNET_CONTAINER_slist_end (i) != GNUNET_YES;
@@ -1262,6 +1301,10 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
               fh = (struct GNUNET_DISK_FileHandle *) GNUNET_CONTAINER_slist_get (i, NULL);
               if (fh->type == GNUNET_PIPE)
                 {
+#if DEBUG_W32_CYCLES
+                  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                              "Polling pipe 0x%x (0x%x)\n", fh, fh->h);
+#endif
                   if (!PeekNamedPipe (fh->h, NULL, 0, NULL, &dwBytes, NULL))
 
                     {
@@ -1313,8 +1356,13 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
     select_loop_end:
       if (retcode == 0)
       {
+        /* For pipes, there have been no select() call, so the poll is
+         * more likely to miss first time around. For now just don't increase
+         * the delay for pipes only.
+         */
+        if (nfds != 0)
+          cycle_delay = cycle_delay * 2 > 250000 ? 250000 : cycle_delay * 1.4;
         /* Missed an I/O - double the cycle time */
-        cycle_delay = cycle_delay * 2 > 250 ? 250 : cycle_delay * 1.4;
 #if DEBUG_W32_CYCLES
         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                     "The cycle missed, increased the delay to %dms\n", cycle_delay);
@@ -1323,14 +1371,25 @@ GNUNET_NETWORK_socket_select (struct GNUNET_NETWORK_FDSet *rfds,
       else
       {
         /* Successfully selected something - decrease the cycle time */
-        cycle_delay -= cycle_delay > 2 ? 2 : 0;
+        /* Minimum is 5 microseconds. Decrease the delay by half,
+         * or by 5000 - whichever is higher.
+         */
+        cycle_delay -= cycle_delay > 5000 ? GNUNET_MAX (5000, cycle_delay / 2) : cycle_delay - 5;
 #if DEBUG_W32_CYCLES
         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                     "The cycle hit, decreased the delay to %dms\n", cycle_delay);
 #endif
       }
       if (retcode == 0 && nfds == 0)
-        Sleep (GNUNET_MIN (cycle_delay * 1000, limit - GetTickCount ()));
+      {
+        long long diff = limit - GetTickCount ();
+        diff = diff > 0 ? diff : 0;
+#if DEBUG_W32_CYCLES
+        GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+                    "No sockets, sleeping for %d or %d ms\n", cycle_delay / 1000, diff);
+#endif
+        Sleep (GNUNET_MIN (cycle_delay / 1000, diff));
+      }
     }
   while (retcode == 0 && (ms_total == INFINITE || GetTickCount () < limit));
 
-- 
1.7.4

Relationships

related to 0001620 closedNDurner poll() implementation for W32 

Activities

Christian Grothoff

2011-07-14 19:09

manager   ~0004503

Committed as revision 15963.

LRN

2011-07-18 00:35

developer   ~0004517

Reopened to add another patch.

LRN

2011-07-18 00:42

developer   ~0004518

Added a patch that adjusts the delay.
1) Correctly uses microseconds, because select() takes timeout value in microseconds, so the code that is in current SVN HEAD actually times out after 250 _microseconds_ tops - obviously, that's a bit low.
2) Won't adjust the delay when poll misses on pipes and there are no sockets in fd_sets. Because pipes are checked first, and only then waited upon, it is not appropriate to count this against the the cycle length.
3) Delay adjustment code is made more aggressive towards decreasing the delay: It will cut it by half or by 5000 microseconds (whichever is higher) on every hit, while increasing it only by 1.4 times on every miss. This allows for the usual (fast) performance on transport tests (previous, unpublished, versions of this patch were stuck at 250000 microseconds, because misses influenced the delay more than hits did).

Christian Grothoff

2011-07-18 13:32

manager   ~0004519

That patch does not apply at all against SVN 16080. Can you supply one against SVN HEAD? (I don't even have an easy time finding the respective lines for sure...).

LRN

2011-07-18 18:48

developer   ~0004526

Replaced the patch with the correct version.

Christian Grothoff

2011-07-18 19:56

manager   ~0004527

Applied as SVN 16097.

Issue History

Date Modified Username Field Change
2011-07-13 02:12 LRN New Issue
2011-07-13 02:12 LRN File Added: 0001-Use-adaptive-cycle-delay-in-w32-select.patch
2011-07-14 19:09 Christian Grothoff Note Added: 0004503
2011-07-14 19:09 Christian Grothoff Status new => resolved
2011-07-14 19:09 Christian Grothoff Resolution open => fixed
2011-07-14 19:09 Christian Grothoff Assigned To => Christian Grothoff
2011-07-14 19:09 Christian Grothoff Assigned To Christian Grothoff => LRN
2011-07-15 14:38 Christian Grothoff Relationship added related to 0001620
2011-07-18 00:35 LRN Note Added: 0004517
2011-07-18 00:35 LRN Status resolved => feedback
2011-07-18 00:35 LRN Resolution fixed => reopened
2011-07-18 00:36 LRN File Added: 0001-Adjust-adaptive-cycle-delay-logic-a-bit.patch
2011-07-18 00:42 LRN Note Added: 0004518
2011-07-18 13:32 Christian Grothoff Note Added: 0004519
2011-07-18 18:48 LRN File Added: 0001-Change-the-cycle-timeout-adjustment-for-w32-select.patch
2011-07-18 18:48 LRN File Deleted: 0001-Adjust-adaptive-cycle-delay-logic-a-bit.patch
2011-07-18 18:48 LRN Note Added: 0004526
2011-07-18 19:56 Christian Grothoff Note Added: 0004527
2011-07-18 19:56 Christian Grothoff Status feedback => resolved
2011-07-18 19:56 Christian Grothoff Resolution reopened => fixed
2011-07-18 19:56 Christian Grothoff Status resolved => closed