sched: Optimize the case of zero timeouts.
authorAndre Noll <maan@systemlinux.org>
Thu, 21 Jul 2011 17:59:46 +0000 (19:59 +0200)
committerAndre Noll <maan@systemlinux.org>
Sat, 30 Jul 2011 18:27:55 +0000 (20:27 +0200)
If a pre_select method calls sched_min_delay() there is no
point in calling the pre_select hooks of the other tasks since
these can not decrease the timeout any further, and adding file
descriptors to the fd sets makes no sense either. So we may
break out early in sched_preselect() in this case.

If the timeout is zero we may even omit the entire select call as
well as the subsequent gettimeofday() since select() will return
immediately anyway. This patch teaches sched_postselect() to do so
which saves at least two system calls (plus locking in case of
para_server) in a rather hot path.

sched.c

diff --git a/sched.c b/sched.c
index 7b5ca63..ca365f1 100644 (file)
--- a/sched.c
+++ b/sched.c
@@ -9,6 +9,7 @@
 #include <regex.h>
 #include <assert.h>
 #include <sys/time.h>
+#include <stdbool.h>
 
 #include "para.h"
 #include "ipc.h"
@@ -46,14 +47,25 @@ static void unregister_task(struct task *t)
                list_del(&t->post_select_node);
 }
 
+static inline bool timeout_is_zero(struct sched *s)
+{
+       struct timeval *tv = &s->select_timeout;
+       return tv->tv_sec == 0 && tv->tv_usec == 0;
+}
+
 static void sched_preselect(struct sched *s)
 {
        struct task *t, *tmp;
        list_for_each_entry_safe(t, tmp, &pre_select_list, pre_select_node) {
-               if (t->pre_select)
-                       t->pre_select(s, t);
-               if (t->error < 0)
+               if (t->error < 0) {
                        unregister_task(t);
+                       continue;
+               }
+               if (!t->pre_select)
+                       continue;
+               t->pre_select(s, t);
+               if (timeout_is_zero(s))
+                       break;
        }
 }
 
@@ -131,21 +143,23 @@ again:
        sched_preselect(s);
        if (list_empty(&pre_select_list) && list_empty(&post_select_list))
                return 0;
-       ret = s->select_function(s->max_fileno + 1, &s->rfds, &s->wfds,
-               &s->select_timeout);
-       if (ret < 0)
-               return ret;
-       if (ret == 0) {
-               /*
-                * APUE: Be careful not to check the descriptor sets on return
-                * unless the return value is greater than zero. The return
-                * state of the descriptor sets is implementation dependent if
-                * either a signal is caught or the timer expires.
-                */
-               FD_ZERO(&s->rfds);
-               FD_ZERO(&s->wfds);
+       if (!timeout_is_zero(s)) {
+               ret = s->select_function(s->max_fileno + 1, &s->rfds, &s->wfds,
+                       &s->select_timeout);
+               if (ret < 0)
+                       return ret;
+               if (ret == 0) {
+                       /*
+                        * APUE: Be careful not to check the descriptor sets on return
+                        * unless the return value is greater than zero. The return
+                        * state of the descriptor sets is implementation dependent if
+                        * either a signal is caught or the timer expires.
+                        */
+                       FD_ZERO(&s->rfds);
+                       FD_ZERO(&s->wfds);
+               }
+               gettimeofday(now, NULL);
        }
-       gettimeofday(now, NULL);
        sched_post_select(s);
        if (list_empty(&pre_select_list) && list_empty(&post_select_list))
                return 0;