<div dir="ltr">Hi Zbigniew,<div><br></div><div>Thank you very much for reviewing. Please find my comments below.<br><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Apr 1, 2013 at 6:19 AM, Zbigniew Jędrzejewski-Szmek <span dir="ltr"><<a href="mailto:zbyszek@in.waw.pl" target="_blank">zbyszek@in.waw.pl</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Sun, Mar 31, 2013 at 08:22:05PM +0200, Umut Tezduyar wrote:<br>
> ---<br>
> src/cgtop/cgtop.c | 108 ++++++++++++++++++++++++++++++++++++-----------------<br>
> 1 files changed, 74 insertions(+), 34 deletions(-)<br>
><br>
> diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c<br>
> index eebebf0..0ef4fcc 100644<br>
> --- a/src/cgtop/cgtop.c<br>
> +++ b/src/cgtop/cgtop.c<br>
> @@ -69,6 +69,11 @@ static enum {<br>
> ORDER_IO<br>
> } arg_order = ORDER_CPU;<br>
><br>
> +static enum {<br>
> + CPU_PERCENT,<br>
> + CPU_TIME,<br>
> +} arg_cpu_type = CPU_PERCENT;<br>
> +<br>
> static void group_free(Group *g) {<br>
> assert(g);<br>
><br>
> @@ -372,16 +377,22 @@ static int group_compare(const void*a, const void *b) {<br>
> return 1;<br>
><br>
> if (arg_order == ORDER_CPU) {<br>
> - if (x->cpu_valid && y->cpu_valid) {<br>
> -<br>
> - if (x->cpu_fraction > y->cpu_fraction)<br>
> + if (arg_cpu_type == CPU_PERCENT) {<br>
> + if (x->cpu_valid && y->cpu_valid) {<br>
> + if (x->cpu_fraction > y->cpu_fraction)<br>
> + return -1;<br>
> + else if (x->cpu_fraction < y->cpu_fraction)<br>
> + return 1;<br>
> + } else if (x->cpu_valid)<br>
> return -1;<br>
> - else if (x->cpu_fraction < y->cpu_fraction)<br>
> + else if (y->cpu_valid)<br>
> return 1;<br>
> - } else if (x->cpu_valid)<br>
> - return -1;<br>
> - else if (y->cpu_valid)<br>
> - return 1;<br>
> + } else {<br>
> + if (x->cpu_usage > y->cpu_usage)<br>
> + return -1;<br>
> + else if (x->cpu_usage < y->cpu_usage)<br>
> + return 1;<br>
> + }<br>
> }<br>
><br>
> if (arg_order == ORDER_TASKS) {<br>
> @@ -428,13 +439,16 @@ static int display(Hashmap *a) {<br>
> Iterator i;<br>
> Group *g;<br>
> Group **array;<br>
> - unsigned rows, path_columns, n = 0, j;<br>
> + signed path_columns;<br>
> + unsigned rows, n = 0, j, maxtcpu = 0, maxtpath = 0;<br>
> + char cpu_title[21];<br>
><br>
> assert(a);<br>
><br>
> /* Set cursor to top left corner and clear screen */<br>
> - fputs("\033[H"<br>
> - "\033[2J", stdout);<br>
> + if (on_tty())<br>
> + fputs("\033[H"<br>
> + "\033[2J", stdout);<br>
><br>
> array = alloca(sizeof(Group*) * hashmap_size(a));<br>
><br>
> @@ -444,33 +458,50 @@ static int display(Hashmap *a) {<br>
><br>
> qsort(array, n, sizeof(Group*), group_compare);<br>
><br>
> + /* Find longest names in one run */<br>
> + for (j = 0; j < n; j++) {<br>
> + snprintf(cpu_title, sizeof(cpu_title), "%llu", array[j]->cpu_usage);<br>
> + if (strlen(cpu_title) > maxtcpu)<br>
> + maxtcpu = strlen(cpu_title);<br>
> + if (strlen(array[j]->path) > maxtpath)<br>
> + maxtpath = strlen(array[j]->path);<br>
</div></div>The compiler *might* be smart enough, but let's not depend on that.<br>
strlen() result should be cached. Maybe just use MAX?<br></blockquote><div style>Umut: Sounds reasonable. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
> + }<br>
> +<br>
> + if (arg_cpu_type == CPU_PERCENT)<br>
> + snprintf(cpu_title, sizeof(cpu_title), "%6s", "%CPU");<br>
> + else<br>
> + snprintf(cpu_title, sizeof(cpu_title), "%*s", maxtcpu, "CPU Time");<br>
> +<br>
> rows = lines();<br>
> if (rows <= 10)<br>
> rows = 10;<br>
><br>
> - path_columns = columns() - 42;<br>
> - if (path_columns < 10)<br>
> - path_columns = 10;<br>
> -<br>
> - printf("%s%-*s%s %s%7s%s %s%6s%s %s%8s%s %s%8s%s %s%8s%s\n\n",<br>
> - arg_order == ORDER_PATH ? ANSI_HIGHLIGHT_ON : "", path_columns, "Path",<br>
> - arg_order == ORDER_PATH ? ANSI_HIGHLIGHT_OFF : "",<br>
> - arg_order == ORDER_TASKS ? ANSI_HIGHLIGHT_ON : "", "Tasks",<br>
> - arg_order == ORDER_TASKS ? ANSI_HIGHLIGHT_OFF : "",<br>
> - arg_order == ORDER_CPU ? ANSI_HIGHLIGHT_ON : "", "%CPU",<br>
> - arg_order == ORDER_CPU ? ANSI_HIGHLIGHT_OFF : "",<br>
> - arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_ON : "", "Memory",<br>
> - arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_OFF : "",<br>
> - arg_order == ORDER_IO ? ANSI_HIGHLIGHT_ON : "", "Input/s",<br>
> - arg_order == ORDER_IO ? ANSI_HIGHLIGHT_OFF : "",<br>
> - arg_order == ORDER_IO ? ANSI_HIGHLIGHT_ON : "", "Output/s",<br>
> - arg_order == ORDER_IO ? ANSI_HIGHLIGHT_OFF : "");<br>
> + if (on_tty()) {<br>
> + path_columns = columns() - 36 - strlen(cpu_title);<br>
> + if (path_columns < 10)<br>
> + path_columns = 10;<br>
> + } else<br>
> + path_columns = maxtpath;<br>
> +<br>
> + printf("%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s\n\n",<br>
> + on_tty() && arg_order == ORDER_PATH ? ANSI_HIGHLIGHT_ON : "", path_columns, "Path",<br>
> + on_tty() && arg_order == ORDER_PATH ? ANSI_HIGHLIGHT_OFF : "",<br>
> + on_tty() && arg_order == ORDER_TASKS ? ANSI_HIGHLIGHT_ON : "", "Tasks",<br>
> + on_tty() && arg_order == ORDER_TASKS ? ANSI_HIGHLIGHT_OFF : "",<br>
> + on_tty() && arg_order == ORDER_CPU ? ANSI_HIGHLIGHT_ON : "", cpu_title,<br>
> + on_tty() && arg_order == ORDER_CPU ? ANSI_HIGHLIGHT_OFF : "",<br>
> + on_tty() && arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_ON : "", "Memory",<br>
> + on_tty() && arg_order == ORDER_MEMORY ? ANSI_HIGHLIGHT_OFF : "",<br>
> + on_tty() && arg_order == ORDER_IO ? ANSI_HIGHLIGHT_ON : "", "Input/s",<br>
> + on_tty() && arg_order == ORDER_IO ? ANSI_HIGHLIGHT_OFF : "",<br>
> + on_tty() && arg_order == ORDER_IO ? ANSI_HIGHLIGHT_ON : "", "Output/s",<br>
> + on_tty() && arg_order == ORDER_IO ? ANSI_HIGHLIGHT_OFF : "");<br>
</div></div>What about defining<br>
const char *on = on_tty() ? ANSI_HIGHLIGHT_ON : "", *off = on_tty() ? ANSI_HIGHLIGHT_OFF : "",<br>
to make this easier to read?<br></blockquote><div style>Umut: I agree. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
><br>
> for (j = 0; j < n; j++) {<br>
> char *p;<br>
> char m[FORMAT_BYTES_MAX];<br>
><br>
> - if (j + 5 > rows)<br>
> + if (on_tty() && j + 5 > rows)<br>
> break;<br>
><br>
> g = array[j];<br>
> @@ -484,10 +515,13 @@ static int display(Hashmap *a) {<br>
> else<br>
> fputs(" -", stdout);<br>
><br>
> - if (g->cpu_valid)<br>
> - printf(" %6.1f", g->cpu_fraction*100);<br>
> + if (arg_cpu_type == CPU_PERCENT)<br>
> + if (g->cpu_valid)<br>
> + printf(" %6.1f", g->cpu_fraction*100);<br>
> + else<br>
> + fputs(" -", stdout);<br>
> else<br>
> - fputs(" -", stdout);<br>
> + printf(" %*llu", maxtcpu, g->cpu_usage);<br>
><br>
> if (g->memory_valid)<br>
> printf(" %8s", format_bytes(m, sizeof(m), g->memory));<br>
> @@ -519,6 +553,7 @@ static void help(void) {<br>
> " -c Order by CPU load\n"<br>
> " -m Order by memory load\n"<br>
> " -i Order by IO load\n"<br>
> + " --cpu=TYPE time or percentage (default) as CPU type\n"<br>
> " -d --delay=DELAY Specify delay\n"<br>
> " -n --iterations=N Run for N iterations before exiting\n"<br>
> " -b --batch Run in batch mode, accepting no input\n"<br>
> @@ -535,6 +570,7 @@ static int parse_argv(int argc, char *argv[]) {<br>
> enum {<br>
> ARG_VERSION = 0x100,<br>
> ARG_DEPTH,<br>
> + ARG_CPU_TYPE<br>
> };<br>
><br>
> static const struct option options[] = {<br>
> @@ -544,6 +580,7 @@ static int parse_argv(int argc, char *argv[]) {<br>
> { "iterations", required_argument, NULL, 'n' },<br>
> { "batch", no_argument, NULL, 'b' },<br>
> { "depth", required_argument, NULL, ARG_DEPTH },<br>
> + { "cpu", required_argument, NULL, ARG_CPU_TYPE},<br>
</div></div>I think this should be optional_argument.<br></blockquote><div style>Umut: Didn't quite understand this. Please explain why you think it should be optional? </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im"><br>
> { NULL, 0, NULL, 0 }<br>
> };<br>
><br>
> @@ -565,6 +602,11 @@ static int parse_argv(int argc, char *argv[]) {<br>
> version();<br>
> return 0;<br>
><br>
> + case ARG_CPU_TYPE:<br>
> + if (strcmp(optarg, "time") == 0)<br>
> + arg_cpu_type = CPU_TIME;<br>
> + break;<br>
</div>This should check for errors, especially that we want cgtop to be<br>
scriptable. So an unsupported type should result in an error.<br></blockquote><div style>Umut: I will add the type limitation. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="im"><br>
> case ARG_DEPTH:<br>
> r = safe_atou(optarg, &arg_depth);<br>
> if (r < 0) {<br>
> @@ -777,8 +819,6 @@ int main(int argc, char *argv[]) {<br>
> }<br>
> }<br>
><br>
> - log_info("Exiting.");<br>
> -<br>
> r = 0;<br>
</div>I thought that it was supposed to break off after one loop, if !on_tty().<br>
It seems to loop. Also, for me is still prints too much headers:<br></blockquote><div style>Umut: I thought not to put a 1 loop limitation when not on tty. Someone might want to record data over a period of time. Thats why I kept the limit. I have also noticed the repeating column headers but the reason why I kept them was, to provide a splitter between consecutive data output. If the consensus is only printing them once, I will fix it.</div>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
$ systemd-cgtop|cat<br>
Path Tasks %CPU Memory Input/s Output/s<br>
<br>
/ 395 18.8 2.7G - -<br>
...<br>
<br>
I guess that you might be developing on 32 bits. Please put something like<br>
this on top:<br></blockquote><div style>Umut: I am indeed on 32 bit. I will use the format modifiers from stdint. </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
diff --git src/cgtop/cgtop.c src/cgtop/cgtop.c<br>
index 0ef4fcc..9f7ffd6 100644<br>
--- src/cgtop/cgtop.c<br>
+++ src/cgtop/cgtop.c<br>
@@ -19,9 +19,11 @@<br>
along with systemd; If not, see <<a href="http://www.gnu.org/licenses/" target="_blank">http://www.gnu.org/licenses/</a>>.<br>
***/<br>
<br>
+#define __STDC_FORMAT_MACROS<br>
#include <errno.h><br>
#include <string.h><br>
#include <stdlib.h><br>
+#include <stdint.h><br>
#include <unistd.h><br>
#include <alloca.h><br>
#include <getopt.h><br>
@@ -460,7 +462,7 @@ static int display(Hashmap *a) {<br>
<div class="im"><br>
/* Find longest names in one run */<br>
</div><div class="im"> for (j = 0; j < n; j++) {<br>
- snprintf(cpu_title, sizeof(cpu_title), "%llu", array[j]->cpu_usage);<br>
</div>+ snprintf(cpu_title, sizeof(cpu_title), "%"PRIu64, array[j]->cpu_usage);<br>
if (strlen(cpu_title) > maxtcpu)<br>
maxtcpu = strlen(cpu_title);<br>
<div class="im"> if (strlen(array[j]->path) > maxtpath)<br>
</div>@@ -521,7 +523,7 @@ static int display(Hashmap *a) {<br>
<div class="im"> else<br>
fputs(" -", stdout);<br>
</div> else<br>
<div class="im">- printf(" %*llu", maxtcpu, g->cpu_usage);<br>
</div>+ printf(" %*"PRIu64, maxtcpu, g->cpu_usage);<br>
<div class="im"><br>
if (g->memory_valid)<br>
printf(" %8s", format_bytes(m, sizeof(m), g->memory));<br>
<br>
</div>HTH,<br>
Zbyszek<br>
</blockquote></div><br></div></div></div>