]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] poll: add a measurement of idle vs work time
authorWilly Tarreau <w@1wt.eu>
Sat, 10 Sep 2011 14:56:42 +0000 (16:56 +0200)
committerWilly Tarreau <w@1wt.eu>
Sat, 10 Sep 2011 16:01:41 +0000 (18:01 +0200)
We now measure the work and idle times in order to report the idle
time in the stats. It's expected that we'll be able to use it at
other places later.

include/common/time.h
src/dumpstats.c
src/ev_epoll.c
src/ev_kqueue.c
src/ev_poll.c
src/ev_select.c
src/ev_sepoll.c
src/time.c

index abc1ccfa3f356ea4307a340fd26f52ec274e8502..14ca58959d7243c9604bad96742e15f86e3d9ddc 100644 (file)
@@ -1,23 +1,23 @@
 /*
-  include/common/time.h
-  Time calculation functions and macros.
-
 Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
-  
-  This library is free software; you can redistribute it and/or
-  modify it under the terms of the GNU Lesser General Public
-  License as published by the Free Software Foundation, version 2.1
-  exclusively.
-
-  This library is distributed in the hope that it will be useful,
-  but WITHOUT ANY WARRANTY; without even the implied warranty of
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  Lesser General Public License for more details.
-
-  You should have received a copy of the GNU Lesser General Public
-  License along with this library; if not, write to the Free Software
-  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
-*/
* include/common/time.h
* Time calculation functions and macros.
+ *
* Copyright (C) 2000-2011 Willy Tarreau - w@1wt.eu
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, version 2.1
* exclusively.
+ *
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
+ *
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
 
 #ifndef _COMMON_TIME_H
 #define _COMMON_TIME_H
 extern unsigned int   curr_sec_ms;      /* millisecond of current second (0..999) */
 extern unsigned int   curr_sec_ms_scaled;  /* millisecond of current second (0..2^32-1) */
 extern unsigned int   now_ms;           /* internal date in milliseconds (may wrap) */
+extern unsigned int   samp_time;        /* total elapsed time over current sample */
+extern unsigned int   idle_time;        /* total idle time over current sample */
+extern unsigned int   idle_pct;         /* idle to total ratio over last sample (percent) */
 extern struct timeval now;              /* internal date is a monotonic function of real clock */
 extern struct timeval date;             /* the real current date */
 extern struct timeval start_date;       /* the process's start date */
+extern struct timeval before_poll;      /* system date before calling poll() */
+extern struct timeval after_poll;       /* system date after leaving poll() */
 
 
 /**** exported functions *************************************************/
@@ -516,6 +521,35 @@ REGPRM3 static inline struct timeval *__tv_ms_add(struct timeval *tv, const stru
 
 char *human_time(int t, short hz_div);
 
+/* Update the idle time value twice a second, to be called after
+ * tv_update_date() when called after poll(). It relies on <before_poll> to be
+ * updated to the system time before calling poll().
+ */
+static inline void measure_idle()
+{
+       /* Let's compute the idle to work ratio. We worked between after_poll
+        * and before_poll, and slept between before_poll and date. The idle_pct
+        * is updated at most twice every second. Note that the current second
+        * rarely changes so we avoid a multiply when not needed.
+        */
+       int delta;
+
+       if ((delta = date.tv_sec - before_poll.tv_sec))
+               delta *= 1000000;
+       idle_time += delta + (date.tv_usec - before_poll.tv_usec);
+
+       if ((delta = date.tv_sec - after_poll.tv_sec))
+               delta *= 1000000;
+       samp_time += delta + (date.tv_usec - after_poll.tv_usec);
+
+       after_poll.tv_sec = date.tv_sec; after_poll.tv_usec = date.tv_usec;
+       if (samp_time < 500000)
+               return;
+
+       idle_pct = (100 * idle_time + samp_time / 2) / samp_time;
+       idle_time = samp_time = 0;
+}
+
 #endif /* _COMMON_TIME_H */
 
 /*
index 5dcd8c4b7285b39a6ce3e21732fc7d14e4ba8968..ebfb17966a6ff904329706980d121e8443f690fc 100644 (file)
@@ -1605,6 +1605,7 @@ static int stats_dump_raw_to_buffer(struct stream_interface *si)
                                     "MaxConnRate: %d\n"
                                     "Tasks: %d\n"
                                     "Run_queue: %d\n"
+                                    "Idle_pct: %d\n"
                                     "node: %s\n"
                                     "description: %s\n"
                                     "",
@@ -1618,7 +1619,7 @@ static int stats_dump_raw_to_buffer(struct stream_interface *si)
                                     global.maxsock, global.maxconn, global.hardmaxconn, global.maxpipes,
                                     actconn, pipes_used, pipes_free,
                                     read_freq_ctr(&global.conn_per_sec), global.cps_lim, global.cps_max,
-                                    nb_tasks_cur, run_queue_cur,
+                                    nb_tasks_cur, run_queue_cur, idle_pct,
                                     global.node, global.desc?global.desc:""
                                     );
                        if (buffer_feed_chunk(si->ib, &msg) >= 0)
@@ -1934,7 +1935,7 @@ static int stats_dump_http(struct stream_interface *si, struct uri_auth *uri)
                             "<b>system limits:</b> memmax = %s%s; ulimit-n = %d<br>\n"
                             "<b>maxsock = </b> %d; <b>maxconn = </b> %d; <b>maxpipes = </b> %d<br>\n"
                             "current conns = %d; current pipes = %d/%d; conn rate = %d/sec<br>\n"
-                            "Running tasks: %d/%d<br>\n"
+                            "Running tasks: %d/%d; idle = %d %%<br>\n"
                             "</td><td align=\"center\" nowrap>\n"
                             "<table class=\"lgd\"><tr>\n"
                             "<td class=\"active3\">&nbsp;</td><td class=\"noborder\">active UP </td>"
@@ -1967,7 +1968,7 @@ static int stats_dump_http(struct stream_interface *si, struct uri_auth *uri)
                             global.rlimit_nofile,
                             global.maxsock, global.maxconn, global.maxpipes,
                             actconn, pipes_used, pipes_used+pipes_free, read_freq_ctr(&global.conn_per_sec),
-                            run_queue_cur, nb_tasks_cur
+                            run_queue_cur, nb_tasks_cur, idle_pct
                             );
 
                        if (si->applet.ctx.stats.flags & STAT_HIDE_DOWN)
index 958c4e68f4bb2ae09c9c76eacb855ab5f7de218d..bc7493b406a0372a2413817bb4d8fa2713a126b4 100644 (file)
@@ -236,8 +236,10 @@ REGPRM2 static void _do_poll(struct poller *p, int exp)
        }
 
        fd = MIN(maxfd, global.tune.maxpollevents);
+       gettimeofday(&before_poll, NULL);
        status = epoll_wait(epoll_fd, epoll_events, fd, wait_time);
        tv_update_date(wait_time, status);
+       measure_idle();
 
        for (count = 0; count < status; count++) {
                fd = epoll_events[count].data.fd;
index e16798424197eae98e1f6fad02399c683906538a..b43533ab5c09bdcd5081589477ae779c2090805b 100644 (file)
@@ -126,6 +126,7 @@ REGPRM2 static void _do_poll(struct poller *p, int exp)
        }
 
        fd = MIN(maxfd, global.tune.maxpollevents);
+       gettimeofday(&before_poll, NULL);
        status = kevent(kqueue_fd, // int kq
                        NULL,      // const struct kevent *changelist
                        0,         // int nchanges
@@ -133,6 +134,7 @@ REGPRM2 static void _do_poll(struct poller *p, int exp)
                        fd,        // int nevents
                        &timeout); // const struct timespec *timeout
        tv_update_date(delta_ms, status);
+       measure_idle();
 
        for (count = 0; count < status; count++) {
                fd = kev[count].ident;
index f5d011eea4bfe5595d8aee0a05ffe81c86ac088c..ec18863b44f9bc2b285f782c0caa089c9fb07f06 100644 (file)
@@ -137,8 +137,10 @@ REGPRM2 static void _do_poll(struct poller *p, int exp)
                        wait_time = MAX_DELAY_MS;
        }
 
+       gettimeofday(&before_poll, NULL);
        status = poll(poll_events, nbfd, wait_time);
        tv_update_date(wait_time, status);
+       measure_idle();
 
        for (count = 0; status > 0 && count < nbfd; count++) {
                fd = poll_events[count].fd;
index 5a87282d29f5d196353ad1edf9ebeb9fffdbd243..0924e3fda99a0fddaddb4ba93b6d4d274bd25eb9 100644 (file)
@@ -125,6 +125,7 @@ REGPRM2 static void _do_poll(struct poller *p, int exp)
        //          
        //      }
 
+       gettimeofday(&before_poll, NULL);
        status = select(maxfd,
                        readnotnull ? tmp_evts[DIR_RD] : NULL,
                        writenotnull ? tmp_evts[DIR_WR] : NULL,
@@ -132,6 +133,7 @@ REGPRM2 static void _do_poll(struct poller *p, int exp)
                        &delta);
       
        tv_update_date(delta_ms, status);
+       measure_idle();
 
        if (status <= 0)
                return;
index c9c59787703f91993b8fdfa319a5ccb6630d3608..a7fb64c227f00fcc63eddb3b768d8970e2f5c9e0 100644 (file)
@@ -475,8 +475,10 @@ REGPRM2 static void _do_poll(struct poller *p, int exp)
        /* we want to detect if an accept() will create new speculative FDs here */
        fd_created = 0;
        spec_processed = 0;
+       gettimeofday(&before_poll, NULL);
        status = epoll_wait(epoll_fd, epoll_events, fd, wait_time);
        tv_update_date(wait_time, status);
+       measure_idle();
 
        for (count = 0; count < status; count++) {
                int e = epoll_events[count].events;
index 1b0f72c45bd7e1ee0bb089f166da3b58a87a01d9..4c412391828e262e127604e6ecca59e43dcc9518 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Time calculation functions.
  *
- * Copyright 2000-2009 Willy Tarreau <w@1wt.eu>
+ * Copyright 2000-2011 Willy Tarreau <w@1wt.eu>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 unsigned int   curr_sec_ms;      /* millisecond of current second (0..999) */
 unsigned int   curr_sec_ms_scaled;  /* millisecond of current second (0..2^32-1) */
 unsigned int   now_ms;          /* internal date in milliseconds (may wrap) */
+unsigned int   samp_time;       /* total elapsed time over current sample */
+unsigned int   idle_time;       /* total idle time over current sample */
+unsigned int   idle_pct;        /* idle to total ratio over last sample (percent) */
 struct timeval now;             /* internal date is a monotonic function of real clock */
 struct timeval date;            /* the real current date */
 struct timeval start_date;      /* the process's start date */
+struct timeval before_poll;     /* system date before calling poll() */
+struct timeval after_poll;      /* system date after leaving poll() */
 
 /*
  * adds <ms> ms to <from>, set the result to <tv> and returns a pointer <tv>
@@ -165,6 +170,9 @@ REGPRM2 void tv_update_date(int max_wait, int interrupted)
        if (unlikely(max_wait < 0)) {
                tv_zero(&tv_offset);
                adjusted = date;
+               after_poll = date;
+               samp_time = idle_time = 0;
+               idle_pct = 100;
                goto to_ms;
        }
        __tv_add(&adjusted, &date, &tv_offset);