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!");