summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ifpps.87
-rw-r--r--ifpps.c92
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;