Hi,

One thing I miss from our top(1) is the ability to see overall CPU
utilisation at a glance (I usually scan for the idle percentage and
invert it in my head).

This diff adds a way to toggle (using `B`) CPU utilisation bars, like this:

```
load averages:  0.92,  0.52,  1.26                          arrakis.home 
15:31:14
110 processes: 108 idle, 1 stopped, 1 on processor                up 1 day,  
2:15
[############################                                            ]  
37.1%
[#################################                                       ]  
45.0%
[################################                                        ]  
42.8%
[###################################                                     ]  
47.2%
Memory: Real: 4399M/12G act/tot Free: 11G Cache: 6204M Swap: 0K/1028M
```

The value reported is the inverse of the idle percentage and the bars
replace the 'user, nice, sys, ...' lines.

Can also be enabled from the command line with `-B`.

What do people think?

(I know htop from ports does utilisation bars, but I prefer pretty much
everything else about our in-base top.)


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   13 Apr 2020 14:43:10 -0000
@@ -105,6 +105,7 @@ extern int combine_cpus;
 extern struct process_select ps;
 
 int header_status = true;
+int cpu_bars = false;
 
 static int
 empty(void)
@@ -382,6 +383,13 @@ i_cpustates(int64_t *ostates, int *onlin
        double value;
        int64_t *states;
        char **names, *thisname;
+       char cpu_bar[MAX_COLS];
+       int hash_space = screen_width - 8; /* space for hash chars in bars */
+
+       /* this is used as an offset into cpu_bar and must never be negative */
+       if (hash_space < 0) {
+               hash_space = 0;
+       }
 
        if (combine_cpus) {
                static double *values;
@@ -438,18 +446,30 @@ 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);
+                       if (!cpu_bars) {
+                               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);
+                                       }
                                }
+                       } else {
+                               float idle_ratio = (states[5] >= 1000 ? 1000 : 
states[5]) / 1000.;
+                               int n_idle_chars = hash_space * idle_ratio;
+                               int n_busy_chars = hash_space - n_idle_chars;
+
+                               cpu_bar[0] = '[';
+                               memset(cpu_bar + 1, '#', n_busy_chars);
+                               memset(cpu_bar + 1 + n_busy_chars, ' ', 
n_idle_chars);
+                               snprintf(cpu_bar + hash_space, 9, "] %5.1f%%",
+                                   100 - idle_ratio * 100);
+                               printwp("%s", cpu_bar);
                        }
                        putn();
                        cpu_line++;
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       13 Apr 2020 14:43:10 -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,8 @@ 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.
 .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       13 Apr 2020 14:43:10 -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

Reply via email to