diff --git a/include/common/time.h b/include/common/time.h index abc1ccfa3..14ca58959 100644 --- a/include/common/time.h +++ b/include/common/time.h @@ -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 @@ -57,9 +57,14 @@ 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 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 */ /* diff --git a/src/dumpstats.c b/src/dumpstats.c index 5dcd8c4b7..ebfb17966 100644 --- a/src/dumpstats.c +++ b/src/dumpstats.c @@ -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) "system limits: memmax = %s%s; ulimit-n = %d
\n" "maxsock = %d; maxconn = %d; maxpipes = %d
\n" "current conns = %d; current pipes = %d/%d; conn rate = %d/sec
\n" - "Running tasks: %d/%d
\n" + "Running tasks: %d/%d; idle = %d %%
\n" "\n" "\n" "" @@ -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) diff --git a/src/ev_epoll.c b/src/ev_epoll.c index 958c4e68f..bc7493b40 100644 --- a/src/ev_epoll.c +++ b/src/ev_epoll.c @@ -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; diff --git a/src/ev_kqueue.c b/src/ev_kqueue.c index e16798424..b43533ab5 100644 --- a/src/ev_kqueue.c +++ b/src/ev_kqueue.c @@ -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; diff --git a/src/ev_poll.c b/src/ev_poll.c index f5d011eea..ec18863b4 100644 --- a/src/ev_poll.c +++ b/src/ev_poll.c @@ -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; diff --git a/src/ev_select.c b/src/ev_select.c index 5a87282d2..0924e3fda 100644 --- a/src/ev_select.c +++ b/src/ev_select.c @@ -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; diff --git a/src/ev_sepoll.c b/src/ev_sepoll.c index c9c597877..a7fb64c22 100644 --- a/src/ev_sepoll.c +++ b/src/ev_sepoll.c @@ -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; diff --git a/src/time.c b/src/time.c index 1b0f72c45..4c4123918 100644 --- a/src/time.c +++ b/src/time.c @@ -1,7 +1,7 @@ /* * Time calculation functions. * - * Copyright 2000-2009 Willy Tarreau + * Copyright 2000-2011 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -19,9 +19,14 @@ 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 to , set the result to and returns a pointer @@ -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);
 active UP