From 971b1d95e2e3d1ddc640e33f8cab06396cf10661 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 12 Jul 2013 11:28:11 +0200 Subject: ifpps: Optionally display median values for CPU load and interrupts Using the -m/--median command line option, median values across all CPUs are displayed for CPU load, interrupts per interval, sw interrupts per interval and absolute number of interrupts. Also update the manpage accordingly. Signed-off-by: Tobias Klauser --- ifpps.8 | 7 ++++- ifpps.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/ifpps.8 b/ifpps.8 index 16bbf6d..c151899 100644 --- a/ifpps.8 +++ b/ifpps.8 @@ -41,7 +41,8 @@ the number of CPUs exceeds 5 or the number specified by the user with the heavy hitters. The topmost heavy hitter CPU will be marked with \[lq]+\[rq]. The least heavy hitter will always be displayed and is marked with \[lq]-\[rq]. In addition, the average for all the above per-CPU data is -shown. +shown. Optionally the median values can be displayed using the \[lq]\-m\[rq] +command line option. .PP ifpps also supports directly the gnuplot(1) data sample format. This facilitates creation of gnuplot figures from ifpps time series. @@ -70,6 +71,10 @@ is only available, if option \[lq]\-c\[rq] is given. For \[lq]\-l\[rq] it is usually recommended to redirect the output into a file that is to be be processed later with gnuplot(1). .PP +.SS -m, --median +Show median values across all CPUs for CPU load, interrupts (per interval and +absolute) and software interrupts. +.PP .SS -W, --no-warn Suppress possible warnings in the ncurses output, e.g. about a too low sampling interval that could cause performance regression. diff --git a/ifpps.c b/ifpps.c index eb9b899..0c684e6 100644 --- a/ifpps.c +++ b/ifpps.c @@ -72,10 +72,11 @@ static struct ifstat stats_old, stats_new, stats_delta; static struct cpu_hit *cpu_hits; static struct avg_stat stats_avg; static int stats_loop = 0; +static int show_median = 0; static WINDOW *stats_screen = NULL; static struct utsname uts; -static const char *short_options = "d:t:n:vhclpW"; +static const char *short_options = "d:t:n:vhclpmW"; static const struct option long_options[] = { {"dev", required_argument, NULL, 'd'}, {"interval", required_argument, NULL, 't'}, @@ -83,6 +84,7 @@ static const struct option long_options[] = { {"promisc", no_argument, NULL, 'p'}, {"csv", no_argument, NULL, 'c'}, {"loop", no_argument, NULL, 'l'}, + {"median", no_argument, NULL, 'm'}, {"no-warn", no_argument, NULL, 'W'}, {"version", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 'h'}, @@ -798,6 +800,14 @@ static void screen_percpu_states_one(WINDOW *screen, const struct ifstat *rel, 100.0 * rel->cpu_iow[idx] / all); } +#define MEDIAN_EVEN(member) do { \ + m_##member = (rel->member[i] + rel->member[j]) / 2; \ +} while (0) + +#define MEDIAN_ODD(member) do { \ + m_##member = rel->member[i]; \ +} while (0) + static void screen_percpu_states(WINDOW *screen, const struct ifstat *rel, const struct avg_stat *avg, int top_cpus, int *voff) @@ -834,6 +844,40 @@ static void screen_percpu_states(WINDOW *screen, const struct ifstat *rel, 100.0 * avg->cpu_sys / all, 100.0 * avg->cpu_idle /all, 100.0 * avg->cpu_iow / all); + + if (show_median) { + long double m_cpu_user, m_cpu_nice, m_cpu_sys, m_cpu_idle, m_cpu_iow; + + i = cpu_hits[cpus / 2].idx; + if (cpus % 2 == 0) { + /* take the mean of the 2 middle entries */ + int j = cpu_hits[(cpus / 2) - 1].idx; + + MEDIAN_EVEN(cpu_user); + MEDIAN_EVEN(cpu_nice); + MEDIAN_EVEN(cpu_sys); + MEDIAN_EVEN(cpu_idle); + MEDIAN_EVEN(cpu_iow); + } else { + /* take the middle entry as is */ + MEDIAN_ODD(cpu_user); + MEDIAN_ODD(cpu_nice); + MEDIAN_ODD(cpu_sys); + MEDIAN_ODD(cpu_idle); + MEDIAN_ODD(cpu_iow); + } + + all = m_cpu_user + m_cpu_sys + m_cpu_nice + m_cpu_idle + m_cpu_iow; + mvwprintw(screen, (*voff)++, 2, + "med: %14.1lf%% " + "%9.1lf%% " + "%10.1lf%% " + "%11.1lf%%", + 100.0 * (m_cpu_user + m_cpu_nice) / all, + 100.0 * m_cpu_sys / all, + 100.0 * m_cpu_idle /all, + 100.0 * m_cpu_iow / all); + } } static void screen_percpu_irqs_rel_one(WINDOW *screen, const struct ifstat *rel, @@ -875,6 +919,31 @@ static void screen_percpu_irqs_rel(WINDOW *screen, const struct ifstat *rel, "%17.1Lf " "%17.1Lf", max_padd, "", avg->irqs_rel, avg->irqs_srx_rel, avg->irqs_stx_rel); + + if (show_median) { + long double m_irqs, m_irqs_srx, m_irqs_stx; + + i = cpu_hits[cpus / 2].idx; + if (cpus % 2 == 0) { + /* take the mean of the 2 middle entries */ + int j = cpu_hits[(cpus / 2) - 1].idx; + + MEDIAN_EVEN(irqs); + MEDIAN_EVEN(irqs_srx); + MEDIAN_EVEN(irqs_stx); + } else { + /* take the middle entry as is */ + MEDIAN_ODD(irqs); + MEDIAN_ODD(irqs_srx); + MEDIAN_ODD(irqs_stx); + } + + mvwprintw(screen, (*voff)++, 2, + "med:%*s%17.1Lf " + "%17.1Lf " + "%17.1Lf", max_padd, "", + m_irqs, m_irqs_srx, m_irqs_stx); + } } static void screen_percpu_irqs_abs_one(WINDOW *screen, const struct ifstat *abs, @@ -908,6 +977,24 @@ static void screen_percpu_irqs_abs(WINDOW *screen, const struct ifstat *abs, mvwprintw(screen, (*voff)++, 2, "avg:%*s%17.1Lf", max_padd, "", avg->irqs_abs); + + if (show_median) { + long double m_irqs; + + i = cpu_hits[cpus / 2].idx; + if (cpus % 2 == 0) { + /* take the mean of the 2 middle entries */ + int j = cpu_hits[(cpus / 2) - 1].idx; + + m_irqs = (abs->irqs[i] + abs->irqs[j]) / 2; + } else { + /* take the middle entry as is */ + m_irqs = abs->irqs[i]; + } + + mvwprintw(screen, (*voff)++, 2, + "med:%*s%17.1Lf", max_padd, "", m_irqs); + } } static void screen_wireless(WINDOW *screen, const struct ifstat *rel, @@ -1225,6 +1312,9 @@ int main(int argc, char **argv) case 'p': promisc = 1; break; + case 'm': + show_median = 1; + break; case 'c': func_main = term_main; break; -- cgit v1.2.3-54-g00ecf