Hi, On Mon, Apr 13, 2020 at 07:18:34PM +0100, Stuart Henderson wrote: > It would make better use of the screen space if it worked like systat vm - > multiple characters | (interrupt), @ (spin), = (sys), > (user) ... this fits > a lot more information into the same space than just using a single char to > represent any type of cpu use.
Ah, gotcha. Here's what I've done: - Use different symbols for different CPU states, like systat(1) does. - Made "combined" mode work. In doing so, put the code that draws the bars into a function. - There are now some long lines that are hard to wrap. I was tempted to factor out the code that writes the textual CPU states into its own function, as that'd reduce nesting and duplication. However, I've refrained fow now. Example output (with system under load -- compiling LLVM): ``` load averages: 5.49, 5.35, 5.06 arrakis.home 21:04:53 153 processes: 6 running, 142 idle, 1 dead, 4 on processor up 2 days, 7:49 CPU0: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@============================>>>>>>>>>>> CPU1: @@@@@@@@@@@@@@@@@@@@@@@============================>>>>>>>>>>>>>>>> CPU2: @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@========>>>>>>>>>>>>>>>>>>> CPU3: @@@@@@@@@@@@@@@@@====================================>>>>>>>>>>>>>>> Memory: Real: 2972M/16G act/tot Free: 7053M Cache: 11G Swap: 0K/1028M PID USERNAME PRI NICE SIZE RES STATE WAIT TIME CPU COMMAND ... ``` Diff follows, thanks. Index: display.c =================================================================== RCS file: /cvs/src/usr.bin/top/display.c,v retrieving revision 1.61 diff -u -p -r1.61 display.c --- display.c 27 Oct 2019 13:52:26 -0000 1.61 +++ display.c 14 Apr 2020 19:55:33 -0000 @@ -106,6 +106,11 @@ extern struct process_select ps; int header_status = true; +/* stuff for graphical display of CPU utilisation */ +int cpu_bars = false; +static char cpubar_chars[] = { '|', '@', '=', '>' }; +static char cpubar_order[] = { CP_INTR, CP_SPIN, CP_SYS, CP_USER }; + static int empty(void) { @@ -376,6 +381,30 @@ cpustates_tag(int cpu) } void +draw_cpubar(long long states[], int width, int num_cpus) +{ +#define NUM_CPUBAR_CHARS(V, NCPUS, PP) V / NCPUS / 10 * PP + int i, st, num_chars; + double pperc; + + width = width < 0 ? 0 : width; + pperc = width / 100.0; /* characters per-percent */ + + for (i = 0; i < sizeof(cpubar_order) / sizeof(cpubar_order[0]); i++) { + st = cpubar_order[i]; + num_chars = NUM_CPUBAR_CHARS(states[st], num_cpus, pperc); + + /* CP_USER is merged with CP_NICE, like in systat(1) */ + if (st == CP_USER) + num_chars += NUM_CPUBAR_CHARS(states[CP_NICE], num_cpus, pperc); + + while (num_chars-- > 0) { + addch(cpubar_chars[i]); + } + } +} + +void i_cpustates(int64_t *ostates, int *online) { int i, first, cpu, cpu_line; @@ -384,7 +413,7 @@ i_cpustates(int64_t *ostates, int *onlin char **names, *thisname; if (combine_cpus) { - static double *values; + static long long *values; if (!values) { values = calloc(num_cpustates, sizeof(*values)); if (!values) @@ -412,14 +441,19 @@ i_cpustates(int64_t *ostates, int *onlin clrtoeol(); printwp("%-3d CPUs: ", ncpuonline); - while ((thisname = *names++) != NULL) { - if (*thisname != '\0') { - value = values[i++] / ncpuonline; - /* if percentage is >= 1000, print it as 100% */ - printwp((value >= 1000 ? "%s%4.0f%% %s" : - "%s%4.1f%% %s"), first++ == 0 ? "" : ", ", - value / 10., thisname); + if (!cpu_bars) { + while ((thisname = *names++) != NULL) { + if (*thisname != '\0') { + value = (double) values[i++] / ncpuonline; + /* if percentage is >= 1000, print it as 100% */ + printwp((value >= 1000 ? "%s%4.0f%% %s" : + "%s%4.1f%% %s"), first++ == 0 ? "" : ", ", + value / 10., thisname); + } } + } else { + /* "NNN CPUs: " is 10 characters */ + draw_cpubar(values, screen_width - 10, ncpuonline); } putn(); } @@ -438,18 +472,22 @@ i_cpustates(int64_t *ostates, int *onlin if (screen_length > 2 + cpu_line || !smart_terminal) { move(2 + cpu_line, 0); clrtoeol(); - addstrp(cpustates_tag(cpu)); - - while ((thisname = *names++) != NULL) { - if (*thisname != '\0') { - /* retrieve the value and remember it */ - value = *states++; - - /* if percentage is >= 1000, print it as 100% */ - printwp((value >= 1000 ? "%s%4.0f%% %s" : - "%s%4.1f%% %s"), first++ == 0 ? "" : ", ", - value / 10., thisname); + char *cputag = cpustates_tag(cpu); + addstrp(cputag); + if (!cpu_bars) { + while ((thisname = *names++) != NULL) { + if (*thisname != '\0') { + /* retrieve the value and remember it */ + value = *states++; + + /* if percentage is >= 1000, print it as 100% */ + printwp((value >= 1000 ? "%s%4.0f%% %s" : + "%s%4.1f%% %s"), first++ == 0 ? "" : ", ", + value / 10., thisname); + } } + } else { + draw_cpubar(states, screen_width - strlen(cputag), 1); } putn(); cpu_line++; Index: display.h =================================================================== RCS file: /cvs/src/usr.bin/top/display.h,v retrieving revision 1.15 diff -u -p -r1.15 display.h --- display.h 17 Nov 2018 23:10:08 -0000 1.15 +++ display.h 14 Apr 2020 19:55:33 -0000 @@ -40,6 +40,7 @@ void u_loadave(int, double *); void i_timeofday(time_t *); void i_procstates(int, int *, int); void u_procstates(int, int *); +void draw_cpubar(long long[], int, int); void i_cpustates(int64_t *, int *); void u_cpustates(int64_t *); void i_memory(int *); Index: top.1 =================================================================== RCS file: /cvs/src/usr.bin/top/top.1,v retrieving revision 1.73 diff -u -p -r1.73 top.1 --- top.1 7 Jan 2020 13:30:43 -0000 1.73 +++ top.1 14 Apr 2020 19:55:33 -0000 @@ -90,6 +90,8 @@ and .Ql ^\e ) still have an effect. This is the default on a dumb terminal, or when the output is not a terminal. +.It Fl B +Show CPU utilisation bars instead of CPU states. .It Fl C Show command line arguments as well as the process itself. @@ -295,6 +297,10 @@ Toggle the display of per CPU or combine Scroll up/down the process list by one line. .It \&( | \&) Scroll up/down the process list by screen half. +.It B +Toggle the display of CPU utilisation bars. +Bars are displayed in the same format as the vmstat view in +.Xr systat 1 . .It C Toggle the display of process command line arguments. .It d Ar count Index: top.c =================================================================== RCS file: /cvs/src/usr.bin/top/top.c,v retrieving revision 1.102 diff -u -p -r1.102 top.c --- top.c 6 Jan 2020 20:05:10 -0000 1.102 +++ top.c 14 Apr 2020 19:55:33 -0000 @@ -72,6 +72,7 @@ static int skip; /* how many processes extern int ncpu; extern int ncpuonline; +extern int cpu_bars; extern int (*proc_compares[])(const void *, const void *); int order_index; @@ -131,6 +132,7 @@ struct statics statics; #define CMD_up 25 #define CMD_pagedown 26 #define CMD_pageup 27 +#define CMD_bars 28 static void usage(void) @@ -212,11 +214,14 @@ parseargs(int ac, char **av) char *endp; int i; - while ((i = getopt(ac, av, "1SHICbinqus:d:p:U:o:g:")) != -1) { + while ((i = getopt(ac, av, "1SHICbinqus:d:p:U:o:g:B")) != -1) { switch (i) { case '1': combine_cpus = 1; break; + case 'B': + cpu_bars = true; + break; case 'C': show_args = true; break; @@ -632,7 +637,7 @@ rundisplay(void) char ch, *iptr; int change, i; struct pollfd pfd[1]; - static char command_chars[] = "\f qh?en#sdkriIuSopCHg+P109)("; + static char command_chars[] = "\f qh?en#sdkriIuSopCHg+P109)(B"; /* * assume valid command unless told @@ -995,6 +1000,9 @@ rundisplay(void) skip -= max_topn / 2; if (skip < 0) skip = 0; + break; + case CMD_bars: + cpu_bars = !cpu_bars; break; default: new_message(MT_standout, " BAD CASE IN SWITCH!"); -- Best Regards Edd Barrett http://www.theunixzoo.co.uk