From a2c9f63136775b128bdb9fb3e1b57f5ad977d5cb Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Fri, 22 May 2015 16:20:49 -0500 Subject: [PATCH 1/4] cgtop: raw output option (disable conversion to human-readable units) --- man/systemd-cgtop.xml | 9 +++++++++ src/cgtop/cgtop.c | 34 +++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/man/systemd-cgtop.xml b/man/systemd-cgtop.xml index b0c88001d4..b3298b64f3 100644 --- a/man/systemd-cgtop.xml +++ b/man/systemd-cgtop.xml @@ -142,6 +142,15 @@ file. + + + + + Format byte counts (as in memory usage and IO metrics) + with raw numeric values rather than human-readable + numbers. + + diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index a390cf3256..8c58cd2c04 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -62,6 +62,7 @@ typedef struct Group { static unsigned arg_depth = 3; static unsigned arg_iterations = 0; static bool arg_batch = false; +static bool arg_raw = false; static usec_t arg_delay = 1*USEC_PER_SEC; static enum { @@ -96,6 +97,16 @@ static void group_hashmap_free(Hashmap *h) { hashmap_free(h); } +static const char *maybe_format_bytes(char *buf, size_t l, bool is_valid, off_t t) { + if (!is_valid) + return "-"; + if (arg_raw) { + snprintf(buf, l, "%jd", t); + return buf; + } + return format_bytes(buf, l, t); +} + static int process(const char *controller, const char *path, Hashmap *a, Hashmap *b, unsigned iteration) { Group *g; int r; @@ -532,18 +543,9 @@ static int display(Hashmap *a) { } else printf(" %*s", maxtcpu, format_timespan(buffer, sizeof(buffer), (nsec_t) (g->cpu_usage / NSEC_PER_USEC), 0)); - if (g->memory_valid) - printf(" %8s", format_bytes(buffer, sizeof(buffer), g->memory)); - else - fputs(" -", stdout); - - if (g->io_valid) { - printf(" %8s", - format_bytes(buffer, sizeof(buffer), g->io_input_bps)); - printf(" %8s", - format_bytes(buffer, sizeof(buffer), g->io_output_bps)); - } else - fputs(" - -", stdout); + printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->memory_valid, g->memory)); + printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_input_bps)); + printf(" %8s", maybe_format_bytes(buffer, sizeof(buffer), g->io_valid, g->io_output_bps)); putchar('\n'); } @@ -561,6 +563,7 @@ static void help(void) { " -c Order by CPU load\n" " -m Order by memory load\n" " -i Order by IO load\n" + " -r --raw Provide raw (not human-readable) numbers\n" " --cpu[=TYPE] Show CPU usage as time or percentage (default)\n" " -d --delay=DELAY Delay between updates\n" " -n --iterations=N Run for N iterations before exiting\n" @@ -583,6 +586,7 @@ static int parse_argv(int argc, char *argv[]) { { "delay", required_argument, NULL, 'd' }, { "iterations", required_argument, NULL, 'n' }, { "batch", no_argument, NULL, 'b' }, + { "raw", no_argument, NULL, 'r' }, { "depth", required_argument, NULL, ARG_DEPTH }, { "cpu", optional_argument, NULL, ARG_CPU_TYPE}, {} @@ -594,7 +598,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 1); assert(argv); - while ((c = getopt_long(argc, argv, "hptcmin:bd:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hptcmin:brd:", options, NULL)) >= 0) switch (c) { @@ -649,6 +653,10 @@ static int parse_argv(int argc, char *argv[]) { arg_batch = true; break; + case 'r': + arg_raw = true; + break; + case 'p': arg_order = ORDER_PATH; break; From 780fe62ecab08850cefd136b95f38c15cb31c0ec Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Fri, 22 May 2015 22:18:15 -0500 Subject: [PATCH 2/4] cgtop: allow user to force looping behavior even in non-TTY mode --- man/systemd-cgtop.xml | 14 ++++++++------ src/cgtop/cgtop.c | 6 +++--- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/man/systemd-cgtop.xml b/man/systemd-cgtop.xml index b3298b64f3..d14564480d 100644 --- a/man/systemd-cgtop.xml +++ b/man/systemd-cgtop.xml @@ -65,10 +65,12 @@ groups of the local Linux control group hierarchy, ordered by their CPU, memory, or disk I/O load. The display is refreshed in regular intervals (by default every 1s), similar in style to - top1. - If systemd-cgtop is not connected to a tty, - only one iteration is performed and no columns headers are - printed. This mode is suitable for scripting. + top1. + + If systemd-cgtop is not connected to a tty, no + column headers are printed and the default is to only run one iteration. + The --iterations argument, if given, is still honored. + This mode is suitable for scripting. Resource usage is only accounted for control groups in the relevant hierarchy, i.e. CPU usage is only accounted for control @@ -155,8 +157,8 @@ - Perform only this many iterations. - + Perform only this many iterations. A value of 0 + indicates that the program should run indefinitely. diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 8c58cd2c04..d04d6f225c 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -60,7 +60,7 @@ typedef struct Group { } Group; static unsigned arg_depth = 3; -static unsigned arg_iterations = 0; +static unsigned arg_iterations = (unsigned)-1; static bool arg_batch = false; static bool arg_raw = false; static usec_t arg_delay = 1*USEC_PER_SEC; @@ -715,8 +715,8 @@ int main(int argc, char *argv[]) { signal(SIGWINCH, columns_lines_cache_reset); - if (!on_tty()) - arg_iterations = 1; + if (arg_iterations == (unsigned)-1) + arg_iterations = on_tty() ? 0 : 1; while (!quit) { Hashmap *c; From dcc7aacd67505b812214058dc9a8d321d8d98c7c Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Wed, 27 May 2015 17:30:11 -0500 Subject: [PATCH 3/4] cgtop: more sensible flushing behavior w/ non-TTY output - Explicitly flush stdout before sleep between iterations - Only clear user keystrokes when output is to TTY - Add a newline between output batches when output is not to TTY --- src/cgtop/cgtop.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index d04d6f225c..3a2842dac6 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -749,6 +749,10 @@ int main(int argc, char *argv[]) { if (arg_iterations && iteration >= arg_iterations) break; + if (!on_tty()) /* non-TTY: Empty newline as delimiter between polls */ + fputs("\n", stdout); + fflush(stdout); + if (arg_batch) { usleep(last_refresh + arg_delay - t); } else { @@ -762,8 +766,10 @@ int main(int argc, char *argv[]) { } } - fputs("\r \r", stdout); - fflush(stdout); + if (on_tty()) { /* TTY: Clear any user keystroke */ + fputs("\r \r", stdout); + fflush(stdout); + } if (arg_batch) continue; From 1d84ae050cb1eb6bfbcd17a10de4e5804fdd4722 Mon Sep 17 00:00:00 2001 From: Charles Duffy Date: Tue, 2 Jun 2015 17:38:49 -0500 Subject: [PATCH 4/4] cgtop: IO readings are valid if any data is available, even if unchanged since last tick Emit "0" rather than "-" if no change in IO values are seen for a process since last tick, so long as accounting has registered content at all. --- src/cgtop/cgtop.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index 3a2842dac6..d630e35882 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -281,11 +281,10 @@ static int process(const char *controller, const char *path, Hashmap *a, Hashmap yr = rd - g->io_input; yw = wr - g->io_output; - if (yr > 0 || yw > 0) { + if (g->io_input > 0 || g->io_output > 0) { g->io_input_bps = (yr * 1000000000ULL) / x; g->io_output_bps = (yw * 1000000000ULL) / x; g->io_valid = true; - } }