top: add graphs modes for cpu and memory, program code

This patch makes 't' (View_STATES) & 'm' (View_MEMORY)
commands into 4-way toggles. The two new modes provide
for two different graphs of the cpu and/or memory use.

These new capabilities are similar to those offered by
the 'htop' program. However they're aesthetically more
pleasing (to me) plus the scalings are more authentic.

Poor ol' top has long been troubled by the comparisons
offered up by the 'htop' program. Many of those things
were only true of the original redhat top while others
are no longer true of this current top program. So let
me use this commit msg to begin to correct the record.

Corrected comparisons between 'htop' & 'top' programs:
------------------------------------------------------
+ htop does not start faster, actually reverse is true
+ top offers scrolling vertically and horizontally too
. (and top offers better <Home> and <End> key support)
+ unassigned keystrokes don't subject top to any delay
. (but htop suffers that annoying ncurses <Esc> delay)
+ in top one need not type the PID to kill the process
+ in top one need not type the PID to renice a process

Some things the 'htop' program was not bragging about:
------------------------------------------------------
+ top can outperform the htop program by a wide margin
+ htop + SIGWINCH = corrupted display + restart likely
+ htop cannot preserve its screen data at suspend/exit
+ the htop column management scheme is very cumbersome
+ htop allows columns to be duplicated again and again
+ htop displays only full command lines, not pgm names
. (and that 'Command' column must always be displayed)
. (and it must always remain as the last column shown)
+ htop does not provide for any sort of command recall
+ htop's search feature does not highlight any matches
+ there is no 'find next' outside of htop search modes
+ htop does not allow Header or Process memory scaling
+ htop provides no flexibility on column justification
+ htop does not provide the means to change col widths
+ htop provides less control over colors configuration
+ htop always overwrites the rcfile with any UI change

Someday, maybe we'll provide a better comparison as an
addendum for (or replacement of) that README.top file.

Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2014-06-18 00:00:00 -05:00 committed by Craig Small
parent 318919094d
commit 1d171ec741
2 changed files with 95 additions and 24 deletions

View File

@ -235,6 +235,11 @@ static int (*Numa_max_node)(void);
static int (*Numa_node_of_cpu)(int num);
#endif
#endif
/* Support for Graphing of the View_STATES ('t') and View_MEMORY ('m')
commands -- which are now both 4-way toggles */
static const char Graph_blks[] = " ";
static const char Graph_bars[] = "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||";
/*###### Sort callbacks ################################################*/
@ -3423,7 +3428,8 @@ static int config_cvt (WIN_t *q) {
* line a: contains w->winname, fieldscur
* line b: contains w->winflags, sortindx, maxtasks
* line c: contains w->summclr, msgsclr, headclr, taskclr
* line 15 : Fixed_widest, Summ_mscale, Task_mscale, Zero_suppress */
* line 15 : miscellaneous additional global settings
* Any remaining lines are devoted to the 'Inspect Other' feature */
static void configs_read (void) {
float tmp_delay = DEF_DELAY;
char fbuf[LRGBUFSIZ];
@ -3505,8 +3511,9 @@ static void configs_read (void) {
} // end: for (GROUPSMAX)
// any new addition(s) last, for older rcfiles compatibility...
if (fscanf(fp, "Fixed_widest=%d, Summ_mscale=%d, Task_mscale=%d, Zero_suppress=%d\n"
, &Rc.fixed_widest, &Rc.summ_mscale, &Rc.task_mscale, &Rc.zero_suppress))
if (fscanf(fp, "Fixed_widest=%d, Summ_mscale=%d, Task_mscale=%d, Zero_suppress=%d, Graph_cpus=%d, Graph_mems=%d\n"
, &Rc.fixed_widest, &Rc.summ_mscale, &Rc.task_mscale, &Rc.zero_suppress
, &Rc.graph_cpus, &Rc.graph_mems))
; // avoid -Wunused-result
try_inspect_entries:
@ -4317,8 +4324,9 @@ static void write_rcfile (void) {
}
// any new addition(s) last, for older rcfiles compatibility...
fprintf(fp, "Fixed_widest=%d, Summ_mscale=%d, Task_mscale=%d, Zero_suppress=%d\n"
, Rc.fixed_widest, Rc.summ_mscale, Rc.task_mscale, Rc.zero_suppress);
fprintf(fp, "Fixed_widest=%d, Summ_mscale=%d, Task_mscale=%d, Zero_suppress=%d, Graph_cpus=%d, Graph_mems=%d\n"
, Rc.fixed_widest, Rc.summ_mscale, Rc.task_mscale, Rc.zero_suppress
, Rc.graph_cpus, Rc.graph_mems);
if (Inspect.raw)
fputs(Inspect.raw, fp);
@ -4500,10 +4508,20 @@ static void keys_summary (int ch) {
TOGw(w, View_LOADAV);
break;
case 'm':
TOGw(w, View_MEMORY);
if (!CHKw(w, View_MEMORY))
SETw(w, View_MEMORY);
else if (++Rc.graph_mems > 2) {
Rc.graph_mems = 0;;
OFFw(w, View_MEMORY);
}
break;
case 't':
TOGw(w, View_STATES);
if (!CHKw(w, View_STATES))
SETw(w, View_STATES);
else if (++Rc.graph_cpus > 2) {
Rc.graph_cpus = 0;;
OFFw(w, View_STATES);
}
break;
default: // keep gcc happy
break;
@ -5038,11 +5056,33 @@ static void summary_hlp (CPU_t *cpu, const char *pfx) {
/* display some kinda' cpu state percentages
(who or what is explained by the passed prefix) */
if (Rc.graph_cpus) {
static struct {
const char *user; const char *syst; const char *type;
} gtab[] = {
{ "%-.*s~7", "%-.*s~8", Graph_bars },
{ "%-.*s~4", "%-.*s~6", Graph_blks }
};
char graph_user[SMLBUFSIZ], graph_syst[SMLBUFSIZ], graph_dual[MEDBUFSIZ];
int ix = Rc.graph_cpus - 1;
float percent_user = (float)(u_frme + n_frme) * scale,
percent_syst = (float)s_frme * scale;
snprintf(graph_user, sizeof(graph_user), gtab[ix].user, (int)(percent_user + .5), gtab[ix].type);
snprintf(graph_syst, sizeof(graph_syst), gtab[ix].syst, (int)(percent_syst + .5), gtab[ix].type);
snprintf(graph_dual, sizeof(graph_dual), "%s%s", graph_user, graph_syst);
#ifdef GRAPHS_ALIGN
show_special(0, fmtmk("%%%s ~3%#5.1f~2/%-#8.1f~3 [~1%-104.104s]~1\n"
#else
show_special(0, fmtmk("%%%s ~3%#5.1f~2/%-#5.1f~3 [~1%-104.104s]~1\n"
#endif
, pfx, percent_user, percent_syst, graph_dual));
} else {
show_special(0, fmtmk(Cpu_States_fmts, pfx
, (float)u_frme * scale, (float)s_frme * scale
, (float)n_frme * scale, (float)i_frme * scale
, (float)w_frme * scale, (float)x_frme * scale
, (float)y_frme * scale, (float)z_frme * scale));
}
#undef TRIMz
} // end: summary_hlp
@ -5147,7 +5187,7 @@ numa_nope:
const char *fmts;
const char *label;
} scaletab[] = {
{ 1, "%8.0f ", NULL }, // kibibytes
{ 1, "%1.0f ", NULL }, // kibibytes
{ 1024.0, "%#4.3f ", NULL }, // mebibytes
{ 1024.0*1024, "%#4.3f ", NULL }, // gibibytes
{ 1024.0*1024*1024, "%#4.3f ", NULL }, // tebibytes
@ -5171,15 +5211,43 @@ numa_nope:
}
kb_main_my_used = kb_main_used - kb_main_buffers - kb_main_cached;
if (Rc.graph_mems) {
static struct {
const char *used; const char *misc; const char *swap; const char *type;
} gtab[] = {
{ "%-.*s~7", "%-.*s~8", "%-.*s~8", Graph_bars },
{ "%-.*s~4", "%-.*s~6", "%-.*s~6", Graph_blks }
};
char graph_used[SMLBUFSIZ], graph_util[SMLBUFSIZ], graph_dual[MEDBUFSIZ];
int ix = Rc.graph_mems - 1;
float percent_used = (float)kb_main_my_used * (100.0 / (float)kb_main_total),
percent_misc = (float)(kb_main_buffers + kb_main_cached) * (100.0 / (float)kb_main_total),
percent_swap = (float)kb_swap_used * (100.0 / (float)kb_swap_total);
snprintf(graph_used, sizeof(graph_used), gtab[ix].used, (int)(percent_used + .5), gtab[ix].type);
snprintf(graph_util, sizeof(graph_util), gtab[ix].misc, (int)(percent_misc + .5), gtab[ix].type);
snprintf(graph_dual, sizeof(graph_dual), "%s%s", graph_used, graph_util);
snprintf(graph_util, sizeof(graph_util), gtab[ix].swap, (int)(percent_swap + .5), gtab[ix].type);
prT(bfT(0), mkM(total)); prT(bfT(1), mkS(total));
show_special(0, fmtmk(
#ifdef GRAPHS_ALIGN
/* note: without this define, cpu and memory graphs can usually be aligned via scaling
(the 'E' command) and without any waisted space preceeding the cpu graphs */
"%s %s:~3%#5.1f~2/%-9.9s~3[~1%-104.104s]~1\n%s %s:~3%#5.1f~2/%-9.9s~3[~1%-102.102s]~1\n"
#else
"%s %s:~3%#5.1f~2/%-.9s~3[~1%-104.104s]~1\n%s %s:~3%#5.1f~2/%-.9s~3[~1%-102.102s]~1\n"
#endif
, scT(label), N_txt(WORD_abv_mem_txt), percent_used + percent_misc, bfT(0), graph_dual
, scT(label), N_txt(WORD_abv_swp_txt), percent_swap, bfT(1), graph_util));
} else {
prT(bfT(0), mkM(total)); prT(bfT(1), mkM(free));
prT(bfT(2), mkM(my_used)); prT(bfT(3), mkM(buffers));
prT(bfT(4), mkS(total)); prT(bfT(5), mkS(free));
prT(bfT(6), mkS(used)); prT(bfT(7), mkM(cached));
show_special(0, fmtmk(N_unq(MEMORY_lines_fmt)
, scT(label), N_txt(WORD_abv_mem_txt), bfT(0), bfT(1), bfT(2), bfT(3)
, scT(label), N_txt(WORD_abv_swp_txt), bfT(4), bfT(5), bfT(6), bfT(7)
, N_txt(WORD_abv_mem_txt)));
}
Msg_row += 2;
#undef bfT
#undef scT

View File

@ -36,6 +36,7 @@
//#define CASEUP_SUFIX /* show time/mem/cnts suffix in upper case */
//#define CPU_ZEROTICS /* tolerate few tics when cpu off vs. idle */
//#define EQUCOLHDRYES /* yes, do equalize column header lengths */
//#define GRAPHS_ALIGN /* force cpu & memory graphs to be aligned */
//#define INSP_JUSTNOT /* don't smooth unprintable right margins */
//#define INSP_OFFDEMO /* disable demo screens, issue msg instead */
//#define INSP_SAVEBUF /* preserve 'Insp_buf' contents in a file */
@ -208,7 +209,7 @@ enum pflag {
/* The scaling 'target' used with memory fields */
enum scale_enum {
SK_Kb, SK_Mb, SK_Gb, SK_Tb, SK_Pb, SK_Eb, SK_SENTINEL
SK_Kb, SK_Mb, SK_Gb, SK_Tb, SK_Pb, SK_Eb
};
/* Used to manipulate (and document) the Frames_signal states */
@ -366,6 +367,8 @@ typedef struct RCF_t {
int summ_mscale; // 'E' - scaling of summary memory values
int task_mscale; // 'e' - scaling of process memory values
int zero_suppress; // '0' - suppress scaled zeros toggle
int graph_cpus; // 't' - View_STATES supplementary values
int graph_mems; // 'm' - View_MEMORY supplememtary values
} RCF_t;
/* This structure stores configurable information for each window.
@ -610,7 +613,7 @@ typedef struct WIN_t {
{ EU_UEN, DEF_WINFLGS, 0, \
COLOR_YELLOW, COLOR_YELLOW, COLOR_GREEN, COLOR_YELLOW, \
"Usr", USR_FIELDS } \
}, 0, SK_Kb, SK_Kb, 0 }
}, 0, SK_Kb, SK_Kb, 0, 0, 0 }
/* Summary Lines specially formatted string(s) --
see 'show_special' for syntax details + other cautions. */