/*
- 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 *************************************************/
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 */
/*
"MaxConnRate: %d\n"
"Tasks: %d\n"
"Run_queue: %d\n"
+ "Idle_pct: %d\n"
"node: %s\n"
"description: %s\n"
"",
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)
"<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\"> </td><td class=\"noborder\">active UP </td>"
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)
}
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;
}
fd = MIN(maxfd, global.tune.maxpollevents);
+ gettimeofday(&before_poll, NULL);
status = kevent(kqueue_fd, // int kq
NULL, // const struct kevent *changelist
0, // int nchanges
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;
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;
//
// }
+ gettimeofday(&before_poll, NULL);
status = select(maxfd,
readnotnull ? tmp_evts[DIR_RD] : NULL,
writenotnull ? tmp_evts[DIR_WR] : NULL,
&delta);
tv_update_date(delta_ms, status);
+ measure_idle();
if (status <= 0)
return;
/* 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;
/*
* 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>
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);